http://blog.youkuaiyun.com/shunzi__1984/article/details/6192998
一般在一个网络应用系统中,都会一下几类事件: 网络事件, timer事件,以及设备事件,设备事件主要指鼠标,按键,以及paint等消息事件
webkit也不例外,小弟分析了一下32平台的实现,也无特殊之处
1. 设备事件
设备事件仍然是通过win32平台的消息循环来派发,消息处理函数如下:
- LRESULT CALLBACK WebView::WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- LRESULT lResult = 0;
- LONG_PTR longPtr = GetWindowLongPtr(hWnd, 0);
- WebView* webView = reinterpret_cast<WebView*>(longPtr);
- WebFrame* mainFrameImpl = webView ? webView->topLevelFrame() : 0;
- if (!mainFrameImpl || webView->isBeingDestroyed())
- return DefWindowProc(hWnd, message, wParam, lParam);
- // hold a ref, since the WebView could go away in an event handler.
- COMPtr<WebView> protector(webView);
- ASSERT(webView);
- // Windows Media Player has a modal message loop that will deliver messages
- // to us at inappropriate times and we will crash if we handle them when
- // they are delivered. We repost paint messages so that we eventually get
- // a chance to paint once the modal loop has exited, but other messages
- // aren't safe to repost, so we just drop them.
- if (PluginView::isCallingPlugin()) {
- if (message == WM_PAINT)
- PostMessage(hWnd, message, wParam, lParam);
- return 0;
- }
- bool handled = true;
- switch (message) {
- case WM_PAINT: {
- webView->paint(0, 0);
- break;
- }
- case WM_PRINTCLIENT:
- webView->paint((HDC)wParam, lParam);
- break;
- case WM_DESTROY:
- webView->setIsBeingDestroyed();
- webView->close();
- break;
- case WM_GESTURENOTIFY:
- handled = webView->gestureNotify(wParam, lParam);
- break;
- case WM_GESTURE:
- handled = webView->gesture(wParam, lParam);
- 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:
- case WM_CANCELMODE:
- if (Frame* coreFrame = core(mainFrameImpl))
- if (coreFrame->view()->didFirstLayout())
- handled = webView->handleMouseEvent(message, wParam, lParam);
- break;
- case WM_MOUSEWHEEL:
- case WM_VISTA_MOUSEHWHEEL:
- if (Frame* coreFrame = core(mainFrameImpl))
- if (coreFrame->view()->didFirstLayout())
- handled = webView->mouseWheel(wParam, lParam, message == WM_VISTA_MOUSEHWHEEL);
- break;
- case WM_SYSKEYDOWN:
- handled = webView->keyDown(wParam, lParam, true);
- break;
- case WM_KEYDOWN:
- handled = webView->keyDown(wParam, lParam);
- break;
- case WM_SYSKEYUP:
- handled = webView->keyUp(wParam, lParam, true);
- break;
- case WM_KEYUP:
- handled = webView->keyUp(wParam, lParam);
- break;
- case WM_SYSCHAR:
- handled = webView->keyPress(wParam, lParam, true);
- break;
- case WM_CHAR:
- handled = webView->keyPress(wParam, lParam);
- break;
- // FIXME: We need to check WM_UNICHAR to support supplementary characters (that don't fit in 16 bits).
- case WM_SIZE:
- if (lParam != 0)
- webView->sizeChanged(IntSize(LOWORD(lParam), HIWORD(lParam)));
- break;
- case WM_SHOWWINDOW:
- lResult = DefWindowProc(hWnd, message, wParam, lParam);
- 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)
- uiDelegatePrivate->webViewReceivedFocus(webView);
- FocusController* focusController = webView->page()->focusController();
- if (Frame* frame = focusController->focusedFrame()) {
- // Send focus events unless the previously focused window is a
- // child of ours (for example a plugin).
- if (!IsChild(hWnd, reinterpret_cast<HWND>(wParam)))
- focusController->setFocused(true);
- } else
- focusController->setFocused(true);
- break;
- }
- case WM_KILLFOCUS: {
- 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)
- uiDelegatePrivate->webViewLostFocus(webView, (OLE_HANDLE)(ULONG64)newFocusWnd);
- FocusController* focusController = webView->page()->focusController();
- Frame* frame = focusController->focusedOrMainFrame();
- webView->resetIME(frame);
- // 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:
- if (reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_SHOWWINDOW)
- webView->updateActiveStateSoon();
- handled = false;
- break;
- case WM_CUT:
- webView->cut(0);
- break;
- case WM_COPY:
- webView->copy(0);
- break;
- case WM_PASTE:
- webView->paste(0);
- break;
- case WM_CLEAR:
- webView->delete_(0);
- break;
- case WM_COMMAND:
- if (HIWORD(wParam))
- handled = webView->execCommand(wParam, lParam);
- else // If the high word of wParam is 0, the message is from a menu
- webView->performContextMenuAction(wParam, lParam, false);
- break;
- case WM_MENUCOMMAND:
- webView->performContextMenuAction(wParam, lParam, true);
- break;
- case WM_CONTEXTMENU:
- handled = webView->handleContextMenuEvent(wParam, lParam);
- break;
- case WM_INITMENUPOPUP:
- handled = webView->onInitMenuPopup(wParam, lParam);
- break;
- case WM_MEASUREITEM:
- handled = webView->onMeasureItem(wParam, lParam);
- break;
- case WM_DRAWITEM:
- handled = webView->onDrawItem(wParam, lParam);
- break;
- case WM_UNINITMENUPOPUP:
- handled = webView->onUninitMenuPopup(wParam, lParam);
- break;
- case WM_XP_THEMECHANGED:
- if (Frame* coreFrame = core(mainFrameImpl)) {
- webView->deleteBackingStore();
- coreFrame->page()->theme()->themeChanged();
- ScrollbarTheme::nativeTheme()->themeChanged();
- 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);
- handled = false;
- break;
- case WM_GETDLGCODE: {
- COMPtr<IWebUIDelegate> uiDelegate;
- COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate;
- LONG_PTR dlgCode = 0;
- UINT keyCode = 0;
- if (lParam) {
- LPMSG lpMsg = (LPMSG)lParam;
- 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)))
- return dlgCode;
- handled = false;
- break;
- }
- case WM_GETOBJECT:
- handled = webView->onGetObject(wParam, lParam, lResult);
- break;
- case WM_IME_STARTCOMPOSITION:
- handled = webView->onIMEStartComposition();
- break;
- case WM_IME_REQUEST:
- lResult = webView->onIMERequest(wParam, lParam);
- break;
- case WM_IME_COMPOSITION:
- handled = webView->onIMEComposition(lParam);
- break;
- case WM_IME_ENDCOMPOSITION:
- handled = webView->onIMEEndComposition();
- break;
- case WM_IME_CHAR:
- handled = webView->onIMEChar(wParam, lParam);
- break;
- case WM_IME_NOTIFY:
- handled = webView->onIMENotify(wParam, lParam, &lResult);
- break;
- case WM_IME_SELECT:
- handled = webView->onIMESelect(wParam, lParam);
- break;
- case WM_IME_SETCONTEXT:
- handled = webView->onIMESetContext(wParam, lParam);
- break;
- case WM_TIMER:
- switch (wParam) {
- case UpdateActiveStateTimer:
- KillTimer(hWnd, UpdateActiveStateTimer);
- webView->updateActiveState();
- break;
- case DeleteBackingStoreTimer:
- webView->deleteBackingStore();
- break;
- }
- break;
- case WM_SETCURSOR:
- handled = ::SetCursor(webView->m_lastSetCursor);
- break;
- case WM_VSCROLL:
- handled = webView->verticalScroll(wParam, lParam);
- break;
- case WM_HSCROLL:
- handled = webView->horizontalScroll(wParam, lParam);
- break;
- default:
- handled = false;
- break;
- }
- if (!handled)
- lResult = DefWindowProc(hWnd, message, wParam, lParam);
- // Let the client know whether we consider this message handled.
- return (message == WM_KEYDOWN || message == WM_SYSKEYDOWN || message == WM_KEYUP || message == WM_SYSKEYUP) ? !handled : lResult;
- }
在32平台,webView仅仅需要实现消息处理函数,然后创建窗口,将其消息处理函数注册给目的窗口
2. 网络事件
32平台是用的curl网络库,通过调用网络库的异步函数, webkit引擎与网络库的接口是ResouceHandler,发起网络请求,需要调用ResouceHandle::start(NetworkingContext* context),函数当网络事件到达,会调用如下函数:
- void didReceiveData(CFURLConnectionRef conn, CFDataRef data, CFIndex originalLength, const void* clientInfo)
- {
- ResourceHandle* handle = static_cast<ResourceHandle*>(const_cast<void*>(clientInfo));
- const UInt8* bytes = CFDataGetBytePtr(data);
- CFIndex length = CFDataGetLength(data);
- LOG(Network, "CFNet - didReceiveData(conn=%p, handle=%p, bytes=%d) (%s)", conn, handle, length, handle->firstRequest().url().string().utf8().data());
- if (handle->client())
- handle->client()->didReceiveData(handle, (const char*)bytes, length, originalLength);
- }
3.timer事件
timer事件的处理类似于设备事件,timer的平台初始化函数:
- static void initializeOffScreenTimerWindow()
- {
- if (timerWindowHandle)
- return;
- WNDCLASSEX wcex;
- memset(&wcex, 0, sizeof(WNDCLASSEX));
- wcex.cbSize = sizeof(WNDCLASSEX);
- wcex.lpfnWndProc = TimerWindowWndProc;
- wcex.hInstance = WebCore::instanceHandle();
- wcex.lpszClassName = kTimerWindowClassName;
- RegisterClassEx(&wcex);
- timerWindowHandle = CreateWindow(kTimerWindowClassName, 0, 0,
- CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, HWND_MESSAGE, 0, WebCore::instanceHandle(), 0);
- timerFiredMessage = RegisterWindowMessage(L"com.apple.WebKit.TimerFired");
- }
timer的消息处理函数如下:
- LRESULT CALLBACK TimerWindowWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- #if PLATFORM(WIN)
- // Windows Media Player has a modal message loop that will deliver messages
- // to us at inappropriate times and we will crash if we handle them when
- // they are delivered. We repost all messages so that we will get to handle
- // them once the modal loop exits.
- if (PluginView::isCallingPlugin()) {
- PostMessage(hWnd, message, wParam, lParam);
- return 0;
- }
- #endif
- if (message == timerFiredMessage) {
- InterlockedExchange(&pendingTimers, 0);
- processingCustomTimerMessage = true;
- sharedTimerFiredFunction();
- processingCustomTimerMessage = false;
- } else if (message == WM_TIMER) {
- if (wParam == sharedTimerID) {
- KillTimer(timerWindowHandle, sharedTimerID);
- sharedTimerFiredFunction();
- } else if (wParam == endHighResTimerID) {
- KillTimer(timerWindowHandle, endHighResTimerID);
- highResTimerActive = false;
- timeEndPeriod(timerResolution);
- }
- } else
- return DefWindowProc(hWnd, message, wParam, lParam);
- return 0;
- }
引擎内部事件如何处理?
通过分析发现引擎内部的异步是通过timer来实现,具体请参照前面讲解timer的文章
通过上面的分析发现,webkit没有将事件的处理统一起来,如果在引擎中自己有一个事件的处理者,或者将以上事件的处理统一起来,其架构看起来会不会更加优美?