<commit_before>// Copyright (c) 2006-2008 The Chromium 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 "config.h"

#include "base/compiler_specific.h"

MSVC_PUSH_WARNING_LEVEL(0);
#include "ContextMenu.h"
#include "Document.h"
#include "DocumentLoader.h"
#include "Editor.h"
#include "FrameLoader.h"
#include "FrameView.h"
#include "HitTestResult.h"
#include "KURL.h"
#include "Widget.h"
MSVC_POP_WARNING();
#undef LOG

#include "webkit/glue/context_menu_client_impl.h"

#include "base/string_util.h"
#include "webkit/glue/context_node_types.h"
#include "webkit/glue/glue_util.h"
#include "webkit/glue/webdocumentloader_impl.h"
#include "webkit/glue/webview_impl.h"

#include "base/word_iterator.h"

// Helper function to determine whether text is a single word or a sentence.
static bool IsASingleWord(const std::wstring& text) {
  WordIterator iter(text, WordIterator::BREAK_WORD);
  int word_count = 0;
  if (!iter.Init()) return false;
  while (iter.Advance()) {
    if (iter.IsWord()) {
      word_count++;
      if (word_count > 1) // More than one word.
        return false;
    }
  }
  
  // Check for 0 words.
  if (!word_count)
    return false;
  
  // Has a single word.
  return true;
}

// Helper function to get misspelled word on which context menu 
// is to be evolked. This function also sets the word on which context menu
// has been evoked to be the selected word, as required.
static std::wstring GetMisspelledWord(WebCore::ContextMenu* default_menu,
                                      WebCore::Frame* selected_frame) {
  std::wstring misspelled_word_string;

  // First select from selectedText to check for multiple word selection.
  misspelled_word_string = CollapseWhitespace(
      webkit_glue::StringToStdWString(selected_frame->selectedText()),
      false);

  // Don't provide suggestions for multiple words.
  if (!misspelled_word_string.empty() && 
      !IsASingleWord(misspelled_word_string))
    return L"";

  // Expand around the click to see if we clicked a word.
  WebCore::Selection selection;
  WebCore::VisiblePosition pos(default_menu->hitTestResult().innerNode()->
      renderer()->positionForPoint(default_menu->hitTestResult().
                                   localPoint()));

  if (pos.isNotNull()) {
    selection = WebCore::Selection(pos);
    selection.expandUsingGranularity(WebCore::WordGranularity);
  }
      
  if (selection.isRange()) { 
    selected_frame->setSelectionGranularity(WebCore::WordGranularity);
  }
        
  if (selected_frame->shouldChangeSelection(selection))
    selected_frame->selection()->setSelection(selection);
       
  misspelled_word_string = CollapseWhitespace(
      webkit_glue::StringToStdWString(selected_frame->selectedText()),                  
                                      false);
  
  return misspelled_word_string;
}

ContextMenuClientImpl::~ContextMenuClientImpl() {
}

void ContextMenuClientImpl::contextMenuDestroyed() {
  delete this;
}

// Figure out the URL of a page or subframe. Returns |page_type| as the type,
// which indicates page or subframe, or ContextNode::NONE if the URL could not
// be determined for some reason.
static ContextNode::Type GetTypeAndURLFromFrame(WebCore::Frame* frame,
                                                GURL* url,
                                                ContextNode::Type page_type) {
  ContextNode::Type type = ContextNode::NONE;
  if (frame) {
    WebCore::DocumentLoader* dl = frame->loader()->documentLoader();
    if (dl) {
      WebDataSource* ds = static_cast<WebDocumentLoaderImpl*>(dl)->
          GetDataSource();
      if (ds) {
        type = page_type;
        *url = ds->HasUnreachableURL() ? ds->GetUnreachableURL()
                                       : ds->GetRequest().GetURL();
      }
    }
  }
  return type;
}

