blob: 4e20cbea015e59dd269dce0841f3bea78e0f8f97 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitf5b16fe2008-07-27 00:20:514
5#include "config.h"
6
[email protected]fa419692008-10-16 21:46:147#include "base/compiler_specific.h"
8
9MSVC_PUSH_WARNING_LEVEL(0);
initial.commitf5b16fe2008-07-27 00:20:5110#include "ContextMenu.h"
11#include "Document.h"
12#include "DocumentLoader.h"
13#include "Editor.h"
[email protected]985f0e62008-10-29 01:05:0814#include "EventHandler.h"
initial.commitf5b16fe2008-07-27 00:20:5115#include "FrameLoader.h"
16#include "FrameView.h"
17#include "HitTestResult.h"
18#include "KURL.h"
19#include "Widget.h"
[email protected]fa419692008-10-16 21:46:1420MSVC_POP_WARNING();
initial.commitf5b16fe2008-07-27 00:20:5121#undef LOG
22
23#include "webkit/glue/context_menu_client_impl.h"
24
25#include "base/string_util.h"
26#include "webkit/glue/context_node_types.h"
27#include "webkit/glue/glue_util.h"
28#include "webkit/glue/webdocumentloader_impl.h"
29#include "webkit/glue/webview_impl.h"
30
31#include "base/word_iterator.h"
32
[email protected]985f0e62008-10-29 01:05:0833namespace {
34
initial.commitf5b16fe2008-07-27 00:20:5135// Helper function to determine whether text is a single word or a sentence.
[email protected]985f0e62008-10-29 01:05:0836bool IsASingleWord(const std::wstring& text) {
initial.commitf5b16fe2008-07-27 00:20:5137 WordIterator iter(text, WordIterator::BREAK_WORD);
38 int word_count = 0;
39 if (!iter.Init()) return false;
40 while (iter.Advance()) {
41 if (iter.IsWord()) {
42 word_count++;
43 if (word_count > 1) // More than one word.
44 return false;
45 }
46 }
47
48 // Check for 0 words.
49 if (!word_count)
50 return false;
51
52 // Has a single word.
53 return true;
54}
55
56// Helper function to get misspelled word on which context menu
57// is to be evolked. This function also sets the word on which context menu
58// has been evoked to be the selected word, as required.
[email protected]985f0e62008-10-29 01:05:0859std::wstring GetMisspelledWord(const WebCore::ContextMenu* default_menu,
60 WebCore::Frame* selected_frame) {
initial.commitf5b16fe2008-07-27 00:20:5161 std::wstring misspelled_word_string;
62
63 // First select from selectedText to check for multiple word selection.
64 misspelled_word_string = CollapseWhitespace(
65 webkit_glue::StringToStdWString(selected_frame->selectedText()),
66 false);
67
68 // Don't provide suggestions for multiple words.
69 if (!misspelled_word_string.empty() &&
70 !IsASingleWord(misspelled_word_string))
71 return L"";
72
[email protected]3a500b352008-10-31 17:10:2173 WebCore::HitTestResult hit_test_result = selected_frame->eventHandler()->
74 hitTestResultAtPoint(default_menu->hitTestResult().point(), true);
75 WebCore::Node* inner_node = hit_test_result.innerNode();
76 WebCore::VisiblePosition pos(inner_node->renderer()->positionForPoint(
77 hit_test_result.localPoint()));
[email protected]985f0e62008-10-29 01:05:0878
79 WebCore::Selection selection;
initial.commitf5b16fe2008-07-27 00:20:5180 if (pos.isNotNull()) {
81 selection = WebCore::Selection(pos);
82 selection.expandUsingGranularity(WebCore::WordGranularity);
83 }
84
85 if (selection.isRange()) {
86 selected_frame->setSelectionGranularity(WebCore::WordGranularity);
87 }
88
89 if (selected_frame->shouldChangeSelection(selection))
[email protected]de56f3782008-10-01 22:31:3590 selected_frame->selection()->setSelection(selection);
initial.commitf5b16fe2008-07-27 00:20:5191
92 misspelled_word_string = CollapseWhitespace(
93 webkit_glue::StringToStdWString(selected_frame->selectedText()),
94 false);
95
96 return misspelled_word_string;
97}
98
[email protected]985f0e62008-10-29 01:05:0899} // namespace
100
initial.commitf5b16fe2008-07-27 00:20:51101ContextMenuClientImpl::~ContextMenuClientImpl() {
102}
103
104void ContextMenuClientImpl::contextMenuDestroyed() {
105 delete this;
106}
107
108// Figure out the URL of a page or subframe. Returns |page_type| as the type,
109// which indicates page or subframe, or ContextNode::NONE if the URL could not
110// be determined for some reason.
111static ContextNode::Type GetTypeAndURLFromFrame(WebCore::Frame* frame,
112 GURL* url,
113 ContextNode::Type page_type) {
114 ContextNode::Type type = ContextNode::NONE;
115 if (frame) {
116 WebCore::DocumentLoader* dl = frame->loader()->documentLoader();
117 if (dl) {
118 WebDataSource* ds = static_cast<WebDocumentLoaderImpl*>(dl)->
119 GetDataSource();
120 if (ds) {
121 type = page_type;
122 *url = ds->HasUnreachableURL() ? ds->GetUnreachableURL()
123 : ds->GetRequest().GetURL();
124 }
125 }
126 }
127 return type;
128}
129
130WebCore::PlatformMenuDescription
131 ContextMenuClientImpl::getCustomMenuFromDefaultItems(
132 WebCore::ContextMenu* default_menu) {
133 // Displaying the context menu in this function is a big hack as we don't
134 // have context, i.e. whether this is being invoked via a script or in
135 // response to user input (Mouse event WM_RBUTTONDOWN,
136 // Keyboard events KeyVK_APPS, Shift+F10). Check if this is being invoked
137 // in response to the above input events before popping up the context menu.
138 if (!webview_->context_menu_allowed())
139 return NULL;
140
141 WebCore::HitTestResult r = default_menu->hitTestResult();
142 WebCore::Frame* selected_frame = r.innerNonSharedNode()->document()->frame();
143
144 WebCore::IntPoint menu_point =
145 selected_frame->view()->contentsToWindow(r.point());
146
147 ContextNode::Type type = ContextNode::NONE;
148
149 // Links, Images and Image-Links take preference over all else.
150 WebCore::KURL link_url = r.absoluteLinkURL();
initial.commitf5b16fe2008-07-27 00:20:51151 if (!link_url.isEmpty()) {
152 type = ContextNode::LINK;
153 }
154 WebCore::KURL image_url = r.absoluteImageURL();
initial.commitf5b16fe2008-07-27 00:20:51155 if (!image_url.isEmpty()) {
156 type = ContextNode::IMAGE;
157 }
158 if (!image_url.isEmpty() && !link_url.isEmpty())
159 type = ContextNode::IMAGE_LINK;
160
161 // If it's not a link, an image or an image link, show a selection menu or a
162 // more generic page menu.
163 std::wstring selection_text_string;
164 std::wstring misspelled_word_string;
165 GURL frame_url;
166 GURL page_url;
[email protected]6aa376b2008-09-23 18:49:52167 std::string security_info;
initial.commitf5b16fe2008-07-27 00:20:51168
[email protected]e38f40152008-09-12 23:08:30169 std::wstring frame_encoding;
initial.commitf5b16fe2008-07-27 00:20:51170 // Send the frame and page URLs in any case.
171 ContextNode::Type frame_type = ContextNode::NONE;
172 ContextNode::Type page_type =
173 GetTypeAndURLFromFrame(webview_->main_frame()->frame(),
174 &page_url,
175 ContextNode::PAGE);
176 if (selected_frame != webview_->main_frame()->frame()) {
177 frame_type = GetTypeAndURLFromFrame(selected_frame,
178 &frame_url,
179 ContextNode::FRAME);
[email protected]e38f40152008-09-12 23:08:30180 frame_encoding = webkit_glue::StringToStdWString(
181 selected_frame->loader()->encoding());
initial.commitf5b16fe2008-07-27 00:20:51182 }
183
184 if (type == ContextNode::NONE) {
185 if (r.isContentEditable()) {
186 type = ContextNode::EDITABLE;
187 if (webview_->FocusedFrameNeedsSpellchecking()) {
[email protected]985f0e62008-10-29 01:05:08188 misspelled_word_string = GetMisspelledWord(default_menu,
initial.commitf5b16fe2008-07-27 00:20:51189 selected_frame);
190 }
191 } else if (r.isSelected()) {
192 type = ContextNode::SELECTION;
193 selection_text_string =
194 CollapseWhitespace(
195 webkit_glue::StringToStdWString(selected_frame->selectedText()),
196 false);
197 } else if (selected_frame != webview_->main_frame()->frame()) {
198 type = frame_type;
199 } else {
200 type = page_type;
201 }
202 }
203
[email protected]6aa376b2008-09-23 18:49:52204 // Now retrieve the security info.
205 WebCore::DocumentLoader* dl = selected_frame->loader()->documentLoader();
206 if (dl) {
207 WebDataSource* ds = static_cast<WebDocumentLoaderImpl*>(dl)->
208 GetDataSource();
209 if (ds) {
210 const WebResponse& response = ds->GetResponse();
211 security_info = response.GetSecurityInfo();
212 }
213 }
214
initial.commitf5b16fe2008-07-27 00:20:51215 int edit_flags = ContextNode::CAN_DO_NONE;
216 if (webview_->GetFocusedWebCoreFrame()->editor()->canUndo())
217 edit_flags |= ContextNode::CAN_UNDO;
218 if (webview_->GetFocusedWebCoreFrame()->editor()->canRedo())
219 edit_flags |= ContextNode::CAN_REDO;
220 if (webview_->GetFocusedWebCoreFrame()->editor()->canCut())
221 edit_flags |= ContextNode::CAN_CUT;
222 if (webview_->GetFocusedWebCoreFrame()->editor()->canCopy())
223 edit_flags |= ContextNode::CAN_COPY;
224 if (webview_->GetFocusedWebCoreFrame()->editor()->canPaste())
225 edit_flags |= ContextNode::CAN_PASTE;
226 if (webview_->GetFocusedWebCoreFrame()->editor()->canDelete())
227 edit_flags |= ContextNode::CAN_DELETE;
228 // We can always select all...
229 edit_flags |= ContextNode::CAN_SELECT_ALL;
230
231 WebViewDelegate* d = webview_->delegate();
232 if (d) {
233 d->ShowContextMenu(webview_,
234 type,
235 menu_point.x(),
236 menu_point.y(),
237 webkit_glue::KURLToGURL(link_url),
238 webkit_glue::KURLToGURL(image_url),
239 page_url,
240 frame_url,
241 selection_text_string,
242 misspelled_word_string,
[email protected]6aa376b2008-09-23 18:49:52243 edit_flags,
244 security_info);
initial.commitf5b16fe2008-07-27 00:20:51245 }
246 return NULL;
247}
248
249void ContextMenuClientImpl::contextMenuItemSelected(
250 WebCore::ContextMenuItem*, const WebCore::ContextMenu*) {
251}
252
253void ContextMenuClientImpl::downloadURL(const WebCore::KURL&) {
254}
255
256void ContextMenuClientImpl::copyImageToClipboard(const WebCore::HitTestResult&) {
257}
258
259void ContextMenuClientImpl::searchWithGoogle(const WebCore::Frame*) {
260}
261
262void ContextMenuClientImpl::lookUpInDictionary(WebCore::Frame*) {
263}
264
265void ContextMenuClientImpl::speak(const WebCore::String&) {
266}
267
268void ContextMenuClientImpl::stopSpeaking() {
269}
270
271bool ContextMenuClientImpl::shouldIncludeInspectElementItem() {
272 return false; // TODO(jackson): Eventually include the inspector context menu item
273}
license.botbf09a502008-08-24 00:55:55274
[email protected]7284c6502008-09-09 20:27:26275#if defined(OS_MACOSX)
276void ContextMenuClientImpl::searchWithSpotlight() {
277 // TODO(pinkerton): write this
278}
279#endif