2 * Copyright (C) 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
29 #include "ChunkedUpdateDrawingAreaProxy.h"
30 #include "DrawingAreaProxyImpl.h"
31 #include "FindIndicator.h"
33 #include "NativeWebKeyboardEvent.h"
36 #include "WKAPICast.h"
37 #include "WebContext.h"
38 #include "WebContextMenuProxyWin.h"
39 #include "WebEditCommandProxy.h"
40 #include "WebEventFactory.h"
41 #include "WebPageProxy.h"
42 #include "WebPopupMenuProxyWin.h"
44 #include <WebCore/BitmapInfo.h>
45 #include <WebCore/Cursor.h>
46 #include <WebCore/FloatRect.h>
47 #include <WebCore/GraphicsContextCG.h>
48 #include <WebCore/IntRect.h>
49 #include <WebCore/SoftLinking.h>
50 #include <WebCore/WebCoreInstanceHandle.h>
51 #include <WebCore/WindowMessageBroadcaster.h>
52 #include <wtf/text/WTFString.h>
55 // We need these functions in a separate namespace, because in the global namespace they conflict
56 // with the definitions in imm.h only by the type modifier (the macro defines them as static) and
57 // imm.h is included by windows.h
58 SOFT_LINK_LIBRARY(IMM32)
59 SOFT_LINK(IMM32, ImmGetContext, HIMC, WINAPI, (HWND hwnd), (hwnd))
60 SOFT_LINK(IMM32, ImmReleaseContext, BOOL, WINAPI, (HWND hWnd, HIMC hIMC), (hWnd, hIMC))
61 SOFT_LINK(IMM32, ImmGetCompositionStringW, LONG, WINAPI, (HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen), (hIMC, dwIndex, lpBuf, dwBufLen))
62 SOFT_LINK(IMM32, ImmSetCandidateWindow, BOOL, WINAPI, (HIMC hIMC, LPCANDIDATEFORM lpCandidate), (hIMC, lpCandidate))
63 SOFT_LINK(IMM32, ImmSetOpenStatus, BOOL, WINAPI, (HIMC hIMC, BOOL fOpen), (hIMC, fOpen))
64 SOFT_LINK(IMM32, ImmNotifyIME, BOOL, WINAPI, (HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue), (hIMC, dwAction, dwIndex, dwValue))
65 SOFT_LINK(IMM32, ImmAssociateContextEx, BOOL, WINAPI, (HWND hWnd, HIMC hIMC, DWORD dwFlags), (hWnd, hIMC, dwFlags))
68 using namespace WebCore;
72 static const LPCWSTR kWebKit2WebViewWindowClassName = L"WebKit2WebViewWindowClass";
74 // Constants not available on all platforms.
75 const int WM_XP_THEMECHANGED = 0x031A;
76 const int WM_VISTA_MOUSEHWHEEL = 0x020E;
78 static const int kMaxToolTipWidth = 250;
81 UpdateActiveStateTimer = 1,
84 static bool useNewDrawingArea()
86 // FIXME: Remove this function and the old drawing area code once we aren't interested in
87 // testing the old drawing area anymore.
91 LRESULT CALLBACK WebView::WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
93 LONG_PTR longPtr = ::GetWindowLongPtr(hWnd, 0);
95 if (WebView* webView = reinterpret_cast<WebView*>(longPtr))
96 return webView->wndProc(hWnd, message, wParam, lParam);
98 if (message == WM_CREATE) {
99 LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
101 // Associate the WebView with the window.
102 ::SetWindowLongPtr(hWnd, 0, (LONG_PTR)createStruct->lpCreateParams);
106 return ::DefWindowProc(hWnd, message, wParam, lParam);
109 LRESULT WebView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
119 m_isBeingDestroyed = true;
126 lResult = onPaintEvent(hWnd, message, wParam, lParam, handled);
129 lResult = onPrintClientEvent(hWnd, message, wParam, lParam, handled);
131 case WM_MOUSEACTIVATE:
132 setWasActivatedByMouseEvent(true);
139 case WM_LBUTTONDBLCLK:
140 case WM_MBUTTONDBLCLK:
141 case WM_RBUTTONDBLCLK:
146 lResult = onMouseEvent(hWnd, message, wParam, lParam, handled);
149 case WM_VISTA_MOUSEHWHEEL:
150 lResult = onWheelEvent(hWnd, message, wParam, lParam, handled);
158 lResult = onKeyEvent(hWnd, message, wParam, lParam, handled);
161 lResult = onSizeEvent(hWnd, message, wParam, lParam, handled);
163 case WM_WINDOWPOSCHANGED:
164 lResult = onWindowPositionChangedEvent(hWnd, message, wParam, lParam, handled);
167 lResult = onSetFocusEvent(hWnd, message, wParam, lParam, handled);
170 lResult = onKillFocusEvent(hWnd, message, wParam, lParam, handled);
173 lResult = onTimerEvent(hWnd, message, wParam, lParam, handled);
176 lResult = onShowWindowEvent(hWnd, message, wParam, lParam, handled);
179 lResult = onSetCursor(hWnd, message, wParam, lParam, handled);
181 case WM_IME_STARTCOMPOSITION:
182 handled = onIMEStartComposition();
185 lResult = onIMERequest(wParam, lParam);
187 case WM_IME_COMPOSITION:
188 handled = onIMEComposition(lParam);
190 case WM_IME_ENDCOMPOSITION:
191 handled = onIMEEndComposition();
194 handled = onIMESelect(wParam, lParam);
196 case WM_IME_SETCONTEXT:
197 handled = onIMESetContext(wParam, lParam);
205 lResult = ::DefWindowProc(hWnd, message, wParam, lParam);
210 bool WebView::registerWebViewWindowClass()
212 static bool haveRegisteredWindowClass = false;
213 if (haveRegisteredWindowClass)
215 haveRegisteredWindowClass = true;
219 wcex.cbSize = sizeof(WNDCLASSEX);
220 wcex.style = CS_DBLCLKS;
221 wcex.lpfnWndProc = WebView::WebViewWndProc;
223 wcex.cbWndExtra = sizeof(WebView*);
224 wcex.hInstance = instanceHandle();
226 wcex.hCursor = ::LoadCursor(0, IDC_ARROW);
227 wcex.hbrBackground = 0;
228 wcex.lpszMenuName = 0;
229 wcex.lpszClassName = kWebKit2WebViewWindowClassName;
232 return !!::RegisterClassEx(&wcex);
235 WebView::WebView(RECT rect, WebContext* context, WebPageGroup* pageGroup, HWND parentWindow)
236 : m_topLevelParentWindow(0)
240 , m_overrideCursor(0)
241 , m_trackingMouseLeave(false)
242 , m_isInWindow(false)
244 , m_wasActivatedByMouseEvent(false)
245 , m_isBeingDestroyed(false)
246 , m_inIMEComposition(0)
247 , m_findIndicatorCallback(0)
248 , m_findIndicatorCallbackContext(0)
250 registerWebViewWindowClass();
252 m_window = ::CreateWindowExW(0, kWebKit2WebViewWindowClassName, 0, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE,
253 rect.top, rect.left, rect.right - rect.left, rect.bottom - rect.top, parentWindow ? parentWindow : HWND_MESSAGE, 0, instanceHandle(), this);
254 ASSERT(::IsWindow(m_window));
255 // We only check our window style, and not ::IsWindowVisible, because m_isVisible only tracks
256 // this window's visibility status, while ::IsWindowVisible takes our ancestors' visibility
257 // status into account. <http://webkit.org/b/54104>
258 ASSERT(m_isVisible == static_cast<bool>(::GetWindowLong(m_window, GWL_STYLE) & WS_VISIBLE));
260 m_page = context->createWebPage(this, pageGroup);
261 m_page->initializeWebPage();
263 CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, IID_IDropTargetHelper, (void**)&m_dropTargetHelper);
265 // FIXME: Initializing the tooltip window here matches WebKit win, but seems like something
266 // we could do on demand to save resources.
267 initializeToolTipWindow();
269 // Initialize the top level parent window and register it with the WindowMessageBroadcaster.
270 windowAncestryDidChange();
275 // Tooltip window needs to be explicitly destroyed since it isn't a WS_CHILD.
276 if (::IsWindow(m_toolTipWindow))
277 ::DestroyWindow(m_toolTipWindow);
280 void WebView::initialize()
282 ::RegisterDragDrop(m_window, this);
285 void WebView::setParentWindow(HWND parentWindow)
288 // If the host window hasn't changed, bail.
289 if (::GetParent(m_window) == parentWindow)
292 ::SetParent(m_window, parentWindow);
293 else if (!m_isBeingDestroyed) {
294 // Turn the WebView into a message-only window so it will no longer be a child of the
295 // old parent window and will be hidden from screen. We only do this when
296 // isBeingDestroyed() is false because doing this while handling WM_DESTROY can leave
297 // m_window in a weird state (see <http://webkit.org/b/29337>).
298 ::SetParent(m_window, HWND_MESSAGE);
302 windowAncestryDidChange();
305 static HWND findTopLevelParentWindow(HWND window)
310 HWND current = window;
311 for (HWND parent = GetParent(current); current; current = parent, parent = GetParent(parent)) {
312 if (!parent || !(GetWindowLongPtr(current, GWL_STYLE) & (WS_POPUP | WS_CHILD)))
315 ASSERT_NOT_REACHED();
319 void WebView::windowAncestryDidChange()
321 HWND newTopLevelParentWindow;
323 newTopLevelParentWindow = findTopLevelParentWindow(m_window);
325 // There's no point in tracking active state changes of our parent window if we don't have
326 // a window ourselves.
327 newTopLevelParentWindow = 0;
330 if (newTopLevelParentWindow == m_topLevelParentWindow)
333 if (m_topLevelParentWindow)
334 WindowMessageBroadcaster::removeListener(m_topLevelParentWindow, this);
336 m_topLevelParentWindow = newTopLevelParentWindow;
338 if (m_topLevelParentWindow)
339 WindowMessageBroadcaster::addListener(m_topLevelParentWindow, this);
344 LRESULT WebView::onMouseEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
346 WebMouseEvent mouseEvent = WebEventFactory::createWebMouseEvent(hWnd, message, wParam, lParam, m_wasActivatedByMouseEvent);
347 setWasActivatedByMouseEvent(false);
353 ::SetFocus(m_window);
354 ::SetCapture(m_window);
362 startTrackingMouseLeave();
365 stopTrackingMouseLeave();
367 case WM_LBUTTONDBLCLK:
368 case WM_MBUTTONDBLCLK:
369 case WM_RBUTTONDBLCLK:
372 ASSERT_NOT_REACHED();
375 m_page->handleMouseEvent(mouseEvent);
381 LRESULT WebView::onWheelEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
383 WebWheelEvent wheelEvent = WebEventFactory::createWebWheelEvent(hWnd, message, wParam, lParam);
384 if (wheelEvent.controlKey()) {
385 // We do not want WebKit to handle Control + Wheel, this should be handled by the client application
391 m_page->handleWheelEvent(wheelEvent);
397 LRESULT WebView::onKeyEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
399 m_page->handleKeyboardEvent(NativeWebKeyboardEvent(hWnd, message, wParam, lParam));
401 // We claim here to always have handled the event. If the event is not in fact handled, we will
402 // find out later in didNotHandleKeyEvent.
407 static void drawPageBackground(HDC dc, const RECT& rect)
409 // Mac checks WebPageProxy::drawsBackground and
410 // WebPageProxy::drawsTransparentBackground here, but those are always false on
411 // Windows currently (see <http://webkit.org/b/52009>).
412 ::FillRect(dc, &rect, reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1));
415 void WebView::paint(HDC hdc, const IntRect& dirtyRect)
417 m_page->endPrinting();
418 if (useNewDrawingArea()) {
419 if (DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(m_page->drawingArea())) {
420 // FIXME: We should port WebKit1's rect coalescing logic here.
421 Region unpaintedRegion;
422 drawingArea->paint(hdc, dirtyRect, unpaintedRegion);
424 Vector<IntRect> unpaintedRects = unpaintedRegion.rects();
425 for (size_t i = 0; i < unpaintedRects.size(); ++i) {
426 RECT winRect = unpaintedRects[i];
427 drawPageBackground(hdc, unpaintedRects[i]);
430 drawPageBackground(hdc, dirtyRect);
434 if (m_page->isValid() && m_page->drawingArea() && m_page->drawingArea()->paint(dirtyRect, hdc))
437 drawPageBackground(hdc, dirtyRect);
441 static void flashRects(HDC dc, const IntRect rects[], size_t rectCount, HBRUSH brush)
443 for (size_t i = 0; i < rectCount; ++i) {
444 RECT winRect = rects[i];
445 ::FillRect(dc, &winRect, brush);
452 static OwnPtr<HBRUSH> createBrush(const Color& color)
454 return adoptPtr(::CreateSolidBrush(RGB(color.red(), color.green(), color.blue())));
457 LRESULT WebView::onPaintEvent(HWND hWnd, UINT message, WPARAM, LPARAM, bool& handled)
459 PAINTSTRUCT paintStruct;
460 HDC hdc = ::BeginPaint(m_window, &paintStruct);
462 if (WebPageProxy::debugPaintFlags() & kWKDebugFlashViewUpdates) {
463 static HBRUSH brush = createBrush(WebPageProxy::viewUpdatesFlashColor().rgb()).leakPtr();
464 IntRect rect = paintStruct.rcPaint;
465 flashRects(hdc, &rect, 1, brush);
468 paint(hdc, paintStruct.rcPaint);
470 ::EndPaint(m_window, &paintStruct);
476 LRESULT WebView::onPrintClientEvent(HWND hWnd, UINT, WPARAM wParam, LPARAM, bool& handled)
478 HDC hdc = reinterpret_cast<HDC>(wParam);
480 ::GetClientRect(hWnd, &winRect);
488 LRESULT WebView::onSizeEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
490 int width = LOWORD(lParam);
491 int height = HIWORD(lParam);
493 if (m_page && m_page->drawingArea())
494 m_page->drawingArea()->setSize(IntSize(width, height), IntSize());
500 LRESULT WebView::onWindowPositionChangedEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
502 if (reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_SHOWWINDOW)
503 updateActiveStateSoon();
509 LRESULT WebView::onSetFocusEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
511 m_page->viewStateDidChange(WebPageProxy::ViewIsFocused);
516 LRESULT WebView::onKillFocusEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
518 m_page->viewStateDidChange(WebPageProxy::ViewIsFocused);
523 LRESULT WebView::onTimerEvent(HWND hWnd, UINT, WPARAM wParam, LPARAM, bool& handled)
526 case UpdateActiveStateTimer:
527 ::KillTimer(hWnd, UpdateActiveStateTimer);
536 LRESULT WebView::onShowWindowEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
538 // lParam is 0 when the message is sent because of a ShowWindow call.
539 // FIXME: Since we don't get notified when an ancestor window is hidden or shown, we will keep
540 // painting even when we have a hidden ancestor. <http://webkit.org/b/54104>
542 m_isVisible = wParam;
544 m_page->viewStateDidChange(WebPageProxy::ViewIsVisible);
551 LRESULT WebView::onSetCursor(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
553 if (!m_lastCursorSet) {
558 ::SetCursor(m_lastCursorSet);
562 void WebView::updateActiveState()
564 m_page->viewStateDidChange(WebPageProxy::ViewWindowIsActive);
567 void WebView::updateActiveStateSoon()
569 // This function is called while processing the WM_NCACTIVATE message.
570 // While processing WM_NCACTIVATE when we are being deactivated, GetActiveWindow() will
571 // still return our window. If we were to call updateActiveState() in that case, we would
572 // wrongly think that we are still the active window. To work around this, we update our
573 // active state after a 0-delay timer fires, at which point GetActiveWindow() will return
574 // the newly-activated window.
576 ::SetTimer(m_window, UpdateActiveStateTimer, 0, 0);
579 static bool initCommonControls()
581 static bool haveInitialized = false;
585 INITCOMMONCONTROLSEX init;
586 init.dwSize = sizeof(init);
587 init.dwICC = ICC_TREEVIEW_CLASSES;
588 haveInitialized = !!::InitCommonControlsEx(&init);
589 return haveInitialized;
592 void WebView::initializeToolTipWindow()
594 if (!initCommonControls())
597 m_toolTipWindow = ::CreateWindowEx(WS_EX_TRANSPARENT, TOOLTIPS_CLASS, 0, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
598 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
600 if (!m_toolTipWindow)
604 info.cbSize = sizeof(info);
605 info.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
606 info.uId = reinterpret_cast<UINT_PTR>(m_window);
608 ::SendMessage(m_toolTipWindow, TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(&info));
609 ::SendMessage(m_toolTipWindow, TTM_SETMAXTIPWIDTH, 0, kMaxToolTipWidth);
610 ::SetWindowPos(m_toolTipWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
613 void WebView::startTrackingMouseLeave()
615 if (m_trackingMouseLeave)
617 m_trackingMouseLeave = true;
619 TRACKMOUSEEVENT trackMouseEvent;
620 trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
621 trackMouseEvent.dwFlags = TME_LEAVE;
622 trackMouseEvent.hwndTrack = m_window;
624 ::TrackMouseEvent(&trackMouseEvent);
627 void WebView::stopTrackingMouseLeave()
629 if (!m_trackingMouseLeave)
631 m_trackingMouseLeave = false;
633 TRACKMOUSEEVENT trackMouseEvent;
634 trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
635 trackMouseEvent.dwFlags = TME_LEAVE | TME_CANCEL;
636 trackMouseEvent.hwndTrack = m_window;
638 ::TrackMouseEvent(&trackMouseEvent);
641 void WebView::close()
643 ::RevokeDragDrop(m_window);
650 PassOwnPtr<DrawingAreaProxy> WebView::createDrawingAreaProxy()
652 if (useNewDrawingArea())
653 return DrawingAreaProxyImpl::create(m_page.get());
655 return ChunkedUpdateDrawingAreaProxy::create(this, m_page.get());
658 void WebView::setViewNeedsDisplay(const WebCore::IntRect& rect)
661 ::InvalidateRect(m_window, &r, false);
664 void WebView::displayView()
666 ::UpdateWindow(m_window);
669 void WebView::scrollView(const IntRect& scrollRect, const IntSize& scrollOffset)
671 // FIXME: Actually scroll the view contents.
672 setViewNeedsDisplay(scrollRect);
675 void WebView::flashBackingStoreUpdates(const Vector<IntRect>& updateRects)
677 static HBRUSH brush = createBrush(WebPageProxy::backingStoreUpdatesFlashColor().rgb()).leakPtr();
678 HDC dc = ::GetDC(m_window);
679 flashRects(dc, updateRects.data(), updateRects.size(), brush);
680 ::ReleaseDC(m_window, dc);
683 WebCore::IntSize WebView::viewSize()
686 GetClientRect(m_window, &clientRect);
688 return IntRect(clientRect).size();
691 bool WebView::isViewWindowActive()
693 HWND activeWindow = ::GetActiveWindow();
694 return (activeWindow && m_topLevelParentWindow == findTopLevelParentWindow(activeWindow));
697 bool WebView::isViewFocused()
699 return ::GetFocus() == m_window;
702 bool WebView::isViewVisible()
707 bool WebView::isViewInWindow()
712 void WebView::pageClosed()
716 void WebView::processDidCrash()
718 updateNativeCursor();
719 ::InvalidateRect(m_window, 0, TRUE);
722 void WebView::didRelaunchProcess()
724 updateNativeCursor();
725 ::InvalidateRect(m_window, 0, TRUE);
728 void WebView::takeFocus(bool)
732 void WebView::toolTipChanged(const String&, const String& newToolTip)
734 if (!m_toolTipWindow)
737 if (!newToolTip.isEmpty()) {
738 // This is necessary because String::charactersWithNullTermination() is not const.
739 String toolTip = newToolTip;
742 info.cbSize = sizeof(info);
743 info.uFlags = TTF_IDISHWND;
744 info.uId = reinterpret_cast<UINT_PTR>(m_window);
745 info.lpszText = const_cast<UChar*>(toolTip.charactersWithNullTermination());
746 ::SendMessage(m_toolTipWindow, TTM_UPDATETIPTEXT, 0, reinterpret_cast<LPARAM>(&info));
749 ::SendMessage(m_toolTipWindow, TTM_ACTIVATE, !newToolTip.isEmpty(), 0);
752 HCURSOR WebView::cursorToShow() const
754 if (!m_page->isValid())
757 // We only show the override cursor if the default (arrow) cursor is showing.
758 static HCURSOR arrowCursor = ::LoadCursor(0, IDC_ARROW);
759 if (m_overrideCursor && m_webCoreCursor == arrowCursor)
760 return m_overrideCursor;
762 return m_webCoreCursor;
765 void WebView::updateNativeCursor()
767 m_lastCursorSet = cursorToShow();
768 if (!m_lastCursorSet)
770 ::SetCursor(m_lastCursorSet);
773 void WebView::setCursor(const WebCore::Cursor& cursor)
775 if (!cursor.platformCursor()->nativeCursor())
777 m_webCoreCursor = cursor.platformCursor()->nativeCursor();
778 updateNativeCursor();
781 void WebView::setOverrideCursor(HCURSOR overrideCursor)
783 m_overrideCursor = overrideCursor;
784 updateNativeCursor();
787 void WebView::setInitialFocus(bool forward)
789 m_page->setInitialFocus(forward);
792 void WebView::setViewportArguments(const WebCore::ViewportArguments&)
796 void WebView::registerEditCommand(PassRefPtr<WebEditCommandProxy>, WebPageProxy::UndoOrRedo)
800 void WebView::clearAllEditCommands()
804 FloatRect WebView::convertToDeviceSpace(const FloatRect& rect)
809 IntRect WebView::windowToScreen(const IntRect& rect)
814 FloatRect WebView::convertToUserSpace(const FloatRect& rect)
819 HIMC WebView::getIMMContext()
821 return Ime::ImmGetContext(m_window);
824 void WebView::prepareCandidateWindow(HIMC hInputContext)
826 IntRect caret = m_page->firstRectForCharacterInSelectedRange(0);
829 form.dwStyle = CFS_EXCLUDE;
830 form.ptCurrentPos.x = caret.x();
831 form.ptCurrentPos.y = caret.maxY();
832 form.rcArea.top = caret.y();
833 form.rcArea.bottom = caret.maxY();
834 form.rcArea.left = caret.x();
835 form.rcArea.right = caret.maxX();
836 Ime::ImmSetCandidateWindow(hInputContext, &form);
839 void WebView::resetIME()
841 HIMC hInputContext = getIMMContext();
844 Ime::ImmNotifyIME(hInputContext, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
845 Ime::ImmReleaseContext(m_window, hInputContext);
848 void WebView::setInputMethodState(bool enabled)
850 Ime::ImmAssociateContextEx(m_window, 0, enabled ? IACE_DEFAULT : 0);
853 void WebView::compositionSelectionChanged(bool hasChanged)
855 if (m_page->selectionState().hasComposition && !hasChanged)
859 bool WebView::onIMEStartComposition()
861 LOG(TextInput, "onIMEStartComposition");
862 m_inIMEComposition++;
864 HIMC hInputContext = getIMMContext();
867 prepareCandidateWindow(hInputContext);
868 Ime::ImmReleaseContext(m_window, hInputContext);
872 static bool getCompositionString(HIMC hInputContext, DWORD type, String& result)
874 LONG compositionLength = Ime::ImmGetCompositionStringW(hInputContext, type, 0, 0);
875 if (compositionLength <= 0)
877 Vector<UChar> compositionBuffer(compositionLength / 2);
878 compositionLength = Ime::ImmGetCompositionStringW(hInputContext, type, compositionBuffer.data(), compositionLength);
879 result = String::adopt(compositionBuffer);
883 static void compositionToUnderlines(const Vector<DWORD>& clauses, const Vector<BYTE>& attributes, Vector<CompositionUnderline>& underlines)
885 if (clauses.isEmpty()) {
890 size_t numBoundaries = clauses.size() - 1;
891 underlines.resize(numBoundaries);
892 for (unsigned i = 0; i < numBoundaries; ++i) {
893 underlines[i].startOffset = clauses[i];
894 underlines[i].endOffset = clauses[i + 1];
895 BYTE attribute = attributes[clauses[i]];
896 underlines[i].thick = attribute == ATTR_TARGET_CONVERTED || attribute == ATTR_TARGET_NOTCONVERTED;
897 underlines[i].color = Color::black;
902 #define APPEND_ARGUMENT_NAME(name) \
903 if (lparam & name) { \
910 static String imeCompositionArgumentNames(LPARAM lparam)
913 bool needsComma = false;
915 APPEND_ARGUMENT_NAME(GCS_COMPATTR);
916 APPEND_ARGUMENT_NAME(GCS_COMPCLAUSE);
917 APPEND_ARGUMENT_NAME(GCS_COMPREADSTR);
918 APPEND_ARGUMENT_NAME(GCS_COMPREADATTR);
919 APPEND_ARGUMENT_NAME(GCS_COMPREADCLAUSE);
920 APPEND_ARGUMENT_NAME(GCS_COMPSTR);
921 APPEND_ARGUMENT_NAME(GCS_CURSORPOS);
922 APPEND_ARGUMENT_NAME(GCS_DELTASTART);
923 APPEND_ARGUMENT_NAME(GCS_RESULTCLAUSE);
924 APPEND_ARGUMENT_NAME(GCS_RESULTREADCLAUSE);
925 APPEND_ARGUMENT_NAME(GCS_RESULTREADSTR);
926 APPEND_ARGUMENT_NAME(GCS_RESULTSTR);
927 APPEND_ARGUMENT_NAME(CS_INSERTCHAR);
928 APPEND_ARGUMENT_NAME(CS_NOMOVECARET);
933 static String imeRequestName(WPARAM wparam)
936 case IMR_CANDIDATEWINDOW:
937 return "IMR_CANDIDATEWINDOW";
938 case IMR_COMPOSITIONFONT:
939 return "IMR_COMPOSITIONFONT";
940 case IMR_COMPOSITIONWINDOW:
941 return "IMR_COMPOSITIONWINDOW";
942 case IMR_CONFIRMRECONVERTSTRING:
943 return "IMR_CONFIRMRECONVERTSTRING";
944 case IMR_DOCUMENTFEED:
945 return "IMR_DOCUMENTFEED";
946 case IMR_QUERYCHARPOSITION:
947 return "IMR_QUERYCHARPOSITION";
948 case IMR_RECONVERTSTRING:
949 return "IMR_RECONVERTSTRING";
951 return "Unknown (" + String::number(wparam) + ")";
956 bool WebView::onIMEComposition(LPARAM lparam)
958 LOG(TextInput, "onIMEComposition %s", imeCompositionArgumentNames(lparam).latin1().data());
959 HIMC hInputContext = getIMMContext();
963 if (!m_page->selectionState().isContentEditable)
966 prepareCandidateWindow(hInputContext);
968 if (lparam & GCS_RESULTSTR || !lparam) {
969 String compositionString;
970 if (!getCompositionString(hInputContext, GCS_RESULTSTR, compositionString) && lparam)
973 m_page->confirmComposition(compositionString);
977 String compositionString;
978 if (!getCompositionString(hInputContext, GCS_COMPSTR, compositionString))
981 // Composition string attributes
982 int numAttributes = Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPATTR, 0, 0);
983 Vector<BYTE> attributes(numAttributes);
984 Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPATTR, attributes.data(), numAttributes);
987 int numBytes = Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPCLAUSE, 0, 0);
988 Vector<DWORD> clauses(numBytes / sizeof(DWORD));
989 Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPCLAUSE, clauses.data(), numBytes);
991 Vector<CompositionUnderline> underlines;
992 compositionToUnderlines(clauses, attributes, underlines);
994 int cursorPosition = LOWORD(Ime::ImmGetCompositionStringW(hInputContext, GCS_CURSORPOS, 0, 0));
996 m_page->setComposition(compositionString, underlines, cursorPosition);
1001 bool WebView::onIMEEndComposition()
1003 LOG(TextInput, "onIMEEndComposition");
1004 // If the composition hasn't been confirmed yet, it needs to be cancelled.
1005 // This happens after deleting the last character from inline input hole.
1006 if (m_page->selectionState().hasComposition)
1007 m_page->confirmComposition(String());
1009 if (m_inIMEComposition)
1010 m_inIMEComposition--;
1015 LRESULT WebView::onIMERequestCharPosition(IMECHARPOSITION* charPos)
1017 if (charPos->dwCharPos && !m_page->selectionState().hasComposition)
1019 IntRect caret = m_page->firstRectForCharacterInSelectedRange(charPos->dwCharPos);
1020 charPos->pt.x = caret.x();
1021 charPos->pt.y = caret.y();
1022 ::ClientToScreen(m_window, &charPos->pt);
1023 charPos->cLineHeight = caret.height();
1024 ::GetWindowRect(m_window, &charPos->rcDocument);
1028 LRESULT WebView::onIMERequestReconvertString(RECONVERTSTRING* reconvertString)
1030 String text = m_page->getSelectedText();
1031 unsigned totalSize = sizeof(RECONVERTSTRING) + text.length() * sizeof(UChar);
1033 if (!reconvertString)
1036 if (totalSize > reconvertString->dwSize)
1038 reconvertString->dwCompStrLen = text.length();
1039 reconvertString->dwStrLen = text.length();
1040 reconvertString->dwTargetStrLen = text.length();
1041 reconvertString->dwStrOffset = sizeof(RECONVERTSTRING);
1042 memcpy(reconvertString + 1, text.characters(), text.length() * sizeof(UChar));
1046 LRESULT WebView::onIMERequest(WPARAM request, LPARAM data)
1048 LOG(TextInput, "onIMERequest %s", imeRequestName(request).latin1().data());
1049 if (!m_page->selectionState().isContentEditable)
1053 case IMR_RECONVERTSTRING:
1054 return onIMERequestReconvertString(reinterpret_cast<RECONVERTSTRING*>(data));
1056 case IMR_QUERYCHARPOSITION:
1057 return onIMERequestCharPosition(reinterpret_cast<IMECHARPOSITION*>(data));
1062 bool WebView::onIMESelect(WPARAM wparam, LPARAM lparam)
1064 UNUSED_PARAM(wparam);
1065 UNUSED_PARAM(lparam);
1066 LOG(TextInput, "onIMESelect locale %ld %s", lparam, wparam ? "select" : "deselect");
1070 bool WebView::onIMESetContext(WPARAM wparam, LPARAM)
1072 LOG(TextInput, "onIMESetContext %s", wparam ? "active" : "inactive");
1076 void WebView::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool wasEventHandled)
1078 // Calling ::DefWindowProcW will ensure that pressing the Alt key will generate a WM_SYSCOMMAND
1079 // event, e.g. See <http://webkit.org/b/47671>.
1080 if (!wasEventHandled)
1081 ::DefWindowProcW(event.nativeEvent()->hwnd, event.nativeEvent()->message, event.nativeEvent()->wParam, event.nativeEvent()->lParam);
1084 PassRefPtr<WebPopupMenuProxy> WebView::createPopupMenuProxy(WebPageProxy* page)
1086 return WebPopupMenuProxyWin::create(this, page);
1089 PassRefPtr<WebContextMenuProxy> WebView::createContextMenuProxy(WebPageProxy* page)
1091 return WebContextMenuProxyWin::create(m_window, page);
1094 void WebView::setFindIndicator(PassRefPtr<FindIndicator> prpFindIndicator, bool fadeOut)
1096 if (!m_findIndicatorCallback)
1100 IntRect selectionRect;
1102 if (RefPtr<FindIndicator> findIndicator = prpFindIndicator) {
1103 if (ShareableBitmap* contentImage = findIndicator->contentImage()) {
1104 // Render the contentImage to an HBITMAP.
1106 HDC hdc = ::CreateCompatibleDC(0);
1107 int width = contentImage->bounds().width();
1108 int height = contentImage->bounds().height();
1109 BitmapInfo bitmapInfo = BitmapInfo::create(contentImage->size());
1111 hbmp = CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, static_cast<void**>(&bits), 0, 0);
1112 HBITMAP hbmpOld = static_cast<HBITMAP>(SelectObject(hdc, hbmp));
1113 RetainPtr<CGContextRef> context(AdoptCF, CGBitmapContextCreate(bits, width, height,
1114 8, width * sizeof(RGBQUAD), deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
1116 GraphicsContext graphicsContext(context.get());
1117 contentImage->paint(graphicsContext, IntPoint(), contentImage->bounds());
1119 ::SelectObject(hdc, hbmpOld);
1123 selectionRect = IntRect(findIndicator->selectionRectInWindowCoordinates());
1126 // The callback is responsible for calling ::DeleteObject(hbmp).
1127 (*m_findIndicatorCallback)(toAPI(this), hbmp, selectionRect, fadeOut, m_findIndicatorCallbackContext);
1130 void WebView::setFindIndicatorCallback(WKViewFindIndicatorCallback callback, void* context)
1132 m_findIndicatorCallback = callback;
1133 m_findIndicatorCallbackContext = context;
1136 WKViewFindIndicatorCallback WebView::getFindIndicatorCallback(void** context)
1139 *context = m_findIndicatorCallbackContext;
1141 return m_findIndicatorCallback;
1144 void WebView::didCommitLoadForMainFrame(bool useCustomRepresentation)
1148 void WebView::didFinishLoadingDataForCustomRepresentation(const String& suggestedFilename, const CoreIPC::DataReference&)
1152 double WebView::customRepresentationZoomFactor()
1157 void WebView::setCustomRepresentationZoomFactor(double)
1161 void WebView::didChangeScrollbarsForMainFrame() const
1165 void WebView::setIsInWindow(bool isInWindow)
1167 m_isInWindow = isInWindow;
1168 m_page->viewStateDidChange(WebPageProxy::ViewIsInWindow);
1171 #if USE(ACCELERATED_COMPOSITING)
1173 void WebView::enterAcceleratedCompositingMode(const LayerTreeContext&)
1175 ASSERT(useNewDrawingArea());
1176 // FIXME: Implement.
1177 ASSERT_NOT_REACHED();
1180 void WebView::exitAcceleratedCompositingMode()
1182 ASSERT(useNewDrawingArea());
1183 // FIXME: Implement.
1184 ASSERT_NOT_REACHED();
1187 #endif // USE(ACCELERATED_COMPOSITING)
1189 HWND WebView::nativeWindow()
1194 // WebCore::WindowMessageListener
1196 void WebView::windowReceivedMessage(HWND, UINT message, WPARAM wParam, LPARAM)
1200 updateActiveStateSoon();
1202 case WM_SETTINGCHANGE:
1203 // systemParameterChanged(wParam);
1208 HRESULT STDMETHODCALLTYPE WebView::QueryInterface(REFIID riid, void** ppvObject)
1211 if (IsEqualGUID(riid, IID_IUnknown))
1212 *ppvObject = static_cast<IUnknown*>(this);
1213 else if (IsEqualGUID(riid, IID_IDropTarget))
1214 *ppvObject = static_cast<IDropTarget*>(this);
1216 return E_NOINTERFACE;
1222 ULONG STDMETHODCALLTYPE WebView::AddRef(void)
1228 ULONG STDMETHODCALLTYPE WebView::Release(void)
1234 static DWORD dragOperationToDragCursor(DragOperation op)
1236 DWORD res = DROPEFFECT_NONE;
1237 if (op & DragOperationCopy)
1238 res = DROPEFFECT_COPY;
1239 else if (op & DragOperationLink)
1240 res = DROPEFFECT_LINK;
1241 else if (op & DragOperationMove)
1242 res = DROPEFFECT_MOVE;
1243 else if (op & DragOperationGeneric)
1244 res = DROPEFFECT_MOVE; // This appears to be the Firefox behaviour
1248 WebCore::DragOperation WebView::keyStateToDragOperation(DWORD grfKeyState) const
1251 return DragOperationNone;
1253 // Conforms to Microsoft's key combinations as documented for
1254 // IDropTarget::DragOver. Note, grfKeyState is the current
1255 // state of the keyboard modifier keys on the keyboard. See:
1256 // <http://msdn.microsoft.com/en-us/library/ms680129(VS.85).aspx>.
1257 DragOperation operation = m_page->dragOperation();
1259 if ((grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT))
1260 operation = DragOperationLink;
1261 else if ((grfKeyState & MK_CONTROL) == MK_CONTROL)
1262 operation = DragOperationCopy;
1263 else if ((grfKeyState & MK_SHIFT) == MK_SHIFT)
1264 operation = DragOperationGeneric;
1269 HRESULT STDMETHODCALLTYPE WebView::DragEnter(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
1272 m_page->resetDragOperation();
1274 if (m_dropTargetHelper)
1275 m_dropTargetHelper->DragEnter(m_window, pDataObject, (POINT*)&pt, *pdwEffect);
1277 POINTL localpt = pt;
1278 ::ScreenToClient(m_window, (LPPOINT)&localpt);
1279 DragData data(pDataObject, IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
1280 m_page->performDragControllerAction(DragControllerActionEntered, &data);
1281 *pdwEffect = dragOperationToDragCursor(m_page->dragOperation());
1283 m_lastDropEffect = *pdwEffect;
1284 m_dragData = pDataObject;
1289 HRESULT STDMETHODCALLTYPE WebView::DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
1291 if (m_dropTargetHelper)
1292 m_dropTargetHelper->DragOver((POINT*)&pt, *pdwEffect);
1295 POINTL localpt = pt;
1296 ::ScreenToClient(m_window, (LPPOINT)&localpt);
1297 DragData data(m_dragData.get(), IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
1298 m_page->performDragControllerAction(DragControllerActionUpdated, &data);
1299 *pdwEffect = dragOperationToDragCursor(m_page->dragOperation());
1301 *pdwEffect = DROPEFFECT_NONE;
1303 m_lastDropEffect = *pdwEffect;
1307 HRESULT STDMETHODCALLTYPE WebView::DragLeave()
1309 if (m_dropTargetHelper)
1310 m_dropTargetHelper->DragLeave();
1313 DragData data(m_dragData.get(), IntPoint(), IntPoint(), DragOperationNone);
1314 m_page->performDragControllerAction(DragControllerActionExited, &data);
1316 m_page->resetDragOperation();
1321 HRESULT STDMETHODCALLTYPE WebView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
1323 if (m_dropTargetHelper)
1324 m_dropTargetHelper->Drop(pDataObject, (POINT*)&pt, *pdwEffect);
1327 *pdwEffect = m_lastDropEffect;
1328 POINTL localpt = pt;
1329 ::ScreenToClient(m_window, (LPPOINT)&localpt);
1330 DragData data(pDataObject, IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
1331 m_page->performDragControllerAction(DragControllerActionPerformDrag, &data);
1335 } // namespace WebKit