mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			479 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			479 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
 | 
						|
// reserved. Use of this source code is governed by a BSD-style license that can
 | 
						|
// be found in the LICENSE file.
 | 
						|
 | 
						|
#include "libcef/browser/menu_manager.h"
 | 
						|
 | 
						|
#include <tuple>
 | 
						|
#include <utility>
 | 
						|
 | 
						|
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
 | 
						|
#include "libcef/browser/context_menu_params_impl.h"
 | 
						|
#include "libcef/browser/menu_runner.h"
 | 
						|
#include "libcef/browser/thread_util.h"
 | 
						|
#include "libcef/common/app_manager.h"
 | 
						|
 | 
						|
#include "base/compiler_specific.h"
 | 
						|
#include "base/logging.h"
 | 
						|
#include "cef/grit/cef_strings.h"
 | 
						|
#include "chrome/grit/generated_resources.h"
 | 
						|
#include "content/public/browser/render_frame_host.h"
 | 
						|
#include "content/public/browser/render_process_host.h"
 | 
						|
#include "content/public/browser/render_widget_host_view.h"
 | 
						|
#include "third_party/blink/public/mojom/context_menu/context_menu.mojom.h"
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
CefString GetLabel(int message_id) {
 | 
						|
  std::u16string label =
 | 
						|
      CefAppManager::Get()->GetContentClient()->GetLocalizedString(message_id);
 | 
						|
  DCHECK(!label.empty());
 | 
						|
  return label;
 | 
						|
}
 | 
						|
 | 
						|
const int kInvalidCommandId = -1;
 | 
						|
const cef_event_flags_t kEmptyEventFlags = static_cast<cef_event_flags_t>(0);
 | 
						|
 | 
						|
