OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/extension_menu_manager.h" | 5 #include "chrome/browser/extensions/extension_menu_manager.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
| 9 #include "app/resource_bundle.h" |
9 #include "base/logging.h" | 10 #include "base/logging.h" |
10 #include "base/string_util.h" | 11 #include "base/string_util.h" |
11 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
12 #include "base/values.h" | 13 #include "base/values.h" |
13 #include "base/json/json_writer.h" | 14 #include "base/json/json_writer.h" |
14 #include "chrome/app/chrome_dll_resource.h" | 15 #include "chrome/app/chrome_dll_resource.h" |
15 #include "chrome/browser/extensions/extension_message_service.h" | 16 #include "chrome/browser/extensions/extension_message_service.h" |
16 #include "chrome/browser/extensions/extension_tabs_module.h" | 17 #include "chrome/browser/extensions/extension_tabs_module.h" |
17 #include "chrome/browser/profile.h" | 18 #include "chrome/browser/profile.h" |
18 #include "chrome/common/extensions/extension.h" | 19 #include "chrome/common/extensions/extension.h" |
| 20 #include "chrome/common/extensions/extension_resource.h" |
| 21 #include "gfx/favicon_size.h" |
| 22 #include "gfx/size.h" |
| 23 #include "grit/theme_resources.h" |
| 24 #include "skia/ext/image_operations.h" |
19 #include "webkit/glue/context_menu.h" | 25 #include "webkit/glue/context_menu.h" |
20 | 26 |
21 ExtensionMenuItem::ExtensionMenuItem(const std::string& extension_id, | 27 ExtensionMenuItem::ExtensionMenuItem(const std::string& extension_id, |
22 std::string title, | 28 std::string title, |
23 bool checked, Type type, | 29 bool checked, Type type, |
24 const ContextList& contexts, | 30 const ContextList& contexts, |
25 const ContextList& enabled_contexts) | 31 const ContextList& enabled_contexts) |
26 : extension_id_(extension_id), | 32 : extension_id_(extension_id), |
27 title_(title), | 33 title_(title), |
28 id_(0), | 34 id_(0), |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 return false; | 95 return false; |
90 checked_ = checked; | 96 checked_ = checked; |
91 return true; | 97 return true; |
92 } | 98 } |
93 | 99 |
94 void ExtensionMenuItem::AddChild(ExtensionMenuItem* item) { | 100 void ExtensionMenuItem::AddChild(ExtensionMenuItem* item) { |
95 item->parent_id_ = id_; | 101 item->parent_id_ = id_; |
96 children_.push_back(item); | 102 children_.push_back(item); |
97 } | 103 } |
98 | 104 |
99 ExtensionMenuManager::ExtensionMenuManager() : next_item_id_(1) { | 105 ExtensionMenuManager::ExtensionMenuManager() |
| 106 : next_item_id_(1), |
| 107 ALLOW_THIS_IN_INITIALIZER_LIST(image_tracker_(this)) { |
100 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, | 108 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, |
101 NotificationService::AllSources()); | 109 NotificationService::AllSources()); |
102 } | 110 } |
103 | 111 |
104 ExtensionMenuManager::~ExtensionMenuManager() { | 112 ExtensionMenuManager::~ExtensionMenuManager() { |
105 MenuItemMap::iterator i; | 113 MenuItemMap::iterator i; |
106 for (i = context_items_.begin(); i != context_items_.end(); ++i) { | 114 for (i = context_items_.begin(); i != context_items_.end(); ++i) { |
107 STLDeleteElements(&(i->second)); | 115 STLDeleteElements(&(i->second)); |
108 } | 116 } |
109 } | 117 } |
110 | 118 |
111 std::set<std::string> ExtensionMenuManager::ExtensionIds() { | 119 std::set<std::string> ExtensionMenuManager::ExtensionIds() { |
112 std::set<std::string> id_set; | 120 std::set<std::string> id_set; |
113 for (MenuItemMap::const_iterator i = context_items_.begin(); | 121 for (MenuItemMap::const_iterator i = context_items_.begin(); |
114 i != context_items_.end(); ++i) { | 122 i != context_items_.end(); ++i) { |
115 id_set.insert(i->first); | 123 id_set.insert(i->first); |
116 } | 124 } |
117 return id_set; | 125 return id_set; |
118 } | 126 } |
119 | 127 |
120 const ExtensionMenuItem::List* ExtensionMenuManager::MenuItems( | 128 const ExtensionMenuItem::List* ExtensionMenuManager::MenuItems( |
121 const std::string& extension_id) { | 129 const std::string& extension_id) { |
122 MenuItemMap::iterator i = context_items_.find(extension_id); | 130 MenuItemMap::iterator i = context_items_.find(extension_id); |
123 if (i != context_items_.end()) { | 131 if (i != context_items_.end()) { |
124 return &(i->second); | 132 return &(i->second); |
125 } | 133 } |
126 return NULL; | 134 return NULL; |
127 } | 135 } |
128 | 136 |
129 int ExtensionMenuManager::AddContextItem(ExtensionMenuItem* item) { | 137 int ExtensionMenuManager::AddContextItem(Extension* extension, |
| 138 ExtensionMenuItem* item) { |
130 const std::string& extension_id = item->extension_id(); | 139 const std::string& extension_id = item->extension_id(); |
131 // The item must have a non-empty extension id. | 140 // The item must have a non-empty extension id. |
132 if (extension_id.empty()) | 141 if (extension_id.empty()) |
133 return 0; | 142 return 0; |
134 | 143 |
| 144 DCHECK_EQ(extension->id(), extension_id); |
| 145 |
135 DCHECK_EQ(0, item->id()); | 146 DCHECK_EQ(0, item->id()); |
136 item->set_id(next_item_id_++); | 147 item->set_id(next_item_id_++); |
137 | 148 |
| 149 bool first_item = !ContainsKey(context_items_, extension_id); |
138 context_items_[extension_id].push_back(item); | 150 context_items_[extension_id].push_back(item); |
139 items_by_id_[item->id()] = item; | 151 items_by_id_[item->id()] = item; |
140 | 152 |
141 if (item->type() == ExtensionMenuItem::RADIO && item->checked()) | 153 if (item->type() == ExtensionMenuItem::RADIO && item->checked()) |
142 RadioItemSelected(item); | 154 RadioItemSelected(item); |
143 | 155 |
| 156 // If this is the first item for this extension, start loading its icon. |
| 157 if (first_item) { |
| 158 ExtensionResource icon_resource; |
| 159 extension->GetIconPathAllowLargerSize(&icon_resource, |
| 160 Extension::EXTENSION_ICON_BITTY); |
| 161 if (!icon_resource.extension_root().empty()) { |
| 162 image_tracker_.LoadImage(extension, |
| 163 icon_resource, |
| 164 gfx::Size(kFavIconSize, kFavIconSize), |
| 165 ImageLoadingTracker::CACHE); |
| 166 } |
| 167 } |
| 168 |
144 return item->id(); | 169 return item->id(); |
145 } | 170 } |
146 | 171 |
147 int ExtensionMenuManager::AddChildItem(int parent_id, | 172 int ExtensionMenuManager::AddChildItem(int parent_id, |
148 ExtensionMenuItem* child) { | 173 ExtensionMenuItem* child) { |
149 ExtensionMenuItem* parent = GetItemById(parent_id); | 174 ExtensionMenuItem* parent = GetItemById(parent_id); |
150 if (!parent || parent->type() != ExtensionMenuItem::NORMAL || | 175 if (!parent || parent->type() != ExtensionMenuItem::NORMAL || |
151 parent->extension_id() != child->extension_id()) | 176 parent->extension_id() != child->extension_id()) |
152 return 0; | 177 return 0; |
153 child->set_id(next_item_id_++); | 178 child->set_id(next_item_id_++); |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 if (!ContainsKey(items_by_id_, id)) | 251 if (!ContainsKey(items_by_id_, id)) |
227 return false; | 252 return false; |
228 | 253 |
229 std::string extension_id = GetItemById(id)->extension_id(); | 254 std::string extension_id = GetItemById(id)->extension_id(); |
230 MenuItemMap::iterator i = context_items_.find(extension_id); | 255 MenuItemMap::iterator i = context_items_.find(extension_id); |
231 if (i == context_items_.end()) { | 256 if (i == context_items_.end()) { |
232 NOTREACHED(); | 257 NOTREACHED(); |
233 return false; | 258 return false; |
234 } | 259 } |
235 | 260 |
| 261 bool result = false; |
236 ExtensionMenuItem::List& list = i->second; | 262 ExtensionMenuItem::List& list = i->second; |
237 ExtensionMenuItem::List::iterator j; | 263 ExtensionMenuItem::List::iterator j; |
238 for (j = list.begin(); j < list.end(); ++j) { | 264 for (j = list.begin(); j < list.end(); ++j) { |
239 // See if the current item is a match, or if one of its children was. | 265 // See if the current item is a match, or if one of its children was. |
240 if ((*j)->id() == id) { | 266 if ((*j)->id() == id) { |
241 delete *j; | 267 delete *j; |
242 list.erase(j); | 268 list.erase(j); |
243 items_by_id_.erase(id); | 269 items_by_id_.erase(id); |
244 return true; | 270 result = true; |
| 271 break; |
245 } else if ((*j)->RemoveChild(id)) { | 272 } else if ((*j)->RemoveChild(id)) { |
246 items_by_id_.erase(id); | 273 items_by_id_.erase(id); |
247 return true; | 274 result = true; |
| 275 break; |
248 } | 276 } |
249 } | 277 } |
250 NOTREACHED(); // The check at the very top should prevent getting here. | 278 DCHECK(result); // The check at the very top should have prevented this. |
251 return false; | 279 |
| 280 if (list.empty() && ContainsKey(extension_icons_, extension_id)) |
| 281 extension_icons_.erase(extension_id); |
| 282 |
| 283 return result; |
252 } | 284 } |
253 | 285 |
254 void ExtensionMenuManager::RemoveAllContextItems(std::string extension_id) { | 286 void ExtensionMenuManager::RemoveAllContextItems(std::string extension_id) { |
255 ExtensionMenuItem::List::iterator i; | 287 ExtensionMenuItem::List::iterator i; |
256 for (i = context_items_[extension_id].begin(); | 288 for (i = context_items_[extension_id].begin(); |
257 i != context_items_[extension_id].end(); ++i) { | 289 i != context_items_[extension_id].end(); ++i) { |
258 ExtensionMenuItem* item = *i; | 290 ExtensionMenuItem* item = *i; |
259 items_by_id_.erase(item->id()); | 291 items_by_id_.erase(item->id()); |
260 | 292 |
261 // Remove descendants from this item and erase them from the lookup cache. | 293 // Remove descendants from this item and erase them from the lookup cache. |
262 std::set<int> removed_ids = item->RemoveAllDescendants(); | 294 std::set<int> removed_ids = item->RemoveAllDescendants(); |
263 for (std::set<int>::const_iterator j = removed_ids.begin(); | 295 for (std::set<int>::const_iterator j = removed_ids.begin(); |
264 j != removed_ids.end(); ++j) { | 296 j != removed_ids.end(); ++j) { |
265 items_by_id_.erase(*j); | 297 items_by_id_.erase(*j); |
266 } | 298 } |
267 } | 299 } |
268 STLDeleteElements(&context_items_[extension_id]); | 300 STLDeleteElements(&context_items_[extension_id]); |
269 context_items_.erase(extension_id); | 301 context_items_.erase(extension_id); |
| 302 |
| 303 if (ContainsKey(extension_icons_, extension_id)) |
| 304 extension_icons_.erase(extension_id); |
270 } | 305 } |
271 | 306 |
272 ExtensionMenuItem* ExtensionMenuManager::GetItemById(int id) const { | 307 ExtensionMenuItem* ExtensionMenuManager::GetItemById(int id) const { |
273 std::map<int, ExtensionMenuItem*>::const_iterator i = items_by_id_.find(id); | 308 std::map<int, ExtensionMenuItem*>::const_iterator i = items_by_id_.find(id); |
274 if (i != items_by_id_.end()) | 309 if (i != items_by_id_.end()) |
275 return i->second; | 310 return i->second; |
276 else | 311 else |
277 return NULL; | 312 return NULL; |
278 } | 313 } |
279 | 314 |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
415 // Remove menu items for disabled/uninstalled extensions. | 450 // Remove menu items for disabled/uninstalled extensions. |
416 if (type != NotificationType::EXTENSION_UNLOADED) { | 451 if (type != NotificationType::EXTENSION_UNLOADED) { |
417 NOTREACHED(); | 452 NOTREACHED(); |
418 return; | 453 return; |
419 } | 454 } |
420 Extension* extension = Details<Extension>(details).ptr(); | 455 Extension* extension = Details<Extension>(details).ptr(); |
421 if (ContainsKey(context_items_, extension->id())) { | 456 if (ContainsKey(context_items_, extension->id())) { |
422 RemoveAllContextItems(extension->id()); | 457 RemoveAllContextItems(extension->id()); |
423 } | 458 } |
424 } | 459 } |
| 460 |
| 461 const SkBitmap& ExtensionMenuManager::GetIconForExtension( |
| 462 const std::string& extension_id) { |
| 463 const SkBitmap* result = NULL; |
| 464 if (ContainsKey(extension_icons_, extension_id)) { |
| 465 result = &(extension_icons_[extension_id]); |
| 466 } else { |
| 467 EnsureDefaultIcon(); |
| 468 result = &default_icon_; |
| 469 } |
| 470 DCHECK(result); |
| 471 DCHECK(result->width() == kFavIconSize); |
| 472 DCHECK(result->height() == kFavIconSize); |
| 473 return *result; |
| 474 } |
| 475 |
| 476 void ExtensionMenuManager::OnImageLoaded(SkBitmap* image, |
| 477 ExtensionResource resource, |
| 478 int index) { |
| 479 if (!image) |
| 480 return; |
| 481 |
| 482 const std::string extension_id = resource.extension_id(); |
| 483 |
| 484 // Make sure we still have menu items for this extension (since image loading |
| 485 // is asynchronous, there's a slight chance they may have all been removed |
| 486 // while the icon was loading). |
| 487 if (!ContainsKey(context_items_, extension_id)) |
| 488 return; |
| 489 |
| 490 if (image->width() == kFavIconSize && image->height() == kFavIconSize) |
| 491 extension_icons_[extension_id] = *image; |
| 492 else |
| 493 extension_icons_[extension_id] = ScaleToFavIconSize(*image); |
| 494 } |
| 495 |
| 496 void ExtensionMenuManager::EnsureDefaultIcon() { |
| 497 if (default_icon_.empty()) { |
| 498 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 499 SkBitmap* src = rb.GetBitmapNamed(IDR_EXTENSIONS_SECTION); |
| 500 if (src->width() == kFavIconSize && src->height() == kFavIconSize) { |
| 501 default_icon_ = *src; |
| 502 } else { |
| 503 default_icon_ = SkBitmap(ScaleToFavIconSize(*src)); |
| 504 } |
| 505 } |
| 506 } |
| 507 |
| 508 SkBitmap ExtensionMenuManager::ScaleToFavIconSize(const SkBitmap& source) { |
| 509 return skia::ImageOperations::Resize(source, |
| 510 skia::ImageOperations::RESIZE_LANCZOS3, |
| 511 kFavIconSize, |
| 512 kFavIconSize); |
| 513 } |
OLD | NEW |