Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(93)

Side by Side Diff: webkit/glue/webview_impl.cc

Issue 341030: Moves webview_impl.cc, webframe_impl.cc and webframeloaderclient_impl.cc into... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/glue/webview_impl.h ('k') | webkit/webkit.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2007-2009 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.
4
5 #include "config.h"
6
7 #include "AXObjectCache.h"
8 #include "CSSStyleSelector.h"
9 #include "CSSValueKeywords.h"
10 #include "Cursor.h"
11 #include "Document.h"
12 #include "DocumentLoader.h"
13 #include "DragController.h"
14 #include "DragData.h"
15 #include "Editor.h"
16 #include "EventHandler.h"
17 #include "FocusController.h"
18 #include "FontDescription.h"
19 #include "FrameLoader.h"
20 #include "FrameTree.h"
21 #include "FrameView.h"
22 #include "GraphicsContext.h"
23 #include "HTMLNames.h"
24 #include "HTMLInputElement.h"
25 #include "HTMLMediaElement.h"
26 #include "HitTestResult.h"
27 #include "Image.h"
28 #include "InspectorController.h"
29 #include "IntRect.h"
30 #include "KeyboardCodes.h"
31 #include "KeyboardEvent.h"
32 #include "MIMETypeRegistry.h"
33 #include "NodeRenderStyle.h"
34 #include "Page.h"
35 #include "PageGroup.h"
36 #include "Pasteboard.h"
37 #include "PlatformContextSkia.h"
38 #include "PlatformKeyboardEvent.h"
39 #include "PlatformMouseEvent.h"
40 #include "PlatformWheelEvent.h"
41 #include "PluginInfoStore.h"
42 #include "PopupMenuChromium.h"
43 #include "PopupMenuClient.h"
44 #include "RenderView.h"
45 #include "ResourceHandle.h"
46 #include "SecurityOrigin.h"
47 #include "SelectionController.h"
48 #include "Settings.h"
49 #include "TypingCommand.h"
50 #if PLATFORM(WIN_OS)
51 #include "KeyboardCodesWin.h"
52 #include "RenderThemeChromiumWin.h"
53 #else
54 #include "KeyboardCodesPosix.h"
55 #include "RenderTheme.h"
56 #endif
57 #undef LOG
58
59 #include "webkit/api/public/WebAccessibilityObject.h"
60 #include "webkit/api/public/WebDragData.h"
61 #include "webkit/api/public/WebInputEvent.h"
62 #include "webkit/api/public/WebMediaPlayerAction.h"
63 #include "webkit/api/public/WebPoint.h"
64 #include "webkit/api/public/WebRect.h"
65 #include "webkit/api/public/WebString.h"
66 #include "webkit/api/public/WebVector.h"
67 #include "webkit/api/public/WebViewClient.h"
68 #include "webkit/api/src/DOMUtilitiesPrivate.h"
69 #include "webkit/api/src/WebInputEventConversion.h"
70 #include "webkit/api/src/WebPopupMenuImpl.h"
71 #include "webkit/api/src/WebSettingsImpl.h"
72 #include "webkit/glue/glue_util.h"
73 #include "webkit/glue/webdevtoolsagent_impl.h"
74 #include "webkit/glue/webkit_glue.h"
75 #include "webkit/glue/webview_impl.h"
76
77 // Get rid of WTF's pow define so we can use std::pow.
78 #undef pow
79 #include <cmath> // for std::pow
80
81 using namespace WebCore;
82
83 using WebKit::ChromeClientImpl;
84 using WebKit::EditorClientImpl;
85 using WebKit::PlatformKeyboardEventBuilder;
86 using WebKit::PlatformMouseEventBuilder;
87 using WebKit::PlatformWheelEventBuilder;
88 using WebKit::WebAccessibilityObject;
89 using WebKit::WebCanvas;
90 using WebKit::WebCompositionCommand;
91 using WebKit::WebCompositionCommandConfirm;
92 using WebKit::WebCompositionCommandDiscard;
93 using WebKit::WebDevToolsAgent;
94 using WebKit::WebDevToolsAgentClient;
95 using WebKit::WebDragData;
96 using WebKit::WebDragOperation;
97 using WebKit::WebDragOperationCopy;
98 using WebKit::WebDragOperationNone;
99 using WebKit::WebDragOperationsMask;
100 using WebKit::WebFrame;
101 using WebKit::WebFrameClient;
102 using WebKit::WebInputEvent;
103 using WebKit::WebKeyboardEvent;
104 using WebKit::WebMediaPlayerAction;
105 using WebKit::WebMouseEvent;
106 using WebKit::WebMouseWheelEvent;
107 using WebKit::WebNavigationPolicy;
108 using WebKit::WebNode;
109 using WebKit::WebPoint;
110 using WebKit::WebPopupMenuImpl;
111 using WebKit::WebRect;
112 using WebKit::WebSettings;
113 using WebKit::WebSettingsImpl;
114 using WebKit::WebSize;
115 using WebKit::WebString;
116 using WebKit::WebTextDirection;
117 using WebKit::WebTextDirectionDefault;
118 using WebKit::WebTextDirectionLeftToRight;
119 using WebKit::WebTextDirectionRightToLeft;
120 using WebKit::WebURL;
121 using WebKit::WebVector;
122 using WebKit::WebViewClient;
123
124 using webkit_glue::AccessibilityObjectToWebAccessibilityObject;
125
126 // Change the text zoom level by kTextSizeMultiplierRatio each time the user
127 // zooms text in or out (ie., change by 20%). The min and max values limit
128 // text zoom to half and 3x the original text size. These three values match
129 // those in Apple's port in WebKit/WebKit/WebView/WebView.mm
130 static const double kTextSizeMultiplierRatio = 1.2;
131 static const double kMinTextSizeMultiplier = 0.5;
132 static const double kMaxTextSizeMultiplier = 3.0;
133
134 // The group name identifies a namespace of pages. Page group is used on OSX
135 // for some programs that use HTML views to display things that don't seem like
136 // web pages to the user (so shouldn't have visited link coloring). We only use
137 // one page group.
138 // FIXME: This needs to go into the WebKit API implementation and be hidden
139 // from the API's users.
140 const char* pageGroupName = "default";
141
142 // Ensure that the WebKit::WebDragOperation enum values stay in sync with
143 // the original WebCore::DragOperation constants.
144 #define COMPILE_ASSERT_MATCHING_ENUM(webcore_name) \
145 COMPILE_ASSERT(int(WebCore::webcore_name) == int(WebKit::Web##webcore_name),\
146 dummy##webcore_name)
147 COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone);
148 COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy);
149 COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink);
150 COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric);
151 COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate);
152 COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove);
153 COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete);
154 COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery);
155
156 // AutocompletePopupMenuClient
157 class AutocompletePopupMenuClient : public WebCore::PopupMenuClient {
158 public:
159 AutocompletePopupMenuClient(WebViewImpl* webview) : text_field_(NULL),
160 selected_index_(0),
161 webview_(webview) {
162 }
163
164 void Init(WebCore::HTMLInputElement* text_field,
165 const WebVector<WebString>& suggestions,
166 int default_suggestion_index) {
167 ASSERT(default_suggestion_index < static_cast<int>(suggestions.size()));
168 text_field_ = text_field;
169 selected_index_ = default_suggestion_index;
170 SetSuggestions(suggestions);
171
172 FontDescription font_description;
173 webview_->theme()->systemFont(CSSValueWebkitControl, font_description);
174 // Use a smaller font size to match IE/Firefox.
175 // TODO(jcampan): http://crbug.com/7376 use the system size instead of a
176 // fixed font size value.
177 font_description.setComputedSize(12.0);
178 Font font(font_description, 0, 0);
179 font.update(text_field->document()->styleSelector()->fontSelector());
180 // The direction of text in popup menu is set the same as the direction of
181 // the input element: text_field.
182 style_.set(new PopupMenuStyle(Color::black, Color::white, font, true,
183 Length(WebCore::Fixed), text_field->renderer()->style()->direction()));
184 }
185
186 virtual ~AutocompletePopupMenuClient() {
187 }
188
189 // WebCore::PopupMenuClient implementation.
190 virtual void valueChanged(unsigned listIndex, bool fireEvents = true) {
191 text_field_->setValue(suggestions_[listIndex]);
192 EditorClientImpl* editor =
193 static_cast<EditorClientImpl*>(webview_->page()->editorClient());
194 ASSERT(editor);
195 editor->onAutofillSuggestionAccepted(
196 static_cast<WebCore::HTMLInputElement*>(text_field_.get()));
197 }
198
199 virtual WebCore::String itemText(unsigned list_index) const {
200 return suggestions_[list_index];
201 }
202
203 virtual WebCore::String itemToolTip(unsigned last_index) const {
204 notImplemented();
205 return WebCore::String();
206 }
207
208 virtual bool itemIsEnabled(unsigned listIndex) const {
209 return true;
210 }
211
212 virtual PopupMenuStyle itemStyle(unsigned listIndex) const {
213 return *style_;
214 }
215
216 virtual PopupMenuStyle menuStyle() const {
217 return *style_;
218 }
219
220 virtual int clientInsetLeft() const {
221 return 0;
222 }
223 virtual int clientInsetRight() const {
224 return 0;
225 }
226 virtual int clientPaddingLeft() const {
227 // Bug http://crbug.com/7708 seems to indicate the style can be NULL.
228 WebCore::RenderStyle* style = GetTextFieldStyle();
229 return style ? webview_->theme()->popupInternalPaddingLeft(style) : 0;
230 }
231 virtual int clientPaddingRight() const {
232 // Bug http://crbug.com/7708 seems to indicate the style can be NULL.
233 WebCore::RenderStyle* style = GetTextFieldStyle();
234 return style ? webview_->theme()->popupInternalPaddingRight(style) : 0;
235 }
236 virtual int listSize() const {
237 return suggestions_.size();
238 }
239 virtual int selectedIndex() const {
240 return selected_index_;
241 }
242 virtual void popupDidHide() {
243 webview_->AutoCompletePopupDidHide();
244 }
245 virtual bool itemIsSeparator(unsigned listIndex) const {
246 return false;
247 }
248 virtual bool itemIsLabel(unsigned listIndex) const {
249 return false;
250 }
251 virtual bool itemIsSelected(unsigned listIndex) const {
252 return false;
253 }
254 virtual bool shouldPopOver() const {
255 return false;
256 }
257 virtual bool valueShouldChangeOnHotTrack() const {
258 return false;
259 }
260
261 virtual void setTextFromItem(unsigned listIndex) {
262 text_field_->setValue(suggestions_[listIndex]);
263 }
264
265 virtual FontSelector* fontSelector() const {
266 return text_field_->document()->styleSelector()->fontSelector();
267 }
268
269 virtual HostWindow* hostWindow() const {
270 return text_field_->document()->view()->hostWindow();
271 }
272
273 virtual PassRefPtr<Scrollbar> createScrollbar(
274 ScrollbarClient* client,
275 ScrollbarOrientation orientation,
276 ScrollbarControlSize size) {
277 RefPtr<Scrollbar> widget = Scrollbar::createNativeScrollbar(client,
278 orientation,
279 size);
280 return widget.release();
281 }
282
283 // AutocompletePopupMenuClient specific methods:
284 void SetSuggestions(const WebVector<WebString>& suggestions) {
285 suggestions_.clear();
286 for (size_t i = 0; i < suggestions.size(); ++i)
287 suggestions_.append(webkit_glue::WebStringToString(suggestions[i]));
288 // Try to preserve selection if possible.
289 if (selected_index_ >= static_cast<int>(suggestions.size()))
290 selected_index_ = -1;
291 }
292
293 void RemoveItemAtIndex(int index) {
294 ASSERT(index >= 0 && index < static_cast<int>(suggestions_.size()));
295 suggestions_.remove(index);
296 }
297
298 WebCore::HTMLInputElement* text_field() const {
299 return text_field_.get();
300 }
301
302 WebCore::RenderStyle* GetTextFieldStyle() const {
303 WebCore::RenderStyle* style = text_field_->computedStyle();
304 if (!style) {
305 // It seems we can only have an NULL style in a TextField if the node is
306 // dettached, in which case we the popup shoud not be showing. Please
307 // report this in http://crbug.com/7708 and include the page you were
308 // visiting.
309 ASSERT_NOT_REACHED();
310 }
311 return style;
312 }
313
314 private:
315 RefPtr<WebCore::HTMLInputElement> text_field_;
316 Vector<WebCore::String> suggestions_;
317 int selected_index_;
318 WebViewImpl* webview_;
319 OwnPtr<PopupMenuStyle> style_;
320 };
321
322 // Note that focusOnShow is false so that the autocomplete popup is shown not
323 // activated. We need the page to still have focus so the user can keep typing
324 // while the popup is showing.
325 static const WebCore::PopupContainerSettings kAutocompletePopupSettings = {
326 false, // focusOnShow
327 false, // setTextOnIndexChange
328 false, // acceptOnAbandon
329 true, // loopSelectionNavigation
330 true, // restrictWidthOfListBox. Same as other browser (Fx, IE, and safari)
331 // For autocomplete, we use the direction of the input field as the direction
332 // of the popup items. The main reason is to keep the display of items in
333 // drop-down the same as the items in the input field.
334 WebCore::PopupContainerSettings::DOMElementDirection,
335 };
336
337 // WebView ----------------------------------------------------------------
338
339 namespace WebKit {
340
341 // static
342 WebView* WebView::create(WebViewClient* client) {
343 return new WebViewImpl(client);
344 }
345
346 // static
347 void WebView::updateVisitedLinkState(unsigned long long link_hash) {
348 WebCore::Page::visitedStateChanged(
349 WebCore::PageGroup::pageGroup(pageGroupName), link_hash);
350 }
351
352 // static
353 void WebView::resetVisitedLinkState() {
354 WebCore::Page::allVisitedStateChanged(
355 WebCore::PageGroup::pageGroup(pageGroupName));
356 }
357
358 } // namespace WebKit
359
360 void WebViewImpl::initializeMainFrame(WebFrameClient* frame_client) {
361 // NOTE: The WebFrameImpl takes a reference to itself within InitMainFrame
362 // and releases that reference once the corresponding Frame is destroyed.
363 RefPtr<WebFrameImpl> main_frame = WebFrameImpl::create(frame_client);
364
365 main_frame->InitMainFrame(this);
366
367 if (client_) {
368 WebDevToolsAgentClient* tools_client = client_->devToolsAgentClient();
369 if (tools_client)
370 devtools_agent_.set(new WebDevToolsAgentImpl(this, tools_client));
371 }
372
373 // Restrict the access to the local file system
374 // (see WebView.mm WebView::_commonInitializationWithFrameName).
375 SecurityOrigin::setLocalLoadPolicy(
376 SecurityOrigin::AllowLocalLoadsForLocalOnly);
377 }
378
379 WebViewImpl::WebViewImpl(WebViewClient* client)
380 : client_(client),
381 ALLOW_THIS_IN_INITIALIZER_LIST(back_forward_list_client_impl_(this)),
382 ALLOW_THIS_IN_INITIALIZER_LIST(chrome_client_impl_(this)),
383 ALLOW_THIS_IN_INITIALIZER_LIST(context_menu_client_impl_(this)),
384 ALLOW_THIS_IN_INITIALIZER_LIST(drag_client_impl_(this)),
385 ALLOW_THIS_IN_INITIALIZER_LIST(editor_client_impl_(this)),
386 ALLOW_THIS_IN_INITIALIZER_LIST(inspector_client_impl_(this)),
387 observed_new_navigation_(false),
388 #ifndef NDEBUG
389 new_navigation_loader_(NULL),
390 #endif
391 zoom_level_(0),
392 context_menu_allowed_(false),
393 doing_drag_and_drop_(false),
394 ignore_input_events_(false),
395 suppress_next_keypress_event_(false),
396 initial_navigation_policy_(WebKit::WebNavigationPolicyIgnore),
397 ime_accept_events_(true),
398 drag_target_dispatch_(false),
399 drag_identity_(0),
400 drop_effect_(DROP_EFFECT_DEFAULT),
401 operations_allowed_(WebKit::WebDragOperationNone),
402 drag_operation_(WebKit::WebDragOperationNone),
403 autocomplete_popup_showing_(false),
404 is_transparent_(false),
405 tabs_to_links_(false) {
406 // WebKit/win/WebView.cpp does the same thing, except they call the
407 // KJS specific wrapper around this method. We need to have threading
408 // initialized because CollatorICU requires it.
409 WTF::initializeThreading();
410
411 // set to impossible point so we always get the first mouse pos
412 last_mouse_position_ = WebPoint(-1, -1);
413
414 // the page will take ownership of the various clients
415 page_.set(new Page(&chrome_client_impl_,
416 &context_menu_client_impl_,
417 &editor_client_impl_,
418 &drag_client_impl_,
419 &inspector_client_impl_,
420 NULL));
421
422 page_->backForwardList()->setClient(&back_forward_list_client_impl_);
423 page_->setGroupName(pageGroupName);
424 }
425
426 WebViewImpl::~WebViewImpl() {
427 ASSERT(page_ == NULL);
428 }
429
430 RenderTheme* WebViewImpl::theme() const {
431 return page_.get() ? page_->theme() : RenderTheme::defaultTheme().get();
432 }
433
434 bool WebViewImpl::tabKeyCyclesThroughElements() const {
435 ASSERT(page_.get());
436 return page_->tabKeyCyclesThroughElements();
437 }
438
439 void WebViewImpl::setTabKeyCyclesThroughElements(bool value) {
440 if (page_ != NULL) {
441 page_->setTabKeyCyclesThroughElements(value);
442 }
443 }
444
445 void WebViewImpl::MouseMove(const WebMouseEvent& event) {
446 if (!main_frame() || !main_frame()->frameview())
447 return;
448
449 last_mouse_position_ = WebPoint(event.x, event.y);
450
451 // We call mouseMoved here instead of handleMouseMovedEvent because we need
452 // our ChromeClientImpl to receive changes to the mouse position and
453 // tooltip text, and mouseMoved handles all of that.
454 main_frame()->frame()->eventHandler()->mouseMoved(
455 PlatformMouseEventBuilder(main_frame()->frameview(), event));
456 }
457
458 void WebViewImpl::MouseLeave(const WebMouseEvent& event) {
459 // This event gets sent as the main frame is closing. In that case, just
460 // ignore it.
461 if (!main_frame() || !main_frame()->frameview())
462 return;
463
464 client_->setMouseOverURL(WebURL());
465
466 main_frame()->frame()->eventHandler()->handleMouseMoveEvent(
467 PlatformMouseEventBuilder(main_frame()->frameview(), event));
468 }
469
470 void WebViewImpl::MouseDown(const WebMouseEvent& event) {
471 if (!main_frame() || !main_frame()->frameview())
472 return;
473
474 last_mouse_down_point_ = WebPoint(event.x, event.y);
475
476 // If a text field that has focus is clicked again, we should display the
477 // autocomplete popup.
478 RefPtr<Node> clicked_node;
479 if (event.button == WebMouseEvent::ButtonLeft) {
480 RefPtr<Node> focused_node = GetFocusedNode();
481 if (focused_node.get() &&
482 WebKit::toHTMLInputElement(focused_node.get())) {
483 IntPoint point(event.x, event.y);
484 point = page_->mainFrame()->view()->windowToContents(point);
485 HitTestResult result(point);
486 result = page_->mainFrame()->eventHandler()->hitTestResultAtPoint(point,
487 false);
488 if (result.innerNonSharedNode() == focused_node) {
489 // Already focused text field was clicked, let's remember this. If
490 // focus has not changed after the mouse event is processed, we'll
491 // trigger the autocomplete.
492 clicked_node = focused_node;
493 }
494 }
495 }
496
497 main_frame()->frame()->eventHandler()->handleMousePressEvent(
498 PlatformMouseEventBuilder(main_frame()->frameview(), event));
499
500 if (clicked_node.get() && clicked_node == GetFocusedNode()) {
501 // Focus has not changed, show the autocomplete popup.
502 static_cast<EditorClientImpl*>(page_->editorClient())->
503 showFormAutofillForNode(clicked_node.get());
504 }
505
506 // Dispatch the contextmenu event regardless of if the click was swallowed.
507 // On Windows, we handle it on mouse up, not down.
508 #if PLATFORM(DARWIN)
509 if (event.button == WebMouseEvent::ButtonRight ||
510 (event.button == WebMouseEvent::ButtonLeft &&
511 event.modifiers & WebMouseEvent::ControlKey)) {
512 MouseContextMenu(event);
513 }
514 #elif PLATFORM(LINUX)
515 if (event.button == WebMouseEvent::ButtonRight)
516 MouseContextMenu(event);
517 #endif
518 }
519
520 void WebViewImpl::MouseContextMenu(const WebMouseEvent& event) {
521 if (!main_frame() || !main_frame()->frameview())
522 return;
523
524 page_->contextMenuController()->clearContextMenu();
525
526 PlatformMouseEventBuilder pme(main_frame()->frameview(), event);
527
528 // Find the right target frame. See issue 1186900.
529 HitTestResult result = HitTestResultForWindowPos(pme.pos());
530 Frame* target_frame;
531 if (result.innerNonSharedNode())
532 target_frame = result.innerNonSharedNode()->document()->frame();
533 else
534 target_frame = page_->focusController()->focusedOrMainFrame();
535
536 #if PLATFORM(WIN_OS)
537 target_frame->view()->setCursor(pointerCursor());
538 #endif
539
540 context_menu_allowed_ = true;
541 target_frame->eventHandler()->sendContextMenuEvent(pme);
542 context_menu_allowed_ = false;
543 // Actually showing the context menu is handled by the ContextMenuClient
544 // implementation...
545 }
546
547 void WebViewImpl::MouseUp(const WebMouseEvent& event) {
548 if (!main_frame() || !main_frame()->frameview())
549 return;
550
551 #if PLATFORM(LINUX)
552 // If the event was a middle click, attempt to copy text into the focused
553 // frame. We execute this before we let the page have a go at the event
554 // because the page may change what is focused during in its event handler.
555 //
556 // This code is in the mouse up handler. There is some debate about putting
557 // this here, as opposed to the mouse down handler.
558 // xterm: pastes on up.
559 // GTK: pastes on down.
560 // Firefox: pastes on up.
561 // Midori: couldn't paste at all with 0.1.2
562 //
563 // There is something of a webcompat angle to this well, as highlighted by
564 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
565 // down then the text is pasted just before the onclick handler runs and
566 // clears the text box. So it's important this happens after the
567 // handleMouseReleaseEvent() earlier in this function
568 if (event.button == WebMouseEvent::ButtonMiddle) {
569 Frame* focused = GetFocusedWebCoreFrame();
570 IntPoint click_point(last_mouse_down_point_.x, last_mouse_down_point_.y);
571 click_point = page_->mainFrame()->view()->windowToContents(click_point);
572 HitTestResult hit_test_result =
573 focused->eventHandler()->hitTestResultAtPoint(click_point, false, false,
574 ShouldHitTestScrollbars);
575 // We don't want to send a paste when middle clicking a scroll bar or a
576 // link (which will navigate later in the code).
577 if (!hit_test_result.scrollbar() && !hit_test_result.isLiveLink() &&
578 focused) {
579 Editor* editor = focused->editor();
580 Pasteboard* pasteboard = Pasteboard::generalPasteboard();
581 bool oldSelectionMode = pasteboard->isSelectionMode();
582 pasteboard->setSelectionMode(true);
583 editor->command(AtomicString("Paste")).execute();
584 pasteboard->setSelectionMode(oldSelectionMode);
585 }
586 }
587 #endif
588
589 mouseCaptureLost();
590 main_frame()->frame()->eventHandler()->handleMouseReleaseEvent(
591 PlatformMouseEventBuilder(main_frame()->frameview(), event));
592
593 #if PLATFORM(WIN_OS)
594 // Dispatch the contextmenu event regardless of if the click was swallowed.
595 // On Mac/Linux, we handle it on mouse down, not up.
596 if (event.button == WebMouseEvent::ButtonRight)
597 MouseContextMenu(event);
598 #endif
599 }
600
601 void WebViewImpl::MouseWheel(const WebMouseWheelEvent& event) {
602 PlatformWheelEventBuilder platform_event(main_frame()->frameview(), event);
603 main_frame()->frame()->eventHandler()->handleWheelEvent(platform_event);
604 }
605
606 bool WebViewImpl::KeyEvent(const WebKeyboardEvent& event) {
607 ASSERT((event.type == WebInputEvent::RawKeyDown) ||
608 (event.type == WebInputEvent::KeyDown) ||
609 (event.type == WebInputEvent::KeyUp));
610
611 // Please refer to the comments explaining the suppress_next_keypress_event_
612 // member.
613 // The suppress_next_keypress_event_ is set if the KeyDown is handled by
614 // Webkit. A keyDown event is typically associated with a keyPress(char)
615 // event and a keyUp event. We reset this flag here as this is a new keyDown
616 // event.
617 suppress_next_keypress_event_ = false;
618
619 // Give autocomplete a chance to consume the key events it is interested in.
620 if (AutocompleteHandleKeyEvent(event))
621 return true;
622
623 Frame* frame = GetFocusedWebCoreFrame();
624 if (!frame)
625 return false;
626
627 EventHandler* handler = frame->eventHandler();
628 if (!handler)
629 return KeyEventDefault(event);
630
631 #if PLATFORM(WIN_OS) || PLATFORM(LINUX)
632 if (((event.modifiers == 0) && (event.windowsKeyCode == VKEY_APPS)) ||
633 ((event.modifiers == WebInputEvent::ShiftKey) &&
634 (event.windowsKeyCode == VKEY_F10))) {
635 SendContextMenuEvent(event);
636 return true;
637 }
638 #endif
639
640 // It's not clear if we should continue after detecting a capslock keypress.
641 // I'll err on the side of continuing, which is the pre-existing behaviour.
642 if (event.windowsKeyCode == VKEY_CAPITAL)
643 handler->capsLockStateMayHaveChanged();
644
645 PlatformKeyboardEventBuilder evt(event);
646
647 if (handler->keyEvent(evt)) {
648 if (WebInputEvent::RawKeyDown == event.type && !evt.isSystemKey())
649 suppress_next_keypress_event_ = true;
650 return true;
651 }
652
653 return KeyEventDefault(event);
654 }
655
656 bool WebViewImpl::AutocompleteHandleKeyEvent(const WebKeyboardEvent& event) {
657 if (!autocomplete_popup_showing_ ||
658 // Home and End should be left to the text field to process.
659 event.windowsKeyCode == VKEY_HOME ||
660 event.windowsKeyCode == VKEY_END) {
661 return false;
662 }
663
664 // Pressing delete triggers the removal of the selected suggestion from the
665 // DB.
666 if (event.windowsKeyCode == VKEY_DELETE &&
667 autocomplete_popup_->selectedIndex() != -1) {
668 Node* node = GetFocusedNode();
669 if (!node || (node->nodeType() != WebCore::Node::ELEMENT_NODE)) {
670 ASSERT_NOT_REACHED();
671 return false;
672 }
673 WebCore::Element* element = static_cast<WebCore::Element*>(node);
674 if (!element->hasLocalName(WebCore::HTMLNames::inputTag)) {
675 ASSERT_NOT_REACHED();
676 return false;
677 }
678
679 int selected_index = autocomplete_popup_->selectedIndex();
680 WebCore::HTMLInputElement* input_element =
681 static_cast<WebCore::HTMLInputElement*>(element);
682 const WebString& name = webkit_glue::StringToWebString(
683 input_element->name());
684 const WebString& value = webkit_glue::StringToWebString(
685 autocomplete_popup_client_->itemText(selected_index));
686 client_->removeAutofillSuggestions(name, value);
687 // Update the entries in the currently showing popup to reflect the
688 // deletion.
689 autocomplete_popup_client_->RemoveItemAtIndex(selected_index);
690 RefreshAutofillPopup();
691 return false;
692 }
693
694 if (!autocomplete_popup_->isInterestedInEventForKey(event.windowsKeyCode))
695 return false;
696
697 if (autocomplete_popup_->handleKeyEvent(
698 PlatformKeyboardEventBuilder(event))) {
699 // We need to ignore the next Char event after this otherwise pressing
700 // enter when selecting an item in the menu will go to the page.
701 if (WebInputEvent::RawKeyDown == event.type)
702 suppress_next_keypress_event_ = true;
703 return true;
704 }
705
706 return false;
707 }
708
709 bool WebViewImpl::CharEvent(const WebKeyboardEvent& event) {
710 ASSERT(event.type == WebInputEvent::Char);
711
712 // Please refer to the comments explaining the suppress_next_keypress_event_
713 // member.
714 // The suppress_next_keypress_event_ is set if the KeyDown is handled by
715 // Webkit. A keyDown event is typically associated with a keyPress(char)
716 // event and a keyUp event. We reset this flag here as it only applies
717 // to the current keyPress event.
718 if (suppress_next_keypress_event_) {
719 suppress_next_keypress_event_ = false;
720 return true;
721 }
722
723 Frame* frame = GetFocusedWebCoreFrame();
724 if (!frame)
725 return false;
726
727 EventHandler* handler = frame->eventHandler();
728 if (!handler)
729 return KeyEventDefault(event);
730
731 PlatformKeyboardEventBuilder evt(event);
732 if (!evt.isCharacterKey())
733 return true;
734
735 // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
736 // the eventHandler::keyEvent. We mimic this behavior on all platforms since
737 // for now we are converting other platform's key events to windows key
738 // events.
739 if (evt.isSystemKey())
740 return handler->handleAccessKey(evt);
741
742 if (!handler->keyEvent(evt))
743 return KeyEventDefault(event);
744
745 return true;
746 }
747
748 /*
749 * The WebViewImpl::SendContextMenuEvent function is based on the Webkit
750 * function
751 * bool WebView::handleContextMenuEvent(WPARAM wParam, LPARAM lParam) in
752 * webkit\webkit\win\WebView.cpp. The only significant change in this
753 * function is the code to convert from a Keyboard event to the Right
754 * Mouse button up event.
755 *
756 * This function is an ugly copy/paste and should be cleaned up when the
757 * WebKitWin version is cleaned: https://bugs.webkit.org/show_bug.cgi?id=20438
758 */
759 #if PLATFORM(WIN_OS) || PLATFORM(LINUX)
760 // TODO(pinkerton): implement on non-windows
761 bool WebViewImpl::SendContextMenuEvent(const WebKeyboardEvent& event) {
762 static const int kContextMenuMargin = 1;
763 Frame* main_frame = page()->mainFrame();
764 FrameView* view = main_frame->view();
765 if (!view)
766 return false;
767
768 IntPoint coords(-1, -1);
769 #if PLATFORM(WIN_OS)
770 int right_aligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
771 #else
772 int right_aligned = 0;
773 #endif
774 IntPoint location;
775
776 // The context menu event was generated from the keyboard, so show the
777 // context menu by the current selection.
778 Position start = main_frame->selection()->selection().start();
779 Position end = main_frame->selection()->selection().end();
780
781 if (!start.node() || !end.node()) {
782 location =
783 IntPoint(right_aligned ? view->contentsWidth() - kContextMenuMargin
784 : kContextMenuMargin, kContextMenuMargin);
785 } else {
786 RenderObject* renderer = start.node()->renderer();
787 if (!renderer)
788 return false;
789
790 RefPtr<Range> selection = main_frame->selection()->toNormalizedRange();
791 IntRect first_rect = main_frame->firstRectForRange(selection.get());
792
793 int x = right_aligned ? first_rect.right() : first_rect.x();
794 location = IntPoint(x, first_rect.bottom());
795 }
796
797 location = view->contentsToWindow(location);
798 // FIXME: The IntSize(0, -1) is a hack to get the hit-testing to result in
799 // the selected element. Ideally we'd have the position of a context menu
800 // event be separate from its target node.
801 coords = location + IntSize(0, -1);
802
803 // The contextMenuController() holds onto the last context menu that was
804 // popped up on the page until a new one is created. We need to clear
805 // this menu before propagating the event through the DOM so that we can
806 // detect if we create a new menu for this event, since we won't create
807 // a new menu if the DOM swallows the event and the defaultEventHandler does
808 // not run.
809 page()->contextMenuController()->clearContextMenu();
810
811 Frame* focused_frame = page()->focusController()->focusedOrMainFrame();
812 focused_frame->view()->setCursor(pointerCursor());
813 WebMouseEvent mouse_event;
814 mouse_event.button = WebMouseEvent::ButtonRight;
815 mouse_event.x = coords.x();
816 mouse_event.y = coords.y();
817 mouse_event.type = WebInputEvent::MouseUp;
818
819 PlatformMouseEventBuilder platform_event(view, mouse_event);
820
821 context_menu_allowed_ = true;
822 bool handled =
823 focused_frame->eventHandler()->sendContextMenuEvent(platform_event);
824 context_menu_allowed_ = false;
825 return handled;
826 }
827 #endif
828
829 bool WebViewImpl::KeyEventDefault(const WebKeyboardEvent& event) {
830 Frame* frame = GetFocusedWebCoreFrame();
831 if (!frame)
832 return false;
833
834 switch (event.type) {
835 case WebInputEvent::Char: {
836 if (event.windowsKeyCode == VKEY_SPACE) {
837 int key_code = ((event.modifiers & WebInputEvent::ShiftKey) ?
838 VKEY_PRIOR : VKEY_NEXT);
839 return ScrollViewWithKeyboard(key_code, event.modifiers);
840 }
841 break;
842 }
843
844 case WebInputEvent::RawKeyDown: {
845 if (event.modifiers == WebInputEvent::ControlKey) {
846 switch (event.windowsKeyCode) {
847 case 'A':
848 focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll"));
849 return true;
850 case VKEY_INSERT:
851 case 'C':
852 focusedFrame()->executeCommand(WebString::fromUTF8("Copy"));
853 return true;
854 // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
855 // key combinations which affect scrolling. Safari is buggy in the
856 // sense that it scrolls the page for all Ctrl+scrolling key
857 // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
858 case VKEY_HOME:
859 case VKEY_END:
860 break;
861 default:
862 return false;
863 }
864 }
865 if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey)) {
866 return ScrollViewWithKeyboard(event.windowsKeyCode, event.modifiers);
867 }
868 break;
869 }
870
871 default:
872 break;
873 }
874 return false;
875 }
876
877 bool WebViewImpl::ScrollViewWithKeyboard(int key_code, int modifiers) {
878 ScrollDirection scroll_direction;
879 ScrollGranularity scroll_granularity;
880
881 switch (key_code) {
882 case VKEY_LEFT:
883 scroll_direction = ScrollLeft;
884 scroll_granularity = ScrollByLine;
885 break;
886 case VKEY_RIGHT:
887 scroll_direction = ScrollRight;
888 scroll_granularity = ScrollByLine;
889 break;
890 case VKEY_UP:
891 scroll_direction = ScrollUp;
892 scroll_granularity = ScrollByLine;
893 break;
894 case VKEY_DOWN:
895 scroll_direction = ScrollDown;
896 scroll_granularity = ScrollByLine;
897 break;
898 case VKEY_HOME:
899 scroll_direction = ScrollUp;
900 scroll_granularity = ScrollByDocument;
901 break;
902 case VKEY_END:
903 scroll_direction = ScrollDown;
904 scroll_granularity = ScrollByDocument;
905 break;
906 case VKEY_PRIOR: // page up
907 scroll_direction = ScrollUp;
908 scroll_granularity = ScrollByPage;
909 break;
910 case VKEY_NEXT: // page down
911 scroll_direction = ScrollDown;
912 scroll_granularity = ScrollByPage;
913 break;
914 default:
915 return false;
916 }
917
918 return PropagateScroll(scroll_direction, scroll_granularity);
919 }
920
921 bool WebViewImpl::PropagateScroll(
922 WebCore::ScrollDirection scroll_direction,
923 WebCore::ScrollGranularity scroll_granularity) {
924
925 Frame* frame = GetFocusedWebCoreFrame();
926 if (!frame)
927 return false;
928
929 bool scroll_handled =
930 frame->eventHandler()->scrollOverflow(scroll_direction,
931 scroll_granularity);
932 Frame* current_frame = frame;
933 while (!scroll_handled && current_frame) {
934 scroll_handled = current_frame->view()->scroll(scroll_direction,
935 scroll_granularity);
936 current_frame = current_frame->tree()->parent();
937 }
938 return scroll_handled;
939 }
940
941 Frame* WebViewImpl::GetFocusedWebCoreFrame() {
942 return page_.get() ? page_->focusController()->focusedOrMainFrame() : NULL;
943 }
944
945 // static
946 WebViewImpl* WebViewImpl::FromPage(WebCore::Page* page) {
947 if (!page)
948 return NULL;
949
950 return static_cast<ChromeClientImpl*>(page->chrome()->client())->webview();
951 }
952
953 // WebWidget ------------------------------------------------------------------
954
955 void WebViewImpl::close() {
956 RefPtr<WebFrameImpl> main_frame;
957
958 if (page_.get()) {
959 // Initiate shutdown for the entire frameset. This will cause a lot of
960 // notifications to be sent.
961 if (page_->mainFrame()) {
962 main_frame = WebFrameImpl::FromFrame(page_->mainFrame());
963 page_->mainFrame()->loader()->frameDetached();
964 }
965 page_.clear();
966 }
967
968 // Should happen after page_.reset().
969 if (devtools_agent_.get())
970 devtools_agent_.clear();
971
972 // We drop the client after the page has been destroyed to support the
973 // WebFrameClient::didDestroyScriptContext method.
974 if (main_frame)
975 main_frame->drop_client();
976
977 // Reset the delegate to prevent notifications being sent as we're being
978 // deleted.
979 client_ = NULL;
980
981 deref(); // Balances ref() acquired in WebView::create
982 }
983
984 void WebViewImpl::resize(const WebSize& new_size) {
985 if (size_ == new_size)
986 return;
987 size_ = new_size;
988
989 if (main_frame()->frameview()) {
990 main_frame()->frameview()->resize(size_.width, size_.height);
991 main_frame()->frame()->eventHandler()->sendResizeEvent();
992 }
993
994 if (client_) {
995 WebRect damaged_rect(0, 0, size_.width, size_.height);
996 client_->didInvalidateRect(damaged_rect);
997 }
998 }
999
1000 void WebViewImpl::layout() {
1001 WebFrameImpl* webframe = main_frame();
1002 if (webframe) {
1003 // In order for our child HWNDs (NativeWindowWidgets) to update properly,
1004 // they need to be told that we are updating the screen. The problem is
1005 // that the native widgets need to recalculate their clip region and not
1006 // overlap any of our non-native widgets. To force the resizing, call
1007 // setFrameRect(). This will be a quick operation for most frames, but
1008 // the NativeWindowWidgets will update a proper clipping region.
1009 FrameView* view = webframe->frameview();
1010 if (view)
1011 view->setFrameRect(view->frameRect());
1012
1013 // setFrameRect may have the side-effect of causing existing page
1014 // layout to be invalidated, so layout needs to be called last.
1015
1016 webframe->Layout();
1017 }
1018 }
1019
1020 void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect) {
1021 WebFrameImpl* webframe = main_frame();
1022 if (webframe)
1023 webframe->Paint(canvas, rect);
1024 }
1025
1026 // TODO(eseidel): g_current_input_event should be removed once
1027 // ChromeClient:show() can get the current-event information from WebCore.
1028 /* static */
1029 const WebInputEvent* WebViewImpl::g_current_input_event = NULL;
1030
1031 bool WebViewImpl::handleInputEvent(const WebInputEvent& input_event) {
1032 // If we've started a drag and drop operation, ignore input events until
1033 // we're done.
1034 if (doing_drag_and_drop_)
1035 return true;
1036
1037 if (ignore_input_events_)
1038 return true;
1039
1040 // TODO(eseidel): Remove g_current_input_event.
1041 // This only exists to allow ChromeClient::show() to know which mouse button
1042 // triggered a window.open event.
1043 // Safari must perform a similar hack, ours is in our WebKit glue layer
1044 // theirs is in the application. This should go when WebCore can be fixed
1045 // to pass more event information to ChromeClient::show()
1046 g_current_input_event = &input_event;
1047
1048 bool handled = true;
1049
1050 // TODO(jcampan): WebKit seems to always return false on mouse events
1051 // processing methods. For now we'll assume it has processed them (as we are
1052 // only interested in whether keyboard events are processed).
1053 switch (input_event.type) {
1054 case WebInputEvent::MouseMove:
1055 MouseMove(*static_cast<const WebMouseEvent*>(&input_event));
1056 break;
1057
1058 case WebInputEvent::MouseLeave:
1059 MouseLeave(*static_cast<const WebMouseEvent*>(&input_event));
1060 break;
1061
1062 case WebInputEvent::MouseWheel:
1063 MouseWheel(*static_cast<const WebMouseWheelEvent*>(&input_event));
1064 break;
1065
1066 case WebInputEvent::MouseDown:
1067 MouseDown(*static_cast<const WebMouseEvent*>(&input_event));
1068 break;
1069
1070 case WebInputEvent::MouseUp:
1071 MouseUp(*static_cast<const WebMouseEvent*>(&input_event));
1072 break;
1073
1074 case WebInputEvent::RawKeyDown:
1075 case WebInputEvent::KeyDown:
1076 case WebInputEvent::KeyUp:
1077 handled = KeyEvent(*static_cast<const WebKeyboardEvent*>(&input_event));
1078 break;
1079
1080 case WebInputEvent::Char:
1081 handled = CharEvent(*static_cast<const WebKeyboardEvent*>(&input_event));
1082 break;
1083 default:
1084 handled = false;
1085 }
1086
1087 g_current_input_event = NULL;
1088
1089 return handled;
1090 }
1091
1092 void WebViewImpl::mouseCaptureLost() {
1093 }
1094
1095 void WebViewImpl::setFocus(bool enable) {
1096 page_->focusController()->setFocused(enable);
1097 if (enable) {
1098 // Note that we don't call setActive() when disabled as this cause extra
1099 // focus/blur events to be dispatched.
1100 page_->focusController()->setActive(true);
1101 ime_accept_events_ = true;
1102 } else {
1103 HideAutoCompletePopup();
1104
1105 // Clear focus on the currently focused frame if any.
1106 if (!page_.get())
1107 return;
1108
1109 Frame* frame = page_->mainFrame();
1110 if (!frame)
1111 return;
1112
1113 RefPtr<Frame> focused_frame = page_->focusController()->focusedFrame();
1114 if (focused_frame.get()) {
1115 // Finish an ongoing composition to delete the composition node.
1116 Editor* editor = focused_frame->editor();
1117 if (editor && editor->hasComposition())
1118 editor->confirmComposition();
1119 ime_accept_events_ = false;
1120 }
1121 }
1122 }
1123
1124 bool WebViewImpl::handleCompositionEvent(WebCompositionCommand command,
1125 int cursor_position,
1126 int target_start,
1127 int target_end,
1128 const WebString& ime_string) {
1129 Frame* focused = GetFocusedWebCoreFrame();
1130 if (!focused || !ime_accept_events_) {
1131 return false;
1132 }
1133 Editor* editor = focused->editor();
1134 if (!editor)
1135 return false;
1136 if (!editor->canEdit()) {
1137 // The input focus has been moved to another WebWidget object.
1138 // We should use this |editor| object only to complete the ongoing
1139 // composition.
1140 if (!editor->hasComposition())
1141 return false;
1142 }
1143
1144 // We should verify the parent node of this IME composition node are
1145 // editable because JavaScript may delete a parent node of the composition
1146 // node. In this case, WebKit crashes while deleting texts from the parent
1147 // node, which doesn't exist any longer.
1148 PassRefPtr<Range> range = editor->compositionRange();
1149 if (range) {
1150 const Node* node = range->startPosition().node();
1151 if (!node || !node->isContentEditable())
1152 return false;
1153 }
1154
1155 if (command == WebCompositionCommandDiscard) {
1156 // A browser process sent an IPC message which does not contain a valid
1157 // string, which means an ongoing composition has been canceled.
1158 // If the ongoing composition has been canceled, replace the ongoing
1159 // composition string with an empty string and complete it.
1160 WebCore::String empty_string;
1161 WTF::Vector<WebCore::CompositionUnderline> empty_underlines;
1162 editor->setComposition(empty_string, empty_underlines, 0, 0);
1163 } else {
1164 // A browser process sent an IPC message which contains a string to be
1165 // displayed in this Editor object.
1166 // To display the given string, set the given string to the
1167 // m_compositionNode member of this Editor object and display it.
1168 if (target_start < 0)
1169 target_start = 0;
1170 if (target_end < 0)
1171 target_end = static_cast<int>(ime_string.length());
1172 WebCore::String composition_string(
1173 webkit_glue::WebStringToString(ime_string));
1174 // Create custom underlines.
1175 // To emphasize the selection, the selected region uses a solid black
1176 // for its underline while other regions uses a pale gray for theirs.
1177 WTF::Vector<WebCore::CompositionUnderline> underlines(3);
1178 underlines[0].startOffset = 0;
1179 underlines[0].endOffset = target_start;
1180 underlines[0].thick = true;
1181 underlines[0].color.setRGB(0xd3, 0xd3, 0xd3);
1182 underlines[1].startOffset = target_start;
1183 underlines[1].endOffset = target_end;
1184 underlines[1].thick = true;
1185 underlines[1].color.setRGB(0x00, 0x00, 0x00);
1186 underlines[2].startOffset = target_end;
1187 underlines[2].endOffset = static_cast<int>(ime_string.length());
1188 underlines[2].thick = true;
1189 underlines[2].color.setRGB(0xd3, 0xd3, 0xd3);
1190 // When we use custom underlines, WebKit ("InlineTextBox.cpp" Line 282)
1191 // prevents from writing a text in between 'selectionStart' and
1192 // 'selectionEnd' somehow.
1193 // Therefore, we use the 'cursor_position' for these arguments so that
1194 // there are not any characters in the above region.
1195 editor->setComposition(composition_string, underlines,
1196 cursor_position, cursor_position);
1197 // The given string is a result string, which means the ongoing
1198 // composition has been completed. I have to call the
1199 // Editor::confirmCompletion() and complete this composition.
1200 if (command == WebCompositionCommandConfirm)
1201 editor->confirmComposition();
1202 }
1203
1204 return editor->hasComposition();
1205 }
1206
1207 bool WebViewImpl::queryCompositionStatus(bool* enable_ime,
1208 WebRect* caret_rect) {
1209 // Store whether the selected node needs IME and the caret rectangle.
1210 // This process consists of the following four steps:
1211 // 1. Retrieve the selection controller of the focused frame;
1212 // 2. Retrieve the caret rectangle from the controller;
1213 // 3. Convert the rectangle, which is relative to the parent view, to the
1214 // one relative to the client window, and;
1215 // 4. Store the converted rectangle.
1216 const Frame* focused = GetFocusedWebCoreFrame();
1217 if (!focused)
1218 return false;
1219
1220 const Editor* editor = focused->editor();
1221 if (!editor || !editor->canEdit())
1222 return false;
1223
1224 SelectionController* controller = focused->selection();
1225 if (!controller)
1226 return false;
1227
1228 const Node* node = controller->start().node();
1229 if (!node)
1230 return false;
1231
1232 *enable_ime = node->shouldUseInputMethod() &&
1233 !controller->isInPasswordField();
1234 const FrameView* view = node->document()->view();
1235 if (!view)
1236 return false;
1237
1238 *caret_rect = webkit_glue::IntRectToWebRect(
1239 view->contentsToWindow(controller->absoluteCaretBounds()));
1240 return true;
1241 }
1242
1243 void WebViewImpl::setTextDirection(WebTextDirection direction) {
1244 // The Editor::setBaseWritingDirection() function checks if we can change
1245 // the text direction of the selected node and updates its DOM "dir"
1246 // attribute and its CSS "direction" property.
1247 // So, we just call the function as Safari does.
1248 const Frame* focused = GetFocusedWebCoreFrame();
1249 if (!focused)
1250 return;
1251
1252 Editor* editor = focused->editor();
1253 if (!editor || !editor->canEdit())
1254 return;
1255
1256 switch (direction) {
1257 case WebTextDirectionDefault:
1258 editor->setBaseWritingDirection(WebCore::NaturalWritingDirection);
1259 break;
1260
1261 case WebTextDirectionLeftToRight:
1262 editor->setBaseWritingDirection(WebCore::LeftToRightWritingDirection);
1263 break;
1264
1265 case WebTextDirectionRightToLeft:
1266 editor->setBaseWritingDirection(WebCore::RightToLeftWritingDirection);
1267 break;
1268
1269 default:
1270 notImplemented();
1271 break;
1272 }
1273 }
1274
1275 // WebView --------------------------------------------------------------------
1276
1277 WebSettings* WebViewImpl::settings() {
1278 if (!web_settings_.get())
1279 web_settings_.set(new WebSettingsImpl(page_->settings()));
1280 ASSERT(web_settings_.get());
1281 return web_settings_.get();
1282 }
1283
1284 WebString WebViewImpl::pageEncoding() const {
1285 if (!page_.get())
1286 return WebString();
1287
1288 String encoding_name = page_->mainFrame()->loader()->encoding();
1289 return webkit_glue::StringToWebString(encoding_name);
1290 }
1291
1292 void WebViewImpl::setPageEncoding(const WebString& encoding_name) {
1293 if (!page_.get())
1294 return;
1295
1296 // Only change override encoding, don't change default encoding.
1297 // Note that the new encoding must be NULL if it isn't supposed to be set.
1298 String new_encoding_name;
1299 if (!encoding_name.isEmpty())
1300 new_encoding_name = webkit_glue::WebStringToString(encoding_name);
1301 page_->mainFrame()->loader()->reloadWithOverrideEncoding(new_encoding_name);
1302 }
1303
1304 bool WebViewImpl::dispatchBeforeUnloadEvent() {
1305 // TODO(creis): This should really cause a recursive depth-first walk of all
1306 // frames in the tree, calling each frame's onbeforeunload. At the moment,
1307 // we're consistent with Safari 3.1, not IE/FF.
1308 Frame* frame = page_->focusController()->focusedOrMainFrame();
1309 if (!frame)
1310 return true;
1311
1312 return frame->shouldClose();
1313 }
1314
1315 void WebViewImpl::dispatchUnloadEvent() {
1316 // Run unload handlers.
1317 page_->mainFrame()->loader()->closeURL();
1318 }
1319
1320 WebFrame* WebViewImpl::mainFrame() {
1321 return main_frame();
1322 }
1323
1324 WebFrame* WebViewImpl::findFrameByName(
1325 const WebString& name, WebFrame* relative_to_frame) {
1326 String name_str = webkit_glue::WebStringToString(name);
1327 if (!relative_to_frame)
1328 relative_to_frame = mainFrame();
1329 Frame* frame = static_cast<WebFrameImpl*>(relative_to_frame)->frame();
1330 frame = frame->tree()->find(name_str);
1331 return WebFrameImpl::FromFrame(frame);
1332 }
1333
1334 WebFrame* WebViewImpl::focusedFrame() {
1335 return WebFrameImpl::FromFrame(GetFocusedWebCoreFrame());
1336 }
1337
1338 void WebViewImpl::setFocusedFrame(WebFrame* frame) {
1339 if (!frame) {
1340 // Clears the focused frame if any.
1341 Frame* frame = GetFocusedWebCoreFrame();
1342 if (frame)
1343 frame->selection()->setFocused(false);
1344 return;
1345 }
1346 WebFrameImpl* frame_impl = static_cast<WebFrameImpl*>(frame);
1347 WebCore::Frame* webcore_frame = frame_impl->frame();
1348 webcore_frame->page()->focusController()->setFocusedFrame(webcore_frame);
1349 }
1350
1351 void WebViewImpl::setInitialFocus(bool reverse) {
1352 if (!page_.get())
1353 return;
1354
1355 // Since we don't have a keyboard event, we'll create one.
1356 WebKeyboardEvent keyboard_event;
1357 keyboard_event.type = WebInputEvent::RawKeyDown;
1358 if (reverse)
1359 keyboard_event.modifiers = WebInputEvent::ShiftKey;
1360
1361 // VK_TAB which is only defined on Windows.
1362 keyboard_event.windowsKeyCode = 0x09;
1363 PlatformKeyboardEventBuilder platform_event(keyboard_event);
1364 RefPtr<KeyboardEvent> webkit_event =
1365 KeyboardEvent::create(platform_event, NULL);
1366 page()->focusController()->setInitialFocus(
1367 reverse ? WebCore::FocusDirectionBackward :
1368 WebCore::FocusDirectionForward,
1369 webkit_event.get());
1370 }
1371
1372 void WebViewImpl::clearFocusedNode() {
1373 if (!page_.get())
1374 return;
1375
1376 RefPtr<Frame> frame = page_->mainFrame();
1377 if (!frame.get())
1378 return;
1379
1380 RefPtr<Document> document = frame->document();
1381 if (!document.get())
1382 return;
1383
1384 RefPtr<Node> old_focused_node = document->focusedNode();
1385
1386 // Clear the focused node.
1387 document->setFocusedNode(NULL);
1388
1389 if (!old_focused_node.get())
1390 return;
1391
1392 // If a text field has focus, we need to make sure the selection controller
1393 // knows to remove selection from it. Otherwise, the text field is still
1394 // processing keyboard events even though focus has been moved to the page and
1395 // keystrokes get eaten as a result.
1396 if (old_focused_node->hasTagName(HTMLNames::textareaTag) ||
1397 (old_focused_node->hasTagName(HTMLNames::inputTag) &&
1398 static_cast<HTMLInputElement*>(old_focused_node.get())->isTextField())) {
1399 // Clear the selection.
1400 SelectionController* selection = frame->selection();
1401 selection->clear();
1402 }
1403 }
1404
1405 void WebViewImpl::zoomIn(bool text_only) {
1406 Frame* frame = main_frame()->frame();
1407 double multiplier = std::min(std::pow(kTextSizeMultiplierRatio,
1408 zoom_level_ + 1),
1409 kMaxTextSizeMultiplier);
1410 float zoom_factor = static_cast<float>(multiplier);
1411 if (zoom_factor != frame->zoomFactor()) {
1412 ++zoom_level_;
1413 frame->setZoomFactor(zoom_factor, text_only);
1414 }
1415 }
1416
1417 void WebViewImpl::zoomOut(bool text_only) {
1418 Frame* frame = main_frame()->frame();
1419 double multiplier = std::max(std::pow(kTextSizeMultiplierRatio,
1420 zoom_level_ - 1),
1421 kMinTextSizeMultiplier);
1422 float zoom_factor = static_cast<float>(multiplier);
1423 if (zoom_factor != frame->zoomFactor()) {
1424 --zoom_level_;
1425 frame->setZoomFactor(zoom_factor, text_only);
1426 }
1427 }
1428
1429 void WebViewImpl::zoomDefault() {
1430 // We don't change the zoom mode (text only vs. full page) here. We just want
1431 // to reset whatever is already set.
1432 zoom_level_ = 0;
1433 main_frame()->frame()->setZoomFactor(
1434 1.0f,
1435 main_frame()->frame()->isZoomFactorTextOnly());
1436 }
1437
1438 void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action,
1439 const WebPoint& location) {
1440 HitTestResult result =
1441 HitTestResultForWindowPos(webkit_glue::WebPointToIntPoint(location));
1442 WTF::RefPtr<WebCore::Node> node = result.innerNonSharedNode();
1443 if (!node->hasTagName(WebCore::HTMLNames::videoTag) &&
1444 !node->hasTagName(WebCore::HTMLNames::audioTag))
1445 return;
1446
1447 WTF::RefPtr<WebCore::HTMLMediaElement> media_element =
1448 static_pointer_cast<WebCore::HTMLMediaElement>(node);
1449 switch (action.type) {
1450 case WebMediaPlayerAction::Play:
1451 if (action.enable) {
1452 media_element->play();
1453 } else {
1454 media_element->pause();
1455 }
1456 break;
1457 case WebMediaPlayerAction::Mute:
1458 media_element->setMuted(action.enable);
1459 break;
1460 case WebMediaPlayerAction::Loop:
1461 media_element->setLoop(action.enable);
1462 break;
1463 default:
1464 ASSERT_NOT_REACHED();
1465 }
1466 }
1467
1468 void WebViewImpl::copyImageAt(const WebPoint& point) {
1469 if (!page_.get())
1470 return;
1471
1472 HitTestResult result =
1473 HitTestResultForWindowPos(webkit_glue::WebPointToIntPoint(point));
1474
1475 if (result.absoluteImageURL().isEmpty()) {
1476 // There isn't actually an image at these coordinates. Might be because
1477 // the window scrolled while the context menu was open or because the page
1478 // changed itself between when we thought there was an image here and when
1479 // we actually tried to retreive the image.
1480 //
1481 // TODO: implement a cache of the most recent HitTestResult to avoid having
1482 // to do two hit tests.
1483 return;
1484 }
1485
1486 page_->mainFrame()->editor()->copyImage(result);
1487 }
1488
1489 void WebViewImpl::dragSourceEndedAt(
1490 const WebPoint& client_point,
1491 const WebPoint& screen_point,
1492 WebDragOperation operation) {
1493 PlatformMouseEvent pme(webkit_glue::WebPointToIntPoint(client_point),
1494 webkit_glue::WebPointToIntPoint(screen_point),
1495 LeftButton, MouseEventMoved, 0, false, false, false,
1496 false, 0);
1497 page_->mainFrame()->eventHandler()->dragSourceEndedAt(pme,
1498 static_cast<WebCore::DragOperation>(operation));
1499 }
1500
1501 void WebViewImpl::dragSourceMovedTo(
1502 const WebPoint& client_point,
1503 const WebPoint& screen_point) {
1504 PlatformMouseEvent pme(webkit_glue::WebPointToIntPoint(client_point),
1505 webkit_glue::WebPointToIntPoint(screen_point),
1506 LeftButton, MouseEventMoved, 0, false, false, false,
1507 false, 0);
1508 page_->mainFrame()->eventHandler()->dragSourceMovedTo(pme);
1509 }
1510
1511 void WebViewImpl::dragSourceSystemDragEnded() {
1512 // It's possible for us to get this callback while not doing a drag if
1513 // it's from a previous page that got unloaded.
1514 if (doing_drag_and_drop_) {
1515 page_->dragController()->dragEnded();
1516 doing_drag_and_drop_ = false;
1517 }
1518 }
1519
1520 WebDragOperation WebViewImpl::dragTargetDragEnter(
1521 const WebDragData& web_drag_data, int identity,
1522 const WebPoint& client_point,
1523 const WebPoint& screen_point,
1524 WebDragOperationsMask operations_allowed) {
1525 ASSERT(!current_drag_data_.get());
1526
1527 current_drag_data_ =
1528 webkit_glue::WebDragDataToChromiumDataObject(web_drag_data);
1529 drag_identity_ = identity;
1530 operations_allowed_ = operations_allowed;
1531
1532 DragData drag_data(
1533 current_drag_data_.get(),
1534 webkit_glue::WebPointToIntPoint(client_point),
1535 webkit_glue::WebPointToIntPoint(screen_point),
1536 static_cast<WebCore::DragOperation>(operations_allowed));
1537
1538 drop_effect_ = DROP_EFFECT_DEFAULT;
1539 drag_target_dispatch_ = true;
1540 DragOperation effect = page_->dragController()->dragEntered(&drag_data);
1541 // Mask the operation against the drag source's allowed operations.
1542 if ((effect & drag_data.draggingSourceOperationMask()) != effect) {
1543 effect = DragOperationNone;
1544 }
1545 drag_target_dispatch_ = false;
1546
1547 if (drop_effect_ != DROP_EFFECT_DEFAULT)
1548 drag_operation_ = (drop_effect_ != DROP_EFFECT_NONE) ?
1549 WebDragOperationCopy : WebDragOperationNone;
1550 else
1551 drag_operation_ = static_cast<WebDragOperation>(effect);
1552 return drag_operation_;
1553 }
1554
1555 WebDragOperation WebViewImpl::dragTargetDragOver(
1556 const WebPoint& client_point,
1557 const WebPoint& screen_point,
1558 WebDragOperationsMask operations_allowed) {
1559 ASSERT(current_drag_data_.get());
1560
1561 operations_allowed_ = operations_allowed;
1562 DragData drag_data(
1563 current_drag_data_.get(),
1564 webkit_glue::WebPointToIntPoint(client_point),
1565 webkit_glue::WebPointToIntPoint(screen_point),
1566 static_cast<WebCore::DragOperation>(operations_allowed));
1567
1568 drop_effect_ = DROP_EFFECT_DEFAULT;
1569 drag_target_dispatch_ = true;
1570 DragOperation effect = page_->dragController()->dragUpdated(&drag_data);
1571 // Mask the operation against the drag source's allowed operations.
1572 if ((effect & drag_data.draggingSourceOperationMask()) != effect) {
1573 effect = DragOperationNone;
1574 }
1575 drag_target_dispatch_ = false;
1576
1577 if (drop_effect_ != DROP_EFFECT_DEFAULT)
1578 drag_operation_ = (drop_effect_ != DROP_EFFECT_NONE) ?
1579 WebDragOperationCopy : WebDragOperationNone;
1580 else
1581 drag_operation_ = static_cast<WebDragOperation>(effect);
1582 return drag_operation_;
1583 }
1584
1585 void WebViewImpl::dragTargetDragLeave() {
1586 ASSERT(current_drag_data_.get());
1587
1588 DragData drag_data(
1589 current_drag_data_.get(),
1590 IntPoint(),
1591 IntPoint(),
1592 static_cast<WebCore::DragOperation>(operations_allowed_));
1593
1594 drag_target_dispatch_ = true;
1595 page_->dragController()->dragExited(&drag_data);
1596 drag_target_dispatch_ = false;
1597
1598 current_drag_data_ = NULL;
1599 drop_effect_ = DROP_EFFECT_DEFAULT;
1600 drag_operation_ = WebDragOperationNone;
1601 drag_identity_ = 0;
1602 }
1603
1604 void WebViewImpl::dragTargetDrop(const WebPoint& client_point,
1605 const WebPoint& screen_point) {
1606 ASSERT(current_drag_data_.get());
1607
1608 // If this webview transitions from the "drop accepting" state to the "not
1609 // accepting" state, then our IPC message reply indicating that may be in-
1610 // flight, or else delayed by javascript processing in this webview. If a
1611 // drop happens before our IPC reply has reached the browser process, then
1612 // the browser forwards the drop to this webview. So only allow a drop to
1613 // proceed if our webview drag_operation_ state is not DragOperationNone.
1614
1615 if (drag_operation_ == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop.
1616 dragTargetDragLeave();
1617 return;
1618 }
1619
1620 DragData drag_data(
1621 current_drag_data_.get(),
1622 webkit_glue::WebPointToIntPoint(client_point),
1623 webkit_glue::WebPointToIntPoint(screen_point),
1624 static_cast<WebCore::DragOperation>(operations_allowed_));
1625
1626 drag_target_dispatch_ = true;
1627 page_->dragController()->performDrag(&drag_data);
1628 drag_target_dispatch_ = false;
1629
1630 current_drag_data_ = NULL;
1631 drop_effect_ = DROP_EFFECT_DEFAULT;
1632 drag_operation_ = WebDragOperationNone;
1633 drag_identity_ = 0;
1634 }
1635
1636 int WebViewImpl::dragIdentity() {
1637 if (drag_target_dispatch_)
1638 return drag_identity_;
1639 return 0;
1640 }
1641
1642 void WebViewImpl::inspectElementAt(const WebPoint& point) {
1643 if (!page_.get())
1644 return;
1645
1646 if (point.x == -1 || point.y == -1) {
1647 page_->inspectorController()->inspect(NULL);
1648 } else {
1649 HitTestResult result =
1650 HitTestResultForWindowPos(webkit_glue::WebPointToIntPoint(point));
1651
1652 if (!result.innerNonSharedNode())
1653 return;
1654
1655 page_->inspectorController()->inspect(result.innerNonSharedNode());
1656 }
1657 }
1658
1659 WebString WebViewImpl::inspectorSettings() const {
1660 return inspector_settings_;
1661 }
1662
1663 void WebViewImpl::setInspectorSettings(const WebString& settings) {
1664 inspector_settings_ = settings;
1665 }
1666
1667 WebDevToolsAgent* WebViewImpl::devToolsAgent() {
1668 return devtools_agent_.get();
1669 }
1670
1671 WebAccessibilityObject WebViewImpl::accessibilityObject() {
1672 if (!main_frame())
1673 return WebAccessibilityObject();
1674
1675 WebCore::Document* document = main_frame()->frame()->document();
1676
1677 return AccessibilityObjectToWebAccessibilityObject(
1678 document->axObjectCache()->getOrCreate(document->renderer()));
1679 }
1680
1681 void WebViewImpl::applyAutofillSuggestions(
1682 const WebNode& node,
1683 const WebVector<WebString>& suggestions,
1684 int default_suggestion_index) {
1685 if (!page_.get() || suggestions.isEmpty()) {
1686 HideAutoCompletePopup();
1687 return;
1688 }
1689
1690 ASSERT(default_suggestion_index < static_cast<int>(suggestions.size()));
1691
1692 if (RefPtr<Frame> focused = page_->focusController()->focusedFrame()) {
1693 RefPtr<Document> document = focused->document();
1694 if (!document.get()) {
1695 HideAutoCompletePopup();
1696 return;
1697 }
1698
1699 RefPtr<Node> focused_node = document->focusedNode();
1700 // If the node for which we queried the autofill suggestions is not the
1701 // focused node, then we have nothing to do.
1702 // TODO(jcampan): also check the carret is at the end and that the text has
1703 // not changed.
1704 if (!focused_node.get() ||
1705 focused_node != webkit_glue::WebNodeToNode(node)) {
1706 HideAutoCompletePopup();
1707 return;
1708 }
1709
1710 if (!focused_node->hasTagName(WebCore::HTMLNames::inputTag)) {
1711 ASSERT_NOT_REACHED();
1712 return;
1713 }
1714
1715 WebCore::HTMLInputElement* input_elem =
1716 static_cast<WebCore::HTMLInputElement*>(focused_node.get());
1717
1718 // The first time the autocomplete is shown we'll create the client and the
1719 // popup.
1720 if (!autocomplete_popup_client_.get())
1721 autocomplete_popup_client_.set(new AutocompletePopupMenuClient(this));
1722 autocomplete_popup_client_->Init(input_elem,
1723 suggestions,
1724 default_suggestion_index);
1725 if (!autocomplete_popup_.get()) {
1726 autocomplete_popup_ =
1727 WebCore::PopupContainer::create(autocomplete_popup_client_.get(),
1728 kAutocompletePopupSettings);
1729 }
1730
1731 if (autocomplete_popup_showing_) {
1732 autocomplete_popup_client_->SetSuggestions(suggestions);
1733 RefreshAutofillPopup();
1734 } else {
1735 autocomplete_popup_->show(focused_node->getRect(),
1736 focused_node->ownerDocument()->view(), 0);
1737 autocomplete_popup_showing_ = true;
1738 }
1739 }
1740 }
1741
1742 void WebViewImpl::hideAutofillPopup() {
1743 HideAutoCompletePopup();
1744 }
1745
1746 // WebView --------------------------------------------------------------------
1747
1748 bool WebViewImpl::setDropEffect(bool accept) {
1749 if (drag_target_dispatch_) {
1750 drop_effect_ = accept ? DROP_EFFECT_COPY : DROP_EFFECT_NONE;
1751 return true;
1752 } else {
1753 return false;
1754 }
1755 }
1756
1757 WebDevToolsAgentImpl* WebViewImpl::GetWebDevToolsAgentImpl() {
1758 return devtools_agent_.get();
1759 }
1760
1761 void WebViewImpl::setIsTransparent(bool is_transparent) {
1762 // Set any existing frames to be transparent.
1763 WebCore::Frame* frame = page_->mainFrame();
1764 while (frame) {
1765 frame->view()->setTransparent(is_transparent);
1766 frame = frame->tree()->traverseNext();
1767 }
1768
1769 // Future frames check this to know whether to be transparent.
1770 is_transparent_ = is_transparent;
1771 }
1772
1773 bool WebViewImpl::isTransparent() const {
1774 return is_transparent_;
1775 }
1776
1777 void WebViewImpl::setIsActive(bool active) {
1778 if (page() && page()->focusController())
1779 page()->focusController()->setActive(active);
1780 }
1781
1782 bool WebViewImpl::isActive() const {
1783 return (page() && page()->focusController())
1784 ? page()->focusController()->isActive()
1785 : false;
1786 }
1787
1788 void WebViewImpl::DidCommitLoad(bool* is_new_navigation) {
1789 if (is_new_navigation)
1790 *is_new_navigation = observed_new_navigation_;
1791
1792 #ifndef NDEBUG
1793 ASSERT(!observed_new_navigation_ ||
1794 page_->mainFrame()->loader()->documentLoader() == new_navigation_loader_);
1795 new_navigation_loader_ = NULL;
1796 #endif
1797 observed_new_navigation_ = false;
1798 }
1799
1800 // static
1801 bool WebViewImpl::NavigationPolicyFromMouseEvent(unsigned short button,
1802 bool ctrl, bool shift,
1803 bool alt, bool meta,
1804 WebNavigationPolicy* policy) {
1805 #if PLATFORM(WIN_OS) || PLATFORM(LINUX) || PLATFORM(FREEBSD)
1806 const bool new_tab_modifier = (button == 1) || ctrl;
1807 #elif PLATFORM(DARWIN)
1808 const bool new_tab_modifier = (button == 1) || meta;
1809 #endif
1810 if (!new_tab_modifier && !shift && !alt)
1811 return false;
1812
1813 ASSERT(policy);
1814 if (new_tab_modifier) {
1815 if (shift) {
1816 *policy = WebKit::WebNavigationPolicyNewForegroundTab;
1817 } else {
1818 *policy = WebKit::WebNavigationPolicyNewBackgroundTab;
1819 }
1820 } else {
1821 if (shift) {
1822 *policy = WebKit::WebNavigationPolicyNewWindow;
1823 } else {
1824 *policy = WebKit::WebNavigationPolicyDownload;
1825 }
1826 }
1827 return true;
1828 }
1829
1830 void WebViewImpl::StartDragging(const WebPoint& event_pos,
1831 const WebDragData& drag_data,
1832 WebDragOperationsMask mask) {
1833 if (!client_)
1834 return;
1835 ASSERT(!doing_drag_and_drop_);
1836 doing_drag_and_drop_ = true;
1837 client_->startDragging(event_pos, drag_data, mask);
1838 }
1839
1840 void WebViewImpl::SetCurrentHistoryItem(WebCore::HistoryItem* item) {
1841 back_forward_list_client_impl_.SetCurrentHistoryItem(item);
1842 }
1843
1844 WebCore::HistoryItem* WebViewImpl::GetPreviousHistoryItem() {
1845 return back_forward_list_client_impl_.GetPreviousHistoryItem();
1846 }
1847
1848 void WebViewImpl::ObserveNewNavigation() {
1849 observed_new_navigation_ = true;
1850 #ifndef NDEBUG
1851 new_navigation_loader_ = page_->mainFrame()->loader()->documentLoader();
1852 #endif
1853 }
1854
1855 void WebViewImpl::HideAutoCompletePopup() {
1856 if (autocomplete_popup_showing_) {
1857 autocomplete_popup_->hidePopup();
1858 AutoCompletePopupDidHide();
1859 }
1860 }
1861
1862 void WebViewImpl::AutoCompletePopupDidHide() {
1863 autocomplete_popup_showing_ = false;
1864 }
1865
1866 void WebViewImpl::SetIgnoreInputEvents(bool new_value) {
1867 ASSERT(ignore_input_events_ != new_value);
1868 ignore_input_events_ = new_value;
1869 }
1870
1871 #if ENABLE(NOTIFICATIONS)
1872 WebKit::NotificationPresenterImpl* WebViewImpl::GetNotificationPresenter() {
1873 if (!notification_presenter_.isInitialized() && client_)
1874 notification_presenter_.initialize(client_->notificationPresenter());
1875 return &notification_presenter_;
1876 }
1877 #endif
1878
1879 void WebViewImpl::RefreshAutofillPopup() {
1880 ASSERT(autocomplete_popup_showing_);
1881
1882 // Hide the popup if it has become empty.
1883 if (autocomplete_popup_client_->listSize() == 0) {
1884 HideAutoCompletePopup();
1885 return;
1886 }
1887
1888 IntRect old_bounds = autocomplete_popup_->boundsRect();
1889 autocomplete_popup_->refresh();
1890 IntRect new_bounds = autocomplete_popup_->boundsRect();
1891 // Let's resize the backing window if necessary.
1892 if (old_bounds != new_bounds) {
1893 WebPopupMenuImpl* popup_menu =
1894 static_cast<WebPopupMenuImpl*>(autocomplete_popup_->client());
1895 popup_menu->client()->setWindowRect(
1896 webkit_glue::IntRectToWebRect(new_bounds));
1897 }
1898 }
1899
1900 Node* WebViewImpl::GetFocusedNode() {
1901 Frame* frame = page_->focusController()->focusedFrame();
1902 if (!frame)
1903 return NULL;
1904
1905 Document* document = frame->document();
1906 if (!document)
1907 return NULL;
1908
1909 return document->focusedNode();
1910 }
1911
1912 HitTestResult WebViewImpl::HitTestResultForWindowPos(const IntPoint& pos) {
1913 IntPoint doc_point(
1914 page_->mainFrame()->view()->windowToContents(pos));
1915 return page_->mainFrame()->eventHandler()->
1916 hitTestResultAtPoint(doc_point, false);
1917 }
1918
1919 void WebViewImpl::setTabsToLinks(bool enable) {
1920 tabs_to_links_ = enable;
1921 }
1922
1923 bool WebViewImpl::tabsToLinks() const {
1924 return tabs_to_links_;
1925 }
OLDNEW
« no previous file with comments | « webkit/glue/webview_impl.h ('k') | webkit/webkit.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698