cef/libcef/browser/menu_creator.cc

343 lines
11 KiB
C++
Raw Normal View History

// 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_creator.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/context_menu_params_impl.h"
#include "libcef/common/content_client.h"
#include "base/compiler_specific.h"
#include "base/logging.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 "grit/cef_strings.h"
#if defined(OS_WIN)
#include "libcef/browser/menu_creator_runner_win.h"
#elif defined(OS_MACOSX)
#include "libcef/browser/menu_creator_runner_mac.h"
#elif defined(OS_LINUX)
#include "libcef/browser/menu_creator_runner_linux.h"
#endif
namespace {
CefString GetLabel(int message_id) {
base::string16 label =
CefContentClient::Get()->GetLocalizedString(message_id);
DCHECK(!label.empty());
return label;
}
} // namespace
CefMenuCreator::CefMenuCreator(CefBrowserHostImpl* browser)
: browser_(browser) {
model_ = new CefMenuModelImpl(this);
}
CefMenuCreator::~CefMenuCreator() {
// The model may outlive the delegate if the context menu is visible when the
// application is closed.
model_->set_delegate(NULL);
}
bool CefMenuCreator::IsShowingContextMenu() {
content::WebContents* web_contents = browser_->GetWebContents();
if (!web_contents)
return false;
content::RenderWidgetHostView* view = web_contents->GetRenderWidgetHostView();
return (view && view->IsShowingContextMenu());
}
bool CefMenuCreator::CreateContextMenu(
const content::ContextMenuParams& params) {
if (!CreateRunner())
return true;
// 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();
// 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(&params_));
handler->OnBeforeContextMenu(browser_,
browser_->GetFocusedFrame(),
paramsPtr.get(),
model_.get());
// Do not keep references to the parameters in the callback.
paramsPtr->Detach(NULL);
Introduce the use of Chromium types (issue #1336). Changes to the CEF public API: - Add base::Bind, base::Callback, base::Lock, base::WeakPtr, scoped_refptr, scoped_ptr and supporting types. - Add include/wrapper/cef_closure_task.h helpers for converting a base::Closure to a CefTask. - Change CefRefPtr to extend scoped_refptr. -- Change CefBase method signatures to match RefCountedThreadSafeBase. - Change IMPLEMENT_REFCOUNTING to use base::AtomicRefCount*. -- Remove the CefAtomic* functions. -- IMPLEMENT_REFCOUNTING now enforces via a compile-time error that the correct class name was passed to the macro. - Change IMPLEMENT_LOCKING to use base::Lock. -- Remove the CefCriticalSection class. -- Deprecate the IMPLEMENT_LOCKING macro. -- base::Lock will DCHECK() in Debug builds if lock usage is reentrant. - Move include/internal/cef_tuple.h to include/base/cef_tuple.h. - Allow an empty |callback| parameter passed to CefBeginTracing. Changes to the CEF implementation: - Fix incorrect names passed to the IMPLEMENT_REFCOUNTING macro. - Fix instances of reentrant locking in the CefXmlObject and CefRequest implementations. - Remove use of the IMPLEMENT_LOCKING macro. Changes to cef_unittests: - Add tests/unittests/chromium_includes.h and always include it first from unit test .cc files to avoid name conflicts with Chromium types. - Fix wrong header include ordering. - Remove use of the IMPLEMENT_LOCKING macro. Changes to cefclient and cefsimple: - Use base::Bind and cef_closure_task.h instead of NewCefRunnable*. - Remove use of the IMPEMENT_LOCKING macro. - Fix incorrect/unnecessary locking. - Add additional runtime thread checks. - Windows: Perform actions on the UI thread instead of the main thread when running in multi-threaded-message-loop mode to avoid excessive locking. git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1769 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
2014-07-15 00:18:51 +02:00
DCHECK(paramsPtr->HasOneRef());
DCHECK(model_->VerifyRefCount());
// Menu is empty so notify the client and return.
if (model_->GetCount() == 0) {
MenuClosed(model_);
return true;
}
}
}
return runner_->RunContextMenu(this);
}
Implement off-screen rendering support using delegated rendering (issue #1257). This implementation supports both GPU compositing and software compositing (used when GPU is not supported or when passing `--disable-gpu --disable-gpu-compositing` command-line flags). GPU-accelerated features (WebGL and 3D CSS) that did not work with the previous off-screen rendering implementation do work with this implementation when GPU support is available. Rendering now operates on a per-frame basis. The frame rate is configurable via CefBrowserSettings.windowless_frame_rate up to a maximum of 60fps (potentially limited by how fast the system can generate new frames). CEF generates a bitmap from the compositor backing and passes it to CefRenderHandler::OnPaint. The previous CefRenderHandler/CefBrowserHost API for off-screen rendering has been restored mostly as-is with some minor changes: - CefBrowserHost::Invalidate no longer accepts a CefRect region argument. Instead of invalidating a specific region it now triggers generation of a new frame. - The |dirtyRects| argument to CefRenderHandler::OnPaint will now always be a single CefRect representing the whole view (frame) size. Previously, invalidated regions were listed separately. - Linux: CefBrowserHost::SendKeyEvent now expects X11 event information instead of GTK event information. See cefclient for an example of converting GTK events to the necessary format. - Sizes passed to the CefRenderHandler OnPaint and OnPopupSize methods are now already DPI scaled. Previously, the client had to perform DPI scaling. - Includes drag&drop implementation from issue #1032. - Includes unit test fixes from issue #1245. git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1751 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
2014-07-01 00:30:29 +02:00
void CefMenuCreator::CancelContextMenu() {
if (IsShowingContextMenu())
runner_->CancelContextMenu();
}
bool CefMenuCreator::CreateRunner() {
if (!runner_.get()) {
// Create the menu runner.
#if defined(OS_WIN)
runner_.reset(new CefMenuCreatorRunnerWin);
#elif defined(OS_MACOSX)
runner_.reset(new CefMenuCreatorRunnerMac);
#elif defined(OS_LINUX)
runner_.reset(new CefMenuCreatorRunnerLinux);
#else
// Need an implementation.
NOTREACHED();
#endif
}
return (runner_.get() != NULL);
}
void CefMenuCreator::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(&params_));
bool handled = handler->OnContextMenuCommand(
browser_,
browser_->GetFocusedFrame(),
paramsPtr.get(),
command_id,
event_flags);
// Do not keep references to the parameters in the callback.
paramsPtr->Detach(NULL);
Introduce the use of Chromium types (issue #1336). Changes to the CEF public API: - Add base::Bind, base::Callback, base::Lock, base::WeakPtr, scoped_refptr, scoped_ptr and supporting types. - Add include/wrapper/cef_closure_task.h helpers for converting a base::Closure to a CefTask. - Change CefRefPtr to extend scoped_refptr. -- Change CefBase method signatures to match RefCountedThreadSafeBase. - Change IMPLEMENT_REFCOUNTING to use base::AtomicRefCount*. -- Remove the CefAtomic* functions. -- IMPLEMENT_REFCOUNTING now enforces via a compile-time error that the correct class name was passed to the macro. - Change IMPLEMENT_LOCKING to use base::Lock. -- Remove the CefCriticalSection class. -- Deprecate the IMPLEMENT_LOCKING macro. -- base::Lock will DCHECK() in Debug builds if lock usage is reentrant. - Move include/internal/cef_tuple.h to include/base/cef_tuple.h. - Allow an empty |callback| parameter passed to CefBeginTracing. Changes to the CEF implementation: - Fix incorrect names passed to the IMPLEMENT_REFCOUNTING macro. - Fix instances of reentrant locking in the CefXmlObject and CefRequest implementations. - Remove use of the IMPLEMENT_LOCKING macro. Changes to cef_unittests: - Add tests/unittests/chromium_includes.h and always include it first from unit test .cc files to avoid name conflicts with Chromium types. - Fix wrong header include ordering. - Remove use of the IMPLEMENT_LOCKING macro. Changes to cefclient and cefsimple: - Use base::Bind and cef_closure_task.h instead of NewCefRunnable*. - Remove use of the IMPEMENT_LOCKING macro. - Fix incorrect/unnecessary locking. - Add additional runtime thread checks. - Windows: Perform actions on the UI thread instead of the main thread when running in multi-threaded-message-loop mode to avoid excessive locking. git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1769 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
2014-07-15 00:18:51 +02:00
DCHECK(paramsPtr->HasOneRef());
if (handled)
return;
}
}
// Execute the default command handling.
ExecuteDefaultCommand(command_id);
}
void CefMenuCreator::MenuWillShow(CefRefPtr<CefMenuModelImpl> source) {
// May be called for sub-menus as well.
if (source.get() != model_.get())
return;
content::WebContents* web_contents = browser_->GetWebContents();
if (!web_contents)
return;
// Notify the host before showing the context menu.
content::RenderWidgetHostView* view = web_contents->GetRenderWidgetHostView();
if (view)
view->SetShowingContextMenu(true);
}
void CefMenuCreator::MenuClosed(CefRefPtr<CefMenuModelImpl> source) {
// May be called for sub-menus as well.
if (source.get() != model_.get())
return;
// Notify the client.
CefRefPtr<CefClient> client = browser_->GetClient();
if (client.get()) {
CefRefPtr<CefContextMenuHandler> handler =
client->GetContextMenuHandler();
if (handler.get()) {
handler->OnContextMenuDismissed(browser_, browser_->GetFocusedFrame());
}
}
if (IsShowingContextMenu()) {
// Notify the host after closing the context menu.
content::WebContents* web_contents = browser_->GetWebContents();
content::RenderWidgetHostView* view =
web_contents->GetRenderWidgetHostView();
if (view)
view->SetShowingContextMenu(false);
web_contents->NotifyContextMenuClosed(params_.custom_context);
}
}
bool CefMenuCreator::FormatLabel(base::string16& label) {
return runner_->FormatLabel(label);
}
void CefMenuCreator::CreateDefaultModel() {
if (params_.is_editable) {
// Editable node.
model_->AddItem(MENU_ID_UNDO, GetLabel(IDS_MENU_UNDO));
model_->AddItem(MENU_ID_REDO, GetLabel(IDS_MENU_REDO));
model_->AddSeparator();
model_->AddItem(MENU_ID_CUT, GetLabel(IDS_MENU_CUT));
model_->AddItem(MENU_ID_COPY, GetLabel(IDS_MENU_COPY));
model_->AddItem(MENU_ID_PASTE, GetLabel(IDS_MENU_PASTE));
model_->AddItem(MENU_ID_DELETE, GetLabel(IDS_MENU_DELETE));
model_->AddSeparator();
model_->AddItem(MENU_ID_SELECT_ALL, GetLabel(IDS_MENU_SELECT_ALL));
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);
Add spell checking support (issue #137). This includes: - Red underline of misspelled words in html text areas. - Right-click context menu options to correct the misspelled word. - New CefBrowser::ReplaceMisspelling method for accepting a word replacement. - Methods added to CefContextMenuParams for retrieving spelling-related information. - Uses the unified text checker when auto-correct is not enabled to match Google Chrome behavior. - On Windows and Linux a hunspell dictionary file will be downloaded to the "<cache_path>/Dictionaries" directory as needed, or used from the <cache_path> directory if the file already exists there. The dictionary file will be downloaded from http://cache.pack.google.com/edgedl/chrome/dict/<LANG>-3-0.bdic where <LANG> is the language abbreviation. - On OS X the spell checking implementation will use the system NSSpellChecker implementation. The following command-line flags have been added: --disable-spell-checking => Disable spell-checking support (no red underline, no dictionary file download, etc). --enable-spelling-auto-correct => Automatically correct common misspellings while typing (like 'omre' to 'more' on Windows/Linux or 'ehlo' to 'helo' on OS X). --enable-spelling-service => Enable use of the remote Google spelling service (this requires Google API keys). --override-spell-check-lang=<LANG> => Use the specified dictionary language <LANG> instead of the language specified in the locales.pak file. To see the default/supported dictionary languages: https://code.google.com/p/chromium/codesearch#search/&q=IDS_SPELLCHECK_DICTIONARY%20xtb&sq=package:chromium git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1859 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
2014-10-07 22:44:33 +02:00
if(!params_.misspelled_word.empty()) {
if (!params_.dictionary_suggestions.empty())
model_->AddSeparator();
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].c_str());
}
if (params_.dictionary_suggestions.empty()) {
model_->AddItem(
MENU_ID_NO_SPELLING_SUGGESTIONS,
GetLabel(IDS_MENU_NO_SPELLING_SUGGESTIONS));
}
}
} else if (!params_.selection_text.empty()) {
// Something is selected.
model_->AddItem(MENU_ID_COPY, GetLabel(IDS_MENU_COPY));
} else if (!params_.page_url.is_empty() || !params_.frame_url.is_empty()) {
// Page or frame.
model_->AddItem(MENU_ID_BACK, GetLabel(IDS_MENU_BACK));
model_->AddItem(MENU_ID_FORWARD, GetLabel(IDS_MENU_FORWARD));
model_->AddSeparator();
model_->AddItem(MENU_ID_PRINT, GetLabel(IDS_MENU_PRINT));
model_->AddItem(MENU_ID_VIEW_SOURCE, GetLabel(IDS_MENU_VIEW_SOURCE));
if (!browser_->CanGoBack())
model_->SetEnabled(MENU_ID_BACK, false);
if (!browser_->CanGoForward())
model_->SetEnabled(MENU_ID_FORWARD, false);
}
}
void CefMenuCreator::ExecuteDefaultCommand(int command_id) {
Add spell checking support (issue #137). This includes: - Red underline of misspelled words in html text areas. - Right-click context menu options to correct the misspelled word. - New CefBrowser::ReplaceMisspelling method for accepting a word replacement. - Methods added to CefContextMenuParams for retrieving spelling-related information. - Uses the unified text checker when auto-correct is not enabled to match Google Chrome behavior. - On Windows and Linux a hunspell dictionary file will be downloaded to the "<cache_path>/Dictionaries" directory as needed, or used from the <cache_path> directory if the file already exists there. The dictionary file will be downloaded from http://cache.pack.google.com/edgedl/chrome/dict/<LANG>-3-0.bdic where <LANG> is the language abbreviation. - On OS X the spell checking implementation will use the system NSSpellChecker implementation. The following command-line flags have been added: --disable-spell-checking => Disable spell-checking support (no red underline, no dictionary file download, etc). --enable-spelling-auto-correct => Automatically correct common misspellings while typing (like 'omre' to 'more' on Windows/Linux or 'ehlo' to 'helo' on OS X). --enable-spelling-service => Enable use of the remote Google spelling service (this requires Google API keys). --override-spell-check-lang=<LANG> => Use the specified dictionary language <LANG> instead of the language specified in the locales.pak file. To see the default/supported dictionary languages: https://code.google.com/p/chromium/codesearch#search/&q=IDS_SPELLCHECK_DICTIONARY%20xtb&sq=package:chromium git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1859 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
2014-10-07 22:44:33 +02:00
// 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;
default:
break;
}
}