| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 <algorithm> | |
| 6 #include <set> | 5 #include <set> |
| 7 | 6 |
| 8 #include "chrome/browser/tab_contents/render_view_context_menu.h" | 7 #include "chrome/browser/tab_contents/render_view_context_menu.h" |
| 9 | 8 |
| 10 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 11 #include "base/logging.h" | 10 #include "base/logging.h" |
| 12 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 13 #include "base/stl_util-inl.h" | 12 #include "base/stl_util-inl.h" |
| 14 #include "base/string_util.h" | 13 #include "base/string_util.h" |
| 15 #include "base/time.h" | 14 #include "base/time.h" |
| (...skipping 14 matching lines...) Expand all Loading... |
| 30 #include "chrome/browser/page_info_window.h" | 29 #include "chrome/browser/page_info_window.h" |
| 31 #include "chrome/browser/platform_util.h" | 30 #include "chrome/browser/platform_util.h" |
| 32 #include "chrome/browser/prefs/pref_member.h" | 31 #include "chrome/browser/prefs/pref_member.h" |
| 33 #include "chrome/browser/prefs/pref_service.h" | 32 #include "chrome/browser/prefs/pref_service.h" |
| 34 #include "chrome/browser/printing/print_preview_tab_controller.h" | 33 #include "chrome/browser/printing/print_preview_tab_controller.h" |
| 35 #include "chrome/browser/profiles/profile.h" | 34 #include "chrome/browser/profiles/profile.h" |
| 36 #include "chrome/browser/search_engines/template_url.h" | 35 #include "chrome/browser/search_engines/template_url.h" |
| 37 #include "chrome/browser/search_engines/template_url_model.h" | 36 #include "chrome/browser/search_engines/template_url_model.h" |
| 38 #include "chrome/browser/spellcheck_host.h" | 37 #include "chrome/browser/spellcheck_host.h" |
| 39 #include "chrome/browser/spellchecker_platform_engine.h" | 38 #include "chrome/browser/spellchecker_platform_engine.h" |
| 39 #include "chrome/browser/tab_contents/context_menu_utils.h" |
| 40 #include "chrome/browser/translate/translate_manager.h" | 40 #include "chrome/browser/translate/translate_manager.h" |
| 41 #include "chrome/browser/translate/translate_prefs.h" | 41 #include "chrome/browser/translate/translate_prefs.h" |
| 42 #include "chrome/browser/ui/download/download_tab_helper.h" | 42 #include "chrome/browser/ui/download/download_tab_helper.h" |
| 43 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | 43 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| 44 #include "chrome/common/chrome_constants.h" | 44 #include "chrome/common/chrome_constants.h" |
| 45 #include "chrome/common/chrome_switches.h" | 45 #include "chrome/common/chrome_switches.h" |
| 46 #include "chrome/common/content_restriction.h" | 46 #include "chrome/common/content_restriction.h" |
| 47 #include "chrome/common/pref_names.h" | 47 #include "chrome/common/pref_names.h" |
| 48 #include "chrome/common/print_messages.h" | 48 #include "chrome/common/print_messages.h" |
| 49 #include "chrome/common/url_constants.h" | 49 #include "chrome/common/url_constants.h" |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 RenderViewContextMenu::~RenderViewContextMenu() { | 192 RenderViewContextMenu::~RenderViewContextMenu() { |
| 193 } | 193 } |
| 194 | 194 |
| 195 // Menu construction functions ------------------------------------------------- | 195 // Menu construction functions ------------------------------------------------- |
| 196 | 196 |
| 197 void RenderViewContextMenu::Init() { | 197 void RenderViewContextMenu::Init() { |
| 198 InitMenu(); | 198 InitMenu(); |
| 199 PlatformInit(); | 199 PlatformInit(); |
| 200 } | 200 } |
| 201 | 201 |
| 202 static bool ExtensionContextMatch(const ContextMenuParams& params, | |
| 203 ExtensionMenuItem::ContextList contexts) { | |
| 204 bool has_link = !params.link_url.is_empty(); | |
| 205 bool has_selection = !params.selection_text.empty(); | |
| 206 bool in_frame = !params.frame_url.is_empty(); | |
| 207 | |
| 208 if (contexts.Contains(ExtensionMenuItem::ALL) || | |
| 209 (has_selection && contexts.Contains(ExtensionMenuItem::SELECTION)) || | |
| 210 (has_link && contexts.Contains(ExtensionMenuItem::LINK)) || | |
| 211 (params.is_editable && contexts.Contains(ExtensionMenuItem::EDITABLE)) || | |
| 212 (in_frame && contexts.Contains(ExtensionMenuItem::FRAME))) { | |
| 213 return true; | |
| 214 } | |
| 215 | |
| 216 switch (params.media_type) { | |
| 217 case WebContextMenuData::MediaTypeImage: | |
| 218 return contexts.Contains(ExtensionMenuItem::IMAGE); | |
| 219 | |
| 220 case WebContextMenuData::MediaTypeVideo: | |
| 221 return contexts.Contains(ExtensionMenuItem::VIDEO); | |
| 222 | |
| 223 case WebContextMenuData::MediaTypeAudio: | |
| 224 return contexts.Contains(ExtensionMenuItem::AUDIO); | |
| 225 | |
| 226 default: | |
| 227 break; | |
| 228 } | |
| 229 | |
| 230 // PAGE is the least specific context, so we only examine that if none of the | |
| 231 // other contexts apply (except for FRAME, which is included in PAGE for | |
| 232 // backwards compatibility). | |
| 233 if (!has_link && !has_selection && !params.is_editable && | |
| 234 params.media_type == WebContextMenuData::MediaTypeNone && | |
| 235 contexts.Contains(ExtensionMenuItem::PAGE)) | |
| 236 return true; | |
| 237 | |
| 238 return false; | |
| 239 } | |
| 240 | |
| 241 static bool ExtensionPatternMatch(const ExtensionExtent& patterns, | |
| 242 const GURL& url) { | |
| 243 // No patterns means no restriction, so that implicitly matches. | |
| 244 if (patterns.is_empty()) | |
| 245 return true; | |
| 246 return patterns.ContainsURL(url); | |
| 247 } | |
| 248 | |
| 249 static const GURL& GetDocumentURL(const ContextMenuParams& params) { | |
| 250 return params.frame_url.is_empty() ? params.page_url : params.frame_url; | |
| 251 } | |
| 252 | |
| 253 // Given a list of items, returns the ones that match given the contents | |
| 254 // of |params| and the profile. | |
| 255 static ExtensionMenuItem::List GetRelevantExtensionItems( | |
| 256 const ExtensionMenuItem::List& items, | |
| 257 const ContextMenuParams& params, | |
| 258 Profile* profile, | |
| 259 bool can_cross_incognito) { | |
| 260 ExtensionMenuItem::List result; | |
| 261 for (ExtensionMenuItem::List::const_iterator i = items.begin(); | |
| 262 i != items.end(); ++i) { | |
| 263 const ExtensionMenuItem* item = *i; | |
| 264 | |
| 265 if (!ExtensionContextMatch(params, item->contexts())) | |
| 266 continue; | |
| 267 | |
| 268 const GURL& document_url = GetDocumentURL(params); | |
| 269 if (!ExtensionPatternMatch(item->document_url_patterns(), document_url)) | |
| 270 continue; | |
| 271 | |
| 272 const GURL& target_url = | |
| 273 params.src_url.is_empty() ? params.link_url : params.src_url; | |
| 274 if (!ExtensionPatternMatch(item->target_url_patterns(), target_url)) | |
| 275 continue; | |
| 276 | |
| 277 if (item->id().profile == profile || can_cross_incognito) | |
| 278 result.push_back(*i); | |
| 279 } | |
| 280 return result; | |
| 281 } | |
| 282 | |
| 283 void RenderViewContextMenu::AppendExtensionItems( | 202 void RenderViewContextMenu::AppendExtensionItems( |
| 284 const std::string& extension_id, int* index) { | 203 const std::string& extension_id, int* index) { |
| 285 ExtensionService* service = profile_->GetExtensionService(); | 204 ExtensionService* service = profile_->GetExtensionService(); |
| 286 ExtensionMenuManager* manager = service->menu_manager(); | 205 ExtensionMenuManager* manager = service->menu_manager(); |
| 287 const Extension* extension = service->GetExtensionById(extension_id, false); | 206 const Extension* extension = service->GetExtensionById(extension_id, false); |
| 288 DCHECK_GE(*index, 0); | 207 DCHECK_GE(*index, 0); |
| 289 int max_index = | 208 int max_index = |
| 290 IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST - IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST; | 209 IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST - IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST; |
| 291 if (!extension || *index >= max_index) | 210 if (!extension || *index >= max_index) |
| 292 return; | 211 return; |
| 293 | 212 |
| 294 // Find matching items. | 213 // Find matching items. |
| 295 const ExtensionMenuItem::List* all_items = manager->MenuItems(extension_id); | 214 const ExtensionMenuItem::List* all_items = manager->MenuItems(extension_id); |
| 296 if (!all_items || all_items->empty()) | 215 if (!all_items || all_items->empty()) |
| 297 return; | 216 return; |
| 298 bool can_cross_incognito = service->CanCrossIncognito(extension); | 217 bool can_cross_incognito = service->CanCrossIncognito(extension); |
| 299 ExtensionMenuItem::List items = | 218 ExtensionMenuItem::List items = |
| 300 GetRelevantExtensionItems(*all_items, params_, profile_, | 219 ContextMenuUtils::GetRelevantExtensionItems(*all_items, |
| 301 can_cross_incognito); | 220 params_, |
| 221 profile_, |
| 222 can_cross_incognito); |
| 302 if (items.empty()) | 223 if (items.empty()) |
| 303 return; | 224 return; |
| 304 | 225 |
| 305 // If this is the first extension-provided menu item, add a separator. | 226 // If this is the first extension-provided menu item, add a separator. |
| 306 if (*index == 0) | 227 if (*index == 0) |
| 307 menu_model_.AddSeparator(); | 228 menu_model_.AddSeparator(); |
| 308 | 229 |
| 309 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++; | 230 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++; |
| 310 | 231 |
| 311 // Extensions are only allowed one top-level slot (and it can't be a radio or | 232 // Extensions are only allowed one top-level slot (and it can't be a radio or |
| 312 // checkbox item because we are going to put the extension icon next to it). | 233 // checkbox item because we are going to put the extension icon next to it). |
| 313 // If they have more than that, we automatically push them into a submenu. | 234 // If they have more than that, we automatically push them into a submenu. |
| 314 string16 title; | 235 string16 title; |
| 315 ExtensionMenuItem::List submenu_items; | 236 ExtensionMenuItem::List submenu_items; |
| 316 if (items.size() > 1 || items[0]->type() != ExtensionMenuItem::NORMAL) { | 237 if (items.size() > 1 || items[0]->type() != ExtensionMenuItem::NORMAL) { |
| 317 title = UTF8ToUTF16(extension->name()); | 238 title = UTF8ToUTF16(extension->name()); |
| 318 submenu_items = items; | 239 submenu_items = items; |
| 319 } else { | 240 } else { |
| 320 ExtensionMenuItem* item = items[0]; | 241 ExtensionMenuItem* item = items[0]; |
| 321 extension_item_map_[menu_id] = item->id(); | 242 extension_item_map_[menu_id] = item->id(); |
| 322 title = item->TitleWithReplacement(PrintableSelectionText(), | 243 title = item->TitleWithReplacement(PrintableSelectionText(), |
| 323 kMaxExtensionItemTitleLength); | 244 kMaxExtensionItemTitleLength); |
| 324 submenu_items = GetRelevantExtensionItems(item->children(), params_, | 245 submenu_items = ContextMenuUtils::GetRelevantExtensionItems( |
| 325 profile_, can_cross_incognito); | 246 item->children(), params_, profile_, can_cross_incognito); |
| 326 } | 247 } |
| 327 | 248 |
| 328 // Now add our item(s) to the menu_model_. | 249 // Now add our item(s) to the menu_model_. |
| 329 if (submenu_items.empty()) { | 250 if (submenu_items.empty()) { |
| 330 menu_model_.AddItem(menu_id, title); | 251 menu_model_.AddItem(menu_id, title); |
| 331 } else { | 252 } else { |
| 332 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(this); | 253 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(this); |
| 333 extension_menu_models_.push_back(submenu); | 254 extension_menu_models_.push_back(submenu); |
| 334 menu_model_.AddSubMenu(menu_id, title, submenu); | 255 menu_model_.AddSubMenu(menu_id, title, submenu); |
| 335 RecursivelyAppendExtensionItems(submenu_items, can_cross_incognito, submenu, | 256 RecursivelyAppendExtensionItems(submenu_items, can_cross_incognito, submenu, |
| (...skipping 24 matching lines...) Expand all Loading... |
| 360 } | 281 } |
| 361 | 282 |
| 362 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++; | 283 int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++; |
| 363 if (menu_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) | 284 if (menu_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) |
| 364 return; | 285 return; |
| 365 extension_item_map_[menu_id] = item->id(); | 286 extension_item_map_[menu_id] = item->id(); |
| 366 string16 title = item->TitleWithReplacement(selection_text, | 287 string16 title = item->TitleWithReplacement(selection_text, |
| 367 kMaxExtensionItemTitleLength); | 288 kMaxExtensionItemTitleLength); |
| 368 if (item->type() == ExtensionMenuItem::NORMAL) { | 289 if (item->type() == ExtensionMenuItem::NORMAL) { |
| 369 ExtensionMenuItem::List children = | 290 ExtensionMenuItem::List children = |
| 370 GetRelevantExtensionItems(item->children(), params_, | 291 ContextMenuUtils::GetRelevantExtensionItems( |
| 371 profile_, can_cross_incognito); | 292 item->children(), params_, profile_, can_cross_incognito); |
| 372 if (children.empty()) { | 293 if (children.empty()) { |
| 373 menu_model->AddItem(menu_id, title); | 294 menu_model->AddItem(menu_id, title); |
| 374 } else { | 295 } else { |
| 375 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(this); | 296 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(this); |
| 376 extension_menu_models_.push_back(submenu); | 297 extension_menu_models_.push_back(submenu); |
| 377 menu_model->AddSubMenu(menu_id, title, submenu); | 298 menu_model->AddSubMenu(menu_id, title, submenu); |
| 378 RecursivelyAppendExtensionItems(children, can_cross_incognito, | 299 RecursivelyAppendExtensionItems(children, can_cross_incognito, |
| 379 submenu, index); | 300 submenu, index); |
| 380 } | 301 } |
| 381 } else if (item->type() == ExtensionMenuItem::CHECKBOX) { | 302 } else if (item->type() == ExtensionMenuItem::CHECKBOX) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 | 334 |
| 414 menu_model_.SetIcon(index, icon); | 335 menu_model_.SetIcon(index, icon); |
| 415 } | 336 } |
| 416 | 337 |
| 417 void RenderViewContextMenu::AppendAllExtensionItems() { | 338 void RenderViewContextMenu::AppendAllExtensionItems() { |
| 418 extension_item_map_.clear(); | 339 extension_item_map_.clear(); |
| 419 ExtensionService* service = profile_->GetExtensionService(); | 340 ExtensionService* service = profile_->GetExtensionService(); |
| 420 if (!service) | 341 if (!service) |
| 421 return; // In unit-tests, we may not have an ExtensionService. | 342 return; // In unit-tests, we may not have an ExtensionService. |
| 422 ExtensionMenuManager* menu_manager = service->menu_manager(); | 343 ExtensionMenuManager* menu_manager = service->menu_manager(); |
| 423 const GURL& document_url = GetDocumentURL(params_); | 344 const GURL& document_url = ContextMenuUtils::GetDocumentURL(params_); |
| 424 if (!menu_manager->HasAllowedScheme(document_url)) | 345 if (!menu_manager->HasAllowedScheme(document_url)) |
| 425 return; | 346 return; |
| 426 | 347 |
| 427 // Get a list of extension id's that have context menu items, and sort it by | |
| 428 // the extension's name. | |
| 429 std::set<std::string> ids = menu_manager->ExtensionIds(); | |
| 430 std::vector<std::pair<std::string, std::string> > sorted_ids; | 348 std::vector<std::pair<std::string, std::string> > sorted_ids; |
| 431 for (std::set<std::string>::iterator i = ids.begin(); i != ids.end(); ++i) { | 349 ContextMenuUtils::GetSortedContextMenuExtensionIds(service, menu_manager, |
| 432 const Extension* extension = service->GetExtensionById(*i, false); | 350 &sorted_ids); |
| 433 if (extension) | |
| 434 sorted_ids.push_back( | |
| 435 std::pair<std::string, std::string>(extension->name(), *i)); | |
| 436 } | |
| 437 // TODO(asargent) - See if this works properly for i18n names (bug 32363). | |
| 438 std::sort(sorted_ids.begin(), sorted_ids.end()); | |
| 439 | |
| 440 if (sorted_ids.empty()) | 351 if (sorted_ids.empty()) |
| 441 return; | 352 return; |
| 442 | 353 |
| 443 int index = 0; | 354 int index = 0; |
| 444 base::TimeTicks begin = base::TimeTicks::Now(); | 355 base::TimeTicks begin = base::TimeTicks::Now(); |
| 445 std::vector<std::pair<std::string, std::string> >::const_iterator i; | 356 std::vector<std::pair<std::string, std::string> >::const_iterator i; |
| 446 for (i = sorted_ids.begin(); | 357 for (i = sorted_ids.begin(); |
| 447 i != sorted_ids.end(); ++i) { | 358 i != sorted_ids.end(); ++i) { |
| 448 AppendExtensionItems(i->second, &index); | 359 AppendExtensionItems(i->second, &index); |
| 449 } | 360 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 502 break; | 413 break; |
| 503 case WebContextMenuData::MediaTypeVideo: | 414 case WebContextMenuData::MediaTypeVideo: |
| 504 AppendVideoItems(); | 415 AppendVideoItems(); |
| 505 break; | 416 break; |
| 506 case WebContextMenuData::MediaTypeAudio: | 417 case WebContextMenuData::MediaTypeAudio: |
| 507 AppendAudioItems(); | 418 AppendAudioItems(); |
| 508 break; | 419 break; |
| 509 case WebContextMenuData::MediaTypePlugin: | 420 case WebContextMenuData::MediaTypePlugin: |
| 510 AppendPluginItems(); | 421 AppendPluginItems(); |
| 511 break; | 422 break; |
| 512 #ifdef WEBCONTEXT_MEDIATYPEFILE_DEFINED | |
| 513 case WebContextMenuData::MediaTypeFile: | 423 case WebContextMenuData::MediaTypeFile: |
| 424 AppendFileItems(); |
| 514 break; | 425 break; |
| 515 #endif | |
| 516 } | 426 } |
| 517 | 427 |
| 518 if (params_.is_editable) | 428 if (params_.is_editable) |
| 519 AppendEditableItems(); | 429 AppendEditableItems(); |
| 520 else if (has_selection) | 430 else if (has_selection) |
| 521 AppendCopyItem(); | 431 AppendCopyItem(); |
| 522 | 432 |
| 523 if (has_selection) | 433 if (has_selection) |
| 524 AppendSearchProvider(); | 434 AppendSearchProvider(); |
| 525 | 435 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 595 AppendMediaItems(); | 505 AppendMediaItems(); |
| 596 menu_model_.AddSeparator(); | 506 menu_model_.AddSeparator(); |
| 597 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS, | 507 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS, |
| 598 IDS_CONTENT_CONTEXT_SAVEVIDEOAS); | 508 IDS_CONTENT_CONTEXT_SAVEVIDEOAS); |
| 599 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION, | 509 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION, |
| 600 IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION); | 510 IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION); |
| 601 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB, | 511 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB, |
| 602 IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB); | 512 IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB); |
| 603 } | 513 } |
| 604 | 514 |
| 515 void RenderViewContextMenu::AppendFileItems() { |
| 516 // TODO(zelidrag): Add file context operations here (i.e. cut, copy, paste...) |
| 517 } |
| 518 |
| 605 void RenderViewContextMenu::AppendMediaItems() { | 519 void RenderViewContextMenu::AppendMediaItems() { |
| 606 int media_flags = params_.media_flags; | 520 int media_flags = params_.media_flags; |
| 607 | 521 |
| 608 menu_model_.AddItemWithStringId( | 522 menu_model_.AddItemWithStringId( |
| 609 IDC_CONTENT_CONTEXT_PLAYPAUSE, | 523 IDC_CONTENT_CONTEXT_PLAYPAUSE, |
| 610 media_flags & WebContextMenuData::MediaPaused ? | 524 media_flags & WebContextMenuData::MediaPaused ? |
| 611 IDS_CONTENT_CONTEXT_PLAY : | 525 IDS_CONTENT_CONTEXT_PLAY : |
| 612 IDS_CONTENT_CONTEXT_PAUSE); | 526 IDS_CONTENT_CONTEXT_PAUSE); |
| 613 | 527 |
| 614 menu_model_.AddItemWithStringId( | 528 menu_model_.AddItemWithStringId( |
| (...skipping 937 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1552 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages), | 1466 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages), |
| 1553 g_browser_process->clipboard()); | 1467 g_browser_process->clipboard()); |
| 1554 } | 1468 } |
| 1555 | 1469 |
| 1556 void RenderViewContextMenu::MediaPlayerActionAt( | 1470 void RenderViewContextMenu::MediaPlayerActionAt( |
| 1557 const gfx::Point& location, | 1471 const gfx::Point& location, |
| 1558 const WebMediaPlayerAction& action) { | 1472 const WebMediaPlayerAction& action) { |
| 1559 source_tab_contents_->render_view_host()->MediaPlayerActionAt( | 1473 source_tab_contents_->render_view_host()->MediaPlayerActionAt( |
| 1560 location, action); | 1474 location, action); |
| 1561 } | 1475 } |
| OLD | NEW |