|
1 /* |
|
2 * Copyright (C) 2010 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 "AutoFillPopupMenuClient.h" |
|
35 #include "AXObjectCache.h" |
|
36 #include "Chrome.h" |
|
37 #include "CompositionUnderlineVectorBuilder.h" |
|
38 #include "ContextMenu.h" |
|
39 #include "ContextMenuController.h" |
|
40 #include "ContextMenuItem.h" |
|
41 #include "CSSStyleSelector.h" |
|
42 #include "CSSValueKeywords.h" |
|
43 #include "Cursor.h" |
|
44 #include "Document.h" |
|
45 #include "DocumentLoader.h" |
|
46 #include "DOMUtilitiesPrivate.h" |
|
47 #include "DragController.h" |
|
48 #include "DragScrollTimer.h" |
|
49 #include "DragData.h" |
|
50 #include "Editor.h" |
|
51 #include "EventHandler.h" |
|
52 #include "FocusController.h" |
|
53 #include "FontDescription.h" |
|
54 #include "FrameLoader.h" |
|
55 #include "FrameTree.h" |
|
56 #include "FrameView.h" |
|
57 #include "GLES2Context.h" |
|
58 #include "GLES2ContextInternal.h" |
|
59 #include "GraphicsContext.h" |
|
60 #include "HTMLInputElement.h" |
|
61 #include "HTMLMediaElement.h" |
|
62 #include "HitTestResult.h" |
|
63 #include "HTMLNames.h" |
|
64 #include "Image.h" |
|
65 #include "InspectorController.h" |
|
66 #include "IntRect.h" |
|
67 #include "KeyboardCodes.h" |
|
68 #include "KeyboardEvent.h" |
|
69 #include "MIMETypeRegistry.h" |
|
70 #include "NodeRenderStyle.h" |
|
71 #include "Page.h" |
|
72 #include "PageGroup.h" |
|
73 #include "PageGroupLoadDeferrer.h" |
|
74 #include "Pasteboard.h" |
|
75 #include "PlatformContextSkia.h" |
|
76 #include "PlatformKeyboardEvent.h" |
|
77 #include "PlatformMouseEvent.h" |
|
78 #include "PlatformThemeChromiumGtk.h" |
|
79 #include "PlatformWheelEvent.h" |
|
80 #include "PopupMenuChromium.h" |
|
81 #include "PopupMenuClient.h" |
|
82 #include "ProgressTracker.h" |
|
83 #include "RenderView.h" |
|
84 #include "ResourceHandle.h" |
|
85 #include "SecurityOrigin.h" |
|
86 #include "SelectionController.h" |
|
87 #include "Settings.h" |
|
88 #include "Timer.h" |
|
89 #include "TypingCommand.h" |
|
90 #include "Vector.h" |
|
91 #include "WebAccessibilityObject.h" |
|
92 #include "WebDevToolsAgentPrivate.h" |
|
93 #include "WebDevToolsAgentImpl.h" |
|
94 #include "WebDragData.h" |
|
95 #include "WebFrameImpl.h" |
|
96 #include "WebImage.h" |
|
97 #include "WebInputElement.h" |
|
98 #include "WebInputEvent.h" |
|
99 #include "WebInputEventConversion.h" |
|
100 #include "WebKit.h" |
|
101 #include "WebKitClient.h" |
|
102 #include "WebMediaPlayerAction.h" |
|
103 #include "WebNode.h" |
|
104 #include "WebPlugin.h" |
|
105 #include "WebPluginContainerImpl.h" |
|
106 #include "WebPoint.h" |
|
107 #include "WebPopupMenuImpl.h" |
|
108 #include "WebRect.h" |
|
109 #include "WebSettingsImpl.h" |
|
110 #include "WebString.h" |
|
111 #include "WebVector.h" |
|
112 #include "WebViewClient.h" |
|
113 #include "wtf/OwnPtr.h" |
|
114 |
|
115 #if OS(WINDOWS) |
|
116 #include "RenderThemeChromiumWin.h" |
|
117 #else |
|
118 #if OS(LINUX) |
|
119 #include "RenderThemeChromiumLinux.h" |
|
120 #endif |
|
121 #include "RenderTheme.h" |
|
122 #endif |
|
123 |
|
124 // Get rid of WTF's pow define so we can use std::pow. |
|
125 #undef pow |
|
126 #include <cmath> // for std::pow |
|
127 |
|
128 using namespace WebCore; |
|
129 |
|
130 namespace WebKit { |
|
131 |
|
132 // Change the text zoom level by kTextSizeMultiplierRatio each time the user |
|
133 // zooms text in or out (ie., change by 20%). The min and max values limit |
|
134 // text zoom to half and 3x the original text size. These three values match |
|
135 // those in Apple's port in WebKit/WebKit/WebView/WebView.mm |
|
136 static const double textSizeMultiplierRatio = 1.2; |
|
137 static const double minTextSizeMultiplier = 0.5; |
|
138 static const double maxTextSizeMultiplier = 3.0; |
|
139 |
|
140 // The group name identifies a namespace of pages. Page group is used on OSX |
|
141 // for some programs that use HTML views to display things that don't seem like |
|
142 // web pages to the user (so shouldn't have visited link coloring). We only use |
|
143 // one page group. |
|
144 const char* pageGroupName = "default"; |
|
145 |
|
146 // Used to defer all page activity in cases where the embedder wishes to run |
|
147 // a nested event loop. Using a stack enables nesting of message loop invocations. |
|
148 static Vector<PageGroupLoadDeferrer*> pageGroupLoadDeferrerStack; |
|
149 |
|
150 // Ensure that the WebDragOperation enum values stay in sync with the original |
|
151 // DragOperation constants. |
|
152 #define COMPILE_ASSERT_MATCHING_ENUM(coreName) \ |
|
153 COMPILE_ASSERT(int(coreName) == int(Web##coreName), dummy##coreName) |
|
154 COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone); |
|
155 COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy); |
|
156 COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink); |
|
157 COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric); |
|
158 COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate); |
|
159 COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove); |
|
160 COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete); |
|
161 COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery); |
|
162 |
|
163 static const PopupContainerSettings autoFillPopupSettings = { |
|
164 false, // setTextOnIndexChange |
|
165 false, // acceptOnAbandon |
|
166 true, // loopSelectionNavigation |
|
167 false, // restrictWidthOfListBox (For security reasons show the entire entry |
|
168 // so the user doesn't enter information it did not intend to.) |
|
169 // For suggestions, we use the direction of the input field as the direction |
|
170 // of the popup items. The main reason is to keep the display of items in |
|
171 // drop-down the same as the items in the input field. |
|
172 PopupContainerSettings::DOMElementDirection, |
|
173 }; |
|
174 |
|
175 // WebView ---------------------------------------------------------------- |
|
176 |
|
177 WebView* WebView::create(WebViewClient* client, WebDevToolsAgentClient* devToolsClient) |
|
178 { |
|
179 // Pass the WebViewImpl's self-reference to the caller. |
|
180 return adoptRef(new WebViewImpl(client, devToolsClient)).leakRef(); |
|
181 } |
|
182 |
|
183 void WebView::updateVisitedLinkState(unsigned long long linkHash) |
|
184 { |
|
185 Page::visitedStateChanged(PageGroup::pageGroup(pageGroupName), linkHash); |
|
186 } |
|
187 |
|
188 void WebView::resetVisitedLinkState() |
|
189 { |
|
190 Page::allVisitedStateChanged(PageGroup::pageGroup(pageGroupName)); |
|
191 } |
|
192 |
|
193 void WebView::willEnterModalLoop() |
|
194 { |
|
195 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName); |
|
196 ASSERT(pageGroup); |
|
197 |
|
198 if (pageGroup->pages().isEmpty()) |
|
199 pageGroupLoadDeferrerStack.append(static_cast<PageGroupLoadDeferrer*>(0)); |
|
200 else { |
|
201 // Pick any page in the page group since we are deferring all pages. |
|
202 pageGroupLoadDeferrerStack.append(new PageGroupLoadDeferrer(*pageGroup->pages().begin(), true)); |
|
203 } |
|
204 } |
|
205 |
|
206 void WebView::didExitModalLoop() |
|
207 { |
|
208 ASSERT(pageGroupLoadDeferrerStack.size()); |
|
209 |
|
210 delete pageGroupLoadDeferrerStack.last(); |
|
211 pageGroupLoadDeferrerStack.removeLast(); |
|
212 } |
|
213 |
|
214 void WebViewImpl::initializeMainFrame(WebFrameClient* frameClient) |
|
215 { |
|
216 // NOTE: The WebFrameImpl takes a reference to itself within InitMainFrame |
|
217 // and releases that reference once the corresponding Frame is destroyed. |
|
218 RefPtr<WebFrameImpl> frame = WebFrameImpl::create(frameClient); |
|
219 |
|
220 frame->initializeAsMainFrame(this); |
|
221 |
|
222 // Restrict the access to the local file system |
|
223 // (see WebView.mm WebView::_commonInitializationWithFrameName). |
|
224 SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForLocalOnly); |
|
225 } |
|
226 |
|
227 WebViewImpl::WebViewImpl(WebViewClient* client, WebDevToolsAgentClient* devToolsClient) |
|
228 : m_client(client) |
|
229 , m_backForwardListClientImpl(this) |
|
230 , m_chromeClientImpl(this) |
|
231 , m_contextMenuClientImpl(this) |
|
232 , m_dragClientImpl(this) |
|
233 , m_editorClientImpl(this) |
|
234 , m_inspectorClientImpl(this) |
|
235 , m_observedNewNavigation(false) |
|
236 #ifndef NDEBUG |
|
237 , m_newNavigationLoader(0) |
|
238 #endif |
|
239 , m_zoomLevel(0) |
|
240 , m_contextMenuAllowed(false) |
|
241 , m_doingDragAndDrop(false) |
|
242 , m_ignoreInputEvents(false) |
|
243 , m_suppressNextKeypressEvent(false) |
|
244 , m_initialNavigationPolicy(WebNavigationPolicyIgnore) |
|
245 , m_imeAcceptEvents(true) |
|
246 , m_dragTargetDispatch(false) |
|
247 , m_dragIdentity(0) |
|
248 , m_dropEffect(DropEffectDefault) |
|
249 , m_operationsAllowed(WebDragOperationNone) |
|
250 , m_dragOperation(WebDragOperationNone) |
|
251 , m_autoFillPopupShowing(false) |
|
252 , m_autoFillPopupClient(0) |
|
253 , m_autoFillPopup(0) |
|
254 , m_isTransparent(false) |
|
255 , m_tabsToLinks(false) |
|
256 , m_dragScrollTimer(new DragScrollTimer()) |
|
257 #if USE(ACCELERATED_COMPOSITING) |
|
258 , m_layerRenderer(0) |
|
259 , m_isAcceleratedCompositingActive(false) |
|
260 #endif |
|
261 , m_gles2Context(0) |
|
262 { |
|
263 // WebKit/win/WebView.cpp does the same thing, except they call the |
|
264 // KJS specific wrapper around this method. We need to have threading |
|
265 // initialized because CollatorICU requires it. |
|
266 WTF::initializeThreading(); |
|
267 WTF::initializeMainThread(); |
|
268 |
|
269 // set to impossible point so we always get the first mouse pos |
|
270 m_lastMousePosition = WebPoint(-1, -1); |
|
271 |
|
272 if (devToolsClient) |
|
273 m_devToolsAgent = new WebDevToolsAgentImpl(this, devToolsClient); |
|
274 |
|
275 m_page.set(new Page(&m_chromeClientImpl, &m_contextMenuClientImpl, &m_editorClientImpl, &m_dragClientImpl, &m_inspectorClientImpl, 0, 0, 0, 0)); |
|
276 |
|
277 // the page will take ownership of the various clients |
|
278 |
|
279 m_page->backForwardList()->setClient(&m_backForwardListClientImpl); |
|
280 m_page->setGroupName(pageGroupName); |
|
281 |
|
282 m_inspectorSettingsMap.set(new SettingsMap); |
|
283 } |
|
284 |
|
285 WebViewImpl::~WebViewImpl() |
|
286 { |
|
287 ASSERT(!m_page); |
|
288 } |
|
289 |
|
290 RenderTheme* WebViewImpl::theme() const |
|
291 { |
|
292 return m_page.get() ? m_page->theme() : RenderTheme::defaultTheme().get(); |
|
293 } |
|
294 |
|
295 WebFrameImpl* WebViewImpl::mainFrameImpl() |
|
296 { |
|
297 return m_page.get() ? WebFrameImpl::fromFrame(m_page->mainFrame()) : 0; |
|
298 } |
|
299 |
|
300 bool WebViewImpl::tabKeyCyclesThroughElements() const |
|
301 { |
|
302 ASSERT(m_page.get()); |
|
303 return m_page->tabKeyCyclesThroughElements(); |
|
304 } |
|
305 |
|
306 void WebViewImpl::setTabKeyCyclesThroughElements(bool value) |
|
307 { |
|
308 if (m_page) |
|
309 m_page->setTabKeyCyclesThroughElements(value); |
|
310 } |
|
311 |
|
312 void WebViewImpl::mouseMove(const WebMouseEvent& event) |
|
313 { |
|
314 if (!mainFrameImpl() || !mainFrameImpl()->frameView()) |
|
315 return; |
|
316 |
|
317 m_lastMousePosition = WebPoint(event.x, event.y); |
|
318 |
|
319 // We call mouseMoved here instead of handleMouseMovedEvent because we need |
|
320 // our ChromeClientImpl to receive changes to the mouse position and |
|
321 // tooltip text, and mouseMoved handles all of that. |
|
322 mainFrameImpl()->frame()->eventHandler()->mouseMoved( |
|
323 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event)); |
|
324 } |
|
325 |
|
326 void WebViewImpl::mouseLeave(const WebMouseEvent& event) |
|
327 { |
|
328 // This event gets sent as the main frame is closing. In that case, just |
|
329 // ignore it. |
|
330 if (!mainFrameImpl() || !mainFrameImpl()->frameView()) |
|
331 return; |
|
332 |
|
333 m_client->setMouseOverURL(WebURL()); |
|
334 |
|
335 mainFrameImpl()->frame()->eventHandler()->handleMouseMoveEvent( |
|
336 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event)); |
|
337 } |
|
338 |
|
339 void WebViewImpl::mouseDown(const WebMouseEvent& event) |
|
340 { |
|
341 if (!mainFrameImpl() || !mainFrameImpl()->frameView()) |
|
342 return; |
|
343 |
|
344 // If there is a select popup open, close it as the user is clicking on |
|
345 // the page (outside of the popup). We also save it so we can prevent a |
|
346 // click on the select element from immediately reopening the popup. |
|
347 RefPtr<WebCore::PopupContainer> selectPopup; |
|
348 if (event.button == WebMouseEvent::ButtonLeft) { |
|
349 selectPopup = m_selectPopup; |
|
350 hideSelectPopup(); |
|
351 ASSERT(!m_selectPopup); |
|
352 } |
|
353 |
|
354 m_lastMouseDownPoint = WebPoint(event.x, event.y); |
|
355 |
|
356 RefPtr<Node> clickedNode; |
|
357 if (event.button == WebMouseEvent::ButtonLeft) { |
|
358 IntPoint point(event.x, event.y); |
|
359 point = m_page->mainFrame()->view()->windowToContents(point); |
|
360 HitTestResult result(m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, false)); |
|
361 Node* hitNode = result.innerNonSharedNode(); |
|
362 |
|
363 // Take capture on a mouse down on a plugin so we can send it mouse events. |
|
364 if (hitNode && hitNode->renderer() && hitNode->renderer()->isEmbeddedObject()) |
|
365 m_mouseCaptureNode = hitNode; |
|
366 |
|
367 // If a text field that has focus is clicked again, we should display the |
|
368 // AutoFill popup. |
|
369 RefPtr<Node> focusedNode = focusedWebCoreNode(); |
|
370 if (focusedNode.get() && toHTMLInputElement(focusedNode.get())) { |
|
371 if (hitNode == focusedNode) { |
|
372 // Already focused text field was clicked, let's remember this. If |
|
373 // focus has not changed after the mouse event is processed, we'll |
|
374 // trigger the autocomplete. |
|
375 clickedNode = focusedNode; |
|
376 } |
|
377 } |
|
378 } |
|
379 |
|
380 mainFrameImpl()->frame()->loader()->resetMultipleFormSubmissionProtection(); |
|
381 |
|
382 mainFrameImpl()->frame()->eventHandler()->handleMousePressEvent( |
|
383 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event)); |
|
384 |
|
385 if (clickedNode.get() && clickedNode == focusedWebCoreNode()) { |
|
386 // Focus has not changed, show the AutoFill popup. |
|
387 static_cast<EditorClientImpl*>(m_page->editorClient())-> |
|
388 showFormAutofillForNode(clickedNode.get()); |
|
389 } |
|
390 if (m_selectPopup && m_selectPopup == selectPopup) { |
|
391 // That click triggered a select popup which is the same as the one that |
|
392 // was showing before the click. It means the user clicked the select |
|
393 // while the popup was showing, and as a result we first closed then |
|
394 // immediately reopened the select popup. It needs to be closed. |
|
395 hideSelectPopup(); |
|
396 } |
|
397 |
|
398 // Dispatch the contextmenu event regardless of if the click was swallowed. |
|
399 // On Windows, we handle it on mouse up, not down. |
|
400 #if OS(DARWIN) |
|
401 if (event.button == WebMouseEvent::ButtonRight |
|
402 || (event.button == WebMouseEvent::ButtonLeft |
|
403 && event.modifiers & WebMouseEvent::ControlKey)) |
|
404 mouseContextMenu(event); |
|
405 #elif OS(LINUX) |
|
406 if (event.button == WebMouseEvent::ButtonRight) |
|
407 mouseContextMenu(event); |
|
408 #endif |
|
409 } |
|
410 |
|
411 void WebViewImpl::mouseContextMenu(const WebMouseEvent& event) |
|
412 { |
|
413 if (!mainFrameImpl() || !mainFrameImpl()->frameView()) |
|
414 return; |
|
415 |
|
416 m_page->contextMenuController()->clearContextMenu(); |
|
417 |
|
418 PlatformMouseEventBuilder pme(mainFrameImpl()->frameView(), event); |
|
419 |
|
420 // Find the right target frame. See issue 1186900. |
|
421 HitTestResult result = hitTestResultForWindowPos(pme.pos()); |
|
422 Frame* targetFrame; |
|
423 if (result.innerNonSharedNode()) |
|
424 targetFrame = result.innerNonSharedNode()->document()->frame(); |
|
425 else |
|
426 targetFrame = m_page->focusController()->focusedOrMainFrame(); |
|
427 |
|
428 #if OS(WINDOWS) |
|
429 targetFrame->view()->setCursor(pointerCursor()); |
|
430 #endif |
|
431 |
|
432 m_contextMenuAllowed = true; |
|
433 targetFrame->eventHandler()->sendContextMenuEvent(pme); |
|
434 m_contextMenuAllowed = false; |
|
435 // Actually showing the context menu is handled by the ContextMenuClient |
|
436 // implementation... |
|
437 } |
|
438 |
|
439 void WebViewImpl::mouseUp(const WebMouseEvent& event) |
|
440 { |
|
441 if (!mainFrameImpl() || !mainFrameImpl()->frameView()) |
|
442 return; |
|
443 |
|
444 #if OS(LINUX) |
|
445 // If the event was a middle click, attempt to copy text into the focused |
|
446 // frame. We execute this before we let the page have a go at the event |
|
447 // because the page may change what is focused during in its event handler. |
|
448 // |
|
449 // This code is in the mouse up handler. There is some debate about putting |
|
450 // this here, as opposed to the mouse down handler. |
|
451 // xterm: pastes on up. |
|
452 // GTK: pastes on down. |
|
453 // Firefox: pastes on up. |
|
454 // Midori: couldn't paste at all with 0.1.2 |
|
455 // |
|
456 // There is something of a webcompat angle to this well, as highlighted by |
|
457 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on |
|
458 // down then the text is pasted just before the onclick handler runs and |
|
459 // clears the text box. So it's important this happens after the |
|
460 // handleMouseReleaseEvent() earlier in this function |
|
461 if (event.button == WebMouseEvent::ButtonMiddle) { |
|
462 Frame* focused = focusedWebCoreFrame(); |
|
463 FrameView* view = m_page->mainFrame()->view(); |
|
464 IntPoint clickPoint(m_lastMouseDownPoint.x, m_lastMouseDownPoint.y); |
|
465 IntPoint contentPoint = view->windowToContents(clickPoint); |
|
466 HitTestResult hitTestResult = focused->eventHandler()->hitTestResultAtPoint(contentPoint, false, false, ShouldHitTestScrollbars); |
|
467 // We don't want to send a paste when middle clicking a scroll bar or a |
|
468 // link (which will navigate later in the code). The main scrollbars |
|
469 // have to be handled separately. |
|
470 if (!hitTestResult.scrollbar() && !hitTestResult.isLiveLink() && focused && !view->scrollbarAtPoint(clickPoint)) { |
|
471 Editor* editor = focused->editor(); |
|
472 Pasteboard* pasteboard = Pasteboard::generalPasteboard(); |
|
473 bool oldSelectionMode = pasteboard->isSelectionMode(); |
|
474 pasteboard->setSelectionMode(true); |
|
475 editor->command(AtomicString("Paste")).execute(); |
|
476 pasteboard->setSelectionMode(oldSelectionMode); |
|
477 } |
|
478 } |
|
479 #endif |
|
480 |
|
481 mainFrameImpl()->frame()->eventHandler()->handleMouseReleaseEvent( |
|
482 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event)); |
|
483 |
|
484 #if OS(WINDOWS) |
|
485 // Dispatch the contextmenu event regardless of if the click was swallowed. |
|
486 // On Mac/Linux, we handle it on mouse down, not up. |
|
487 if (event.button == WebMouseEvent::ButtonRight) |
|
488 mouseContextMenu(event); |
|
489 #endif |
|
490 } |
|
491 |
|
492 void WebViewImpl::mouseWheel(const WebMouseWheelEvent& event) |
|
493 { |
|
494 PlatformWheelEventBuilder platformEvent(mainFrameImpl()->frameView(), event); |
|
495 mainFrameImpl()->frame()->eventHandler()->handleWheelEvent(platformEvent); |
|
496 } |
|
497 |
|
498 bool WebViewImpl::keyEvent(const WebKeyboardEvent& event) |
|
499 { |
|
500 ASSERT((event.type == WebInputEvent::RawKeyDown) |
|
501 || (event.type == WebInputEvent::KeyDown) |
|
502 || (event.type == WebInputEvent::KeyUp)); |
|
503 |
|
504 // Please refer to the comments explaining the m_suppressNextKeypressEvent |
|
505 // member. |
|
506 // The m_suppressNextKeypressEvent is set if the KeyDown is handled by |
|
507 // Webkit. A keyDown event is typically associated with a keyPress(char) |
|
508 // event and a keyUp event. We reset this flag here as this is a new keyDown |
|
509 // event. |
|
510 m_suppressNextKeypressEvent = false; |
|
511 |
|
512 // Give any select popup a chance at consuming the key event. |
|
513 if (selectPopupHandleKeyEvent(event)) |
|
514 return true; |
|
515 |
|
516 // Give Autocomplete a chance to consume the key events it is interested in. |
|
517 if (autocompleteHandleKeyEvent(event)) |
|
518 return true; |
|
519 |
|
520 Frame* frame = focusedWebCoreFrame(); |
|
521 if (!frame) |
|
522 return false; |
|
523 |
|
524 EventHandler* handler = frame->eventHandler(); |
|
525 if (!handler) |
|
526 return keyEventDefault(event); |
|
527 |
|
528 #if OS(WINDOWS) || OS(LINUX) |
|
529 const WebInputEvent::Type contextMenuTriggeringEventType = |
|
530 #if OS(WINDOWS) |
|
531 WebInputEvent::KeyUp; |
|
532 #elif OS(LINUX) |
|
533 WebInputEvent::RawKeyDown; |
|
534 #endif |
|
535 |
|
536 if (((!event.modifiers && (event.windowsKeyCode == VKEY_APPS)) |
|
537 || ((event.modifiers == WebInputEvent::ShiftKey) && (event.windowsKeyCode == VKEY_F10))) |
|
538 && event.type == contextMenuTriggeringEventType) { |
|
539 sendContextMenuEvent(event); |
|
540 return true; |
|
541 } |
|
542 #endif |
|
543 |
|
544 // It's not clear if we should continue after detecting a capslock keypress. |
|
545 // I'll err on the side of continuing, which is the pre-existing behaviour. |
|
546 if (event.windowsKeyCode == VKEY_CAPITAL) |
|
547 handler->capsLockStateMayHaveChanged(); |
|
548 |
|
549 PlatformKeyboardEventBuilder evt(event); |
|
550 |
|
551 if (handler->keyEvent(evt)) { |
|
552 if (WebInputEvent::RawKeyDown == event.type) { |
|
553 // Suppress the next keypress event unless the focused node is a plug-in node. |
|
554 // (Flash needs these keypress events to handle non-US keyboards.) |
|
555 Node* node = frame->document()->focusedNode(); |
|
556 if (!node || !node->renderer() || !node->renderer()->isEmbeddedObject()) |
|
557 m_suppressNextKeypressEvent = true; |
|
558 } |
|
559 return true; |
|
560 } |
|
561 |
|
562 return keyEventDefault(event); |
|
563 } |
|
564 |
|
565 bool WebViewImpl::selectPopupHandleKeyEvent(const WebKeyboardEvent& event) |
|
566 { |
|
567 if (!m_selectPopup) |
|
568 return false; |
|
569 |
|
570 return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event)); |
|
571 } |
|
572 |
|
573 bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event) |
|
574 { |
|
575 if (!m_autoFillPopupShowing |
|
576 // Home and End should be left to the text field to process. |
|
577 || event.windowsKeyCode == VKEY_HOME |
|
578 || event.windowsKeyCode == VKEY_END) |
|
579 return false; |
|
580 |
|
581 // Pressing delete triggers the removal of the selected suggestion from the DB. |
|
582 if (event.windowsKeyCode == VKEY_DELETE |
|
583 && m_autoFillPopup->selectedIndex() != -1) { |
|
584 Node* node = focusedWebCoreNode(); |
|
585 if (!node || (node->nodeType() != Node::ELEMENT_NODE)) { |
|
586 ASSERT_NOT_REACHED(); |
|
587 return false; |
|
588 } |
|
589 Element* element = static_cast<Element*>(node); |
|
590 if (!element->hasLocalName(HTMLNames::inputTag)) { |
|
591 ASSERT_NOT_REACHED(); |
|
592 return false; |
|
593 } |
|
594 |
|
595 int selectedIndex = m_autoFillPopup->selectedIndex(); |
|
596 |
|
597 if (!m_autoFillPopupClient->canRemoveSuggestionAtIndex(selectedIndex)) |
|
598 return false; |
|
599 |
|
600 WebString name = WebInputElement(static_cast<HTMLInputElement*>(element)).nameForAutofill(); |
|
601 WebString value = m_autoFillPopupClient->itemText(selectedIndex); |
|
602 m_client->removeAutofillSuggestions(name, value); |
|
603 // Update the entries in the currently showing popup to reflect the |
|
604 // deletion. |
|
605 m_autoFillPopupClient->removeSuggestionAtIndex(selectedIndex); |
|
606 refreshAutoFillPopup(); |
|
607 return false; |
|
608 } |
|
609 |
|
610 if (!m_autoFillPopup->isInterestedInEventForKey(event.windowsKeyCode)) |
|
611 return false; |
|
612 |
|
613 if (m_autoFillPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) { |
|
614 // We need to ignore the next Char event after this otherwise pressing |
|
615 // enter when selecting an item in the menu will go to the page. |
|
616 if (WebInputEvent::RawKeyDown == event.type) |
|
617 m_suppressNextKeypressEvent = true; |
|
618 return true; |
|
619 } |
|
620 |
|
621 return false; |
|
622 } |
|
623 |
|
624 bool WebViewImpl::charEvent(const WebKeyboardEvent& event) |
|
625 { |
|
626 ASSERT(event.type == WebInputEvent::Char); |
|
627 |
|
628 // Please refer to the comments explaining the m_suppressNextKeypressEvent |
|
629 // member. The m_suppressNextKeypressEvent is set if the KeyDown is |
|
630 // handled by Webkit. A keyDown event is typically associated with a |
|
631 // keyPress(char) event and a keyUp event. We reset this flag here as it |
|
632 // only applies to the current keyPress event. |
|
633 bool suppress = m_suppressNextKeypressEvent; |
|
634 m_suppressNextKeypressEvent = false; |
|
635 |
|
636 Frame* frame = focusedWebCoreFrame(); |
|
637 if (!frame) |
|
638 return suppress; |
|
639 |
|
640 EventHandler* handler = frame->eventHandler(); |
|
641 if (!handler) |
|
642 return suppress || keyEventDefault(event); |
|
643 |
|
644 PlatformKeyboardEventBuilder evt(event); |
|
645 if (!evt.isCharacterKey()) |
|
646 return true; |
|
647 |
|
648 // Accesskeys are triggered by char events and can't be suppressed. |
|
649 if (handler->handleAccessKey(evt)) |
|
650 return true; |
|
651 |
|
652 // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to |
|
653 // the eventHandler::keyEvent. We mimic this behavior on all platforms since |
|
654 // for now we are converting other platform's key events to windows key |
|
655 // events. |
|
656 if (evt.isSystemKey()) |
|
657 return false; |
|
658 |
|
659 if (!suppress && !handler->keyEvent(evt)) |
|
660 return keyEventDefault(event); |
|
661 |
|
662 return true; |
|
663 } |
|
664 |
|
665 #if ENABLE(TOUCH_EVENTS) |
|
666 bool WebViewImpl::touchEvent(const WebTouchEvent& event) |
|
667 { |
|
668 if (!mainFrameImpl() || !mainFrameImpl()->frameView()) |
|
669 return false; |
|
670 |
|
671 PlatformTouchEventBuilder touchEventBuilder(mainFrameImpl()->frameView(), event); |
|
672 return mainFrameImpl()->frame()->eventHandler()->handleTouchEvent(touchEventBuilder); |
|
673 } |
|
674 #endif |
|
675 |
|
676 #if OS(WINDOWS) || OS(LINUX) |
|
677 // Mac has no way to open a context menu based on a keyboard event. |
|
678 bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event) |
|
679 { |
|
680 // The contextMenuController() holds onto the last context menu that was |
|
681 // popped up on the page until a new one is created. We need to clear |
|
682 // this menu before propagating the event through the DOM so that we can |
|
683 // detect if we create a new menu for this event, since we won't create |
|
684 // a new menu if the DOM swallows the event and the defaultEventHandler does |
|
685 // not run. |
|
686 page()->contextMenuController()->clearContextMenu(); |
|
687 |
|
688 m_contextMenuAllowed = true; |
|
689 Frame* focusedFrame = page()->focusController()->focusedOrMainFrame(); |
|
690 bool handled = focusedFrame->eventHandler()->sendContextMenuEventForKey(); |
|
691 m_contextMenuAllowed = false; |
|
692 return handled; |
|
693 } |
|
694 #endif |
|
695 |
|
696 bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event) |
|
697 { |
|
698 Frame* frame = focusedWebCoreFrame(); |
|
699 if (!frame) |
|
700 return false; |
|
701 |
|
702 switch (event.type) { |
|
703 case WebInputEvent::Char: |
|
704 if (event.windowsKeyCode == VKEY_SPACE) { |
|
705 int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT); |
|
706 return scrollViewWithKeyboard(keyCode, event.modifiers); |
|
707 } |
|
708 break; |
|
709 case WebInputEvent::RawKeyDown: |
|
710 if (event.modifiers == WebInputEvent::ControlKey) { |
|
711 switch (event.windowsKeyCode) { |
|
712 #if !OS(DARWIN) |
|
713 case 'A': |
|
714 focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll")); |
|
715 return true; |
|
716 case VKEY_INSERT: |
|
717 case 'C': |
|
718 focusedFrame()->executeCommand(WebString::fromUTF8("Copy")); |
|
719 return true; |
|
720 #endif |
|
721 // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl |
|
722 // key combinations which affect scrolling. Safari is buggy in the |
|
723 // sense that it scrolls the page for all Ctrl+scrolling key |
|
724 // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc. |
|
725 case VKEY_HOME: |
|
726 case VKEY_END: |
|
727 break; |
|
728 default: |
|
729 return false; |
|
730 } |
|
731 } |
|
732 if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey)) |
|
733 return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers); |
|
734 break; |
|
735 default: |
|
736 break; |
|
737 } |
|
738 return false; |
|
739 } |
|
740 |
|
741 bool WebViewImpl::scrollViewWithKeyboard(int keyCode, int modifiers) |
|
742 { |
|
743 ScrollDirection scrollDirection; |
|
744 ScrollGranularity scrollGranularity; |
|
745 if (!mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity)) |
|
746 return false; |
|
747 return propagateScroll(scrollDirection, scrollGranularity); |
|
748 } |
|
749 |
|
750 bool WebViewImpl::mapKeyCodeForScroll(int keyCode, |
|
751 WebCore::ScrollDirection* scrollDirection, |
|
752 WebCore::ScrollGranularity* scrollGranularity) |
|
753 { |
|
754 switch (keyCode) { |
|
755 case VKEY_LEFT: |
|
756 *scrollDirection = ScrollLeft; |
|
757 *scrollGranularity = ScrollByLine; |
|
758 break; |
|
759 case VKEY_RIGHT: |
|
760 *scrollDirection = ScrollRight; |
|
761 *scrollGranularity = ScrollByLine; |
|
762 break; |
|
763 case VKEY_UP: |
|
764 *scrollDirection = ScrollUp; |
|
765 *scrollGranularity = ScrollByLine; |
|
766 break; |
|
767 case VKEY_DOWN: |
|
768 *scrollDirection = ScrollDown; |
|
769 *scrollGranularity = ScrollByLine; |
|
770 break; |
|
771 case VKEY_HOME: |
|
772 *scrollDirection = ScrollUp; |
|
773 *scrollGranularity = ScrollByDocument; |
|
774 break; |
|
775 case VKEY_END: |
|
776 *scrollDirection = ScrollDown; |
|
777 *scrollGranularity = ScrollByDocument; |
|
778 break; |
|
779 case VKEY_PRIOR: // page up |
|
780 *scrollDirection = ScrollUp; |
|
781 *scrollGranularity = ScrollByPage; |
|
782 break; |
|
783 case VKEY_NEXT: // page down |
|
784 *scrollDirection = ScrollDown; |
|
785 *scrollGranularity = ScrollByPage; |
|
786 break; |
|
787 default: |
|
788 return false; |
|
789 } |
|
790 |
|
791 return true; |
|
792 } |
|
793 |
|
794 void WebViewImpl::hideSelectPopup() |
|
795 { |
|
796 if (m_selectPopup.get()) |
|
797 m_selectPopup->hidePopup(); |
|
798 } |
|
799 |
|
800 bool WebViewImpl::propagateScroll(ScrollDirection scrollDirection, |
|
801 ScrollGranularity scrollGranularity) |
|
802 { |
|
803 Frame* frame = focusedWebCoreFrame(); |
|
804 if (!frame) |
|
805 return false; |
|
806 |
|
807 bool scrollHandled = |
|
808 frame->eventHandler()->scrollOverflow(scrollDirection, |
|
809 scrollGranularity); |
|
810 Frame* currentFrame = frame; |
|
811 while (!scrollHandled && currentFrame) { |
|
812 scrollHandled = currentFrame->view()->scroll(scrollDirection, |
|
813 scrollGranularity); |
|
814 currentFrame = currentFrame->tree()->parent(); |
|
815 } |
|
816 return scrollHandled; |
|
817 } |
|
818 |
|
819 void WebViewImpl::popupOpened(WebCore::PopupContainer* popupContainer) |
|
820 { |
|
821 if (popupContainer->popupType() == WebCore::PopupContainer::Select) { |
|
822 ASSERT(!m_selectPopup); |
|
823 m_selectPopup = popupContainer; |
|
824 } |
|
825 } |
|
826 |
|
827 void WebViewImpl::popupClosed(WebCore::PopupContainer* popupContainer) |
|
828 { |
|
829 if (popupContainer->popupType() == WebCore::PopupContainer::Select) { |
|
830 ASSERT(m_selectPopup.get()); |
|
831 m_selectPopup = 0; |
|
832 } |
|
833 } |
|
834 |
|
835 void WebViewImpl::hideAutoFillPopup() |
|
836 { |
|
837 if (m_autoFillPopupShowing) { |
|
838 m_autoFillPopup->hidePopup(); |
|
839 m_autoFillPopupShowing = false; |
|
840 } |
|
841 } |
|
842 |
|
843 Frame* WebViewImpl::focusedWebCoreFrame() |
|
844 { |
|
845 return m_page.get() ? m_page->focusController()->focusedOrMainFrame() : 0; |
|
846 } |
|
847 |
|
848 WebViewImpl* WebViewImpl::fromPage(Page* page) |
|
849 { |
|
850 if (!page) |
|
851 return 0; |
|
852 |
|
853 return static_cast<ChromeClientImpl*>(page->chrome()->client())->webView(); |
|
854 } |
|
855 |
|
856 // WebWidget ------------------------------------------------------------------ |
|
857 |
|
858 void WebViewImpl::close() |
|
859 { |
|
860 RefPtr<WebFrameImpl> mainFrameImpl; |
|
861 |
|
862 if (m_page.get()) { |
|
863 // Initiate shutdown for the entire frameset. This will cause a lot of |
|
864 // notifications to be sent. |
|
865 if (m_page->mainFrame()) { |
|
866 mainFrameImpl = WebFrameImpl::fromFrame(m_page->mainFrame()); |
|
867 m_page->mainFrame()->loader()->frameDetached(); |
|
868 } |
|
869 m_page.clear(); |
|
870 } |
|
871 |
|
872 // Should happen after m_page.clear(). |
|
873 if (m_devToolsAgent.get()) |
|
874 m_devToolsAgent.clear(); |
|
875 |
|
876 // Reset the delegate to prevent notifications being sent as we're being |
|
877 // deleted. |
|
878 m_client = 0; |
|
879 |
|
880 deref(); // Balances ref() acquired in WebView::create |
|
881 } |
|
882 |
|
883 void WebViewImpl::resize(const WebSize& newSize) |
|
884 { |
|
885 if (m_size == newSize) |
|
886 return; |
|
887 m_size = newSize; |
|
888 |
|
889 if (mainFrameImpl()->frameView()) { |
|
890 mainFrameImpl()->frameView()->resize(m_size.width, m_size.height); |
|
891 mainFrameImpl()->frame()->eventHandler()->sendResizeEvent(); |
|
892 } |
|
893 |
|
894 if (m_client) { |
|
895 WebRect damagedRect(0, 0, m_size.width, m_size.height); |
|
896 m_client->didInvalidateRect(damagedRect); |
|
897 } |
|
898 } |
|
899 |
|
900 void WebViewImpl::layout() |
|
901 { |
|
902 WebFrameImpl* webframe = mainFrameImpl(); |
|
903 if (webframe) { |
|
904 // In order for our child HWNDs (NativeWindowWidgets) to update properly, |
|
905 // they need to be told that we are updating the screen. The problem is |
|
906 // that the native widgets need to recalculate their clip region and not |
|
907 // overlap any of our non-native widgets. To force the resizing, call |
|
908 // setFrameRect(). This will be a quick operation for most frames, but |
|
909 // the NativeWindowWidgets will update a proper clipping region. |
|
910 FrameView* view = webframe->frameView(); |
|
911 if (view) |
|
912 view->setFrameRect(view->frameRect()); |
|
913 |
|
914 // setFrameRect may have the side-effect of causing existing page |
|
915 // layout to be invalidated, so layout needs to be called last. |
|
916 |
|
917 webframe->layout(); |
|
918 } |
|
919 } |
|
920 |
|
921 void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect) |
|
922 { |
|
923 |
|
924 #if USE(ACCELERATED_COMPOSITING) |
|
925 if (!isAcceleratedCompositingActive()) { |
|
926 #endif |
|
927 WebFrameImpl* webframe = mainFrameImpl(); |
|
928 if (webframe) |
|
929 webframe->paint(canvas, rect); |
|
930 #if USE(ACCELERATED_COMPOSITING) |
|
931 } else { |
|
932 // Draw the contents of the root layer. |
|
933 updateRootLayerContents(rect); |
|
934 |
|
935 WebFrameImpl* webframe = mainFrameImpl(); |
|
936 if (!webframe) |
|
937 return; |
|
938 FrameView* view = webframe->frameView(); |
|
939 if (!view) |
|
940 return; |
|
941 |
|
942 // The visibleRect includes scrollbars whereas the contentRect doesn't. |
|
943 IntRect visibleRect = view->visibleContentRect(true); |
|
944 IntRect contentRect = view->visibleContentRect(false); |
|
945 |
|
946 // Ask the layer compositor to redraw all the layers. |
|
947 m_layerRenderer->drawLayers(rect, visibleRect, contentRect, IntPoint(view->scrollX(), view->scrollY())); |
|
948 } |
|
949 #endif |
|
950 } |
|
951 |
|
952 // FIXME: m_currentInputEvent should be removed once ChromeClient::show() can |
|
953 // get the current-event information from WebCore. |
|
954 const WebInputEvent* WebViewImpl::m_currentInputEvent = 0; |
|
955 |
|
956 bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent) |
|
957 { |
|
958 // If we've started a drag and drop operation, ignore input events until |
|
959 // we're done. |
|
960 if (m_doingDragAndDrop) |
|
961 return true; |
|
962 |
|
963 if (m_ignoreInputEvents) |
|
964 return true; |
|
965 |
|
966 if (m_mouseCaptureNode.get() && WebInputEvent::isMouseEventType(inputEvent.type)) { |
|
967 // Save m_mouseCaptureNode since mouseCaptureLost() will clear it. |
|
968 RefPtr<Node> node = m_mouseCaptureNode; |
|
969 |
|
970 // Not all platforms call mouseCaptureLost() directly. |
|
971 if (inputEvent.type == WebInputEvent::MouseUp) |
|
972 mouseCaptureLost(); |
|
973 |
|
974 AtomicString eventType; |
|
975 switch (inputEvent.type) { |
|
976 case WebInputEvent::MouseMove: |
|
977 eventType = eventNames().mousemoveEvent; |
|
978 break; |
|
979 case WebInputEvent::MouseLeave: |
|
980 eventType = eventNames().mouseoutEvent; |
|
981 break; |
|
982 case WebInputEvent::MouseDown: |
|
983 eventType = eventNames().mousedownEvent; |
|
984 break; |
|
985 case WebInputEvent::MouseUp: |
|
986 eventType = eventNames().mouseupEvent; |
|
987 break; |
|
988 default: |
|
989 ASSERT_NOT_REACHED(); |
|
990 } |
|
991 |
|
992 node->dispatchMouseEvent( |
|
993 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), *static_cast<const WebMouseEvent*>(&inputEvent)), |
|
994 eventType); |
|
995 return true; |
|
996 } |
|
997 |
|
998 // FIXME: Remove m_currentInputEvent. |
|
999 // This only exists to allow ChromeClient::show() to know which mouse button |
|
1000 // triggered a window.open event. |
|
1001 // Safari must perform a similar hack, ours is in our WebKit glue layer |
|
1002 // theirs is in the application. This should go when WebCore can be fixed |
|
1003 // to pass more event information to ChromeClient::show() |
|
1004 m_currentInputEvent = &inputEvent; |
|
1005 |
|
1006 bool handled = true; |
|
1007 |
|
1008 // FIXME: WebKit seems to always return false on mouse events processing |
|
1009 // methods. For now we'll assume it has processed them (as we are only |
|
1010 // interested in whether keyboard events are processed). |
|
1011 switch (inputEvent.type) { |
|
1012 case WebInputEvent::MouseMove: |
|
1013 mouseMove(*static_cast<const WebMouseEvent*>(&inputEvent)); |
|
1014 break; |
|
1015 |
|
1016 case WebInputEvent::MouseLeave: |
|
1017 mouseLeave(*static_cast<const WebMouseEvent*>(&inputEvent)); |
|
1018 break; |
|
1019 |
|
1020 case WebInputEvent::MouseWheel: |
|
1021 mouseWheel(*static_cast<const WebMouseWheelEvent*>(&inputEvent)); |
|
1022 break; |
|
1023 |
|
1024 case WebInputEvent::MouseDown: |
|
1025 mouseDown(*static_cast<const WebMouseEvent*>(&inputEvent)); |
|
1026 break; |
|
1027 |
|
1028 case WebInputEvent::MouseUp: |
|
1029 mouseUp(*static_cast<const WebMouseEvent*>(&inputEvent)); |
|
1030 break; |
|
1031 |
|
1032 case WebInputEvent::RawKeyDown: |
|
1033 case WebInputEvent::KeyDown: |
|
1034 case WebInputEvent::KeyUp: |
|
1035 handled = keyEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent)); |
|
1036 break; |
|
1037 |
|
1038 case WebInputEvent::Char: |
|
1039 handled = charEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent)); |
|
1040 break; |
|
1041 |
|
1042 #if ENABLE(TOUCH_EVENTS) |
|
1043 case WebInputEvent::TouchStart: |
|
1044 case WebInputEvent::TouchMove: |
|
1045 case WebInputEvent::TouchEnd: |
|
1046 case WebInputEvent::TouchCancel: |
|
1047 handled = touchEvent(*static_cast<const WebTouchEvent*>(&inputEvent)); |
|
1048 break; |
|
1049 #endif |
|
1050 |
|
1051 default: |
|
1052 handled = false; |
|
1053 } |
|
1054 |
|
1055 m_currentInputEvent = 0; |
|
1056 |
|
1057 return handled; |
|
1058 } |
|
1059 |
|
1060 void WebViewImpl::mouseCaptureLost() |
|
1061 { |
|
1062 m_mouseCaptureNode = 0; |
|
1063 } |
|
1064 |
|
1065 void WebViewImpl::setFocus(bool enable) |
|
1066 { |
|
1067 m_page->focusController()->setFocused(enable); |
|
1068 if (enable) { |
|
1069 // Note that we don't call setActive() when disabled as this cause extra |
|
1070 // focus/blur events to be dispatched. |
|
1071 m_page->focusController()->setActive(true); |
|
1072 RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame(); |
|
1073 if (focusedFrame) { |
|
1074 Node* focusedNode = focusedFrame->document()->focusedNode(); |
|
1075 if (focusedNode && focusedNode->isElementNode() |
|
1076 && focusedFrame->selection()->selection().isNone()) { |
|
1077 // If the selection was cleared while the WebView was not |
|
1078 // focused, then the focus element shows with a focus ring but |
|
1079 // no caret and does respond to keyboard inputs. |
|
1080 Element* element = static_cast<Element*>(focusedNode); |
|
1081 if (element->isTextFormControl()) |
|
1082 element->updateFocusAppearance(true); |
|
1083 else if (focusedNode->isContentEditable()) { |
|
1084 // updateFocusAppearance() selects all the text of |
|
1085 // contentseditable DIVs. So we set the selection explicitly |
|
1086 // instead. Note that this has the side effect of moving the |
|
1087 // caret back to the beginning of the text. |
|
1088 Position position(focusedNode, 0, |
|
1089 Position::PositionIsOffsetInAnchor); |
|
1090 focusedFrame->selection()->setSelection( |
|
1091 VisibleSelection(position, SEL_DEFAULT_AFFINITY)); |
|
1092 } |
|
1093 } |
|
1094 } |
|
1095 m_imeAcceptEvents = true; |
|
1096 } else { |
|
1097 hideAutoFillPopup(); |
|
1098 hideSelectPopup(); |
|
1099 |
|
1100 // Clear focus on the currently focused frame if any. |
|
1101 if (!m_page.get()) |
|
1102 return; |
|
1103 |
|
1104 Frame* frame = m_page->mainFrame(); |
|
1105 if (!frame) |
|
1106 return; |
|
1107 |
|
1108 RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame(); |
|
1109 if (focusedFrame.get()) { |
|
1110 // Finish an ongoing composition to delete the composition node. |
|
1111 Editor* editor = focusedFrame->editor(); |
|
1112 if (editor && editor->hasComposition()) |
|
1113 editor->confirmComposition(); |
|
1114 m_imeAcceptEvents = false; |
|
1115 } |
|
1116 } |
|
1117 } |
|
1118 |
|
1119 bool WebViewImpl::setComposition( |
|
1120 const WebString& text, |
|
1121 const WebVector<WebCompositionUnderline>& underlines, |
|
1122 int selectionStart, |
|
1123 int selectionEnd) |
|
1124 { |
|
1125 Frame* focused = focusedWebCoreFrame(); |
|
1126 if (!focused || !m_imeAcceptEvents) |
|
1127 return false; |
|
1128 Editor* editor = focused->editor(); |
|
1129 if (!editor) |
|
1130 return false; |
|
1131 |
|
1132 // The input focus has been moved to another WebWidget object. |
|
1133 // We should use this |editor| object only to complete the ongoing |
|
1134 // composition. |
|
1135 if (!editor->canEdit() && !editor->hasComposition()) |
|
1136 return false; |
|
1137 |
|
1138 // We should verify the parent node of this IME composition node are |
|
1139 // editable because JavaScript may delete a parent node of the composition |
|
1140 // node. In this case, WebKit crashes while deleting texts from the parent |
|
1141 // node, which doesn't exist any longer. |
|
1142 PassRefPtr<Range> range = editor->compositionRange(); |
|
1143 if (range) { |
|
1144 const Node* node = range->startPosition().node(); |
|
1145 if (!node || !node->isContentEditable()) |
|
1146 return false; |
|
1147 } |
|
1148 |
|
1149 // If we're not going to fire a keypress event, then the keydown event was |
|
1150 // canceled. In that case, cancel any existing composition. |
|
1151 if (text.isEmpty() || m_suppressNextKeypressEvent) { |
|
1152 // A browser process sent an IPC message which does not contain a valid |
|
1153 // string, which means an ongoing composition has been canceled. |
|
1154 // If the ongoing composition has been canceled, replace the ongoing |
|
1155 // composition string with an empty string and complete it. |
|
1156 String emptyString; |
|
1157 Vector<CompositionUnderline> emptyUnderlines; |
|
1158 editor->setComposition(emptyString, emptyUnderlines, 0, 0); |
|
1159 return text.isEmpty(); |
|
1160 } |
|
1161 |
|
1162 // When the range of composition underlines overlap with the range between |
|
1163 // selectionStart and selectionEnd, WebKit somehow won't paint the selection |
|
1164 // at all (see InlineTextBox::paint() function in InlineTextBox.cpp). |
|
1165 // But the selection range actually takes effect. |
|
1166 editor->setComposition(String(text), |
|
1167 CompositionUnderlineVectorBuilder(underlines), |
|
1168 selectionStart, selectionEnd); |
|
1169 |
|
1170 return editor->hasComposition(); |
|
1171 } |
|
1172 |
|
1173 bool WebViewImpl::confirmComposition() |
|
1174 { |
|
1175 Frame* focused = focusedWebCoreFrame(); |
|
1176 if (!focused || !m_imeAcceptEvents) |
|
1177 return false; |
|
1178 Editor* editor = focused->editor(); |
|
1179 if (!editor || !editor->hasComposition()) |
|
1180 return false; |
|
1181 |
|
1182 // We should verify the parent node of this IME composition node are |
|
1183 // editable because JavaScript may delete a parent node of the composition |
|
1184 // node. In this case, WebKit crashes while deleting texts from the parent |
|
1185 // node, which doesn't exist any longer. |
|
1186 PassRefPtr<Range> range = editor->compositionRange(); |
|
1187 if (range) { |
|
1188 const Node* node = range->startPosition().node(); |
|
1189 if (!node || !node->isContentEditable()) |
|
1190 return false; |
|
1191 } |
|
1192 |
|
1193 editor->confirmComposition(); |
|
1194 return true; |
|
1195 } |
|
1196 |
|
1197 WebTextInputType WebViewImpl::textInputType() |
|
1198 { |
|
1199 WebTextInputType type = WebTextInputTypeNone; |
|
1200 const Frame* focused = focusedWebCoreFrame(); |
|
1201 if (!focused) |
|
1202 return type; |
|
1203 |
|
1204 const Editor* editor = focused->editor(); |
|
1205 if (!editor || !editor->canEdit()) |
|
1206 return type; |
|
1207 |
|
1208 SelectionController* controller = focused->selection(); |
|
1209 if (!controller) |
|
1210 return type; |
|
1211 |
|
1212 const Node* node = controller->start().node(); |
|
1213 if (!node) |
|
1214 return type; |
|
1215 |
|
1216 // FIXME: Support more text input types when necessary, eg. Number, |
|
1217 // Date, Email, URL, etc. |
|
1218 if (controller->isInPasswordField()) |
|
1219 type = WebTextInputTypePassword; |
|
1220 else if (node->shouldUseInputMethod()) |
|
1221 type = WebTextInputTypeText; |
|
1222 |
|
1223 return type; |
|
1224 } |
|
1225 |
|
1226 WebRect WebViewImpl::caretOrSelectionBounds() |
|
1227 { |
|
1228 WebRect rect; |
|
1229 const Frame* focused = focusedWebCoreFrame(); |
|
1230 if (!focused) |
|
1231 return rect; |
|
1232 |
|
1233 SelectionController* controller = focused->selection(); |
|
1234 if (!controller) |
|
1235 return rect; |
|
1236 |
|
1237 const FrameView* view = focused->view(); |
|
1238 if (!view) |
|
1239 return rect; |
|
1240 |
|
1241 const Node* node = controller->start().node(); |
|
1242 if (!node || !node->renderer()) |
|
1243 return rect; |
|
1244 |
|
1245 if (controller->isCaret()) |
|
1246 rect = view->contentsToWindow(controller->absoluteCaretBounds()); |
|
1247 else if (controller->isRange()) { |
|
1248 node = controller->end().node(); |
|
1249 if (!node || !node->renderer()) |
|
1250 return rect; |
|
1251 RefPtr<Range> range = controller->toNormalizedRange(); |
|
1252 rect = view->contentsToWindow(focused->firstRectForRange(range.get())); |
|
1253 } |
|
1254 return rect; |
|
1255 } |
|
1256 |
|
1257 void WebViewImpl::setTextDirection(WebTextDirection direction) |
|
1258 { |
|
1259 // The Editor::setBaseWritingDirection() function checks if we can change |
|
1260 // the text direction of the selected node and updates its DOM "dir" |
|
1261 // attribute and its CSS "direction" property. |
|
1262 // So, we just call the function as Safari does. |
|
1263 const Frame* focused = focusedWebCoreFrame(); |
|
1264 if (!focused) |
|
1265 return; |
|
1266 |
|
1267 Editor* editor = focused->editor(); |
|
1268 if (!editor || !editor->canEdit()) |
|
1269 return; |
|
1270 |
|
1271 switch (direction) { |
|
1272 case WebTextDirectionDefault: |
|
1273 editor->setBaseWritingDirection(NaturalWritingDirection); |
|
1274 break; |
|
1275 |
|
1276 case WebTextDirectionLeftToRight: |
|
1277 editor->setBaseWritingDirection(LeftToRightWritingDirection); |
|
1278 break; |
|
1279 |
|
1280 case WebTextDirectionRightToLeft: |
|
1281 editor->setBaseWritingDirection(RightToLeftWritingDirection); |
|
1282 break; |
|
1283 |
|
1284 default: |
|
1285 notImplemented(); |
|
1286 break; |
|
1287 } |
|
1288 } |
|
1289 |
|
1290 bool WebViewImpl::isAcceleratedCompositingActive() const |
|
1291 { |
|
1292 #if USE(ACCELERATED_COMPOSITING) |
|
1293 return m_isAcceleratedCompositingActive; |
|
1294 #else |
|
1295 return false; |
|
1296 #endif |
|
1297 } |
|
1298 |
|
1299 // WebView -------------------------------------------------------------------- |
|
1300 |
|
1301 WebSettings* WebViewImpl::settings() |
|
1302 { |
|
1303 if (!m_webSettings.get()) |
|
1304 m_webSettings.set(new WebSettingsImpl(m_page->settings())); |
|
1305 ASSERT(m_webSettings.get()); |
|
1306 return m_webSettings.get(); |
|
1307 } |
|
1308 |
|
1309 WebString WebViewImpl::pageEncoding() const |
|
1310 { |
|
1311 if (!m_page.get()) |
|
1312 return WebString(); |
|
1313 |
|
1314 return m_page->mainFrame()->loader()->writer()->encoding(); |
|
1315 } |
|
1316 |
|
1317 void WebViewImpl::setPageEncoding(const WebString& encodingName) |
|
1318 { |
|
1319 if (!m_page.get()) |
|
1320 return; |
|
1321 |
|
1322 // Only change override encoding, don't change default encoding. |
|
1323 // Note that the new encoding must be 0 if it isn't supposed to be set. |
|
1324 String newEncodingName; |
|
1325 if (!encodingName.isEmpty()) |
|
1326 newEncodingName = encodingName; |
|
1327 m_page->mainFrame()->loader()->reloadWithOverrideEncoding(newEncodingName); |
|
1328 } |
|
1329 |
|
1330 bool WebViewImpl::dispatchBeforeUnloadEvent() |
|
1331 { |
|
1332 // FIXME: This should really cause a recursive depth-first walk of all |
|
1333 // frames in the tree, calling each frame's onbeforeunload. At the moment, |
|
1334 // we're consistent with Safari 3.1, not IE/FF. |
|
1335 Frame* frame = m_page->mainFrame(); |
|
1336 if (!frame) |
|
1337 return true; |
|
1338 |
|
1339 return frame->loader()->shouldClose(); |
|
1340 } |
|
1341 |
|
1342 void WebViewImpl::dispatchUnloadEvent() |
|
1343 { |
|
1344 // Run unload handlers. |
|
1345 m_page->mainFrame()->loader()->closeURL(); |
|
1346 } |
|
1347 |
|
1348 WebFrame* WebViewImpl::mainFrame() |
|
1349 { |
|
1350 return mainFrameImpl(); |
|
1351 } |
|
1352 |
|
1353 WebFrame* WebViewImpl::findFrameByName( |
|
1354 const WebString& name, WebFrame* relativeToFrame) |
|
1355 { |
|
1356 if (!relativeToFrame) |
|
1357 relativeToFrame = mainFrame(); |
|
1358 Frame* frame = static_cast<WebFrameImpl*>(relativeToFrame)->frame(); |
|
1359 frame = frame->tree()->find(name); |
|
1360 return WebFrameImpl::fromFrame(frame); |
|
1361 } |
|
1362 |
|
1363 WebFrame* WebViewImpl::focusedFrame() |
|
1364 { |
|
1365 return WebFrameImpl::fromFrame(focusedWebCoreFrame()); |
|
1366 } |
|
1367 |
|
1368 void WebViewImpl::setFocusedFrame(WebFrame* frame) |
|
1369 { |
|
1370 if (!frame) { |
|
1371 // Clears the focused frame if any. |
|
1372 Frame* frame = focusedWebCoreFrame(); |
|
1373 if (frame) |
|
1374 frame->selection()->setFocused(false); |
|
1375 return; |
|
1376 } |
|
1377 WebFrameImpl* frameImpl = static_cast<WebFrameImpl*>(frame); |
|
1378 Frame* webcoreFrame = frameImpl->frame(); |
|
1379 webcoreFrame->page()->focusController()->setFocusedFrame(webcoreFrame); |
|
1380 } |
|
1381 |
|
1382 void WebViewImpl::setInitialFocus(bool reverse) |
|
1383 { |
|
1384 if (!m_page.get()) |
|
1385 return; |
|
1386 |
|
1387 // Since we don't have a keyboard event, we'll create one. |
|
1388 WebKeyboardEvent keyboardEvent; |
|
1389 keyboardEvent.type = WebInputEvent::RawKeyDown; |
|
1390 if (reverse) |
|
1391 keyboardEvent.modifiers = WebInputEvent::ShiftKey; |
|
1392 |
|
1393 // VK_TAB which is only defined on Windows. |
|
1394 keyboardEvent.windowsKeyCode = 0x09; |
|
1395 PlatformKeyboardEventBuilder platformEvent(keyboardEvent); |
|
1396 RefPtr<KeyboardEvent> webkitEvent = KeyboardEvent::create(platformEvent, 0); |
|
1397 page()->focusController()->setInitialFocus( |
|
1398 reverse ? FocusDirectionBackward : FocusDirectionForward, |
|
1399 webkitEvent.get()); |
|
1400 } |
|
1401 |
|
1402 void WebViewImpl::clearFocusedNode() |
|
1403 { |
|
1404 if (!m_page.get()) |
|
1405 return; |
|
1406 |
|
1407 RefPtr<Frame> frame = m_page->mainFrame(); |
|
1408 if (!frame.get()) |
|
1409 return; |
|
1410 |
|
1411 RefPtr<Document> document = frame->document(); |
|
1412 if (!document.get()) |
|
1413 return; |
|
1414 |
|
1415 RefPtr<Node> oldFocusedNode = document->focusedNode(); |
|
1416 |
|
1417 // Clear the focused node. |
|
1418 document->setFocusedNode(0); |
|
1419 |
|
1420 if (!oldFocusedNode.get()) |
|
1421 return; |
|
1422 |
|
1423 // If a text field has focus, we need to make sure the selection controller |
|
1424 // knows to remove selection from it. Otherwise, the text field is still |
|
1425 // processing keyboard events even though focus has been moved to the page and |
|
1426 // keystrokes get eaten as a result. |
|
1427 if (oldFocusedNode->hasTagName(HTMLNames::textareaTag) |
|
1428 || (oldFocusedNode->hasTagName(HTMLNames::inputTag) |
|
1429 && static_cast<HTMLInputElement*>(oldFocusedNode.get())->isTextField())) { |
|
1430 // Clear the selection. |
|
1431 SelectionController* selection = frame->selection(); |
|
1432 selection->clear(); |
|
1433 } |
|
1434 } |
|
1435 |
|
1436 int WebViewImpl::zoomLevel() |
|
1437 { |
|
1438 return m_zoomLevel; |
|
1439 } |
|
1440 |
|
1441 int WebViewImpl::setZoomLevel(bool textOnly, int zoomLevel) |
|
1442 { |
|
1443 float zoomFactor = static_cast<float>( |
|
1444 std::max(std::min(std::pow(textSizeMultiplierRatio, zoomLevel), |
|
1445 maxTextSizeMultiplier), |
|
1446 minTextSizeMultiplier)); |
|
1447 Frame* frame = mainFrameImpl()->frame(); |
|
1448 FrameView* view = frame->view(); |
|
1449 if (!view) |
|
1450 return m_zoomLevel; |
|
1451 if (zoomFactor != view->zoomFactor()) { |
|
1452 view->setZoomFactor(zoomFactor, textOnly ? ZoomTextOnly : ZoomPage); |
|
1453 WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame); |
|
1454 if (pluginContainer) |
|
1455 pluginContainer->plugin()->setZoomFactor(zoomFactor, textOnly); |
|
1456 m_zoomLevel = zoomLevel; |
|
1457 } |
|
1458 return m_zoomLevel; |
|
1459 } |
|
1460 |
|
1461 void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action, |
|
1462 const WebPoint& location) |
|
1463 { |
|
1464 HitTestResult result = |
|
1465 hitTestResultForWindowPos(location); |
|
1466 RefPtr<Node> node = result.innerNonSharedNode(); |
|
1467 if (!node->hasTagName(HTMLNames::videoTag) && !node->hasTagName(HTMLNames::audioTag)) |
|
1468 return; |
|
1469 |
|
1470 RefPtr<HTMLMediaElement> mediaElement = |
|
1471 static_pointer_cast<HTMLMediaElement>(node); |
|
1472 switch (action.type) { |
|
1473 case WebMediaPlayerAction::Play: |
|
1474 if (action.enable) |
|
1475 mediaElement->play(mediaElement->processingUserGesture()); |
|
1476 else |
|
1477 mediaElement->pause(mediaElement->processingUserGesture()); |
|
1478 break; |
|
1479 case WebMediaPlayerAction::Mute: |
|
1480 mediaElement->setMuted(action.enable); |
|
1481 break; |
|
1482 case WebMediaPlayerAction::Loop: |
|
1483 mediaElement->setLoop(action.enable); |
|
1484 break; |
|
1485 case WebMediaPlayerAction::Controls: |
|
1486 mediaElement->setControls(action.enable); |
|
1487 break; |
|
1488 default: |
|
1489 ASSERT_NOT_REACHED(); |
|
1490 } |
|
1491 } |
|
1492 |
|
1493 void WebViewImpl::copyImageAt(const WebPoint& point) |
|
1494 { |
|
1495 if (!m_page.get()) |
|
1496 return; |
|
1497 |
|
1498 HitTestResult result = hitTestResultForWindowPos(point); |
|
1499 |
|
1500 if (result.absoluteImageURL().isEmpty()) { |
|
1501 // There isn't actually an image at these coordinates. Might be because |
|
1502 // the window scrolled while the context menu was open or because the page |
|
1503 // changed itself between when we thought there was an image here and when |
|
1504 // we actually tried to retreive the image. |
|
1505 // |
|
1506 // FIXME: implement a cache of the most recent HitTestResult to avoid having |
|
1507 // to do two hit tests. |
|
1508 return; |
|
1509 } |
|
1510 |
|
1511 m_page->mainFrame()->editor()->copyImage(result); |
|
1512 } |
|
1513 |
|
1514 void WebViewImpl::dragSourceEndedAt( |
|
1515 const WebPoint& clientPoint, |
|
1516 const WebPoint& screenPoint, |
|
1517 WebDragOperation operation) |
|
1518 { |
|
1519 PlatformMouseEvent pme(clientPoint, |
|
1520 screenPoint, |
|
1521 LeftButton, MouseEventMoved, 0, false, false, false, |
|
1522 false, 0); |
|
1523 m_page->mainFrame()->eventHandler()->dragSourceEndedAt(pme, |
|
1524 static_cast<DragOperation>(operation)); |
|
1525 m_dragScrollTimer->stop(); |
|
1526 } |
|
1527 |
|
1528 void WebViewImpl::dragSourceMovedTo( |
|
1529 const WebPoint& clientPoint, |
|
1530 const WebPoint& screenPoint, |
|
1531 WebDragOperation operation) |
|
1532 { |
|
1533 m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint); |
|
1534 } |
|
1535 |
|
1536 void WebViewImpl::dragSourceSystemDragEnded() |
|
1537 { |
|
1538 // It's possible for us to get this callback while not doing a drag if |
|
1539 // it's from a previous page that got unloaded. |
|
1540 if (m_doingDragAndDrop) { |
|
1541 m_page->dragController()->dragEnded(); |
|
1542 m_doingDragAndDrop = false; |
|
1543 } |
|
1544 } |
|
1545 |
|
1546 WebDragOperation WebViewImpl::dragTargetDragEnter( |
|
1547 const WebDragData& webDragData, int identity, |
|
1548 const WebPoint& clientPoint, |
|
1549 const WebPoint& screenPoint, |
|
1550 WebDragOperationsMask operationsAllowed) |
|
1551 { |
|
1552 ASSERT(!m_currentDragData.get()); |
|
1553 |
|
1554 m_currentDragData = webDragData; |
|
1555 m_dragIdentity = identity; |
|
1556 m_operationsAllowed = operationsAllowed; |
|
1557 |
|
1558 return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragEnter); |
|
1559 } |
|
1560 |
|
1561 WebDragOperation WebViewImpl::dragTargetDragOver( |
|
1562 const WebPoint& clientPoint, |
|
1563 const WebPoint& screenPoint, |
|
1564 WebDragOperationsMask operationsAllowed) |
|
1565 { |
|
1566 m_operationsAllowed = operationsAllowed; |
|
1567 |
|
1568 return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragOver); |
|
1569 } |
|
1570 |
|
1571 void WebViewImpl::dragTargetDragLeave() |
|
1572 { |
|
1573 ASSERT(m_currentDragData.get()); |
|
1574 |
|
1575 DragData dragData( |
|
1576 m_currentDragData.get(), |
|
1577 IntPoint(), |
|
1578 IntPoint(), |
|
1579 static_cast<DragOperation>(m_operationsAllowed)); |
|
1580 |
|
1581 m_dragTargetDispatch = true; |
|
1582 m_page->dragController()->dragExited(&dragData); |
|
1583 m_dragTargetDispatch = false; |
|
1584 |
|
1585 m_currentDragData = 0; |
|
1586 m_dropEffect = DropEffectDefault; |
|
1587 m_dragOperation = WebDragOperationNone; |
|
1588 m_dragIdentity = 0; |
|
1589 } |
|
1590 |
|
1591 void WebViewImpl::dragTargetDrop(const WebPoint& clientPoint, |
|
1592 const WebPoint& screenPoint) |
|
1593 { |
|
1594 ASSERT(m_currentDragData.get()); |
|
1595 |
|
1596 // If this webview transitions from the "drop accepting" state to the "not |
|
1597 // accepting" state, then our IPC message reply indicating that may be in- |
|
1598 // flight, or else delayed by javascript processing in this webview. If a |
|
1599 // drop happens before our IPC reply has reached the browser process, then |
|
1600 // the browser forwards the drop to this webview. So only allow a drop to |
|
1601 // proceed if our webview m_dragOperation state is not DragOperationNone. |
|
1602 |
|
1603 if (m_dragOperation == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop. |
|
1604 dragTargetDragLeave(); |
|
1605 return; |
|
1606 } |
|
1607 |
|
1608 DragData dragData( |
|
1609 m_currentDragData.get(), |
|
1610 clientPoint, |
|
1611 screenPoint, |
|
1612 static_cast<DragOperation>(m_operationsAllowed)); |
|
1613 |
|
1614 m_dragTargetDispatch = true; |
|
1615 m_page->dragController()->performDrag(&dragData); |
|
1616 m_dragTargetDispatch = false; |
|
1617 |
|
1618 m_currentDragData = 0; |
|
1619 m_dropEffect = DropEffectDefault; |
|
1620 m_dragOperation = WebDragOperationNone; |
|
1621 m_dragIdentity = 0; |
|
1622 m_dragScrollTimer->stop(); |
|
1623 } |
|
1624 |
|
1625 int WebViewImpl::dragIdentity() |
|
1626 { |
|
1627 if (m_dragTargetDispatch) |
|
1628 return m_dragIdentity; |
|
1629 return 0; |
|
1630 } |
|
1631 |
|
1632 WebDragOperation WebViewImpl::dragTargetDragEnterOrOver(const WebPoint& clientPoint, const WebPoint& screenPoint, DragAction dragAction) |
|
1633 { |
|
1634 ASSERT(m_currentDragData.get()); |
|
1635 |
|
1636 DragData dragData( |
|
1637 m_currentDragData.get(), |
|
1638 clientPoint, |
|
1639 screenPoint, |
|
1640 static_cast<DragOperation>(m_operationsAllowed)); |
|
1641 |
|
1642 m_dropEffect = DropEffectDefault; |
|
1643 m_dragTargetDispatch = true; |
|
1644 DragOperation effect = dragAction == DragEnter ? m_page->dragController()->dragEntered(&dragData) |
|
1645 : m_page->dragController()->dragUpdated(&dragData); |
|
1646 // Mask the operation against the drag source's allowed operations. |
|
1647 if (!(effect & dragData.draggingSourceOperationMask())) |
|
1648 effect = DragOperationNone; |
|
1649 m_dragTargetDispatch = false; |
|
1650 |
|
1651 if (m_dropEffect != DropEffectDefault) { |
|
1652 m_dragOperation = (m_dropEffect != DropEffectNone) ? WebDragOperationCopy |
|
1653 : WebDragOperationNone; |
|
1654 } else |
|
1655 m_dragOperation = static_cast<WebDragOperation>(effect); |
|
1656 |
|
1657 if (dragAction == DragOver) |
|
1658 m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint); |
|
1659 else |
|
1660 m_dragScrollTimer->stop(); |
|
1661 |
|
1662 |
|
1663 return m_dragOperation; |
|
1664 } |
|
1665 |
|
1666 unsigned long WebViewImpl::createUniqueIdentifierForRequest() |
|
1667 { |
|
1668 if (m_page) |
|
1669 return m_page->progress()->createUniqueIdentifier(); |
|
1670 return 0; |
|
1671 } |
|
1672 |
|
1673 void WebViewImpl::inspectElementAt(const WebPoint& point) |
|
1674 { |
|
1675 if (!m_page.get()) |
|
1676 return; |
|
1677 |
|
1678 if (point.x == -1 || point.y == -1) |
|
1679 m_page->inspectorController()->inspect(0); |
|
1680 else { |
|
1681 HitTestResult result = hitTestResultForWindowPos(point); |
|
1682 |
|
1683 if (!result.innerNonSharedNode()) |
|
1684 return; |
|
1685 |
|
1686 m_page->inspectorController()->inspect(result.innerNonSharedNode()); |
|
1687 } |
|
1688 } |
|
1689 |
|
1690 WebString WebViewImpl::inspectorSettings() const |
|
1691 { |
|
1692 return m_inspectorSettings; |
|
1693 } |
|
1694 |
|
1695 void WebViewImpl::setInspectorSettings(const WebString& settings) |
|
1696 { |
|
1697 m_inspectorSettings = settings; |
|
1698 } |
|
1699 |
|
1700 bool WebViewImpl::inspectorSetting(const WebString& key, WebString* value) const |
|
1701 { |
|
1702 if (!m_inspectorSettingsMap->contains(key)) |
|
1703 return false; |
|
1704 *value = m_inspectorSettingsMap->get(key); |
|
1705 return true; |
|
1706 } |
|
1707 |
|
1708 void WebViewImpl::setInspectorSetting(const WebString& key, |
|
1709 const WebString& value) |
|
1710 { |
|
1711 m_inspectorSettingsMap->set(key, value); |
|
1712 client()->didUpdateInspectorSetting(key, value); |
|
1713 } |
|
1714 |
|
1715 WebDevToolsAgent* WebViewImpl::devToolsAgent() |
|
1716 { |
|
1717 return m_devToolsAgent.get(); |
|
1718 } |
|
1719 |
|
1720 WebAccessibilityObject WebViewImpl::accessibilityObject() |
|
1721 { |
|
1722 if (!mainFrameImpl()) |
|
1723 return WebAccessibilityObject(); |
|
1724 |
|
1725 Document* document = mainFrameImpl()->frame()->document(); |
|
1726 return WebAccessibilityObject( |
|
1727 document->axObjectCache()->getOrCreate(document->renderer())); |
|
1728 } |
|
1729 |
|
1730 void WebViewImpl::applyAutoFillSuggestions( |
|
1731 const WebNode& node, |
|
1732 const WebVector<WebString>& names, |
|
1733 const WebVector<WebString>& labels, |
|
1734 int separatorIndex) |
|
1735 { |
|
1736 WebVector<int> uniqueIDs(names.size()); |
|
1737 applyAutoFillSuggestions(node, names, labels, uniqueIDs, separatorIndex); |
|
1738 } |
|
1739 |
|
1740 void WebViewImpl::applyAutoFillSuggestions( |
|
1741 const WebNode& node, |
|
1742 const WebVector<WebString>& names, |
|
1743 const WebVector<WebString>& labels, |
|
1744 const WebVector<int>& uniqueIDs, |
|
1745 int separatorIndex) |
|
1746 { |
|
1747 ASSERT(names.size() == labels.size()); |
|
1748 ASSERT(names.size() == uniqueIDs.size()); |
|
1749 ASSERT(separatorIndex < static_cast<int>(names.size())); |
|
1750 |
|
1751 if (names.isEmpty()) { |
|
1752 hideAutoFillPopup(); |
|
1753 return; |
|
1754 } |
|
1755 |
|
1756 RefPtr<Node> focusedNode = focusedWebCoreNode(); |
|
1757 // If the node for which we queried the AutoFill suggestions is not the |
|
1758 // focused node, then we have nothing to do. FIXME: also check the |
|
1759 // caret is at the end and that the text has not changed. |
|
1760 if (!focusedNode || focusedNode != PassRefPtr<Node>(node)) { |
|
1761 hideAutoFillPopup(); |
|
1762 return; |
|
1763 } |
|
1764 |
|
1765 HTMLInputElement* inputElem = |
|
1766 static_cast<HTMLInputElement*>(focusedNode.get()); |
|
1767 |
|
1768 // The first time the AutoFill popup is shown we'll create the client and |
|
1769 // the popup. |
|
1770 if (!m_autoFillPopupClient.get()) |
|
1771 m_autoFillPopupClient.set(new AutoFillPopupMenuClient); |
|
1772 |
|
1773 m_autoFillPopupClient->initialize( |
|
1774 inputElem, names, labels, uniqueIDs, separatorIndex); |
|
1775 |
|
1776 if (!m_autoFillPopup.get()) { |
|
1777 m_autoFillPopup = PopupContainer::create(m_autoFillPopupClient.get(), |
|
1778 PopupContainer::Suggestion, |
|
1779 autoFillPopupSettings); |
|
1780 } |
|
1781 |
|
1782 if (m_autoFillPopupShowing) { |
|
1783 m_autoFillPopupClient->setSuggestions( |
|
1784 names, labels, uniqueIDs, separatorIndex); |
|
1785 refreshAutoFillPopup(); |
|
1786 } else { |
|
1787 m_autoFillPopup->show(focusedNode->getRect(), |
|
1788 focusedNode->ownerDocument()->view(), 0); |
|
1789 m_autoFillPopupShowing = true; |
|
1790 } |
|
1791 |
|
1792 // DEPRECATED: This special mode will go away once AutoFill and Autocomplete |
|
1793 // merge is complete. |
|
1794 if (m_autoFillPopupClient) |
|
1795 m_autoFillPopupClient->setAutocompleteMode(false); |
|
1796 } |
|
1797 |
|
1798 // DEPRECATED: replacing with applyAutoFillSuggestions. |
|
1799 void WebViewImpl::applyAutocompleteSuggestions( |
|
1800 const WebNode& node, |
|
1801 const WebVector<WebString>& suggestions, |
|
1802 int defaultSuggestionIndex) |
|
1803 { |
|
1804 WebVector<WebString> names(suggestions.size()); |
|
1805 WebVector<WebString> labels(suggestions.size()); |
|
1806 WebVector<int> uniqueIDs(suggestions.size()); |
|
1807 |
|
1808 for (size_t i = 0; i < suggestions.size(); ++i) |
|
1809 names[i] = suggestions[i]; |
|
1810 |
|
1811 applyAutoFillSuggestions(node, names, labels, uniqueIDs, -1); |
|
1812 if (m_autoFillPopupClient) |
|
1813 m_autoFillPopupClient->setAutocompleteMode(true); |
|
1814 } |
|
1815 |
|
1816 void WebViewImpl::hidePopups() |
|
1817 { |
|
1818 hideSelectPopup(); |
|
1819 hideAutoFillPopup(); |
|
1820 } |
|
1821 |
|
1822 void WebViewImpl::performCustomContextMenuAction(unsigned action) |
|
1823 { |
|
1824 if (!m_page) |
|
1825 return; |
|
1826 ContextMenu* menu = m_page->contextMenuController()->contextMenu(); |
|
1827 if (!menu) |
|
1828 return; |
|
1829 ContextMenuItem* item = menu->itemWithAction(static_cast<ContextMenuAction>(ContextMenuItemBaseCustomTag + action)); |
|
1830 if (item) |
|
1831 m_page->contextMenuController()->contextMenuItemSelected(item); |
|
1832 m_page->contextMenuController()->clearContextMenu(); |
|
1833 } |
|
1834 |
|
1835 // WebView -------------------------------------------------------------------- |
|
1836 |
|
1837 bool WebViewImpl::setDropEffect(bool accept) |
|
1838 { |
|
1839 if (m_dragTargetDispatch) { |
|
1840 m_dropEffect = accept ? DropEffectCopy : DropEffectNone; |
|
1841 return true; |
|
1842 } |
|
1843 return false; |
|
1844 } |
|
1845 |
|
1846 void WebViewImpl::setIsTransparent(bool isTransparent) |
|
1847 { |
|
1848 // Set any existing frames to be transparent. |
|
1849 Frame* frame = m_page->mainFrame(); |
|
1850 while (frame) { |
|
1851 frame->view()->setTransparent(isTransparent); |
|
1852 frame = frame->tree()->traverseNext(); |
|
1853 } |
|
1854 |
|
1855 // Future frames check this to know whether to be transparent. |
|
1856 m_isTransparent = isTransparent; |
|
1857 } |
|
1858 |
|
1859 bool WebViewImpl::isTransparent() const |
|
1860 { |
|
1861 return m_isTransparent; |
|
1862 } |
|
1863 |
|
1864 void WebViewImpl::setIsActive(bool active) |
|
1865 { |
|
1866 if (page() && page()->focusController()) |
|
1867 page()->focusController()->setActive(active); |
|
1868 } |
|
1869 |
|
1870 bool WebViewImpl::isActive() const |
|
1871 { |
|
1872 return (page() && page()->focusController()) ? page()->focusController()->isActive() : false; |
|
1873 } |
|
1874 |
|
1875 void WebViewImpl::setScrollbarColors(unsigned inactiveColor, |
|
1876 unsigned activeColor, |
|
1877 unsigned trackColor) { |
|
1878 #if OS(LINUX) |
|
1879 PlatformThemeChromiumGtk::setScrollbarColors(inactiveColor, |
|
1880 activeColor, |
|
1881 trackColor); |
|
1882 #endif |
|
1883 } |
|
1884 |
|
1885 void WebViewImpl::setSelectionColors(unsigned activeBackgroundColor, |
|
1886 unsigned activeForegroundColor, |
|
1887 unsigned inactiveBackgroundColor, |
|
1888 unsigned inactiveForegroundColor) { |
|
1889 #if OS(LINUX) |
|
1890 RenderThemeChromiumLinux::setSelectionColors(activeBackgroundColor, |
|
1891 activeForegroundColor, |
|
1892 inactiveBackgroundColor, |
|
1893 inactiveForegroundColor); |
|
1894 theme()->platformColorsDidChange(); |
|
1895 #endif |
|
1896 } |
|
1897 |
|
1898 void WebView::addUserScript(const WebString& sourceCode, |
|
1899 const WebVector<WebString>& patternsIn, |
|
1900 WebView::UserScriptInjectAt injectAt, |
|
1901 WebView::UserContentInjectIn injectIn) |
|
1902 { |
|
1903 OwnPtr<Vector<String> > patterns(new Vector<String>); |
|
1904 for (size_t i = 0; i < patternsIn.size(); ++i) |
|
1905 patterns->append(patternsIn[i]); |
|
1906 |
|
1907 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName); |
|
1908 RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create()); |
|
1909 pageGroup->addUserScriptToWorld(world.get(), sourceCode, WebURL(), patterns.release(), 0, |
|
1910 static_cast<UserScriptInjectionTime>(injectAt), |
|
1911 static_cast<UserContentInjectedFrames>(injectIn)); |
|
1912 } |
|
1913 |
|
1914 void WebView::addUserStyleSheet(const WebString& sourceCode, |
|
1915 const WebVector<WebString>& patternsIn, |
|
1916 WebView::UserContentInjectIn injectIn) |
|
1917 { |
|
1918 OwnPtr<Vector<String> > patterns(new Vector<String>); |
|
1919 for (size_t i = 0; i < patternsIn.size(); ++i) |
|
1920 patterns->append(patternsIn[i]); |
|
1921 |
|
1922 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName); |
|
1923 RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create()); |
|
1924 pageGroup->addUserStyleSheetToWorld(world.get(), sourceCode, WebURL(), patterns.release(), 0, |
|
1925 static_cast<UserContentInjectedFrames>(injectIn)); |
|
1926 } |
|
1927 |
|
1928 void WebView::removeAllUserContent() |
|
1929 { |
|
1930 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName); |
|
1931 pageGroup->removeAllUserContent(); |
|
1932 } |
|
1933 |
|
1934 void WebViewImpl::didCommitLoad(bool* isNewNavigation) |
|
1935 { |
|
1936 if (isNewNavigation) |
|
1937 *isNewNavigation = m_observedNewNavigation; |
|
1938 |
|
1939 #ifndef NDEBUG |
|
1940 ASSERT(!m_observedNewNavigation |
|
1941 || m_page->mainFrame()->loader()->documentLoader() == m_newNavigationLoader); |
|
1942 m_newNavigationLoader = 0; |
|
1943 #endif |
|
1944 m_observedNewNavigation = false; |
|
1945 } |
|
1946 |
|
1947 bool WebViewImpl::navigationPolicyFromMouseEvent(unsigned short button, |
|
1948 bool ctrl, bool shift, |
|
1949 bool alt, bool meta, |
|
1950 WebNavigationPolicy* policy) |
|
1951 { |
|
1952 #if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD) || OS(SOLARIS) |
|
1953 const bool newTabModifier = (button == 1) || ctrl; |
|
1954 #elif OS(DARWIN) |
|
1955 const bool newTabModifier = (button == 1) || meta; |
|
1956 #endif |
|
1957 if (!newTabModifier && !shift && !alt) |
|
1958 return false; |
|
1959 |
|
1960 ASSERT(policy); |
|
1961 if (newTabModifier) { |
|
1962 if (shift) |
|
1963 *policy = WebNavigationPolicyNewForegroundTab; |
|
1964 else |
|
1965 *policy = WebNavigationPolicyNewBackgroundTab; |
|
1966 } else { |
|
1967 if (shift) |
|
1968 *policy = WebNavigationPolicyNewWindow; |
|
1969 else |
|
1970 *policy = WebNavigationPolicyDownload; |
|
1971 } |
|
1972 return true; |
|
1973 } |
|
1974 |
|
1975 void WebViewImpl::startDragging(const WebDragData& dragData, |
|
1976 WebDragOperationsMask mask, |
|
1977 const WebImage& dragImage, |
|
1978 const WebPoint& dragImageOffset) |
|
1979 { |
|
1980 if (!m_client) |
|
1981 return; |
|
1982 ASSERT(!m_doingDragAndDrop); |
|
1983 m_doingDragAndDrop = true; |
|
1984 m_client->startDragging(dragData, mask, dragImage, dragImageOffset); |
|
1985 } |
|
1986 |
|
1987 void WebViewImpl::setCurrentHistoryItem(HistoryItem* item) |
|
1988 { |
|
1989 m_backForwardListClientImpl.setCurrentHistoryItem(item); |
|
1990 } |
|
1991 |
|
1992 HistoryItem* WebViewImpl::previousHistoryItem() |
|
1993 { |
|
1994 return m_backForwardListClientImpl.previousHistoryItem(); |
|
1995 } |
|
1996 |
|
1997 void WebViewImpl::observeNewNavigation() |
|
1998 { |
|
1999 m_observedNewNavigation = true; |
|
2000 #ifndef NDEBUG |
|
2001 m_newNavigationLoader = m_page->mainFrame()->loader()->documentLoader(); |
|
2002 #endif |
|
2003 } |
|
2004 |
|
2005 void WebViewImpl::setIgnoreInputEvents(bool newValue) |
|
2006 { |
|
2007 ASSERT(m_ignoreInputEvents != newValue); |
|
2008 m_ignoreInputEvents = newValue; |
|
2009 } |
|
2010 |
|
2011 #if ENABLE(NOTIFICATIONS) |
|
2012 NotificationPresenterImpl* WebViewImpl::notificationPresenterImpl() |
|
2013 { |
|
2014 if (!m_notificationPresenter.isInitialized() && m_client) |
|
2015 m_notificationPresenter.initialize(m_client->notificationPresenter()); |
|
2016 return &m_notificationPresenter; |
|
2017 } |
|
2018 #endif |
|
2019 |
|
2020 void WebViewImpl::refreshAutoFillPopup() |
|
2021 { |
|
2022 ASSERT(m_autoFillPopupShowing); |
|
2023 |
|
2024 // Hide the popup if it has become empty. |
|
2025 if (!m_autoFillPopupClient->listSize()) { |
|
2026 hideAutoFillPopup(); |
|
2027 return; |
|
2028 } |
|
2029 |
|
2030 IntRect oldBounds = m_autoFillPopup->boundsRect(); |
|
2031 m_autoFillPopup->refresh(); |
|
2032 IntRect newBounds = m_autoFillPopup->boundsRect(); |
|
2033 // Let's resize the backing window if necessary. |
|
2034 if (oldBounds != newBounds) { |
|
2035 WebPopupMenuImpl* popupMenu = |
|
2036 static_cast<WebPopupMenuImpl*>(m_autoFillPopup->client()); |
|
2037 if (popupMenu) |
|
2038 popupMenu->client()->setWindowRect(newBounds); |
|
2039 } |
|
2040 } |
|
2041 |
|
2042 Node* WebViewImpl::focusedWebCoreNode() |
|
2043 { |
|
2044 Frame* frame = m_page->focusController()->focusedFrame(); |
|
2045 if (!frame) |
|
2046 return 0; |
|
2047 |
|
2048 Document* document = frame->document(); |
|
2049 if (!document) |
|
2050 return 0; |
|
2051 |
|
2052 return document->focusedNode(); |
|
2053 } |
|
2054 |
|
2055 HitTestResult WebViewImpl::hitTestResultForWindowPos(const IntPoint& pos) |
|
2056 { |
|
2057 IntPoint docPoint(m_page->mainFrame()->view()->windowToContents(pos)); |
|
2058 return m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(docPoint, false); |
|
2059 } |
|
2060 |
|
2061 void WebViewImpl::setTabsToLinks(bool enable) |
|
2062 { |
|
2063 m_tabsToLinks = enable; |
|
2064 } |
|
2065 |
|
2066 bool WebViewImpl::tabsToLinks() const |
|
2067 { |
|
2068 return m_tabsToLinks; |
|
2069 } |
|
2070 |
|
2071 #if USE(ACCELERATED_COMPOSITING) |
|
2072 void WebViewImpl::setRootGraphicsLayer(WebCore::PlatformLayer* layer) |
|
2073 { |
|
2074 setIsAcceleratedCompositingActive(layer ? true : false); |
|
2075 if (m_layerRenderer) |
|
2076 m_layerRenderer->setRootLayer(layer); |
|
2077 } |
|
2078 |
|
2079 void WebViewImpl::setIsAcceleratedCompositingActive(bool active) |
|
2080 { |
|
2081 if (m_isAcceleratedCompositingActive == active) |
|
2082 return; |
|
2083 |
|
2084 if (active) { |
|
2085 m_layerRenderer = LayerRendererChromium::create(getOnscreenGLES2Context()); |
|
2086 if (m_layerRenderer->hardwareCompositing()) |
|
2087 m_isAcceleratedCompositingActive = true; |
|
2088 else { |
|
2089 m_layerRenderer.clear(); |
|
2090 m_isAcceleratedCompositingActive = false; |
|
2091 } |
|
2092 } else { |
|
2093 m_layerRenderer = 0; |
|
2094 m_isAcceleratedCompositingActive = false; |
|
2095 } |
|
2096 } |
|
2097 |
|
2098 void WebViewImpl::updateRootLayerContents(const WebRect& rect) |
|
2099 { |
|
2100 if (!isAcceleratedCompositingActive()) |
|
2101 return; |
|
2102 |
|
2103 // FIXME: The accelerated compositing path invalidates a 1x1 rect at (0, 0) |
|
2104 // in order to get the renderer to ask the compositor to redraw. This is only |
|
2105 // temporary until we get the compositor to render directly from its own thread. |
|
2106 if (!rect.x && !rect.y && rect.width == 1 && rect.height == 1) |
|
2107 return; |
|
2108 |
|
2109 WebFrameImpl* webframe = mainFrameImpl(); |
|
2110 if (!webframe) |
|
2111 return; |
|
2112 FrameView* view = webframe->frameView(); |
|
2113 if (!view) |
|
2114 return; |
|
2115 |
|
2116 LayerChromium* rootLayer = m_layerRenderer->rootLayer(); |
|
2117 if (rootLayer) { |
|
2118 IntRect visibleRect = view->visibleContentRect(true); |
|
2119 |
|
2120 m_layerRenderer->setRootLayerCanvasSize(IntSize(rect.width, rect.height)); |
|
2121 GraphicsContext* rootLayerContext = m_layerRenderer->rootLayerGraphicsContext(); |
|
2122 |
|
2123 #if PLATFORM(SKIA) |
|
2124 PlatformContextSkia* skiaContext = rootLayerContext->platformContext(); |
|
2125 skia::PlatformCanvas* platformCanvas = skiaContext->canvas(); |
|
2126 |
|
2127 platformCanvas->save(); |
|
2128 |
|
2129 // Bring the canvas into the coordinate system of the paint rect. |
|
2130 platformCanvas->translate(static_cast<SkScalar>(-rect.x), static_cast<SkScalar>(-rect.y)); |
|
2131 |
|
2132 rootLayerContext->save(); |
|
2133 |
|
2134 webframe->paintWithContext(*rootLayerContext, rect); |
|
2135 rootLayerContext->restore(); |
|
2136 |
|
2137 platformCanvas->restore(); |
|
2138 #endif |
|
2139 } |
|
2140 } |
|
2141 |
|
2142 void WebViewImpl::setRootLayerNeedsDisplay() |
|
2143 { |
|
2144 // FIXME: For now we're posting a repaint event for the entire page which is an overkill. |
|
2145 if (WebFrameImpl* webframe = mainFrameImpl()) { |
|
2146 if (FrameView* view = webframe->frameView()) { |
|
2147 // FIXME: Temporary hack to invalidate part of the page so that we get called to render |
|
2148 // again. |
|
2149 IntRect visibleRect = view->visibleContentRect(true); |
|
2150 m_client->didInvalidateRect(IntRect(0, 0, 1, 1)); |
|
2151 } |
|
2152 } |
|
2153 |
|
2154 if (m_layerRenderer) |
|
2155 m_layerRenderer->setNeedsDisplay(); |
|
2156 } |
|
2157 #endif // USE(ACCELERATED_COMPOSITING) |
|
2158 |
|
2159 PassOwnPtr<GLES2Context> WebViewImpl::getOnscreenGLES2Context() |
|
2160 { |
|
2161 return GLES2Context::create(GLES2ContextInternal::create(gles2Context(), false)); |
|
2162 } |
|
2163 |
|
2164 PassOwnPtr<GLES2Context> WebViewImpl::getOffscreenGLES2Context() |
|
2165 { |
|
2166 WebGLES2Context* context = webKitClient()->createGLES2Context(); |
|
2167 if (!context) |
|
2168 return 0; |
|
2169 if (!context->initialize(0, gles2Context())) |
|
2170 return 0; |
|
2171 return GLES2Context::create(GLES2ContextInternal::create(context, true)); |
|
2172 } |
|
2173 |
|
2174 // Returns the GLES2 context associated with this View. If one doesn't exist |
|
2175 // it will get created first. |
|
2176 WebGLES2Context* WebViewImpl::gles2Context() |
|
2177 { |
|
2178 if (!m_gles2Context) { |
|
2179 m_gles2Context = webKitClient()->createGLES2Context(); |
|
2180 if (!m_gles2Context) |
|
2181 return 0; |
|
2182 |
|
2183 if (!m_gles2Context->initialize(this, 0)) { |
|
2184 m_gles2Context.clear(); |
|
2185 return 0; |
|
2186 } |
|
2187 } |
|
2188 return m_gles2Context.get(); |
|
2189 } |
|
2190 |
|
2191 } // namespace WebKit |