diff options
Diffstat (limited to 'WebKit/win/WebView.cpp')
| -rw-r--r-- | WebKit/win/WebView.cpp | 828 |
1 files changed, 685 insertions, 143 deletions
diff --git a/WebKit/win/WebView.cpp b/WebKit/win/WebView.cpp index b51af67..d98d390 100644 --- a/WebKit/win/WebView.cpp +++ b/WebKit/win/WebView.cpp @@ -31,17 +31,17 @@ #include "DOMCoreClasses.h" #include "MarshallingHelpers.h" #include "SoftLinking.h" +#include "WebBackForwardList.h" +#include "WebChromeClient.h" +#include "WebContextMenuClient.h" +#include "WebCoreTextRenderer.h" #include "WebDatabaseManager.h" #include "WebDocumentLoader.h" #include "WebDownload.h" +#include "WebDragClient.h" #include "WebEditorClient.h" #include "WebElementPropertyBag.h" #include "WebFrame.h" -#include "WebBackForwardList.h" -#include "WebChromeClient.h" -#include "WebContextMenuClient.h" -#include "WebCoreTextRenderer.h" -#include "WebDragClient.h" #include "WebIconDatabase.h" #include "WebInspector.h" #include "WebInspectorClient.h" @@ -50,7 +50,9 @@ #include "WebKitSystemBits.h" #include "WebMutableURLRequest.h" #include "WebNotificationCenter.h" +#include "WebPluginHalterClient.h" #include "WebPreferences.h" +#include "WebScriptWorld.h" #include "WindowsTouch.h" #pragma warning( push, 0 ) #include <WebCore/ApplicationCacheStorage.h> @@ -88,15 +90,18 @@ #include <WebCore/MIMETypeRegistry.h> #include <WebCore/Page.h> #include <WebCore/PageCache.h> +#include <WebCore/PageGroup.h> #include <WebCore/PlatformKeyboardEvent.h> #include <WebCore/PlatformMouseEvent.h> #include <WebCore/PlatformWheelEvent.h> #include <WebCore/PluginDatabase.h> #include <WebCore/PluginInfoStore.h> #include <WebCore/PluginView.h> +#include <WebCore/PopupMenu.h> #include <WebCore/ProgressTracker.h> #include <WebCore/RenderTheme.h> #include <WebCore/RenderView.h> +#include <WebCore/RenderWidget.h> #include <WebCore/ResourceHandle.h> #include <WebCore/ResourceHandleClient.h> #include <WebCore/ScriptValue.h> @@ -128,6 +133,7 @@ #endif #include <wtf/HashSet.h> +#include <comutil.h> #include <dimm.h> #include <oleacc.h> #include <ShlObj.h> @@ -145,9 +151,8 @@ SOFT_LINK_OPTIONAL(Uxtheme, EndPanningFeedback, BOOL, WINAPI, (HWND, BOOL)); SOFT_LINK_OPTIONAL(Uxtheme, UpdatePanningFeedback, BOOL, WINAPI, (HWND, LONG, LONG, BOOL)); using namespace WebCore; +using namespace std; using JSC::JSLock; -using std::min; -using std::max; static HMODULE accessibilityLib; static HashSet<WebView*> pendingDeleteBackingStoreSet; @@ -266,7 +271,6 @@ static const int maxToolTipWidth = 250; static const int delayBeforeDeletingBackingStoreMsec = 5000; static ATOM registerWebView(); -static LRESULT CALLBACK WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); static void initializeStaticObservers(); @@ -290,34 +294,37 @@ enum { bool WebView::s_allowSiteSpecificHacks = false; WebView::WebView() -: m_refCount(0) -, m_hostWindow(0) -, m_viewWindow(0) -, m_mainFrame(0) -, m_page(0) -, m_hasCustomDropTarget(false) -, m_useBackForwardList(true) -, m_userAgentOverridden(false) -, m_zoomMultiplier(1.0f) -, m_mouseActivated(false) -, m_dragData(0) -, m_currentCharacterCode(0) -, m_isBeingDestroyed(false) -, m_paintCount(0) -, m_hasSpellCheckerDocumentTag(false) -, m_smartInsertDeleteEnabled(false) -, m_didClose(false) -, m_inIMEComposition(0) -, m_toolTipHwnd(0) -, m_closeWindowTimer(this, &WebView::closeWindowTimerFired) -, m_topLevelParent(0) -, m_deleteBackingStoreTimerActive(false) -, m_transparent(false) -, m_selectTrailingWhitespaceEnabled(false) -, m_lastPanX(0) -, m_lastPanY(0) -, m_xOverpan(0) -, m_yOverpan(0) + : m_refCount(0) + , m_hostWindow(0) + , m_viewWindow(0) + , m_mainFrame(0) + , m_page(0) + , m_hasCustomDropTarget(false) + , m_useBackForwardList(true) + , m_userAgentOverridden(false) + , m_zoomMultiplier(1.0f) + , m_mouseActivated(false) + , m_dragData(0) + , m_currentCharacterCode(0) + , m_isBeingDestroyed(false) + , m_paintCount(0) + , m_hasSpellCheckerDocumentTag(false) + , m_smartInsertDeleteEnabled(false) + , m_didClose(false) + , m_inIMEComposition(0) + , m_toolTipHwnd(0) + , m_closeWindowTimer(this, &WebView::closeWindowTimerFired) + , m_topLevelParent(0) + , m_deleteBackingStoreTimerActive(false) + , m_transparent(false) + , m_selectTrailingWhitespaceEnabled(false) + , m_lastPanX(0) + , m_lastPanY(0) + , m_xOverpan(0) + , m_yOverpan(0) +#if USE(ACCELERATED_COMPOSITING) + , m_isAcceleratedCompositing(false) +#endif { JSC::initializeThreading(); @@ -613,6 +620,12 @@ HRESULT STDMETHODCALLTYPE WebView::close() m_didClose = true; +#if USE(ACCELERATED_COMPOSITING) + setAcceleratedCompositing(false); +#endif + + WebNotificationCenter::defaultCenterInternal()->postNotificationName(_bstr_t(WebViewWillCloseNotification).GetBSTR(), static_cast<IWebView*>(this), 0); + if (m_uiDelegatePrivate) m_uiDelegatePrivate->webViewClosing(this); @@ -634,10 +647,12 @@ HRESULT STDMETHODCALLTYPE WebView::close() setEditingDelegate(0); setFrameLoadDelegate(0); setFrameLoadDelegatePrivate(0); + setHistoryDelegate(0); setPolicyDelegate(0); setResourceLoadDelegate(0); setUIDelegate(0); setFormDelegate(0); + setPluginHalterDelegate(0); if (m_webInspector) m_webInspector->webViewClosed(); @@ -668,6 +683,11 @@ HRESULT STDMETHODCALLTYPE WebView::close() void WebView::repaint(const WebCore::IntRect& windowRect, bool contentChanged, bool immediate, bool repaintContentOnly) { +#if USE(ACCELERATED_COMPOSITING) + if (isAcceleratedCompositing()) + setRootLayerNeedsDisplay(); +#endif + if (!repaintContentOnly) { RECT rect = windowRect; ::InvalidateRect(m_viewWindow, &rect, false); @@ -719,6 +739,10 @@ bool WebView::ensureBackingStore() void WebView::addToDirtyRegion(const IntRect& dirtyRect) { + // FIXME: We want an assert here saying that the dirtyRect is inside the clienRect, + // but it was being hit during our layout tests, and is being investigated in + // http://webkit.org/b/29350. + HRGN newRegion = ::CreateRectRgn(dirtyRect.x(), dirtyRect.y(), dirtyRect.right(), dirtyRect.bottom()); addToDirtyRegion(newRegion); @@ -782,7 +806,6 @@ void WebView::scrollBackingStore(FrameView* frameView, int dx, int dy, const Int // Clean up. ::DeleteDC(bitmapDC); ::ReleaseDC(m_viewWindow, windowDC); - } // This emulates the Mac smarts for painting rects intelligently. This is very @@ -915,34 +938,28 @@ void WebView::paint(HDC dc, LPARAM options) // Update our backing store if needed. updateBackingStore(frameView, bitmapDC, backingStoreCompletelyDirty, windowsToPaint); - // Now we blit the updated backing store - IntRect windowDirtyRect = rcPaint; - - // Apply the same heuristic for this update region too. - Vector<IntRect> blitRects; - if (region && regionType == COMPLEXREGION) - getUpdateRects(region.get(), windowDirtyRect, blitRects); - else - blitRects.append(windowDirtyRect); +#if USE(ACCELERATED_COMPOSITING) + if (!isAcceleratedCompositing()) { +#endif + // Now we blit the updated backing store + IntRect windowDirtyRect = rcPaint; + + // Apply the same heuristic for this update region too. + Vector<IntRect> blitRects; + if (region && regionType == COMPLEXREGION) + getUpdateRects(region.get(), windowDirtyRect, blitRects); + else + blitRects.append(windowDirtyRect); - for (unsigned i = 0; i < blitRects.size(); ++i) - paintIntoWindow(bitmapDC, hdc, blitRects[i]); + for (unsigned i = 0; i < blitRects.size(); ++i) + paintIntoWindow(bitmapDC, hdc, blitRects[i]); +#if USE(ACCELERATED_COMPOSITING) + } else + updateRootLayerContents(); +#endif ::DeleteDC(bitmapDC); - // Paint the gripper. - COMPtr<IWebUIDelegate> ui; - if (SUCCEEDED(uiDelegate(&ui))) { - COMPtr<IWebUIDelegatePrivate> uiPrivate; - if (SUCCEEDED(ui->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate))) { - RECT r; - if (SUCCEEDED(uiPrivate->webViewResizerRect(this, &r))) { - LOCAL_GDI_COUNTER(2, __FUNCTION__" webViewDrawResizer delegate call"); - uiPrivate->webViewDrawResizer(this, hdc, (frameView->containsScrollbarsAvoidingResizer() ? true : false), &r); - } - } - } - if (!dc) EndPaint(m_viewWindow, &ps); @@ -958,6 +975,10 @@ void WebView::paintIntoBackingStore(FrameView* frameView, HDC bitmapDC, const In { LOCAL_GDI_COUNTER(0, __FUNCTION__); + // FIXME: We want an assert here saying that the dirtyRect is inside the clienRect, + // but it was being hit during our layout tests, and is being investigated in + // http://webkit.org/b/29350. + RECT rect = dirtyRect; #if FLASH_BACKING_STORE_REDRAW @@ -977,6 +998,11 @@ void WebView::paintIntoBackingStore(FrameView* frameView, HDC bitmapDC, const In gc.clearRect(dirtyRect); else FillRect(bitmapDC, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH)); + + COMPtr<IWebUIDelegatePrivate2> uiPrivate(Query, m_uiDelegate); + if (uiPrivate) + uiPrivate->drawBackground(this, reinterpret_cast<OLE_HANDLE>(bitmapDC), &rect); + if (frameView && frameView->frame() && frameView->frame()->contentRenderer()) { gc.clip(dirtyRect); frameView->paint(&gc, dirtyRect); @@ -1270,12 +1296,6 @@ bool WebView::handleMouseEvent(UINT message, WPARAM wParam, LPARAM lParam) abs(globalPrevPoint.y() - mouseEvent.pos().y()) < ::GetSystemMetrics(SM_CYDOUBLECLK); LONG messageTime = ::GetMessageTime(); - if (inResizer(position)) { - if (m_uiDelegatePrivate) - m_uiDelegatePrivate->webViewSendResizeMessage(message, wParam, position); - return true; - } - bool handled = false; if (message == WM_LBUTTONDOWN || message == WM_MBUTTONDOWN || message == WM_RBUTTONDOWN) { @@ -1349,25 +1369,65 @@ bool WebView::gestureNotify(WPARAM wParam, LPARAM lParam) // If we don't have this function, we shouldn't be receiving this message ASSERT(SetGestureConfigPtr()); - DWORD dwPanWant; - DWORD dwPanBlock; - - // Translate gesture location to client to hit test on scrollbars + bool hitScrollbar = false; POINT gestureBeginPoint = {gn->ptsLocation.x, gn->ptsLocation.y}; - IntPoint eventHandlerPoint = m_page->mainFrame()->view()->screenToContents(gestureBeginPoint); + HitTestRequest request(HitTestRequest::ReadOnly); + for (Frame* childFrame = m_page->mainFrame(); childFrame; childFrame = EventHandler::subframeForTargetNode(m_gestureTargetNode.get())) { + FrameView* frameView = childFrame->view(); + if (!frameView) + break; + RenderView* renderView = childFrame->document()->renderView(); + if (!renderView) + break; + RenderLayer* layer = renderView->layer(); + if (!layer) + break; + + HitTestResult result(frameView->screenToContents(gestureBeginPoint)); + layer->hitTest(request, result); + m_gestureTargetNode = result.innerNode(); - HitTestResult scrollbarTest = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(eventHandlerPoint, true, false, ShouldHitTestScrollbars); + if (!hitScrollbar) + hitScrollbar = result.scrollbar(); + } + + if (!hitScrollbar) { + // The hit testing above won't detect if we've hit the main frame's vertical scrollbar. Check that manually now. + RECT webViewRect; + GetWindowRect(m_viewWindow, &webViewRect); + hitScrollbar = view->verticalScrollbar() && (gestureBeginPoint.x > (webViewRect.right - view->verticalScrollbar()->theme()->scrollbarThickness())); + } - if (eventHandlerPoint.x() > view->visibleWidth() || scrollbarTest.scrollbar()) { - // We are in the scrollbar, turn off panning, need to be able to drag the scrollbar - dwPanWant = GC_PAN | GC_PAN_WITH_INERTIA | GC_PAN_WITH_GUTTER; - dwPanBlock = GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY | GC_PAN_WITH_SINGLE_FINGER_VERTICALLY; + bool canBeScrolled = false; + if (m_gestureTargetNode) { + for (RenderObject* renderer = m_gestureTargetNode->renderer(); renderer; renderer = renderer->parent()) { + if (renderer->isBox() && toRenderBox(renderer)->canBeScrolledAndHasScrollableArea()) { + canBeScrolled = true; + break; + } + } + } + + // We always allow two-fingered panning with inertia and a gutter (which limits movement to one + // direction in most cases). + DWORD dwPanWant = GC_PAN | GC_PAN_WITH_INERTIA | GC_PAN_WITH_GUTTER; + // We never allow single-fingered horizontal panning. That gesture is reserved for creating text + // selections. This matches IE. + DWORD dwPanBlock = GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY; + + if (hitScrollbar || !canBeScrolled) { + // The part of the page under the gesture can't be scrolled, or the gesture is on a scrollbar. + // Disallow single-fingered vertical panning in this case, too, so we'll fall back to the default + // behavior (which allows the scrollbar thumb to be dragged, text selections to be made, etc.). + dwPanBlock |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY; } else { - dwPanWant = GC_PAN | GC_PAN_WITH_SINGLE_FINGER_VERTICALLY | GC_PAN_WITH_INERTIA | GC_PAN_WITH_GUTTER; - dwPanBlock = GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY; + // The part of the page the gesture is under can be scrolled, and we're not under a scrollbar. + // Allow single-fingered vertical panning in this case, so the user will be able to pan the page + // with one or two fingers. + dwPanWant |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY; } - GESTURECONFIG gc = { GID_PAN, dwPanWant , dwPanBlock } ; + GESTURECONFIG gc = { GID_PAN, dwPanWant, dwPanBlock }; return SetGestureConfigPtr()(m_viewWindow, 0, 1, &gc, sizeof(GESTURECONFIG)); } @@ -1390,21 +1450,20 @@ bool WebView::gesture(WPARAM wParam, LPARAM lParam) m_lastPanX = gi.ptsLocation.x; m_lastPanY = gi.ptsLocation.y; - CloseGestureInfoHandlePtr()(gestureHandle); + break; + case GID_END: + m_gestureTargetNode = 0; break; case GID_PAN: { // Where are the fingers currently? long currentX = gi.ptsLocation.x; long currentY = gi.ptsLocation.y; - // How far did we pan in each direction? long deltaX = currentX - m_lastPanX; long deltaY = currentY - m_lastPanY; - // Calculate the overpan for window bounce m_yOverpan -= m_lastPanY - currentY; m_xOverpan -= m_lastPanX - currentX; - // Update our class variables with updated values m_lastPanX = currentX; m_lastPanY = currentY; @@ -1414,10 +1473,13 @@ bool WebView::gesture(WPARAM wParam, LPARAM lParam) CloseGestureInfoHandlePtr()(gestureHandle); return false; } - // Represent the pan gesture as a mouse wheel event - PlatformWheelEvent wheelEvent(m_viewWindow, FloatSize(deltaX, deltaY), FloatPoint(currentX, currentY)); - coreFrame->eventHandler()->handleWheelEvent(wheelEvent); + if (!m_gestureTargetNode || !m_gestureTargetNode->renderer()) + return false; + + // We negate here since panning up moves the content up, but moves the scrollbar down. + m_gestureTargetNode->renderer()->enclosingLayer()->scrollByRecursively(-deltaX, -deltaY); + if (!(UpdatePanningFeedbackPtr() && BeginPanningFeedbackPtr() && EndPanningFeedbackPtr())) { CloseGestureInfoHandlePtr()(gestureHandle); return true; @@ -1434,7 +1496,7 @@ bool WebView::gesture(WPARAM wParam, LPARAM lParam) ScrollView* view = coreFrame->view(); if (!view) { CloseGestureInfoHandlePtr()(gestureHandle); - return false; + return true; } Scrollbar* vertScrollbar = view->verticalScrollbar(); if (!vertScrollbar) { @@ -1442,22 +1504,26 @@ bool WebView::gesture(WPARAM wParam, LPARAM lParam) return true; } - // FIXME: Support Horizontal Window Bounce + // FIXME: Support Horizontal Window Bounce. <https://webkit.org/b/28500>. + // FIXME: If the user starts panning down after a window bounce has started, the window doesn't bounce back + // until they release their finger. <https://webkit.org/b/28501>. if (vertScrollbar->currentPos() == 0) UpdatePanningFeedbackPtr()(m_viewWindow, 0, m_yOverpan, gi.dwFlags & GF_INERTIA); else if (vertScrollbar->currentPos() >= vertScrollbar->maximum()) UpdatePanningFeedbackPtr()(m_viewWindow, 0, m_yOverpan, gi.dwFlags & GF_INERTIA); CloseGestureInfoHandlePtr()(gestureHandle); - break; + return true; } default: - // We have encountered an unknown gesture - return false to pass it to DefWindowProc - CloseGestureInfoHandlePtr()(gestureHandle); break; } - return true; + // If we get to this point, the gesture has not been handled. We forward + // the call to DefWindowProc by returning false, and we don't need to + // to call CloseGestureInfoHandle. + // http://msdn.microsoft.com/en-us/library/dd353228(VS.85).aspx + return false; } bool WebView::mouseWheel(WPARAM wParam, LPARAM lParam, bool isMouseHWheel) @@ -1473,6 +1539,23 @@ bool WebView::mouseWheel(WPARAM wParam, LPARAM lParam, bool isMouseHWheel) makeTextLarger(0); return true; } + + // FIXME: This doesn't fix https://bugs.webkit.org/show_bug.cgi?id=28217. This only fixes https://bugs.webkit.org/show_bug.cgi?id=28203. + HWND focusedWindow = GetFocus(); + if (focusedWindow && focusedWindow != m_viewWindow) { + // Our focus is on a different hwnd, see if it's a PopupMenu and if so, set the focus back on us (which will hide the popup). + TCHAR className[256]; + + // Make sure truncation won't affect the comparison. + ASSERT(ARRAYSIZE(className) > _tcslen(PopupMenu::popupClassName())); + + if (GetClassName(focusedWindow, className, ARRAYSIZE(className)) && !_tcscmp(className, PopupMenu::popupClassName())) { + // We don't let the WebView scroll here for two reasons - 1) To match Firefox behavior, 2) If we do scroll, we lose the + // focus ring around the select menu. + SetFocus(m_viewWindow); + return true; + } + } PlatformWheelEvent wheelEvent(m_viewWindow, wParam, lParam, isMouseHWheel); Frame* coreFrame = core(m_mainFrame); @@ -1740,22 +1823,7 @@ bool WebView::keyPress(WPARAM charCode, LPARAM keyData, bool systemKeyDown) return frame->eventHandler()->keyEvent(keyEvent); } -bool WebView::inResizer(LPARAM lParam) -{ - if (!m_uiDelegatePrivate) - return false; - - RECT r; - if (FAILED(m_uiDelegatePrivate->webViewResizerRect(this, &r))) - return false; - - POINT pt; - pt.x = LOWORD(lParam); - pt.y = HIWORD(lParam); - return !!PtInRect(&r, pt); -} - -static bool registerWebViewWindowClass() +bool WebView::registerWebViewWindowClass() { static bool haveRegisteredWindowClass = false; if (haveRegisteredWindowClass) @@ -1799,7 +1867,7 @@ static HWND findTopLevelParent(HWND window) return 0; } -static LRESULT CALLBACK WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +LRESULT CALLBACK WebView::WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { LRESULT lResult = 0; LONG_PTR longPtr = GetWindowLongPtr(hWnd, 0); @@ -1834,8 +1902,8 @@ static LRESULT CALLBACK WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, L webView->paint((HDC)wParam, lParam); break; case WM_DESTROY: - webView->close(); webView->setIsBeingDestroyed(); + webView->close(); webView->revokeDragDrop(); break; case WM_GESTURENOTIFY: @@ -1891,22 +1959,31 @@ static LRESULT CALLBACK WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, L if (lParam != 0) { webView->deleteBackingStore(); +#if USE(ACCELERATED_COMPOSITING) + if (webView->isAcceleratedCompositing()) + webView->resizeLayerRenderer(); +#endif if (Frame* coreFrame = core(mainFrameImpl)) coreFrame->view()->resize(LOWORD(lParam), HIWORD(lParam)); } break; case WM_SHOWWINDOW: lResult = DefWindowProc(hWnd, message, wParam, lParam); - if (wParam == 0) + if (wParam == 0) { // The window is being hidden (e.g., because we switched tabs). // Null out our backing store. webView->deleteBackingStore(); + } +#if USE(ACCELERATED_COMPOSITING) + else if (webView->isAcceleratedCompositing()) + webView->layerRendererBecameVisible(); +#endif break; case WM_SETFOCUS: { COMPtr<IWebUIDelegate> uiDelegate; COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate; - if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate && - SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate) + if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate + && SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate) uiDelegatePrivate->webViewReceivedFocus(webView); FocusController* focusController = webView->page()->focusController(); @@ -1925,8 +2002,8 @@ static LRESULT CALLBACK WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, L COMPtr<IWebUIDelegate> uiDelegate; COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate; HWND newFocusWnd = reinterpret_cast<HWND>(wParam); - if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate && - SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate) + if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate + && SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate) uiDelegatePrivate->webViewLostFocus(webView, (OLE_HANDLE)(ULONG64)newFocusWnd); FocusController* focusController = webView->page()->focusController(); @@ -1935,6 +2012,10 @@ static LRESULT CALLBACK WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, L // Send blur events unless we're losing focus to a child of ours. if (!IsChild(hWnd, newFocusWnd)) focusController->setFocused(false); + + // If we are pan-scrolling when we lose focus, stop the pan scrolling. + frame->eventHandler()->stopAutoscrollTimer(); + break; } case WM_WINDOWPOSCHANGED: @@ -1986,7 +2067,11 @@ static LRESULT CALLBACK WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, L RECT windowRect; ::GetClientRect(hWnd, &windowRect); ::InvalidateRect(hWnd, &windowRect, false); - } +#if USE(ACCELERATED_COMPOSITING) + if (webView->isAcceleratedCompositing()) + webView->setRootLayerNeedsDisplay(); +#endif + } break; case WM_MOUSEACTIVATE: webView->setMouseActivated(true); @@ -2001,9 +2086,9 @@ static LRESULT CALLBACK WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, L if (lpMsg->message == WM_KEYDOWN) keyCode = (UINT) lpMsg->wParam; } - if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate && - SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate && - SUCCEEDED(uiDelegatePrivate->webViewGetDlgCode(webView, keyCode, &dlgCode))) + if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate + && SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate + && SUCCEEDED(uiDelegatePrivate->webViewGetDlgCode(webView, keyCode, &dlgCode))) return dlgCode; handled = false; break; @@ -2281,13 +2366,8 @@ HRESULT STDMETHODCALLTYPE WebView::initWithFrame( registerWebViewWindowClass(); - if (!::IsWindow(m_hostWindow)) { - ASSERT_NOT_REACHED(); - return E_FAIL; - } - - m_viewWindow = CreateWindowEx(0, kWebViewWindowClassName, 0, WS_CHILD | WS_CLIPCHILDREN, - frame.left, frame.top, frame.right - frame.left, frame.bottom - frame.top, m_hostWindow, 0, gInstance, 0); + m_viewWindow = CreateWindowEx(0, kWebViewWindowClassName, 0, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + frame.left, frame.top, frame.right - frame.left, frame.bottom - frame.top, m_hostWindow ? m_hostWindow : HWND_MESSAGE, 0, gInstance, 0); ASSERT(::IsWindow(m_viewWindow)); hr = registerDragDrop(); @@ -2310,7 +2390,11 @@ HRESULT STDMETHODCALLTYPE WebView::initWithFrame( Settings::setShouldPaintNativeControls(shouldPaintNativeControls); #endif - m_page = new Page(new WebChromeClient(this), new WebContextMenuClient(this), new WebEditorClient(this), new WebDragClient(this), new WebInspectorClient(this)); + BOOL useHighResolutionTimer; + if (SUCCEEDED(m_preferences->shouldUseHighResolutionTimers(&useHighResolutionTimer))) + Settings::setShouldUseHighResolutionTimers(useHighResolutionTimer); + + m_page = new Page(new WebChromeClient(this), new WebContextMenuClient(this), new WebEditorClient(this), new WebDragClient(this), new WebInspectorClient(this), new WebPluginHalterClient(this)); BSTR localStoragePath; if (SUCCEEDED(m_preferences->localStorageDatabasePath(&localStoragePath))) { @@ -2818,12 +2902,13 @@ HRESULT STDMETHODCALLTYPE WebView::stringByEvaluatingJavaScriptFromString( if (!coreFrame) return E_FAIL; - JSC::JSValue scriptExecutionResult = coreFrame->loader()->executeScript(WebCore::String(script), true).jsValue(); + JSC::JSValue scriptExecutionResult = coreFrame->script()->executeScript(WebCore::String(script), true).jsValue(); if (!scriptExecutionResult) return E_FAIL; else if (scriptExecutionResult.isString()) { JSLock lock(JSC::SilenceAssertionsOnly); - *result = BString(String(scriptExecutionResult.getString())); + JSC::ExecState* exec = coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec(); + *result = BString(String(scriptExecutionResult.getString(exec))); } return S_OK; @@ -2952,8 +3037,17 @@ HRESULT STDMETHODCALLTYPE WebView::setHostWindow( /* [in] */ OLE_HANDLE oleWindow) { HWND window = (HWND)(ULONG64)oleWindow; - if (m_viewWindow && window) - SetParent(m_viewWindow, window); + if (m_viewWindow) { + if (window) + SetParent(m_viewWindow, window); + else if (!isBeingDestroyed()) { + // Turn the WebView into a message-only window so it will no longer be a child of the + // old host window and will be hidden from screen. We only do this when + // isBeingDestroyed() is false because doing this while handling WM_DESTROY can leave + // m_viewWindow in a weird state (see <http://webkit.org/b/29337>). + SetParent(m_viewWindow, HWND_MESSAGE); + } + } m_hostWindow = window; @@ -3304,10 +3398,34 @@ HRESULT STDMETHODCALLTYPE WebView::setMainFrameURL( } HRESULT STDMETHODCALLTYPE WebView::mainFrameURL( - /* [retval][out] */ BSTR* /*urlString*/) + /* [retval][out] */ BSTR* urlString) { - ASSERT_NOT_REACHED(); - return E_NOTIMPL; + if (!urlString) + return E_POINTER; + + if (!m_mainFrame) + return E_FAIL; + + COMPtr<IWebDataSource> dataSource; + + if (FAILED(m_mainFrame->provisionalDataSource(&dataSource))) { + if (FAILED(m_mainFrame->dataSource(&dataSource))) + return E_FAIL; + } + + if (!dataSource) { + *urlString = 0; + return S_OK; + } + + COMPtr<IWebMutableURLRequest> request; + if (FAILED(dataSource->request(&request)) || !request) + return E_FAIL; + + if (FAILED(request->URL(urlString))) + return E_FAIL; + + return S_OK; } HRESULT STDMETHODCALLTYPE WebView::mainFrameDocument( @@ -3569,6 +3687,15 @@ HRESULT STDMETHODCALLTYPE WebView::toggleGrammarChecking( return setGrammarCheckingEnabled(enabled ? FALSE : TRUE); } +HRESULT STDMETHODCALLTYPE WebView::reloadFromOrigin( + /* [in] */ IUnknown* /*sender*/) +{ + if (!m_mainFrame) + return E_FAIL; + + return m_mainFrame->reloadFromOrigin(); +} + // IWebViewCSS ----------------------------------------------------------------- HRESULT STDMETHODCALLTYPE WebView::computedStyleForElement( @@ -4339,6 +4466,11 @@ HRESULT WebView::notifyPreferencesChanged(IWebNotification* notification) return hr; settings->setLocalStorageEnabled(enabled); + hr = prefsPrivate->experimentalNotificationsEnabled(&enabled); + if (FAILED(hr)) + return hr; + settings->setExperimentalNotificationsEnabled(enabled); + hr = prefsPrivate->isWebSecurityEnabled(&enabled); if (FAILED(hr)) return hr; @@ -4361,6 +4493,21 @@ HRESULT WebView::notifyPreferencesChanged(IWebNotification* notification) settings->setShouldPaintNativeControls(!!enabled); #endif + hr = prefsPrivate->shouldUseHighResolutionTimers(&enabled); + if (FAILED(hr)) + return hr; + settings->setShouldUseHighResolutionTimers(enabled); + + UINT runTime; + hr = prefsPrivate->pluginAllowedRunTime(&runTime); + if (FAILED(hr)) + return hr; + settings->setPluginAllowedRunTime(runTime); + +#if ENABLE(3D_CANVAS) + settings->setExperimentalWebGLEnabled(true); +#endif // ENABLE(3D_CANVAS) + if (!m_closeWindowTimer.isActive()) m_mainFrame->invalidate(); // FIXME @@ -4392,6 +4539,20 @@ HRESULT updateSharedSettingsFromPreferencesIfNeeded(IWebPreferences* preferences // IWebViewPrivate ------------------------------------------------------------ +HRESULT STDMETHODCALLTYPE WebView::MIMETypeForExtension( + /* [in] */ BSTR extension, + /* [retval][out] */ BSTR* mimeType) +{ + if (!mimeType) + return E_POINTER; + + String extensionStr(extension, SysStringLen(extension)); + + *mimeType = BString(MIMETypeRegistry::getMIMETypeForExtension(extensionStr)).release(); + + return S_OK; +} + HRESULT STDMETHODCALLTYPE WebView::setCustomDropTarget( /* [in] */ IDropTarget* dt) { @@ -4515,11 +4676,25 @@ static DWORD dragOperationToDragCursor(DragOperation op) { return res; } -static DragOperation keyStateToDragOperation(DWORD) { - //FIXME: This is currently very simple, it may need to actually - //work out an appropriate DragOperation in future -- however this - //behaviour appears to match FireFox - return (DragOperation)(DragOperationCopy | DragOperationLink); +DragOperation WebView::keyStateToDragOperation(DWORD grfKeyState) const +{ + if (!m_page) + return DragOperationNone; + + // Conforms to Microsoft's key combinations as documented for + // IDropTarget::DragOver. Note, grfKeyState is the current + // state of the keyboard modifier keys on the keyboard. See: + // <http://msdn.microsoft.com/en-us/library/ms680129(VS.85).aspx>. + DragOperation operation = m_page->dragController()->sourceDragOperation(); + + if ((grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT)) + operation = DragOperationLink; + else if ((grfKeyState & MK_CONTROL) == MK_CONTROL) + operation = DragOperationCopy; + else if ((grfKeyState & MK_SHIFT) == MK_SHIFT) + operation = DragOperationGeneric; + + return operation; } HRESULT STDMETHODCALLTYPE WebView::DragEnter( @@ -4536,6 +4711,7 @@ HRESULT STDMETHODCALLTYPE WebView::DragEnter( IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState)); *pdwEffect = dragOperationToDragCursor(m_page->dragController()->dragEntered(&data)); + m_lastDropEffect = *pdwEffect; m_dragData = pDataObject; return S_OK; @@ -4556,6 +4732,7 @@ HRESULT STDMETHODCALLTYPE WebView::DragOver( } else *pdwEffect = DROPEFFECT_NONE; + m_lastDropEffect = *pdwEffect; return S_OK; } @@ -4580,7 +4757,7 @@ HRESULT STDMETHODCALLTYPE WebView::Drop( m_dropTargetHelper->Drop(pDataObject, (POINT*)&pt, *pdwEffect); m_dragData = 0; - *pdwEffect = DROPEFFECT_NONE; + *pdwEffect = m_lastDropEffect; POINTL localpt = pt; ::ScreenToClient(m_viewWindow, (LPPOINT)&localpt); DragData data(pDataObject, IntPoint(localpt.x, localpt.y), @@ -4706,7 +4883,7 @@ HRESULT STDMETHODCALLTYPE WebView::loadBackForwardListFromOtherView( // If this item is showing , save away its current scroll and form state, // since that might have changed since loading and it is normally not saved // until we leave that page. - otherWebView->m_page->mainFrame()->loader()->saveDocumentAndScrollState(); + otherWebView->m_page->mainFrame()->loader()->history()->saveDocumentAndScrollState(); } RefPtr<HistoryItem> newItem = otherBackForwardList->itemAtIndex(i)->copy(); if (!i) @@ -5324,6 +5501,226 @@ HRESULT WebView::setCanStartPlugins(BOOL canStartPlugins) return S_OK; } +static String toString(BSTR bstr) +{ + return String(bstr, SysStringLen(bstr)); +} + +static KURL toKURL(BSTR bstr) +{ + return KURL(KURL(), toString(bstr)); +} + +static PassOwnPtr<Vector<String> > toStringVector(unsigned patternsCount, BSTR* patterns) +{ + // Convert the patterns into a Vector. + if (patternsCount == 0) + return 0; + Vector<String>* patternsVector = new Vector<String>; + for (unsigned i = 0; i < patternsCount; ++i) + patternsVector->append(toString(patterns[i])); + return patternsVector; +} + +HRESULT WebView::addUserScriptToGroup(BSTR groupName, IWebScriptWorld* iWorld, BSTR source, BSTR url, + unsigned whitelistCount, BSTR* whitelist, + unsigned blacklistCount, BSTR* blacklist, + WebUserScriptInjectionTime injectionTime) +{ + COMPtr<WebScriptWorld> world(Query, iWorld); + if (!world) + return E_POINTER; + + String group = toString(groupName); + if (group.isEmpty()) + return E_INVALIDARG; + + PageGroup* pageGroup = PageGroup::pageGroup(group); + ASSERT(pageGroup); + if (!pageGroup) + return E_FAIL; + + pageGroup->addUserScriptToWorld(world->world(), toString(source), toKURL(url), + toStringVector(whitelistCount, whitelist), toStringVector(blacklistCount, blacklist), + injectionTime == WebInjectAtDocumentStart ? InjectAtDocumentStart : InjectAtDocumentEnd); + + return S_OK; +} + +HRESULT WebView::addUserStyleSheetToGroup(BSTR groupName, IWebScriptWorld* iWorld, BSTR source, BSTR url, + unsigned whitelistCount, BSTR* whitelist, + unsigned blacklistCount, BSTR* blacklist) +{ + COMPtr<WebScriptWorld> world(Query, iWorld); + if (!world) + return E_POINTER; + + String group = toString(groupName); + if (group.isEmpty()) + return E_INVALIDARG; + + PageGroup* pageGroup = PageGroup::pageGroup(group); + ASSERT(pageGroup); + if (!pageGroup) + return E_FAIL; + + pageGroup->addUserStyleSheetToWorld(world->world(), toString(source), toKURL(url), + toStringVector(whitelistCount, whitelist), toStringVector(blacklistCount, blacklist)); + + return S_OK; +} + +HRESULT WebView::removeUserScriptFromGroup(BSTR groupName, IWebScriptWorld* iWorld, BSTR url) +{ + COMPtr<WebScriptWorld> world(Query, iWorld); + if (!world) + return E_POINTER; + + String group = toString(groupName); + if (group.isEmpty()) + return E_INVALIDARG; + + PageGroup* pageGroup = PageGroup::pageGroup(group); + ASSERT(pageGroup); + if (!pageGroup) + return E_FAIL; + + pageGroup->removeUserScriptFromWorld(world->world(), toKURL(url)); + + return S_OK; +} + +HRESULT WebView::removeUserStyleSheetFromGroup(BSTR groupName, IWebScriptWorld* iWorld, BSTR url) +{ + COMPtr<WebScriptWorld> world(Query, iWorld); + if (!world) + return E_POINTER; + + String group = toString(groupName); + if (group.isEmpty()) + return E_INVALIDARG; + + PageGroup* pageGroup = PageGroup::pageGroup(group); + ASSERT(pageGroup); + if (!pageGroup) + return E_FAIL; + + pageGroup->removeUserStyleSheetFromWorld(world->world(), toKURL(url)); + + return S_OK; +} + +HRESULT WebView::removeUserScriptsFromGroup(BSTR groupName, IWebScriptWorld* iWorld) +{ + COMPtr<WebScriptWorld> world(Query, iWorld); + if (!world) + return E_POINTER; + + String group = toString(groupName); + if (group.isEmpty()) + return E_INVALIDARG; + + PageGroup* pageGroup = PageGroup::pageGroup(group); + ASSERT(pageGroup); + if (!pageGroup) + return E_FAIL; + + pageGroup->removeUserScriptsFromWorld(world->world()); + return S_OK; +} + +HRESULT WebView::removeUserStyleSheetsFromGroup(BSTR groupName, IWebScriptWorld* iWorld) +{ + COMPtr<WebScriptWorld> world(Query, iWorld); + if (!world) + return E_POINTER; + + String group = toString(groupName); + if (group.isEmpty()) + return E_INVALIDARG; + + PageGroup* pageGroup = PageGroup::pageGroup(group); + ASSERT(pageGroup); + if (!pageGroup) + return E_FAIL; + + pageGroup->removeUserStyleSheetsFromWorld(world->world()); + return S_OK; +} + +HRESULT WebView::removeAllUserContentFromGroup(BSTR groupName) +{ + String group = toString(groupName); + if (group.isEmpty()) + return E_INVALIDARG; + + PageGroup* pageGroup = PageGroup::pageGroup(group); + ASSERT(pageGroup); + if (!pageGroup) + return E_FAIL; + + pageGroup->removeAllUserContent(); + return S_OK; +} + +HRESULT WebView::invalidateBackingStore(const RECT* rect) +{ + if (!IsWindow(m_viewWindow)) + return S_OK; + + RECT clientRect; + if (!GetClientRect(m_viewWindow, &clientRect)) + return E_FAIL; + + RECT rectToInvalidate; + if (!rect) + rectToInvalidate = clientRect; + else if (!IntersectRect(&rectToInvalidate, &clientRect, rect)) + return S_OK; + + repaint(rectToInvalidate, true); + return S_OK; +} + +HRESULT WebView::whiteListAccessFromOrigin(BSTR sourceOrigin, BSTR destinationProtocol, BSTR destinationHost, BOOL allowDestinationSubdomains) +{ + SecurityOrigin::whiteListAccessFromOrigin(*SecurityOrigin::createFromString(String(sourceOrigin, SysStringLen(sourceOrigin))), String(destinationProtocol, SysStringLen(destinationProtocol)), String(destinationHost, SysStringLen(destinationHost)), allowDestinationSubdomains); + return S_OK; +} + +HRESULT WebView::resetOriginAccessWhiteLists() +{ + SecurityOrigin::resetOriginAccessWhiteLists(); + return S_OK; +} + +HRESULT WebView::setHistoryDelegate(IWebHistoryDelegate* historyDelegate) +{ + m_historyDelegate = historyDelegate; + return S_OK; +} + +HRESULT WebView::historyDelegate(IWebHistoryDelegate** historyDelegate) +{ + if (!historyDelegate) + return E_POINTER; + + return m_historyDelegate.copyRefTo(historyDelegate); +} + +HRESULT WebView::addVisitedLinks(BSTR* visitedURLs, unsigned visitedURLCount) +{ + PageGroup& group = core(this)->group(); + + for (unsigned i = 0; i < visitedURLCount; ++i) { + BSTR url = visitedURLs[i]; + unsigned length = SysStringLen(url); + group.addVisitedLink(url, length); + } + + return S_OK; +} + void WebView::downloadURL(const KURL& url) { // It's the delegate's job to ref the WebDownload to keep it alive - otherwise it will be @@ -5332,6 +5729,152 @@ void WebView::downloadURL(const KURL& url) download->start(); } +#if USE(ACCELERATED_COMPOSITING) +void WebView::setRootChildLayer(WebCore::PlatformLayer* layer) +{ + setAcceleratedCompositing(layer ? true : false); + if (m_layerRenderer) + m_layerRenderer->setRootChildLayer(layer); +} + +void WebView::setAcceleratedCompositing(bool accelerated) +{ + if (m_isAcceleratedCompositing == accelerated || !WKCACFLayerRenderer::acceleratedCompositingAvailable()) + return; + + if (accelerated) { + m_layerRenderer = WKCACFLayerRenderer::create(); + if (m_layerRenderer) { + m_isAcceleratedCompositing = true; + + // Create the root layer + ASSERT(m_viewWindow); + m_layerRenderer->setHostWindow(m_viewWindow); + updateRootLayerContents(); + } + } else { + m_layerRenderer = 0; + m_isAcceleratedCompositing = false; + } +} + +void WebView::updateRootLayerContents() +{ + if (!m_backingStoreBitmap || !m_layerRenderer) + return; + + // Get the backing store into a CGImage + BITMAP bitmap; + GetObject(m_backingStoreBitmap.get(), sizeof(bitmap), &bitmap); + int bmSize = bitmap.bmWidthBytes * bitmap.bmHeight; + RetainPtr<CFDataRef> data(AdoptCF, + CFDataCreateWithBytesNoCopy( + 0, static_cast<UInt8*>(bitmap.bmBits), + bmSize, kCFAllocatorNull)); + RetainPtr<CGDataProviderRef> cgData(AdoptCF, CGDataProviderCreateWithCFData(data.get())); + RetainPtr<CGColorSpaceRef> space(AdoptCF, CGColorSpaceCreateDeviceRGB()); + RetainPtr<CGImageRef> backingStoreImage(AdoptCF, CGImageCreate(bitmap.bmWidth, bitmap.bmHeight, + 8, bitmap.bmBitsPixel, + bitmap.bmWidthBytes, space.get(), + kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst, + cgData.get(), 0, false, + kCGRenderingIntentDefault)); + + // Hand the CGImage to CACF for compositing + m_layerRenderer->setRootContents(backingStoreImage.get()); + + // Set the frame and scroll position + Frame* coreFrame = core(m_mainFrame); + if (!coreFrame) + return; + FrameView* frameView = coreFrame->view(); + + m_layerRenderer->setScrollFrame(frameView->layoutWidth(), frameView->layoutHeight(), + frameView->scrollX(), frameView->scrollY()); +} +#endif + +HRESULT STDMETHODCALLTYPE WebView::setPluginHalterDelegate(IWebPluginHalterDelegate* d) +{ + m_pluginHalterDelegate = d; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE WebView::pluginHalterDelegate(IWebPluginHalterDelegate** d) +{ + if (!d) + return E_POINTER; + + if (!m_pluginHalterDelegate) + return E_FAIL; + + return m_pluginHalterDelegate.copyRefTo(d); +} + +static PluginView* pluginViewForNode(IDOMNode* domNode) +{ + COMPtr<DOMNode> webKitDOMNode(Query, domNode); + if (!webKitDOMNode) + return 0; + + Node* node = webKitDOMNode->node(); + if (!node) + return 0; + + RenderObject* renderer = node->renderer(); + if (!renderer || !renderer->isWidget()) + return 0; + + Widget* widget = toRenderWidget(renderer)->widget(); + if (!widget || !widget->isPluginView()) + return 0; + + return static_cast<PluginView*>(widget); +} + +HRESULT WebView::isNodeHaltedPlugin(IDOMNode* domNode, BOOL* result) +{ + if (!domNode || !result) + return E_POINTER; + + *result = FALSE; + + PluginView* view = pluginViewForNode(domNode); + if (!view) + return E_FAIL; + + *result = view->isHalted(); + return S_OK; +} + +HRESULT WebView::restartHaltedPluginForNode(IDOMNode* domNode) +{ + if (!domNode) + return E_POINTER; + + PluginView* view = pluginViewForNode(domNode); + if (!view) + return E_FAIL; + + view->restart(); + return S_OK; +} + +HRESULT WebView::hasPluginForNodeBeenHalted(IDOMNode* domNode, BOOL* result) +{ + if (!domNode || !result) + return E_POINTER; + + *result = FALSE; + + PluginView* view = pluginViewForNode(domNode); + if (!view) + return E_FAIL; + + *result = view->hasBeenHalted(); + return S_OK; +} + class EnumTextMatches : public IEnumTextMatches { long m_ref; @@ -5415,4 +5958,3 @@ Page* core(IWebView* iWebView) return page; } - |