class CefRunContextMenuCallbackImpl : public CefRunContextMenuCallback {
 | 
						|
 public:
 | 
						|
  using Callback = base::OnceCallback<void(int, cef_event_flags_t)>;
 | 
						|
 | 
						|
  explicit CefRunContextMenuCallbackImpl(Callback callback)
 | 
						|
      : callback_(std::move(callback)) {}
 | 
						|
 | 
						|
  CefRunContextMenuCallbackImpl(const CefRunContextMenuCallbackImpl&) = delete;
 | 
						|
  CefRunContextMenuCallbackImpl& operator=(
 | 
						|
      const CefRunContextMenuCallbackImpl&) = delete;
 | 
						|
 | 
						|
  ~CefRunContextMenuCallbackImpl() {
 | 
						|
    if (!callback_.is_null()) {
 | 
						|
      // The callback is still pending. Cancel it now.
 | 
						|
      if (CEF_CURRENTLY_ON_UIT()) {
 | 
						|
        RunNow(std::move(callback_), kInvalidCommandId, kEmptyEventFlags);
 | 
						|
      } else {
 | 
						|
        CEF_POST_TASK(CEF_UIT,
 | 
						|
                      base::BindOnce(&CefRunContextMenuCallbackImpl::RunNow,
 | 
						|
                                     std::move(callback_), kInvalidCommandId,
 | 
						|
                                     kEmptyEventFlags));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  void Continue(int command_id, cef_event_flags_t event_flags) override {
 | 
						|
    if (CEF_CURRENTLY_ON_UIT()) {
 | 
						|
      if (!callback_.is_null()) {
 | 
						|
        RunNow(std::move(callback_), command_id, event_flags);
 | 
						|
        callback_.Reset();
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      CEF_POST_TASK(CEF_UIT,
 | 
						|
                    base::BindOnce(&CefRunContextMenuCallbackImpl::Continue,
 | 
						|
                                   this, command_id, event_flags));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  void Cancel() override { Continue(kInvalidCommandId, kEmptyEventFlags); }
 | 
						|
 | 
						|
  void Disconnect() { callback_.Reset(); }
 | 
						|
 | 
						|
 private:
 | 
						|
  static void RunNow(Callback callback,
 | 
						|
                     int command_id,
 | 
						|
                     cef_event_flags_t event_flags) {
 | 
						|
    CEF_REQUIRE_UIT();
 | 
						|
    std::move(callback).Run(command_id, event_flags);
 | 
						|
  }
 | 
						|
 | 
						|
  Callback callback_;
 | 
						|
 | 
						|
  IMPLEMENT_REFCOUNTING(CefRunContextMenuCallbackImpl);
 | 
						|
};
 | 
						|
 | 
						|
}  // namespace
 | 
						|
 | 
						|
CefMenuManager::CefMenuManager(AlloyBrowserHostImpl* browser,
 | 
						|
                               std::unique_ptr<CefMenuRunner> runner)
 | 
						|
    : content::WebContentsObserver(browser->web_contents()),
 | 
						|
      browser_(browser),
 | 
						|
      runner_(std::move(runner)),
 | 
						|
      custom_menu_callback_(nullptr),
 | 
						|
      weak_ptr_factory_(this) {
 | 
						|
  DCHECK(web_contents());
 | 
						|
  model_ = new CefMenuModelImpl(this, nullptr, false);
 | 
						|
}
 | 
						|
 | 
						|
CefMenuManager::~CefMenuManager() {
 | 
						|
  // The model may outlive the delegate if the context menu is visible when the
 | 
						|
  // application is closed.
 | 
						|
  model_->set_delegate(nullptr);
 | 
						|
}
 | 
						|
 | 
						|
void CefMenuManager::Destroy() {
 | 
						|
  CancelContextMenu();
 | 
						|
  if (runner_)
 | 
						|
    runner_.reset(nullptr);
 | 
						|
}
 | 
						|
 | 
						|
bool CefMenuManager::IsShowingContextMenu() {
 | 
						|
  if (!web_contents())
 | 
						|
    return false;
 | 
						|
  return web_contents()->IsShowingContextMenu();
 | 
						|
}
 | 
						|
 | 
						|
bool CefMenuManager::CreateContextMenu(
 | 
						|
    const content::ContextMenuParams& params) {
 | 
						|
  // The renderer may send the "show context menu" message multiple times, one
 | 
						|
  // for each right click mouse event it receives. Normally, this doesn't happen
 | 
						|
  // because mouse events are not forwarded once the context menu is showing.
 | 
						|
  // However, there's a race - the context menu may not yet be showing when
 | 
						|
  // the second mouse event arrives. In this case, |HandleContextMenu()| will
 | 
						|
  // get called multiple times - if so, don't create another context menu.
 | 
						|
  // TODO(asvitkine): Fix the renderer so that it doesn't do this.
 | 
						|
  if (IsShowingContextMenu())
 | 
						|
    return true;
 | 
						|
 | 
						|
  params_ = params;
 | 
						|
  model_->Clear();
 | 
						|
 | 
						|
  // Create the default menu model.
 | 
						|
  CreateDefaultModel();
 | 
						|
 | 
						|
  bool custom_menu = false;
 | 
						|
  DCHECK(!custom_menu_callback_);
 | 
						|
 | 
						|
  // Give the client a chance to modify the model.
 | 
						|
  CefRefPtr<CefClient> client = browser_->GetClient();
 | 
						|
  if (client.get()) {
 | 
						|
    CefRefPtr<CefContextMenuHandler> handler = client->GetContextMenuHandler();
 | 
						|
    if (handler.get()) {
 | 
						|
      CefRefPtr<CefContextMenuParamsImpl> paramsPtr(
 | 
						|
          new CefContextMenuParamsImpl(¶ms_));
 | 
						|
      CefRefPtr<CefFrame> frame = browser_->GetFocusedFrame();
 | 
						|
 | 
						|
      handler->OnBeforeContextMenu(browser_, frame, paramsPtr.get(),
 | 
						|
                                   model_.get());
 | 
						|
 | 
						|
      MenuWillShow(model_);
 | 
						|
 | 
						|
      if (model_->GetCount() > 0) {
 | 
						|
        CefRefPtr<CefRunContextMenuCallbackImpl> callbackImpl(
 | 
						|
            new CefRunContextMenuCallbackImpl(
 | 
						|
                base::BindOnce(&CefMenuManager::ExecuteCommandCallback,
 | 
						|
                               weak_ptr_factory_.GetWeakPtr())));
 | 
						|
 | 
						|
        // This reference will be cleared when the callback is executed or
 | 
						|
        // the callback object is deleted.
 | 
						|
        custom_menu_callback_ = callbackImpl.get();
 | 
						|
 | 
						|
        if (handler->RunContextMenu(browser_, frame, paramsPtr.get(),
 | 
						|
                                    model_.get(), callbackImpl.get())) {
 | 
						|
          custom_menu = true;
 | 
						|
        } else {
 | 
						|
          // Callback should not be executed if the handler returns false.
 | 
						|
          DCHECK(custom_menu_callback_);
 | 
						|
          custom_menu_callback_ = nullptr;
 | 
						|
          callbackImpl->Disconnect();
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      // Do not keep references to the parameters in the callback.
 | 
						|
      std::ignore = paramsPtr->Detach(nullptr);
 | 
						|
      DCHECK(paramsPtr->HasOneRef());
 | 
						|
      DCHECK(model_->VerifyRefCount());
 | 
						|
 | 
						|
      // Menu is empty so notify the client and return.
 | 
						|
      if (model_->GetCount() == 0 && !custom_menu) {
 | 
						|
        MenuClosed(model_);
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (custom_menu || !runner_)
 | 
						|
    return true;
 | 
						|
  return runner_->RunContextMenu(browser_, model_.get(), params_);
 | 
						|
}
 | 
						|
 | 
						|
void CefMenuManager::CancelContextMenu() {
 | 
						|
  if (IsShowingContextMenu()) {
 | 
						|
    if (custom_menu_callback_)
 | 
						|
      custom_menu_callback_->Cancel();
 | 
						|
    else if (runner_)
 | 
						|
      runner_->CancelContextMenu();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void CefMenuManager::ExecuteCommand(CefRefPtr<CefMenuModelImpl> source,
 | 
						|
                                    int command_id,
 | 
						|
                                    cef_event_flags_t event_flags) {
 | 
						|
  // Give the client a chance to handle the command.
 | 
						|
  CefRefPtr<CefClient> client = browser_->GetClient();
 | 
						|
  if (client.get()) {
 | 
						|
    CefRefPtr<CefContextMenuHandler> handler = client->GetContextMenuHandler();
 | 
						|
    if (handler.get()) {
 | 
						|
      CefRefPtr<CefContextMenuParamsImpl> paramsPtr(
 | 
						|
          new CefContextMenuParamsImpl(¶ms_));
 | 
						|
 | 
						|
      bool handled = handler->OnContextMenuCommand(
 | 
						|
          browser_, browser_->GetFocusedFrame(), paramsPtr.get(), command_id,
 | 
						|
          event_flags);
 | 
						|
 | 
						|
      // Do not keep references to the parameters in the callback.
 | 
						|
      std::ignore = paramsPtr->Detach(nullptr);
 | 
						|
      DCHECK(paramsPtr->HasOneRef());
 | 
						|
 | 
						|
      if (handled)
 | 
						|
        return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Execute the default command handling.
 | 
						|
  ExecuteDefaultCommand(command_id);
 | 
						|
}
 | 
						|
 | 
						|
void CefMenuManager::MenuWillShow(CefRefPtr<CefMenuModelImpl> source) {
 | 
						|
  // May be called for sub-menus as well.
 | 
						|
  if (source.get() != model_.get())
 | 
						|
    return;
 | 
						|
 | 
						|
  if (!web_contents())
 | 
						|
    return;
 | 
						|
 | 
						|
  // May be called multiple times.
 | 
						|
  if (IsShowingContextMenu())
 | 
						|
    return;
 | 
						|
 | 
						|
  // Notify the host before showing the context menu.
 | 
						|
  web_contents()->SetShowingContextMenu(true);
 | 
						|
}
 | 
						|
 | 
						|
void CefMenuManager::MenuClosed(CefRefPtr<CefMenuModelImpl> source) {
 | 
						|
  // May be called for sub-menus as well.
 | 
						|
  if (source.get() != model_.get())
 | 
						|
    return;
 | 
						|
 | 
						|
  if (!web_contents())
 | 
						|
    return;
 | 
						|
 | 
						|
  DCHECK(IsShowingContextMenu());
 | 
						|
 | 
						|
  // Notify the client.
 | 
						|
  CefRefPtr<CefClient> client = browser_->GetClient();
 | 
						|
  if (client.get()) {
 | 
						|
    CefRefPtr<CefContextMenuHandler> handler = client->GetContextMenuHandler();
 | 
						|
    if (handler.get()) {
 | 
						|
      handler->OnContextMenuDismissed(browser_, browser_->GetFocusedFrame());
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Notify the host after closing the context menu.
 | 
						|
  web_contents()->SetShowingContextMenu(false);
 | 
						|
  web_contents()->NotifyContextMenuClosed(params_.link_followed);
 | 
						|
}
 | 
						|
 | 
						|
bool CefMenuManager::FormatLabel(CefRefPtr<CefMenuModelImpl> source,
 | 
						|
                                 std::u16string& label) {
 | 
						|
  if (!runner_)
 | 
						|
    return false;
 | 
						|
  return runner_->FormatLabel(label);
 | 
						|
}
 | 
						|
 | 
						|
void CefMenuManager::ExecuteCommandCallback(int command_id,
 | 
						|
                                            cef_event_flags_t event_flags) {
 | 
						|
  DCHECK(IsShowingContextMenu());
 | 
						|
  DCHECK(custom_menu_callback_);
 | 
						|
  if (command_id != kInvalidCommandId)
 | 
						|
    ExecuteCommand(model_, command_id, event_flags);
 | 
						|
  MenuClosed(model_);
 | 
						|
  custom_menu_callback_ = nullptr;
 | 
						|
}
 | 
						|
 | 
						|
void CefMenuManager::CreateDefaultModel() {
 | 
						|
  if (!params_.custom_items.empty()) {
 | 
						|
    // Custom menu items originating from the renderer process. For example,
 | 
						|
    // plugin placeholder menu items.
 | 
						|
    for (auto& item : params_.custom_items) {
 | 
						|
      auto new_item = item->Clone();
 | 
						|
      new_item->action += MENU_ID_CUSTOM_FIRST;
 | 
						|
      DCHECK_LE(static_cast<int>(new_item->action), MENU_ID_CUSTOM_LAST);
 | 
						|
      model_->AddMenuItem(*new_item);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (params_.is_editable) {
 | 
						|
    // Editable node.
 | 
						|
    model_->AddItem(MENU_ID_UNDO, GetLabel(IDS_CONTENT_CONTEXT_UNDO));
 | 
						|
    model_->AddItem(MENU_ID_REDO, GetLabel(IDS_CONTENT_CONTEXT_REDO));
 | 
						|
 | 
						|
    model_->AddSeparator();
 | 
						|
    model_->AddItem(MENU_ID_CUT, GetLabel(IDS_CONTENT_CONTEXT_CUT));
 | 
						|
    model_->AddItem(MENU_ID_COPY, GetLabel(IDS_CONTENT_CONTEXT_COPY));
 | 
						|
    model_->AddItem(MENU_ID_PASTE, GetLabel(IDS_CONTENT_CONTEXT_PASTE));
 | 
						|
 | 
						|
    model_->AddSeparator();
 | 
						|
    model_->AddItem(MENU_ID_SELECT_ALL,
 | 
						|
                    GetLabel(IDS_CONTENT_CONTEXT_SELECTALL));
 | 
						|
 | 
						|
    if (!(params_.edit_flags & CM_EDITFLAG_CAN_UNDO))
 | 
						|
      model_->SetEnabled(MENU_ID_UNDO, false);
 | 
						|
    if (!(params_.edit_flags & CM_EDITFLAG_CAN_REDO))
 | 
						|
      model_->SetEnabled(MENU_ID_REDO, false);
 | 
						|
    if (!(params_.edit_flags & CM_EDITFLAG_CAN_CUT))
 | 
						|
      model_->SetEnabled(MENU_ID_CUT, false);
 | 
						|
    if (!(params_.edit_flags & CM_EDITFLAG_CAN_COPY))
 | 
						|
      model_->SetEnabled(MENU_ID_COPY, false);
 | 
						|
    if (!(params_.edit_flags & CM_EDITFLAG_CAN_PASTE))
 | 
						|
      model_->SetEnabled(MENU_ID_PASTE, false);
 | 
						|
    if (!(params_.edit_flags & CM_EDITFLAG_CAN_DELETE))
 | 
						|
      model_->SetEnabled(MENU_ID_DELETE, false);
 | 
						|
    if (!(params_.edit_flags & CM_EDITFLAG_CAN_SELECT_ALL))
 | 
						|
      model_->SetEnabled(MENU_ID_SELECT_ALL, false);
 | 
						|
 | 
						|
    if (!params_.misspelled_word.empty()) {
 | 
						|
      // Always add a separator before the list of dictionary suggestions or
 | 
						|
      // "No spelling suggestions".
 | 
						|
      model_->AddSeparator();
 | 
						|
 | 
						|
      if (!params_.dictionary_suggestions.empty()) {
 | 
						|
        for (size_t i = 0; i < params_.dictionary_suggestions.size() &&
 | 
						|
                           MENU_ID_SPELLCHECK_SUGGESTION_0 + i <=
 | 
						|
                               MENU_ID_SPELLCHECK_SUGGESTION_LAST;
 | 
						|
             ++i) {
 | 
						|
          model_->AddItem(MENU_ID_SPELLCHECK_SUGGESTION_0 + static_cast<int>(i),
 | 
						|
                          params_.dictionary_suggestions[i]);
 | 
						|
        }
 | 
						|
 | 
						|
        // When there are dictionary suggestions add a separator before "Add to
 | 
						|
        // dictionary".
 | 
						|
        model_->AddSeparator();
 | 
						|
      } else {
 | 
						|
        model_->AddItem(MENU_ID_NO_SPELLING_SUGGESTIONS,
 | 
						|
                        GetLabel(IDS_CONTENT_CONTEXT_NO_SPELLING_SUGGESTIONS));
 | 
						|
        model_->SetEnabled(MENU_ID_NO_SPELLING_SUGGESTIONS, false);
 | 
						|
      }
 | 
						|
 | 
						|
      model_->AddItem(MENU_ID_ADD_TO_DICTIONARY,
 | 
						|
                      GetLabel(IDS_CONTENT_CONTEXT_ADD_TO_DICTIONARY));
 | 
						|
    }
 | 
						|
  } else if (!params_.selection_text.empty()) {
 | 
						|
    // Something is selected.
 | 
						|
    model_->AddItem(MENU_ID_COPY, GetLabel(IDS_CONTENT_CONTEXT_COPY));
 | 
						|
  } else if (!params_.page_url.is_empty() || !params_.frame_url.is_empty()) {
 | 
						|
    // Page or frame.
 | 
						|
    model_->AddItem(MENU_ID_BACK, GetLabel(IDS_CONTENT_CONTEXT_BACK));
 | 
						|
    model_->AddItem(MENU_ID_FORWARD, GetLabel(IDS_CONTENT_CONTEXT_FORWARD));
 | 
						|
 | 
						|
    model_->AddSeparator();
 | 
						|
    model_->AddItem(MENU_ID_PRINT, GetLabel(IDS_CONTENT_CONTEXT_PRINT));
 | 
						|
    model_->AddItem(MENU_ID_VIEW_SOURCE,
 | 
						|
                    GetLabel(IDS_CONTENT_CONTEXT_VIEWPAGESOURCE));
 | 
						|
 | 
						|
    if (!browser_->CanGoBack())
 | 
						|
      model_->SetEnabled(MENU_ID_BACK, false);
 | 
						|
    if (!browser_->CanGoForward())
 | 
						|
      model_->SetEnabled(MENU_ID_FORWARD, false);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void CefMenuManager::ExecuteDefaultCommand(int command_id) {
 | 
						|
  if (IsCustomContextMenuCommand(command_id)) {
 | 
						|
    if (web_contents()) {
 | 
						|
      web_contents()->ExecuteCustomContextMenuCommand(
 | 
						|
          command_id - MENU_ID_CUSTOM_FIRST, params_.link_followed);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // If the user chose a replacement word for a misspelling, replace it here.
 | 
						|
  if (command_id >= MENU_ID_SPELLCHECK_SUGGESTION_0 &&
 | 
						|
      command_id <= MENU_ID_SPELLCHECK_SUGGESTION_LAST) {
 | 
						|
    const size_t suggestion_index =
 | 
						|
        static_cast<size_t>(command_id) - MENU_ID_SPELLCHECK_SUGGESTION_0;
 | 
						|
    if (suggestion_index < params_.dictionary_suggestions.size()) {
 | 
						|
      browser_->ReplaceMisspelling(
 | 
						|
          params_.dictionary_suggestions[suggestion_index]);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  switch (command_id) {
 | 
						|
    // Navigation.
 | 
						|
    case MENU_ID_BACK:
 | 
						|
      browser_->GoBack();
 | 
						|
      break;
 | 
						|
    case MENU_ID_FORWARD:
 | 
						|
      browser_->GoForward();
 | 
						|
      break;
 | 
						|
    case MENU_ID_RELOAD:
 | 
						|
      browser_->Reload();
 | 
						|
      break;
 | 
						|
    case MENU_ID_RELOAD_NOCACHE:
 | 
						|
      browser_->ReloadIgnoreCache();
 | 
						|
      break;
 | 
						|
    case MENU_ID_STOPLOAD:
 | 
						|
      browser_->StopLoad();
 | 
						|
      break;
 | 
						|
 | 
						|
    // Editing.
 | 
						|
    case MENU_ID_UNDO:
 | 
						|
      browser_->GetFocusedFrame()->Undo();
 | 
						|
      break;
 | 
						|
    case MENU_ID_REDO:
 | 
						|
      browser_->GetFocusedFrame()->Redo();
 | 
						|
      break;
 | 
						|
    case MENU_ID_CUT:
 | 
						|
      browser_->GetFocusedFrame()->Cut();
 | 
						|
      break;
 | 
						|
    case MENU_ID_COPY:
 | 
						|
      browser_->GetFocusedFrame()->Copy();
 | 
						|
      break;
 | 
						|
    case MENU_ID_PASTE:
 | 
						|
      browser_->GetFocusedFrame()->Paste();
 | 
						|
      break;
 | 
						|
    case MENU_ID_DELETE:
 | 
						|
      browser_->GetFocusedFrame()->Delete();
 | 
						|
      break;
 | 
						|
    case MENU_ID_SELECT_ALL:
 | 
						|
      browser_->GetFocusedFrame()->SelectAll();
 | 
						|
      break;
 | 
						|
 | 
						|
    // Miscellaneous.
 | 
						|
    case MENU_ID_FIND:
 | 
						|
      // TODO(cef): Implement.
 | 
						|
      NOTIMPLEMENTED();
 | 
						|
      break;
 | 
						|
    case MENU_ID_PRINT:
 | 
						|
      browser_->Print();
 | 
						|
      break;
 | 
						|
    case MENU_ID_VIEW_SOURCE:
 | 
						|
      browser_->GetFocusedFrame()->ViewSource();
 | 
						|
      break;
 | 
						|
 | 
						|
    // Spell checking.
 | 
						|
    case MENU_ID_ADD_TO_DICTIONARY:
 | 
						|
      browser_->GetHost()->AddWordToDictionary(params_.misspelled_word);
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool CefMenuManager::IsCustomContextMenuCommand(int command_id) {
 | 
						|
  // Verify that the command ID is in the correct range.
 | 
						|
  if (command_id < MENU_ID_CUSTOM_FIRST || command_id > MENU_ID_CUSTOM_LAST)
 | 
						|
    return false;
 | 
						|
 | 
						|
  command_id -= MENU_ID_CUSTOM_FIRST;
 | 
						|
 | 
						|
  // Verify that the specific command ID was passed from the renderer process.
 | 
						|
  if (!params_.custom_items.empty()) {
 | 
						|
    for (size_t i = 0; i < params_.custom_items.size(); ++i) {
 | 
						|
      if (static_cast<int>(params_.custom_items[i]->action) == command_id)
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 |