| 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" | |
| 10 #include "base/logging.h" | 9 #include "base/logging.h" |
| 11 #include "base/stl_util-inl.h" | 10 #include "base/stl_util-inl.h" |
| 12 #include "base/string_util.h" | 11 #include "base/string_util.h" |
| 13 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
| 14 #include "base/values.h" | 13 #include "base/values.h" |
| 15 #include "base/json/json_writer.h" | 14 #include "base/json/json_writer.h" |
| 16 #include "chrome/app/chrome_dll_resource.h" | |
| 17 #include "chrome/browser/extensions/extension_message_service.h" | 15 #include "chrome/browser/extensions/extension_message_service.h" |
| 18 #include "chrome/browser/extensions/extension_tabs_module.h" | 16 #include "chrome/browser/extensions/extension_tabs_module.h" |
| 19 #include "chrome/browser/profile.h" | 17 #include "chrome/browser/profile.h" |
| 20 #include "chrome/common/extensions/extension.h" | 18 #include "chrome/common/extensions/extension.h" |
| 21 #include "chrome/common/extensions/extension_resource.h" | |
| 22 #include "gfx/favicon_size.h" | 19 #include "gfx/favicon_size.h" |
| 23 #include "gfx/size.h" | |
| 24 #include "grit/theme_resources.h" | |
| 25 #include "skia/ext/image_operations.h" | |
| 26 #include "webkit/glue/context_menu.h" | 20 #include "webkit/glue/context_menu.h" |
| 27 | 21 |
| 28 ExtensionMenuItem::ExtensionMenuItem(const Id& id, | 22 ExtensionMenuItem::ExtensionMenuItem(const Id& id, |
| 29 std::string title, | 23 std::string title, |
| 30 bool checked, | 24 bool checked, |
| 31 Type type, | 25 Type type, |
| 32 const ContextList& contexts) | 26 const ContextList& contexts) |
| 33 : id_(id), | 27 : id_(id), |
| 34 title_(title), | 28 title_(title), |
| 35 type_(type), | 29 type_(type), |
| 36 checked_(checked), | 30 checked_(checked), |
| 37 contexts_(contexts), | 31 contexts_(contexts), |
| 38 parent_id_(0) {} | 32 parent_id_(0) { |
| 33 } |
| 39 | 34 |
| 40 ExtensionMenuItem::~ExtensionMenuItem() { | 35 ExtensionMenuItem::~ExtensionMenuItem() { |
| 41 STLDeleteElements(&children_); | 36 STLDeleteElements(&children_); |
| 42 } | 37 } |
| 43 | 38 |
| 44 bool ExtensionMenuItem::RemoveChild(const Id& child_id) { | 39 bool ExtensionMenuItem::RemoveChild(const Id& child_id) { |
| 45 ExtensionMenuItem* child = ReleaseChild(child_id, true); | 40 ExtensionMenuItem* child = ReleaseChild(child_id, true); |
| 46 if (child) { | 41 if (child) { |
| 47 delete child; | 42 delete child; |
| 48 return true; | 43 return true; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 return false; | 89 return false; |
| 95 checked_ = checked; | 90 checked_ = checked; |
| 96 return true; | 91 return true; |
| 97 } | 92 } |
| 98 | 93 |
| 99 void ExtensionMenuItem::AddChild(ExtensionMenuItem* item) { | 94 void ExtensionMenuItem::AddChild(ExtensionMenuItem* item) { |
| 100 item->parent_id_.reset(new Id(id_)); | 95 item->parent_id_.reset(new Id(id_)); |
| 101 children_.push_back(item); | 96 children_.push_back(item); |
| 102 } | 97 } |
| 103 | 98 |
| 104 ExtensionMenuManager::ExtensionMenuManager() | 99 ExtensionMenuManager::ExtensionMenuManager() : next_item_id_(1) { |
| 105 : ALLOW_THIS_IN_INITIALIZER_LIST(image_tracker_(this)) { | |
| 106 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, | 100 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, |
| 107 NotificationService::AllSources()); | 101 NotificationService::AllSources()); |
| 108 } | 102 } |
| 109 | 103 |
| 110 ExtensionMenuManager::~ExtensionMenuManager() { | 104 ExtensionMenuManager::~ExtensionMenuManager() { |
| 111 MenuItemMap::iterator i; | 105 MenuItemMap::iterator i; |
| 112 for (i = context_items_.begin(); i != context_items_.end(); ++i) { | 106 for (i = context_items_.begin(); i != context_items_.end(); ++i) { |
| 113 STLDeleteElements(&(i->second)); | 107 STLDeleteElements(&(i->second)); |
| 114 } | 108 } |
| 115 } | 109 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 143 DCHECK_EQ(extension->id(), extension_id); | 137 DCHECK_EQ(extension->id(), extension_id); |
| 144 | 138 |
| 145 bool first_item = !ContainsKey(context_items_, extension_id); | 139 bool first_item = !ContainsKey(context_items_, extension_id); |
| 146 context_items_[extension_id].push_back(item); | 140 context_items_[extension_id].push_back(item); |
| 147 items_by_id_[item->id()] = item; | 141 items_by_id_[item->id()] = item; |
| 148 | 142 |
| 149 if (item->type() == ExtensionMenuItem::RADIO && item->checked()) | 143 if (item->type() == ExtensionMenuItem::RADIO && item->checked()) |
| 150 RadioItemSelected(item); | 144 RadioItemSelected(item); |
| 151 | 145 |
| 152 // If this is the first item for this extension, start loading its icon. | 146 // If this is the first item for this extension, start loading its icon. |
| 153 if (first_item) { | 147 if (first_item) |
| 154 ExtensionResource icon_resource; | 148 icon_manager_.LoadIcon(extension); |
| 155 extension->GetIconPathAllowLargerSize(&icon_resource, | |
| 156 Extension::EXTENSION_ICON_BITTY); | |
| 157 if (!icon_resource.extension_root().empty()) { | |
| 158 image_tracker_.LoadImage(extension, | |
| 159 icon_resource, | |
| 160 gfx::Size(kFavIconSize, kFavIconSize), | |
| 161 ImageLoadingTracker::CACHE); | |
| 162 } | |
| 163 } | |
| 164 | 149 |
| 165 return true; | 150 return true; |
| 166 } | 151 } |
| 167 | 152 |
| 168 bool ExtensionMenuManager::AddChildItem(const ExtensionMenuItem::Id& parent_id, | 153 bool ExtensionMenuManager::AddChildItem(const ExtensionMenuItem::Id& parent_id, |
| 169 ExtensionMenuItem* child) { | 154 ExtensionMenuItem* child) { |
| 170 ExtensionMenuItem* parent = GetItemById(parent_id); | 155 ExtensionMenuItem* parent = GetItemById(parent_id); |
| 171 if (!parent || parent->type() != ExtensionMenuItem::NORMAL || | 156 if (!parent || parent->type() != ExtensionMenuItem::NORMAL || |
| 172 parent->extension_id() != child->extension_id() || | 157 parent->extension_id() != child->extension_id() || |
| 173 ContainsKey(items_by_id_, child->id())) | 158 ContainsKey(items_by_id_, child->id())) |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 result = true; | 253 result = true; |
| 269 break; | 254 break; |
| 270 } else if ((*j)->RemoveChild(id)) { | 255 } else if ((*j)->RemoveChild(id)) { |
| 271 items_by_id_.erase(id); | 256 items_by_id_.erase(id); |
| 272 result = true; | 257 result = true; |
| 273 break; | 258 break; |
| 274 } | 259 } |
| 275 } | 260 } |
| 276 DCHECK(result); // The check at the very top should have prevented this. | 261 DCHECK(result); // The check at the very top should have prevented this. |
| 277 | 262 |
| 278 if (list.empty() && ContainsKey(extension_icons_, extension_id)) | 263 if (list.empty()) |
| 279 extension_icons_.erase(extension_id); | 264 icon_manager_.RemoveIcon(extension_id); |
| 280 | 265 |
| 281 return result; | 266 return result; |
| 282 } | 267 } |
| 283 | 268 |
| 284 void ExtensionMenuManager::RemoveAllContextItems(std::string extension_id) { | 269 void ExtensionMenuManager::RemoveAllContextItems(std::string extension_id) { |
| 285 ExtensionMenuItem::List::iterator i; | 270 ExtensionMenuItem::List::iterator i; |
| 286 for (i = context_items_[extension_id].begin(); | 271 for (i = context_items_[extension_id].begin(); |
| 287 i != context_items_[extension_id].end(); ++i) { | 272 i != context_items_[extension_id].end(); ++i) { |
| 288 ExtensionMenuItem* item = *i; | 273 ExtensionMenuItem* item = *i; |
| 289 items_by_id_.erase(item->id()); | 274 items_by_id_.erase(item->id()); |
| 290 | 275 |
| 291 // Remove descendants from this item and erase them from the lookup cache. | 276 // Remove descendants from this item and erase them from the lookup cache. |
| 292 std::set<ExtensionMenuItem::Id> removed_ids = item->RemoveAllDescendants(); | 277 std::set<ExtensionMenuItem::Id> removed_ids = item->RemoveAllDescendants(); |
| 293 std::set<ExtensionMenuItem::Id>::const_iterator j; | 278 std::set<ExtensionMenuItem::Id>::const_iterator j; |
| 294 for (j = removed_ids.begin(); j != removed_ids.end(); ++j) { | 279 for (j = removed_ids.begin(); j != removed_ids.end(); ++j) { |
| 295 items_by_id_.erase(*j); | 280 items_by_id_.erase(*j); |
| 296 } | 281 } |
| 297 } | 282 } |
| 298 STLDeleteElements(&context_items_[extension_id]); | 283 STLDeleteElements(&context_items_[extension_id]); |
| 299 context_items_.erase(extension_id); | 284 context_items_.erase(extension_id); |
| 300 | 285 icon_manager_.RemoveIcon(extension_id); |
| 301 if (ContainsKey(extension_icons_, extension_id)) | |
| 302 extension_icons_.erase(extension_id); | |
| 303 } | 286 } |
| 304 | 287 |
| 305 ExtensionMenuItem* ExtensionMenuManager::GetItemById( | 288 ExtensionMenuItem* ExtensionMenuManager::GetItemById( |
| 306 const ExtensionMenuItem::Id& id) const { | 289 const ExtensionMenuItem::Id& id) const { |
| 307 std::map<ExtensionMenuItem::Id, ExtensionMenuItem*>::const_iterator i = | 290 std::map<ExtensionMenuItem::Id, ExtensionMenuItem*>::const_iterator i = |
| 308 items_by_id_.find(id); | 291 items_by_id_.find(id); |
| 309 if (i != items_by_id_.end()) | 292 if (i != items_by_id_.end()) |
| 310 return i->second; | 293 return i->second; |
| 311 else | 294 else |
| 312 return NULL; | 295 return NULL; |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 454 return; | 437 return; |
| 455 } | 438 } |
| 456 Extension* extension = Details<Extension>(details).ptr(); | 439 Extension* extension = Details<Extension>(details).ptr(); |
| 457 if (ContainsKey(context_items_, extension->id())) { | 440 if (ContainsKey(context_items_, extension->id())) { |
| 458 RemoveAllContextItems(extension->id()); | 441 RemoveAllContextItems(extension->id()); |
| 459 } | 442 } |
| 460 } | 443 } |
| 461 | 444 |
| 462 const SkBitmap& ExtensionMenuManager::GetIconForExtension( | 445 const SkBitmap& ExtensionMenuManager::GetIconForExtension( |
| 463 const std::string& extension_id) { | 446 const std::string& extension_id) { |
| 464 const SkBitmap* result = NULL; | 447 return icon_manager_.GetIcon(extension_id); |
| 465 if (ContainsKey(extension_icons_, extension_id)) { | |
| 466 result = &(extension_icons_[extension_id]); | |
| 467 } else { | |
| 468 EnsureDefaultIcon(); | |
| 469 result = &default_icon_; | |
| 470 } | |
| 471 DCHECK(result); | |
| 472 DCHECK(result->width() == kFavIconSize); | |
| 473 DCHECK(result->height() == kFavIconSize); | |
| 474 return *result; | |
| 475 } | 448 } |
| 476 | |
| 477 void ExtensionMenuManager::OnImageLoaded(SkBitmap* image, | |
| 478 ExtensionResource resource, | |
| 479 int index) { | |
| 480 if (!image) | |
| 481 return; | |
| 482 | |
| 483 const std::string extension_id = resource.extension_id(); | |
| 484 | |
| 485 // Make sure we still have menu items for this extension (since image loading | |
| 486 // is asynchronous, there's a slight chance they may have all been removed | |
| 487 // while the icon was loading). | |
| 488 if (!ContainsKey(context_items_, extension_id)) | |
| 489 return; | |
| 490 | |
| 491 if (image->width() == kFavIconSize && image->height() == kFavIconSize) | |
| 492 extension_icons_[extension_id] = *image; | |
| 493 else | |
| 494 extension_icons_[extension_id] = ScaleToFavIconSize(*image); | |
| 495 } | |
| 496 | |
| 497 void ExtensionMenuManager::EnsureDefaultIcon() { | |
| 498 if (default_icon_.empty()) { | |
| 499 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 500 SkBitmap* src = rb.GetBitmapNamed(IDR_EXTENSIONS_SECTION); | |
| 501 if (src->width() == kFavIconSize && src->height() == kFavIconSize) { | |
| 502 default_icon_ = *src; | |
| 503 } else { | |
| 504 default_icon_ = SkBitmap(ScaleToFavIconSize(*src)); | |
| 505 } | |
| 506 } | |
| 507 } | |
| 508 | |
| 509 SkBitmap ExtensionMenuManager::ScaleToFavIconSize(const SkBitmap& source) { | |
| 510 return skia::ImageOperations::Resize(source, | |
| 511 skia::ImageOperations::RESIZE_LANCZOS3, | |
| 512 kFavIconSize, | |
| 513 kFavIconSize); | |
| 514 } | |
| OLD | NEW |