#include "config.h"
#include "WebView.h"
#include "DrawingAreaProxyImpl.h"
#include "FindIndicator.h"
#include "Logging.h"
#include "NativeWebKeyboardEvent.h"
#include "NativeWebMouseEvent.h"
#include "NativeWebWheelEvent.h"
#include "WKAPICast.h"
#include "WebContext.h"
#include "WebContextMenuProxyWin.h"
#include "WebEditCommandProxy.h"
#include "WebEventFactory.h"
#include "WebPageProxy.h"
#include "WebPopupMenuProxyWin.h"
#include <Commctrl.h>
#include <WebCore/BitmapInfo.h>
#include <WebCore/Cursor.h>
#include <WebCore/DragSession.h>
#include <WebCore/Editor.h>
#include <WebCore/FileSystem.h>
#include <WebCore/FloatRect.h>
#include <WebCore/HWndDC.h>
#include <WebCore/IntRect.h>
#include <WebCore/NotImplemented.h>
#include <WebCore/Region.h>
#include <WebCore/RunLoop.h>
#include <WebCore/SoftLinking.h>
#include <WebCore/WebCoreInstanceHandle.h>
#include <WebCore/WindowMessageBroadcaster.h>
#include <WebCore/WindowsTouch.h>
#include <wtf/text/WTFString.h>
#if USE(CG)
#include "WKCACFViewWindow.h"
#include <WebCore/GraphicsContextCG.h>
#endif
#if ENABLE(FULLSCREEN_API)
#include "WebFullScreenManagerProxy.h"
#include <WebCore/FullScreenController.h>
#endif
namespace Ime {
SOFT_LINK_LIBRARY(IMM32)
SOFT_LINK(IMM32, ImmGetContext, HIMC, WINAPI, (HWND hwnd), (hwnd))
SOFT_LINK(IMM32, ImmReleaseContext, BOOL, WINAPI, (HWND hWnd, HIMC hIMC), (hWnd, hIMC))
SOFT_LINK(IMM32, ImmGetCompositionStringW, LONG, WINAPI, (HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen), (hIMC, dwIndex, lpBuf, dwBufLen))
SOFT_LINK(IMM32, ImmSetCandidateWindow, BOOL, WINAPI, (HIMC hIMC, LPCANDIDATEFORM lpCandidate), (hIMC, lpCandidate))
SOFT_LINK(IMM32, ImmSetOpenStatus, BOOL, WINAPI, (HIMC hIMC, BOOL fOpen), (hIMC, fOpen))
SOFT_LINK(IMM32, ImmNotifyIME, BOOL, WINAPI, (HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue), (hIMC, dwAction, dwIndex, dwValue))
SOFT_LINK(IMM32, ImmAssociateContextEx, BOOL, WINAPI, (HWND hWnd, HIMC hIMC, DWORD dwFlags), (hWnd, hIMC, dwFlags))
};
SOFT_LINK_LIBRARY(USER32);
SOFT_LINK_OPTIONAL(USER32, GetGestureInfo, BOOL, WINAPI, (HGESTUREINFO, PGESTUREINFO));
SOFT_LINK_OPTIONAL(USER32, SetGestureConfig, BOOL, WINAPI, (HWND, DWORD, UINT, PGESTURECONFIG, UINT));
SOFT_LINK_OPTIONAL(USER32, CloseGestureInfoHandle, BOOL, WINAPI, (HGESTUREINFO));
SOFT_LINK_LIBRARY(Uxtheme);
SOFT_LINK_OPTIONAL(Uxtheme, BeginPanningFeedback, BOOL, WINAPI, (HWND));
SOFT_LINK_OPTIONAL(Uxtheme, EndPanningFeedback, BOOL, WINAPI, (HWND, BOOL));
SOFT_LINK_OPTIONAL(Uxtheme, UpdatePanningFeedback, BOOL, WINAPI, (HWND, LONG, LONG, BOOL));
using namespace WebCore;
namespace WebKit {
static const LPCWSTR kWebKit2WebViewWindowClassName = L"WebKit2WebViewWindowClass";
const int WM_XP_THEMECHANGED = 0x031A;
const int WM_VISTA_MOUSEHWHEEL = 0x020E;
static const int kMaxToolTipWidth = 250;
enum {
UpdateActiveStateTimer = 1,
};
LRESULT CALLBACK WebView::WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LONG_PTR longPtr = ::GetWindowLongPtr(hWnd, 0);
if (WebView* webView = reinterpret_cast<WebView*>(longPtr))
return webView->wndProc(hWnd, message, wParam, lParam);
if (message == WM_CREATE) {
LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
::SetWindowLongPtr(hWnd, 0, (LONG_PTR)createStruct->lpCreateParams);
return 0;
}
return ::DefWindowProc(hWnd, message, wParam, lParam);
}
LRESULT WebView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = 0;
bool handled = true;
switch (message) {
case WM_CLOSE:
m_page->tryClose();
break;
case WM_DESTROY:
m_isBeingDestroyed = true;
close();
break;
case WM_ERASEBKGND:
lResult = 1;
break;
case WM_PAINT:
lResult = onPaintEvent(hWnd, message, wParam, lParam, handled);
break;
case WM_PRINTCLIENT:
lResult = onPrintClientEvent(hWnd, message, wParam, lParam, handled);
break;
case WM_MOUSEACTIVATE:
setWasActivatedByMouseEvent(true);
handled = false;
break;
case WM_MOUSEMOVE:
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_MBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
case WM_MOUSELEAVE:
lResult = onMouseEvent(hWnd, message, wParam, lParam, handled);
break;
case WM_MOUSEWHEEL:
case WM_VISTA_MOUSEHWHEEL:
lResult = onWheelEvent(hWnd, message, wParam, lParam, handled);
break;
case WM_HSCROLL:
lResult = onHorizontalScroll(hWnd, message, wParam, lParam, handled);
break;
case WM_VSCROLL:
lResult = onVerticalScroll(hWnd, message, wParam, lParam, handled);
break;
case WM_GESTURENOTIFY:
lResult = onGestureNotify(hWnd, message, wParam, lParam, handled);
break;
case WM_GESTURE:
lResult = onGesture(hWnd, message, wParam, lParam, handled);
break;
case WM_SYSKEYDOWN:
case WM_KEYDOWN:
case WM_SYSCHAR:
case WM_CHAR:
case WM_SYSKEYUP:
case WM_KEYUP:
lResult = onKeyEvent(hWnd, message, wParam, lParam, handled);
break;
case WM_SIZE:
lResult = onSizeEvent(hWnd, message, wParam, lParam, handled);
break;
case WM_WINDOWPOSCHANGED:
lResult = onWindowPositionChangedEvent(hWnd, message, wParam, lParam, handled);
break;
case WM_SETFOCUS:
lResult = onSetFocusEvent(hWnd, message, wParam, lParam, handled);
break;
case WM_KILLFOCUS:
lResult = onKillFocusEvent(hWnd, message, wParam, lParam, handled);
break;
case WM_TIMER:
lResult = onTimerEvent(hWnd, message, wParam, lParam, handled);
break;
case WM_SHOWWINDOW:
lResult = onShowWindowEvent(hWnd, message, wParam, lParam, handled);
break;
case WM_SETCURSOR:
lResult = onSetCursor(hWnd, message, wParam, lParam, handled);
break;
case WM_IME_STARTCOMPOSITION:
handled = onIMEStartComposition();
break;
case WM_IME_REQUEST:
lResult = onIMERequest(wParam, lParam);
break;
case WM_IME_COMPOSITION:
handled = onIMEComposition(lParam);
break;
case WM_IME_ENDCOMPOSITION:
handled = onIMEEndComposition();
break;
case WM_IME_SELECT:
handled = onIMESelect(wParam, lParam);
break;
case WM_IME_SETCONTEXT:
handled = onIMESetContext(wParam, lParam);
break;
default:
handled = false;
break;
}
if (!handled)
lResult = ::DefWindowProc(hWnd, message, wParam, lParam);
return lResult;
}
bool WebView::registerWebViewWindowClass()
{
static bool haveRegisteredWindowClass = false;
if (haveRegisteredWindowClass)
return true;
haveRegisteredWindowClass = true;
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_DBLCLKS;
wcex.lpfnWndProc = WebView::WebViewWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(WebView*);
wcex.hInstance = instanceHandle();
wcex.hIcon = 0;
wcex.hCursor = ::LoadCursor(0, IDC_ARROW);
wcex.hbrBackground = 0;
wcex.lpszMenuName = 0;
wcex.lpszClassName = kWebKit2WebViewWindowClassName;
wcex.hIconSm = 0;
return !!::RegisterClassEx(&wcex);
}
WebView::WebView(RECT rect, WebContext* context, WebPageGroup* pageGroup, HWND parentWindow)
: m_topLevelParentWindow(0)
, m_toolTipWindow(0)
, m_lastCursorSet(0)
, m_webCoreCursor(0)
, m_overrideCursor(0)
, m_trackingMouseLeave(false)
, m_isInWindow(false)
, m_isVisible(false)
, m_wasActivatedByMouseEvent(false)
, m_isBeingDestroyed(false)
, m_inIMEComposition(0)
, m_findIndicatorCallback(0)
, m_findIndicatorCallbackContext(0)
, m_pageOverlayInstalled(false)
, m_lastPanX(0)
, m_lastPanY(0)
, m_overPanY(0)
, m_gestureReachedScrollingLimit(false)
#if USE(ACCELERATED_COMPOSITING)
, m_layerHostWindow(0)
#endif
{
registerWebViewWindowClass();
m_window = ::CreateWindowExW(0, kWebKit2WebViewWindowClassName, 0, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE,
rect.top, rect.left, rect.right - rect.left, rect.bottom - rect.top, parentWindow ? parentWindow : HWND_MESSAGE, 0, instanceHandle(), this);
ASSERT(::IsWindow(m_window));
ASSERT(m_isVisible == static_cast<bool>(::GetWindowLong(m_window, GWL_STYLE) & WS_VISIBLE));
m_page = context->createWebPage(this, pageGroup);
m_page->initializeWebPage();
CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, IID_IDropTargetHelper, (void**)&m_dropTargetHelper);
initializeToolTipWindow();
windowAncestryDidChange();
#if ENABLE(FULLSCREEN_API)
m_page->fullScreenManager()->setWebView(this);
#endif
}
WebView::~WebView()
{
if (::IsWindow(m_toolTipWindow))
::DestroyWindow(m_toolTipWindow);
}
void WebView::initialize()
{
::RegisterDragDrop(m_window, this);
if (shouldInitializeTrackPointHack()) {
::CreateWindow(TEXT("SCROLLBAR"), TEXT("FAKETRACKPOINTHSCROLLBAR"), WS_CHILD | WS_VISIBLE | SBS_HORZ, 0, 0, 0, 0, m_window, 0, instanceHandle(), 0);
::CreateWindow(TEXT("SCROLLBAR"), TEXT("FAKETRACKPOINTVSCROLLBAR"), WS_CHILD | WS_VISIBLE | SBS_VERT, 0, 0, 0, 0, m_window, 0, instanceHandle(), 0);
}
}
void WebView::initializeUndoClient(const WKViewUndoClient* client)
{
m_undoClient.initialize(client);
}
void WebView::setParentWindow(HWND parentWindow)
{
if (m_window) {
if (::GetParent(m_window) == parentWindow)
return;
if (parentWindow)
::SetParent(m_window, parentWindow);
else if (!m_isBeingDestroyed) {
::SetParent(m_window, HWND_MESSAGE);
}
}
windowAncestryDidChange();
}
static HWND findTopLevelParentWindow(HWND window)
{
if (!window)
return 0;
HWND current = window;
for (HWND parent = GetParent(current); current; current = parent, parent = GetParent(parent)) {
if (!parent || !(GetWindowLongPtr(current, GWL_STYLE) & (WS_POPUP | WS_CHILD)))
return current;
}
ASSERT_NOT_REACHED();
return 0;
}
void WebView::windowAncestryDidChange()
{
HWND newTopLevelParentWindow;
if (m_window)
newTopLevelParentWindow = findTopLevelParentWindow(m_window);
else {
newTopLevelParentWindow = 0;
}
if (newTopLevelParentWindow == m_topLevelParentWindow)
return;
if (m_topLevelParentWindow)
WindowMessageBroadcaster::removeListener(m_topLevelParentWindow, this);
m_topLevelParentWindow = newTopLevelParentWindow;
if (m_topLevelParentWindow)
WindowMessageBroadcaster::addListener(m_topLevelParentWindow, this);
updateActiveState();
}
LRESULT WebView::onMouseEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
{
NativeWebMouseEvent mouseEvent = NativeWebMouseEvent(hWnd, message, wParam, lParam, m_wasActivatedByMouseEvent);
setWasActivatedByMouseEvent(false);
switch (message) {
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
::SetFocus(m_window);
::SetCapture(m_window);
break;
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
::ReleaseCapture();
break;
case WM_MOUSEMOVE:
startTrackingMouseLeave();
break;
case WM_MOUSELEAVE:
stopTrackingMouseLeave();
break;
case WM_LBUTTONDBLCLK:
case WM_MBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
break;
default:
ASSERT_NOT_REACHED();
}
m_page->handleMouseEvent(mouseEvent);
handled = true;
return 0;
}
LRESULT WebView::onWheelEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
{
NativeWebWheelEvent wheelEvent(hWnd, message, wParam, lParam);
if (wheelEvent.controlKey()) {
handled = false;
return 0;
}
m_page->handleWheelEvent(wheelEvent);
handled = true;
return 0;
}
LRESULT WebView::onHorizontalScroll(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
{
ScrollDirection direction;
ScrollGranularity granularity;
switch (LOWORD(wParam)) {
case SB_LINELEFT:
granularity = ScrollByLine;
direction = ScrollLeft;
break;
case SB_LINERIGHT:
granularity = ScrollByLine;
direction = ScrollRight;
break;
case SB_PAGELEFT:
granularity = ScrollByDocument;
direction = ScrollLeft;
break;
case SB_PAGERIGHT:
granularity = ScrollByDocument;
direction = ScrollRight;
break;
default:
handled = false;
return 0;
}
m_page->scrollBy(direction, granularity);
handled = true;
return 0;
}
LRESULT WebView::onVerticalScroll(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
{
ScrollDirection direction;
ScrollGranularity granularity;
switch (LOWORD(wParam)) {
case SB_LINEDOWN:
granularity = ScrollByLine;
direction = ScrollDown;
break;
case SB_LINEUP:
granularity = ScrollByLine;
direction = ScrollUp;
break;
case SB_PAGEDOWN:
granularity = ScrollByDocument;
direction = ScrollDown;
break;
case SB_PAGEUP:
granularity = ScrollByDocument;
direction = ScrollUp;
break;
default:
handled = false;
return 0;
}
m_page->scrollBy(direction, granularity);
handled = true;
return 0;
}
LRESULT WebView::onGestureNotify(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
{
ASSERT(SetGestureConfigPtr());
GESTURENOTIFYSTRUCT* gn = reinterpret_cast<GESTURENOTIFYSTRUCT*>(lParam);
POINT localPoint = { gn->ptsLocation.x, gn->ptsLocation.y };
::ScreenToClient(m_window, &localPoint);
bool canPan = m_page->gestureWillBegin(localPoint);
DWORD dwPanWant = GC_PAN | GC_PAN_WITH_INERTIA | GC_PAN_WITH_GUTTER;
DWORD dwPanBlock = GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
if (canPan)
dwPanWant |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
else
dwPanBlock |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
GESTURECONFIG gc = { GID_PAN, dwPanWant, dwPanBlock };
return SetGestureConfigPtr()(m_window, 0, 1, &gc, sizeof(gc));
}
LRESULT WebView::onGesture(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
{
ASSERT(GetGestureInfoPtr());
ASSERT(CloseGestureInfoHandlePtr());
ASSERT(UpdatePanningFeedbackPtr());
ASSERT(BeginPanningFeedbackPtr());
ASSERT(EndPanningFeedbackPtr());
if (!GetGestureInfoPtr() || !CloseGestureInfoHandlePtr() || !UpdatePanningFeedbackPtr() || !BeginPanningFeedbackPtr() || !EndPanningFeedbackPtr()) {
handled = false;
return 0;
}
HGESTUREINFO gestureHandle = reinterpret_cast<HGESTUREINFO>(lParam);
GESTUREINFO gi = {0};
gi.cbSize = sizeof(GESTUREINFO);
if (!GetGestureInfoPtr()(gestureHandle, &gi)) {
handled = false;
return 0;
}
switch (gi.dwID) {
case GID_BEGIN:
m_lastPanX = gi.ptsLocation.x;
m_lastPanY = gi.ptsLocation.y;
break;
case GID_END:
m_page->gestureDidEnd();
break;
case GID_PAN: {
int currentX = gi.ptsLocation.x;
int currentY = gi.ptsLocation.y;
int deltaX = m_lastPanX - currentX;
int deltaY = m_lastPanY - currentY;
m_lastPanX = currentX;
m_lastPanY = currentY;
m_overPanY -= deltaY;
if (deltaX || deltaY)
m_page->gestureDidScroll(IntSize(deltaX, deltaY));
if (gi.dwFlags & GF_BEGIN) {
BeginPanningFeedbackPtr()(m_window);
m_gestureReachedScrollingLimit = false;
m_overPanY = 0;
} else if (gi.dwFlags & GF_END) {
EndPanningFeedbackPtr()(m_window, true);
m_overPanY = 0;
}
if (m_gestureReachedScrollingLimit)
UpdatePanningFeedbackPtr()(m_window, 0, m_overPanY, gi.dwFlags & GF_INERTIA);
CloseGestureInfoHandlePtr()(gestureHandle);
handled = true;
return 0;
}
default:
break;
}
handled = false;
return 0;
}
LRESULT WebView::onKeyEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
{
#if ENABLE(FULLSCREEN_API)
if (message == WM_KEYDOWN && wParam == VK_ESCAPE && m_fullScreenController && m_fullScreenController->isFullScreen()) {
m_fullScreenController->exitFullScreen();
return false;
}
#endif
m_page->handleKeyboardEvent(NativeWebKeyboardEvent(hWnd, message, wParam, lParam));
handled = true;
return 0;
}
static void drawPageBackground(HDC dc, const WebPageProxy* page, const RECT& rect)
{
if (!page->drawsBackground() || page->drawsTransparentBackground())
return;
::FillRect(dc, &rect, reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1));
}
void WebView::paint(HDC hdc, const IntRect& dirtyRect)
{
m_page->endPrinting();
if (DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(m_page->drawingArea())) {
Region unpaintedRegion;
drawingArea->paint(hdc, dirtyRect, unpaintedRegion);
Vector<IntRect> unpaintedRects = unpaintedRegion.rects();
for (size_t i = 0; i < unpaintedRects.size(); ++i) {
RECT winRect = unpaintedRects[i];
drawPageBackground(hdc, m_page.get(), unpaintedRects[i]);
}
} else
drawPageBackground(hdc, m_page.get(), dirtyRect);
m_page->didDraw();
}
static void flashRects(HDC dc, const IntRect rects[], size_t rectCount, HBRUSH brush)
{
for (size_t i = 0; i < rectCount; ++i) {
RECT winRect = rects[i];
::FillRect(dc, &winRect, brush);
}
::GdiFlush();
::Sleep(50);
}
static OwnPtr<HBRUSH> createBrush(const Color& color)
{
return adoptPtr(::CreateSolidBrush(RGB(color.red(), color.green(), color.blue())));
}
LRESULT WebView::onPaintEvent(HWND hWnd, UINT message, WPARAM, LPARAM, bool& handled)
{
updateChildWindowGeometries();
PAINTSTRUCT paintStruct;
HDC hdc = ::BeginPaint(m_window, &paintStruct);
if (WebPageProxy::debugPaintFlags() & kWKDebugFlashViewUpdates) {
static HBRUSH brush = createBrush(WebPageProxy::viewUpdatesFlashColor().rgb()).leakPtr();
IntRect rect = paintStruct.rcPaint;
flashRects(hdc, &rect, 1, brush);
}
paint(hdc, paintStruct.rcPaint);
::EndPaint(m_window, &paintStruct);
handled = true;
return 0;
}
LRESULT WebView::onPrintClientEvent(HWND hWnd, UINT, WPARAM wParam, LPARAM, bool& handled)
{
HDC hdc = reinterpret_cast<HDC>(wParam);
RECT winRect;
::GetClientRect(hWnd, &winRect);
bool wasVisible = isViewVisible();
if (!wasVisible)
setIsVisible(true);
paint(hdc, winRect);
if (!wasVisible)
setIsVisible(false);
handled = true;
return 0;
}
LRESULT WebView::onSizeEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
{
int width = LOWORD(lParam);
int height = HIWORD(lParam);
if (m_page && m_page->drawingArea()) {
m_page->drawingArea()->setSize(IntSize(width, height), m_nextResizeScrollOffset);
m_nextResizeScrollOffset = IntSize();
}
#if USE(ACCELERATED_COMPOSITING)
if (m_layerHostWindow)
::MoveWindow(m_layerHostWindow, 0, 0, width, height, FALSE);
#endif
handled = true;
return 0;
}
LRESULT WebView::onWindowPositionChangedEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
{
if (reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_SHOWWINDOW)
updateActiveStateSoon();
handled = false;
return 0;
}
LRESULT WebView::onSetFocusEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
{
m_page->viewStateDidChange(WebPageProxy::ViewIsFocused);
handled = true;
return 0;
}
LRESULT WebView::onKillFocusEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
{
m_page->viewStateDidChange(WebPageProxy::ViewIsFocused);
handled = true;
return 0;
}
LRESULT WebView::onTimerEvent(HWND hWnd, UINT, WPARAM wParam, LPARAM, bool& handled)
{
switch (wParam) {
case UpdateActiveStateTimer:
::KillTimer(hWnd, UpdateActiveStateTimer);
updateActiveState();
break;
}
handled = true;
return 0;
}
LRESULT WebView::onShowWindowEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
{
if (!lParam)
setIsVisible(wParam);
handled = false;
return 0;
}
LRESULT WebView::onSetCursor(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
{
if (!m_lastCursorSet) {
handled = false;
return 0;
}
::SetCursor(m_lastCursorSet);
return 0;
}
void WebView::updateActiveState()
{
m_page->viewStateDidChange(WebPageProxy::ViewWindowIsActive);
}
void WebView::updateActiveStateSoon()
{
::SetTimer(m_window, UpdateActiveStateTimer, 0, 0);
}
static bool initCommonControls()
{
static bool haveInitialized = false;
if (haveInitialized)
return true;
INITCOMMONCONTROLSEX init;
init.dwSize = sizeof(init);
init.dwICC = ICC_TREEVIEW_CLASSES;
haveInitialized = !!::InitCommonControlsEx(&init);
return haveInitialized;
}
void WebView::initializeToolTipWindow()
{
if (!initCommonControls())
return;
m_toolTipWindow = ::CreateWindowEx(WS_EX_TRANSPARENT, TOOLTIPS_CLASS, 0, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
m_window, 0, 0, 0);
if (!m_toolTipWindow)
return;
TOOLINFO info = {0};
info.cbSize = sizeof(info);
info.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
info.uId = reinterpret_cast<UINT_PTR>(m_window);
::SendMessage(m_toolTipWindow, TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(&info));
::SendMessage(m_toolTipWindow, TTM_SETMAXTIPWIDTH, 0, kMaxToolTipWidth);
::SetWindowPos(m_toolTipWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
void WebView::startTrackingMouseLeave()
{
if (m_trackingMouseLeave)
return;
m_trackingMouseLeave = true;
TRACKMOUSEEVENT trackMouseEvent;
trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
trackMouseEvent.dwFlags = TME_LEAVE;
trackMouseEvent.hwndTrack = m_window;
::TrackMouseEvent(&trackMouseEvent);
}
void WebView::stopTrackingMouseLeave()
{
if (!m_trackingMouseLeave)
return;
m_trackingMouseLeave = false;
TRACKMOUSEEVENT trackMouseEvent;
trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
trackMouseEvent.dwFlags = TME_LEAVE | TME_CANCEL;
trackMouseEvent.hwndTrack = m_window;
::TrackMouseEvent(&trackMouseEvent);
}
bool WebView::shouldInitializeTrackPointHack()
{
static bool shouldCreateScrollbars;
static bool hasRunTrackPointCheck;
if (hasRunTrackPointCheck)
return shouldCreateScrollbars;
hasRunTrackPointCheck = true;
const wchar_t* trackPointKeys[] = {
L"Software\\Lenovo\\TrackPoint",
L"Software\\Lenovo\\UltraNav",
L"Software\\Alps\\Apoint\\TrackPoint",
L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2"
};
for (size_t i = 0; i < WTF_ARRAY_LENGTH(trackPointKeys); ++i) {
HKEY trackPointKey;
int readKeyResult = ::RegOpenKeyExW(HKEY_CURRENT_USER, trackPointKeys[i], 0, KEY_READ, &trackPointKey);
::RegCloseKey(trackPointKey);
if (readKeyResult == ERROR_SUCCESS) {
shouldCreateScrollbars = true;
return shouldCreateScrollbars;
}
}
return shouldCreateScrollbars;
}
void WebView::close()
{
m_undoClient.initialize(0);
::RevokeDragDrop(m_window);
if (m_window) {
if (!m_isBeingDestroyed)
DestroyWindow(m_window);
m_window = 0;
}
setParentWindow(0);
m_page->close();
}
PassOwnPtr<DrawingAreaProxy> WebView::createDrawingAreaProxy()
{
return DrawingAreaProxyImpl::create(m_page.get());
}
void WebView::setViewNeedsDisplay(const WebCore::IntRect& rect)
{
RECT r = rect;
::InvalidateRect(m_window, &r, false);
}
void WebView::displayView()
{
::UpdateWindow(m_window);
}
void WebView::scrollView(const IntRect& scrollRect, const IntSize& scrollOffset)
{
setViewNeedsDisplay(scrollRect);
}
void WebView::flashBackingStoreUpdates(const Vector<IntRect>& updateRects)
{
static HBRUSH brush = createBrush(WebPageProxy::backingStoreUpdatesFlashColor().rgb()).leakPtr();
HWndDC dc(m_window);
flashRects(dc, updateRects.data(), updateRects.size(), brush);
}
WebCore::IntSize WebView::viewSize()
{
RECT clientRect;
GetClientRect(m_window, &clientRect);
return IntRect(clientRect).size();
}
bool WebView::isViewWindowActive()
{
HWND activeWindow = ::GetActiveWindow();
return (activeWindow && m_topLevelParentWindow == findTopLevelParentWindow(activeWindow));
}
bool WebView::isViewFocused()
{
return ::GetFocus() == m_window;
}
bool WebView::isViewVisible()
{
return m_isVisible;
}
bool WebView::isViewInWindow()
{
return m_isInWindow;
}
void WebView::pageClosed()
{
}
void WebView::processDidCrash()
{
updateNativeCursor();
::InvalidateRect(m_window, 0, TRUE);
}
void WebView::didRelaunchProcess()
{
updateNativeCursor();
::InvalidateRect(m_window, 0, TRUE);
}
void WebView::toolTipChanged(const String&, const String& newToolTip)
{
if (!m_toolTipWindow)
return;
if (!newToolTip.isEmpty()) {
String toolTip = newToolTip;
TOOLINFO info = {0};
info.cbSize = sizeof(info);
info.uFlags = TTF_IDISHWND;
info.uId = reinterpret_cast<UINT_PTR>(m_window);
info.lpszText = const_cast<UChar*>(toolTip.charactersWithNullTermination());
::SendMessage(m_toolTipWindow, TTM_UPDATETIPTEXT, 0, reinterpret_cast<LPARAM>(&info));
}
::SendMessage(m_toolTipWindow, TTM_ACTIVATE, !newToolTip.isEmpty(), 0);
}
HCURSOR WebView::cursorToShow() const
{
if (!m_page->isValid())
return 0;
static HCURSOR arrowCursor = ::LoadCursor(0, IDC_ARROW);
if (m_overrideCursor && m_webCoreCursor == arrowCursor)
return m_overrideCursor;
return m_webCoreCursor;
}
void WebView::updateNativeCursor()
{
m_lastCursorSet = cursorToShow();
if (!m_lastCursorSet)
return;
::SetCursor(m_lastCursorSet);
}
void WebView::setCursor(const WebCore::Cursor& cursor)
{
if (!cursor.platformCursor()->nativeCursor())
return;
m_webCoreCursor = cursor.platformCursor()->nativeCursor();
updateNativeCursor();
}
void WebView::setCursorHiddenUntilMouseMoves(bool)
{
notImplemented();
}
void WebView::setOverrideCursor(HCURSOR overrideCursor)
{
m_overrideCursor = overrideCursor;
updateNativeCursor();
}
void WebView::setInitialFocus(bool forward, bool isKeyboardEventValid, const WebKeyboardEvent& event)
{
m_page->setInitialFocus(forward, isKeyboardEventValid, event);
}
void WebView::setScrollOffsetOnNextResize(const IntSize& scrollOffset)
{
m_nextResizeScrollOffset = scrollOffset;
}
void WebView::didChangeViewportProperties(const WebCore::ViewportAttributes&)
{
}
void WebView::registerEditCommand(PassRefPtr<WebEditCommandProxy> prpCommand, WebPageProxy::UndoOrRedo undoOrRedo)
{
RefPtr<WebEditCommandProxy> command = prpCommand;
m_undoClient.registerEditCommand(this, command, undoOrRedo);
}
void WebView::clearAllEditCommands()
{
m_undoClient.clearAllEditCommands(this);
}
bool WebView::canUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
{
return m_undoClient.canUndoRedo(this, undoOrRedo);
}
void WebView::executeUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
{
m_undoClient.executeUndoRedo(this, undoOrRedo);
}
void WebView::reapplyEditCommand(WebEditCommandProxy* command)
{
if (!m_page->isValid() || !m_page->isValidEditCommand(command))
return;
command->reapply();
}
void WebView::unapplyEditCommand(WebEditCommandProxy* command)
{
if (!m_page->isValid() || !m_page->isValidEditCommand(command))
return;
command->unapply();
}
void WebView::setCustomDropTarget(IDropTarget* dropTarget)
{
if (!m_page->isValid() || !m_window)
return;
::RevokeDragDrop(m_window);
if (dropTarget)
::RegisterDragDrop(m_window, dropTarget);
else
::RegisterDragDrop(m_window, this);
}
FloatRect WebView::convertToDeviceSpace(const FloatRect& rect)
{
return rect;
}
IntPoint WebView::screenToWindow(const IntPoint& point)
{
return point;
}
IntRect WebView::windowToScreen(const IntRect& rect)
{
return rect;
}
FloatRect WebView::convertToUserSpace(const FloatRect& rect)
{
return rect;
}
HIMC WebView::getIMMContext()
{
return Ime::ImmGetContext(m_window);
}
void WebView::prepareCandidateWindow(HIMC hInputContext)
{
IntRect caret = m_page->firstRectForCharacterInSelectedRange(0);
CANDIDATEFORM form;
form.dwIndex = 0;
form.dwStyle = CFS_EXCLUDE;
form.ptCurrentPos.x = caret.x();
form.ptCurrentPos.y = caret.maxY();
form.rcArea.top = caret.y();
form.rcArea.bottom = caret.maxY();
form.rcArea.left = caret.x();
form.rcArea.right = caret.maxX();
Ime::ImmSetCandidateWindow(hInputContext, &form);
}
void WebView::resetIME()
{
HIMC hInputContext = getIMMContext();
if (!hInputContext)
return;
Ime::ImmNotifyIME(hInputContext, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
Ime::ImmReleaseContext(m_window, hInputContext);
}
void WebView::setInputMethodState(bool enabled)
{
Ime::ImmAssociateContextEx(m_window, 0, enabled ? IACE_DEFAULT : 0);
}
void WebView::compositionSelectionChanged(bool hasChanged)
{
if (m_page->editorState().hasComposition && !hasChanged)
resetIME();
}
bool WebView::onIMEStartComposition()
{
LOG(TextInput, "onIMEStartComposition");
m_inIMEComposition++;
HIMC hInputContext = getIMMContext();
if (!hInputContext)
return false;
prepareCandidateWindow(hInputContext);
Ime::ImmReleaseContext(m_window, hInputContext);
return true;
}
static bool getCompositionString(HIMC hInputContext, DWORD type, String& result)
{
LONG compositionLength = Ime::ImmGetCompositionStringW(hInputContext, type, 0, 0);
if (compositionLength <= 0)
return false;
Vector<UChar> compositionBuffer(compositionLength / 2);
compositionLength = Ime::ImmGetCompositionStringW(hInputContext, type, compositionBuffer.data(), compositionLength);
result = String::adopt(compositionBuffer);
return true;
}
static void compositionToUnderlines(const Vector<DWORD>& clauses, const Vector<BYTE>& attributes, Vector<CompositionUnderline>& underlines)
{
if (clauses.isEmpty()) {
underlines.clear();
return;
}
size_t numBoundaries = clauses.size() - 1;
underlines.resize(numBoundaries);
for (unsigned i = 0; i < numBoundaries; ++i) {
underlines[i].startOffset = clauses[i];
underlines[i].endOffset = clauses[i + 1];
BYTE attribute = attributes[clauses[i]];
underlines[i].thick = attribute == ATTR_TARGET_CONVERTED || attribute == ATTR_TARGET_NOTCONVERTED;
underlines[i].color = Color::black;
}
}
#if !LOG_DISABLED
#define APPEND_ARGUMENT_NAME(name) \
if (lparam & name) { \
if (needsComma) \
result += ", "; \
result += #name; \
needsComma = true; \
}
static String imeCompositionArgumentNames(LPARAM lparam)
{
String result;
bool needsComma = false;
APPEND_ARGUMENT_NAME(GCS_COMPATTR);
APPEND_ARGUMENT_NAME(GCS_COMPCLAUSE);
APPEND_ARGUMENT_NAME(GCS_COMPREADSTR);
APPEND_ARGUMENT_NAME(GCS_COMPREADATTR);
APPEND_ARGUMENT_NAME(GCS_COMPREADCLAUSE);
APPEND_ARGUMENT_NAME(GCS_COMPSTR);
APPEND_ARGUMENT_NAME(GCS_CURSORPOS);
APPEND_ARGUMENT_NAME(GCS_DELTASTART);
APPEND_ARGUMENT_NAME(GCS_RESULTCLAUSE);
APPEND_ARGUMENT_NAME(GCS_RESULTREADCLAUSE);
APPEND_ARGUMENT_NAME(GCS_RESULTREADSTR);
APPEND_ARGUMENT_NAME(GCS_RESULTSTR);
APPEND_ARGUMENT_NAME(CS_INSERTCHAR);
APPEND_ARGUMENT_NAME(CS_NOMOVECARET);
return result;
}
static String imeRequestName(WPARAM wparam)
{
switch (wparam) {
case IMR_CANDIDATEWINDOW:
return "IMR_CANDIDATEWINDOW";
case IMR_COMPOSITIONFONT:
return "IMR_COMPOSITIONFONT";
case IMR_COMPOSITIONWINDOW:
return "IMR_COMPOSITIONWINDOW";
case IMR_CONFIRMRECONVERTSTRING:
return "IMR_CONFIRMRECONVERTSTRING";
case IMR_DOCUMENTFEED:
return "IMR_DOCUMENTFEED";
case IMR_QUERYCHARPOSITION:
return "IMR_QUERYCHARPOSITION";
case IMR_RECONVERTSTRING:
return "IMR_RECONVERTSTRING";
default:
return "Unknown (" + String::number(wparam) + ")";
}
}
#endif
bool WebView::onIMEComposition(LPARAM lparam)
{
LOG(TextInput, "onIMEComposition %s", imeCompositionArgumentNames(lparam).latin1().data());
HIMC hInputContext = getIMMContext();
if (!hInputContext)
return true;
if (!m_page->editorState().isContentEditable)
return true;
prepareCandidateWindow(hInputContext);
if (lparam & GCS_RESULTSTR || !lparam) {
String compositionString;
if (!getCompositionString(hInputContext, GCS_RESULTSTR, compositionString) && lparam)
return true;
m_page->confirmComposition(compositionString);
return true;
}
String compositionString;
if (!getCompositionString(hInputContext, GCS_COMPSTR, compositionString))
return true;
int numAttributes = Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPATTR, 0, 0);
Vector<BYTE> attributes(numAttributes);
Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPATTR, attributes.data(), numAttributes);
int numBytes = Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPCLAUSE, 0, 0);
Vector<DWORD> clauses(numBytes / sizeof(DWORD));
Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPCLAUSE, clauses.data(), numBytes);
Vector<CompositionUnderline> underlines;
compositionToUnderlines(clauses, attributes, underlines);
int cursorPosition = LOWORD(Ime::ImmGetCompositionStringW(hInputContext, GCS_CURSORPOS, 0, 0));
m_page->setComposition(compositionString, underlines, cursorPosition);
return true;
}
bool WebView::onIMEEndComposition()
{
LOG(TextInput, "onIMEEndComposition");
if (m_page->editorState().hasComposition)
m_page->confirmComposition(String());
if (m_inIMEComposition)
m_inIMEComposition--;
return true;
}
LRESULT WebView::onIMERequestCharPosition(IMECHARPOSITION* charPos)
{
if (charPos->dwCharPos && !m_page->editorState().hasComposition)
return 0;
IntRect caret = m_page->firstRectForCharacterInSelectedRange(charPos->dwCharPos);
charPos->pt.x = caret.x();
charPos->pt.y = caret.y();
::ClientToScreen(m_window, &charPos->pt);
charPos->cLineHeight = caret.height();
::GetWindowRect(m_window, &charPos->rcDocument);
return true;
}
LRESULT WebView::onIMERequestReconvertString(RECONVERTSTRING* reconvertString)
{
String text = m_page->getSelectedText();
unsigned totalSize = sizeof(RECONVERTSTRING) + text.length() * sizeof(UChar);
if (!reconvertString)
return totalSize;
if (totalSize > reconvertString->dwSize)
return 0;
reconvertString->dwCompStrLen = text.length();
reconvertString->dwStrLen = text.length();
reconvertString->dwTargetStrLen = text.length();
reconvertString->dwStrOffset = sizeof(RECONVERTSTRING);
memcpy(reconvertString + 1, text.characters(), text.length() * sizeof(UChar));
return totalSize;
}
LRESULT WebView::onIMERequest(WPARAM request, LPARAM data)
{
LOG(TextInput, "onIMERequest %s", imeRequestName(request).latin1().data());
if (!m_page->editorState().isContentEditable)
return 0;
switch (request) {
case IMR_RECONVERTSTRING:
return onIMERequestReconvertString(reinterpret_cast<RECONVERTSTRING*>(data));
case IMR_QUERYCHARPOSITION:
return onIMERequestCharPosition(reinterpret_cast<IMECHARPOSITION*>(data));
}
return 0;
}
bool WebView::onIMESelect(WPARAM wparam, LPARAM lparam)
{
UNUSED_PARAM(wparam);
UNUSED_PARAM(lparam);
LOG(TextInput, "onIMESelect locale %ld %s", lparam, wparam ? "select" : "deselect");
return false;
}
bool WebView::onIMESetContext(WPARAM wparam, LPARAM)
{
LOG(TextInput, "onIMESetContext %s", wparam ? "active" : "inactive");
return false;
}
void WebView::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool wasEventHandled)
{
if (!wasEventHandled)
::DefWindowProcW(event.nativeEvent()->hwnd, event.nativeEvent()->message, event.nativeEvent()->wParam, event.nativeEvent()->lParam);
}
PassRefPtr<WebPopupMenuProxy> WebView::createPopupMenuProxy(WebPageProxy* page)
{
return WebPopupMenuProxyWin::create(this, page);
}
PassRefPtr<WebContextMenuProxy> WebView::createContextMenuProxy(WebPageProxy* page)
{
return WebContextMenuProxyWin::create(m_window, page);
}
void WebView::setFindIndicator(PassRefPtr<FindIndicator> prpFindIndicator, bool fadeOut, bool animate)
{
UNUSED_PARAM(animate);
if (!m_findIndicatorCallback)
return;
HBITMAP hbmp = 0;
IntRect selectionRect;
if (RefPtr<FindIndicator> findIndicator = prpFindIndicator) {
if (ShareableBitmap* contentImage = findIndicator->contentImage()) {
void* bits;
HDC hdc = ::CreateCompatibleDC(0);
int width = contentImage->bounds().width();
int height = contentImage->bounds().height();
BitmapInfo bitmapInfo = BitmapInfo::create(contentImage->size());
hbmp = CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, static_cast<void**>(&bits), 0, 0);
HBITMAP hbmpOld = static_cast<HBITMAP>(SelectObject(hdc, hbmp));
#if USE(CG)
RetainPtr<CGContextRef> context(AdoptCF, CGBitmapContextCreate(bits, width, height,
8, width * sizeof(RGBQUAD), deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
GraphicsContext graphicsContext(context.get());
contentImage->paint(graphicsContext, IntPoint(), contentImage->bounds());
#else
#endif
::SelectObject(hdc, hbmpOld);
::DeleteDC(hdc);
}
selectionRect = IntRect(findIndicator->selectionRectInWindowCoordinates());
}
(*m_findIndicatorCallback)(toAPI(this), hbmp, selectionRect, fadeOut, m_findIndicatorCallbackContext);
}
void WebView::setFindIndicatorCallback(WKViewFindIndicatorCallback callback, void* context)
{
m_findIndicatorCallback = callback;
m_findIndicatorCallbackContext = context;
}
WKViewFindIndicatorCallback WebView::getFindIndicatorCallback(void** context)
{
if (context)
*context = m_findIndicatorCallbackContext;
return m_findIndicatorCallback;
}
void WebView::didInstallOrUninstallPageOverlay(bool didInstall)
{
m_pageOverlayInstalled = didInstall;
}
void WebView::didCommitLoadForMainFrame(bool useCustomRepresentation)
{
}
void WebView::didFinishLoadingDataForCustomRepresentation(const String& suggestedFilename, const CoreIPC::DataReference&)
{
}
double WebView::customRepresentationZoomFactor()
{
return 1;
}
void WebView::setCustomRepresentationZoomFactor(double)
{
}
void WebView::didChangeScrollbarsForMainFrame() const
{
}
void WebView::findStringInCustomRepresentation(const String&, FindOptions, unsigned)
{
}
void WebView::countStringMatchesInCustomRepresentation(const String&, FindOptions, unsigned)
{
}
void WebView::setIsInWindow(bool isInWindow)
{
m_isInWindow = isInWindow;
m_page->viewStateDidChange(WebPageProxy::ViewIsInWindow);
}
void WebView::setIsVisible(bool isVisible)
{
m_isVisible = isVisible;
if (m_page)
m_page->viewStateDidChange(WebPageProxy::ViewIsVisible);
}
#if USE(ACCELERATED_COMPOSITING)
void WebView::enterAcceleratedCompositingMode(const LayerTreeContext& context)
{
#if HAVE(WKQCA)
ASSERT(!context.isEmpty());
m_layerHostWindow = context.window;
IntSize size = viewSize();
::SetWindowPos(m_layerHostWindow, HWND_BOTTOM, 0, 0, size.width(), size.height(), SWP_SHOWWINDOW | SWP_NOACTIVATE);
#else
ASSERT_NOT_REACHED();
#endif
}
void WebView::exitAcceleratedCompositingMode()
{
#if HAVE(WKQCA)
ASSERT(m_layerHostWindow);
::PostMessageW(m_layerHostWindow, WKCACFViewWindow::customDestroyMessage, 0, 0);
m_layerHostWindow = 0;
#else
ASSERT_NOT_REACHED();
#endif
}
void WebView::updateAcceleratedCompositingMode(const LayerTreeContext&)
{
}
#endif // USE(ACCELERATED_COMPOSITING)
HWND WebView::nativeWindow()
{
return m_window;
}
void WebView::scheduleChildWindowGeometryUpdate(const WindowGeometry& geometry)
{
m_geometriesUpdater.addPendingUpdate(geometry);
}
void WebView::updateChildWindowGeometries()
{
m_geometriesUpdater.updateGeometries(DoNotBringToTop);
}
void WebView::windowReceivedMessage(HWND, UINT message, WPARAM wParam, LPARAM)
{
switch (message) {
case WM_NCACTIVATE:
updateActiveStateSoon();
break;
case WM_SETTINGCHANGE:
break;
}
}
HRESULT STDMETHODCALLTYPE WebView::QueryInterface(REFIID riid, void** ppvObject)
{
*ppvObject = 0;
if (IsEqualGUID(riid, IID_IUnknown))
*ppvObject = static_cast<IUnknown*>(this);
else if (IsEqualGUID(riid, IID_IDropTarget))
*ppvObject = static_cast<IDropTarget*>(this);
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
ULONG STDMETHODCALLTYPE WebView::AddRef(void)
{
ref();
return refCount();
}
ULONG STDMETHODCALLTYPE WebView::Release(void)
{
deref();
return refCount();
}
static DWORD dragOperationToDragCursor(DragOperation op)
{
DWORD res = DROPEFFECT_NONE;
if (op & DragOperationCopy)
res = DROPEFFECT_COPY;
else if (op & DragOperationLink)
res = DROPEFFECT_LINK;
else if (op & DragOperationMove)
res = DROPEFFECT_MOVE;
else if (op & DragOperationGeneric)
res = DROPEFFECT_MOVE; return res;
}
WebCore::DragOperation WebView::keyStateToDragOperation(DWORD grfKeyState) const
{
if (!m_page)
return DragOperationNone;
DragOperation operation = m_page->dragSession().operation;
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(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
{
m_dragData = 0;
m_page->resetDragOperation();
if (m_dropTargetHelper)
m_dropTargetHelper->DragEnter(m_window, pDataObject, (POINT*)&pt, *pdwEffect);
POINTL localpt = pt;
::ScreenToClient(m_window, (LPPOINT)&localpt);
DragData data(pDataObject, IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
m_page->dragEntered(&data);
*pdwEffect = dragOperationToDragCursor(m_page->dragSession().operation);
m_lastDropEffect = *pdwEffect;
m_dragData = pDataObject;
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebView::DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
{
if (m_dropTargetHelper)
m_dropTargetHelper->DragOver((POINT*)&pt, *pdwEffect);
if (m_dragData) {
POINTL localpt = pt;
::ScreenToClient(m_window, (LPPOINT)&localpt);
DragData data(m_dragData.get(), IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
m_page->dragUpdated(&data);
*pdwEffect = dragOperationToDragCursor(m_page->dragSession().operation);
} else
*pdwEffect = DROPEFFECT_NONE;
m_lastDropEffect = *pdwEffect;
return S_OK;
}
HRESULT STDMETHODCALLTYPE WebView::DragLeave()
{
if (m_dropTargetHelper)
m_dropTargetHelper->DragLeave();
if (m_dragData) {
DragData data(m_dragData.get(), IntPoint(), IntPoint(), DragOperationNone);
m_page->dragExited(&data);
m_dragData = 0;
m_page->resetDragOperation();
}
return S_OK;
}
static bool maybeCreateSandboxExtensionFromDragData(const DragData& dragData, SandboxExtension::Handle& sandboxExtensionHandle)
{
if (!dragData.containsFiles())
return false;
SandboxExtension::createHandle("\\", SandboxExtension::ReadOnly, sandboxExtensionHandle);
return true;
}
HRESULT STDMETHODCALLTYPE WebView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
{
if (m_dropTargetHelper)
m_dropTargetHelper->Drop(pDataObject, (POINT*)&pt, *pdwEffect);
m_dragData = 0;
*pdwEffect = m_lastDropEffect;
POINTL localpt = pt;
::ScreenToClient(m_window, (LPPOINT)&localpt);
DragData data(pDataObject, IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
SandboxExtension::Handle sandboxExtensionHandle;
bool createdExtension = maybeCreateSandboxExtensionFromDragData(data, sandboxExtensionHandle);
if (createdExtension)
m_page->process()->willAcquireUniversalFileReadSandboxExtension();
SandboxExtension::HandleArray sandboxExtensionForUpload;
m_page->performDrag(&data, String(), sandboxExtensionHandle, sandboxExtensionForUpload);
return S_OK;
}
#if ENABLE(FULLSCREEN_API)
FullScreenController* WebView::fullScreenController()
{
if (!m_fullScreenController)
m_fullScreenController = adoptPtr(new FullScreenController(this));
return m_fullScreenController.get();
}
HWND WebView::fullScreenClientWindow() const
{
return m_window;
}
HWND WebView::fullScreenClientParentWindow() const
{
return ::GetParent(m_window);
}
void WebView::fullScreenClientSetParentWindow(HWND hostWindow)
{
setParentWindow(hostWindow);
}
void WebView::fullScreenClientWillEnterFullScreen()
{
page()->fullScreenManager()->willEnterFullScreen();
}
void WebView::fullScreenClientDidEnterFullScreen()
{
page()->fullScreenManager()->didEnterFullScreen();
}
void WebView::fullScreenClientWillExitFullScreen()
{
page()->fullScreenManager()->willExitFullScreen();
}
void WebView::fullScreenClientDidExitFullScreen()
{
page()->fullScreenManager()->didExitFullScreen();
}
static void fullScreenClientForceRepaintCompleted(WKErrorRef, void* context)
{
ASSERT(context);
static_cast<WebView*>(context)->fullScreenController()->repaintCompleted();
}
void WebView::fullScreenClientForceRepaint()
{
page()->forceRepaint(VoidCallback::create(this, &fullScreenClientForceRepaintCompleted));
}
#endif
}