WebCore::PlatformMenuDescription
    ContextMenuClientImpl::getCustomMenuFromDefaultItems(
        WebCore::ContextMenu* default_menu) {
  // Displaying the context menu in this function is a big hack as we don't
  // have context, i.e. whether this is being invoked via a script or in 
  // response to user input (Mouse event WM_RBUTTONDOWN,
  // Keyboard events KeyVK_APPS, Shift+F10). Check if this is being invoked
  // in response to the above input events before popping up the context menu.
  if (!webview_->context_menu_allowed())
    return NULL;

  WebCore::HitTestResult r = default_menu->hitTestResult();
  WebCore::Frame* selected_frame = r.innerNonSharedNode()->document()->frame();

  WebCore::IntPoint menu_point =
      selected_frame->view()->contentsToWindow(r.point());

  ContextNode::Type type = ContextNode::NONE;

  // Links, Images and Image-Links take preference over all else.
  WebCore::KURL link_url = r.absoluteLinkURL();
  if (!link_url.isEmpty()) {
    type = ContextNode::LINK;
  }
  WebCore::KURL image_url = r.absoluteImageURL();
  if (!image_url.isEmpty()) {
    type = ContextNode::IMAGE;
  }
  if (!image_url.isEmpty() && !link_url.isEmpty())
    type = ContextNode::IMAGE_LINK;

  // If it's not a link, an image or an image link, show a selection menu or a
  // more generic page menu.
  std::wstring selection_text_string;
  std::wstring misspelled_word_string;
  GURL frame_url;
  GURL page_url;
  std::string security_info;
  
  std::wstring frame_encoding;
  // Send the frame and page URLs in any case.
  ContextNode::Type frame_type = ContextNode::NONE;
  ContextNode::Type page_type = 
      GetTypeAndURLFromFrame(webview_->main_frame()->frame(),
                             &page_url,
                             ContextNode::PAGE);
  if (selected_frame != webview_->main_frame()->frame()) {
    frame_type = GetTypeAndURLFromFrame(selected_frame,
                                        &frame_url,
                                        ContextNode::FRAME);
    frame_encoding = webkit_glue::StringToStdWString(
        selected_frame->loader()->encoding());
  }
  
  if (type == ContextNode::NONE) {
    if (r.isContentEditable()) {
      type = ContextNode::EDITABLE;
      if (webview_->FocusedFrameNeedsSpellchecking()) {
        misspelled_word_string = GetMisspelledWord(default_menu, 
                                                   selected_frame);<commit_msg>When right clicking in a text area that is scrolled, the wrong word is selected.  This is because we use the wrong node when getting the selection.  We want to use the shadow inner node, but the hit test result provided to the ContextMenu is not the shadow node.  To work around this, we recompute the hit test result.<commit_after>// Copyright (c) 2006-2008 The Chromium 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 "config.h"

#include "base/compiler_specific.h"

MSVC_PUSH_WARNING_LEVEL(0);
#include "ContextMenu.h"
#include "Document.h"
#include "DocumentLoader.h"
#include "Editor.h"
#include "EventHandler.h"
#include "FrameLoader.h"
#include "FrameView.h"
#include "HitTestResult.h"
#include "KURL.h"
#include "Widget.h"
MSVC_POP_WARNING();
#undef LOG

#include "webkit/glue/context_menu_client_impl.h"

#include "base/string_util.h"
#include "webkit/glue/context_node_types.h"
#include "webkit/glue/glue_util.h"
#include "webkit/glue/webdocumentloader_impl.h"
#include "webkit/glue/webview_impl.h"

#include "base/word_iterator.h"

namespace {

// Helper function to determine whether text is a single word or a sentence.
bool IsASingleWord(const std::wstring& text) {
  WordIterator iter(text, WordIterator::BREAK_WORD);
  int word_count = 0;
  if (!iter.Init()) return false;
  while (iter.Advance()) {
    if (iter.IsWord()) {
      word_count++;
      if (word_count > 1) // More than one word.
        return false;
    }
  }
  
  // Check for 0 words.
  if (!word_count)
    return false;
  
  // Has a single word.
  return true;
}

// Helper function to get misspelled word on which context menu 
// is to be evolked. This function also sets the word on which context menu
// has been evoked to be the selected word, as required.
std::wstring GetMisspelledWord(const WebCore::ContextMenu* default_menu,
                               WebCore::Frame* selected_frame) {
  std::wstring misspelled_word_string;

  // First select from selectedText to check for multiple word selection.
  misspelled_word_string = CollapseWhitespace(
      webkit_glue::StringToStdWString(selected_frame->selectedText()),
      false);

  // Don't provide suggestions for multiple words.
  if (!misspelled_word_string.empty() && 
      !IsASingleWord(misspelled_word_string))
    return L"";

  // Expand around the click to see if we clicked a word.
  WebCore::Node* inner_node = default_menu->hitTestResult().innerNode();
  if (inner_node->renderer()->isTextArea()) {
    WebCore::HitTestResult real_result = selected_frame->eventHandler()->
        hitTestResultAtPoint(default_menu->hitTestResult().localPoint(), true);
    inner_node = real_result.innerNode();
  }

  WebCore::VisiblePosition pos(inner_node->renderer()->
      positionForPoint(default_menu->hitTestResult().localPoint()));

  WebCore::Selection selection;
  if (pos.isNotNull()) {
    selection = WebCore::Selection(pos);
    selection.expandUsingGranularity(WebCore::WordGranularity);
  }
      
  if (selection.isRange()) { 
    selected_frame->setSelectionGranularity(WebCore::WordGranularity);
  }
        
  if (selected_frame->shouldChangeSelection(selection))
    selected_frame->selection()->setSelection(selection);
       
  misspelled_word_string = CollapseWhitespace(
      webkit_glue::StringToStdWString(selected_frame->selectedText()),                  
                                      false);
  
  return misspelled_word_string;
}

}  // namespace

ContextMenuClientImpl::~ContextMenuClientImpl() {
}

void ContextMenuClientImpl::contextMenuDestroyed() {
  delete this;
}

// Figure out the URL of a page or subframe. Returns |page_type| as the type,
// which indicates page or subframe, or ContextNode::NONE if the URL could not
// be determined for some reason.
static ContextNode::Type GetTypeAndURLFromFrame(WebCore::Frame* frame,
                                                GURL* url,
                                                ContextNode::Type page_type) {
  ContextNode::Type type = ContextNode::NONE;
  if (frame) {
    WebCore::DocumentLoader* dl = frame->loader()->documentLoader();
    if (dl) {
      WebDataSource* ds = static_cast<WebDocumentLoaderImpl*>(dl)->
          GetDataSource();
      if (ds) {
        type = page_type;
        *url = ds->HasUnreachableURL() ? ds->GetUnreachableURL()
                                       : ds->GetRequest().GetURL();
      }
    }
  }
  return type;
}

WebCore::PlatformMenuDescription
    ContextMenuClientImpl::getCustomMenuFromDefaultItems(
        WebCore::ContextMenu* default_menu) {
  // Displaying the context menu in this function is a big hack as we don't
  // have context, i.e. whether this is being invoked via a script or in 
  // response to user input (Mouse event WM_RBUTTONDOWN,
  // Keyboard events KeyVK_APPS, Shift+F10). Check if this is being invoked
  // in response to the above input events before popping up the context menu.
  if (!webview_->context_menu_allowed())
    return NULL;

  WebCore::HitTestResult r = default_menu->hitTestResult();
  WebCore::Frame* selected_frame = r.innerNonSharedNode()->document()->frame();

  WebCore::IntPoint menu_point =
      selected_frame->view()->contentsToWindow(r.point());

  ContextNode::Type type = ContextNode::NONE;

  // Links, Images and Image-Links take preference over all else.
  WebCore::KURL link_url = r.absoluteLinkURL();
  if (!link_url.isEmpty()) {
    type = ContextNode::LINK;
  }
  WebCore::KURL image_url = r.absoluteImageURL();
  if (!image_url.isEmpty()) {
    type = ContextNode::IMAGE;
  }
  if (!image_url.isEmpty() && !link_url.isEmpty())
    type = ContextNode::IMAGE_LINK;

  // If it's not a link, an image or an image link, show a selection menu or a
  // more generic page menu.
  std::wstring selection_text_string;
  std::wstring misspelled_word_string;
  GURL frame_url;
  GURL page_url;
  std::string security_info;
  
  std::wstring frame_encoding;
  // Send the frame and page URLs in any case.
  ContextNode::Type frame_type = ContextNode::NONE;
  ContextNode::Type page_type = 
      GetTypeAndURLFromFrame(webview_->main_frame()->frame(),
                             &page_url,
                             ContextNode::PAGE);
  if (selected_frame != webview_->main_frame()->frame()) {
    frame_type = GetTypeAndURLFromFrame(selected_frame,
                                        &frame_url,
                                        ContextNode::FRAME);
    frame_encoding = webkit_glue::StringToStdWString(
        selected_frame->loader()->encoding());
  }
  
  if (type == ContextNode::NONE) {
    if (r.isContentEditable()) {
      type = ContextNode::EDITABLE;
      if (webview_->FocusedFrameNeedsSpellchecking()) {
        misspelled_word_string = GetMisspelledWord(default_menu,
                                                   selected_frame);
{'fraction_non_alphanumeric': 0.10830188679245283, 'fraction_numerical': 0.0021132075471698114, 'mean_word_length': 3.1113869066087494, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 70, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2875512', 'n_tokens_mistral': 3910, 'n_tokens_neox': 3824, 'n_words': 1013}