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