<commit_before>// 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 "base/compiler_specific.h"
#include "base/logging.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/common/content_client.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(TOOLKIT_GTK)
#include "libcef/browser/menu_creator_runner_gtk.h"
#endif

namespace {

CefString GetLabel(int message_id) {
  string16 label = content::GetContentClient()->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::RenderWidgetHostView* view =
      browser_->GetWebContents()->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<CefFrame> frame;
        if (params_.frame_id > 0)
          frame = browser_->GetFrame(params_.frame_id);
        if (!frame.get())
          frame = browser_->GetMainFrame();

        CefRefPtr<CefContextMenuParamsImpl> paramsPtr(
            new CefContextMenuParamsImpl(&params_));

        handler->OnBeforeContextMenu(browser_, frame, paramsPtr.get(),
                                     model_.get());

        // Do not keep references to the parameters in the callback.
        paramsPtr->Detach(NULL);
        DCHECK_EQ(paramsPtr->GetRefCt(), 1);
        DCHECK(model_->VerifyRefCount());

        // Menu is empty so notify the client and return.
        if (model_->GetCount() == 0) {
          MenuClosed(model_);
          return true;
        }
      }
  }

  return runner_->RunContextMenu(this);
}

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(TOOLKIT_GTK)
    runner_.reset(new CefMenuCreatorRunnerGtk);
#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<CefFrame> frame;
        if (params_.frame_id > 0)
          frame = browser_->GetFrame(params_.frame_id);
        if (!frame.get())
          frame = browser_->GetMainFrame();

        CefRefPtr<CefContextMenuParamsImpl> paramsPtr(
            new CefContextMenuParamsImpl(&params_));

        bool handled = handler->OnContextMenuCommand(browser_, frame,
            paramsPtr.get(), command_id, event_flags);

        // Do not keep references to the parameters in the callback.
        paramsPtr->Detach(NULL);
        DCHECK_EQ(paramsPtr->GetRefCt(), 1);

        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;

  // Notify the host before showing the context menu.
  content::RenderWidgetHostView* view =
      browser_->GetWebContents()->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()) {
        CefRefPtr<CefFrame> frame;
        if (params_.frame_id > 0)
          frame = browser_->GetFrame(params_.frame_id);
        if (!frame.get())
          frame = browser_->GetMainFrame();

        handler->OnContextMenuDismissed(browser_, frame);
      }
  }<commit_msg>Fix crash when destroying the browser window while a context menu is displayed.<commit_after>// 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 "base/compiler_specific.h"
#include "base/logging.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/common/content_client.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(TOOLKIT_GTK)
#include "libcef/browser/menu_creator_runner_gtk.h"
#endif

namespace {

CefString GetLabel(int message_id) {
  string16 label = content::GetContentClient()->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<CefFrame> frame;
        if (params_.frame_id > 0)
          frame = browser_->GetFrame(params_.frame_id);
        if (!frame.get())
          frame = browser_->GetMainFrame();

        CefRefPtr<CefContextMenuParamsImpl> paramsPtr(
            new CefContextMenuParamsImpl(&params_));

        handler->OnBeforeContextMenu(browser_, frame, paramsPtr.get(),
                                     model_.get());

        // Do not keep references to the parameters in the callback.
        paramsPtr->Detach(NULL);
        DCHECK_EQ(paramsPtr->GetRefCt(), 1);
        DCHECK(model_->VerifyRefCount());

        // Menu is empty so notify the client and return.
        if (model_->GetCount() == 0) {
          MenuClosed(model_);
          return true;
        }
      }
  }

  return runner_->RunContextMenu(this);
}

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(TOOLKIT_GTK)
    runner_.reset(new CefMenuCreatorRunnerGtk);
#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<CefFrame> frame;
        if (params_.frame_id > 0)
          frame = browser_->GetFrame(params_.frame_id);
        if (!frame.get())
          frame = browser_->GetMainFrame();

        CefRefPtr<CefContextMenuParamsImpl> paramsPtr(
            new CefContextMenuParamsImpl(&params_));

        bool handled = handler->OnContextMenuCommand(browser_, frame,
            paramsPtr.get(), command_id, event_flags);

        // Do not keep references to the parameters in the callback.
        paramsPtr->Detach(NULL);
        DCHECK_EQ(paramsPtr->GetRefCt(), 1);

        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()) {
        CefRefPtr<CefFrame> frame;
        if (params_.frame_id > 0)
          frame = browser_->GetFrame(params_.frame_id);
        if (!frame.get())
          frame = browser_->GetMainFrame();

        handler->OnContextMenuDismissed(browser_, frame);
      }
  }
{'fraction_non_alphanumeric': 0.1126313217688737, 'fraction_numerical': 0.0019545565599804545, 'mean_word_length': 3.2937062937062938, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 99, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3372523', 'n_tokens_mistral': 3769, 'n_tokens_neox': 3682, 'n_words': 913}