diff -r 000000000000 -r 6474c204b198 gfx/skia/trunk/src/views/win/SkOSWindow_win.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/skia/trunk/src/views/win/SkOSWindow_win.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,618 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "SkTypes.h" + +#if defined(SK_BUILD_FOR_WIN) + +#include +#include +#include "SkWGL.h" +#include "SkWindow.h" +#include "SkCanvas.h" +#include "SkOSMenu.h" +#include "SkTime.h" +#include "SkUtils.h" + +#include "SkGraphics.h" + +#if SK_ANGLE +#include "gl/GrGLInterface.h" + +#include "GLES2/gl2.h" + +#define ANGLE_GL_CALL(IFACE, X) \ + do { \ + (IFACE)->fFunctions.f##X; \ + } while (false) + +#endif + +#define INVALIDATE_DELAY_MS 200 + +static SkOSWindow* gCurrOSWin; +static HWND gEventTarget; + +#define WM_EVENT_CALLBACK (WM_USER+0) + +void post_skwinevent() +{ + PostMessage(gEventTarget, WM_EVENT_CALLBACK, 0, 0); +} + +SkOSWindow::SkOSWindow(void* hWnd) { + fHWND = hWnd; +#if SK_SUPPORT_GPU +#if SK_ANGLE + fDisplay = EGL_NO_DISPLAY; + fContext = EGL_NO_CONTEXT; + fSurface = EGL_NO_SURFACE; +#endif + fHGLRC = NULL; +#endif + fAttached = kNone_BackEndType; + gEventTarget = (HWND)hWnd; +} + +SkOSWindow::~SkOSWindow() { +#if SK_SUPPORT_GPU + if (NULL != fHGLRC) { + wglDeleteContext((HGLRC)fHGLRC); + } +#if SK_ANGLE + if (EGL_NO_CONTEXT != fContext) { + eglDestroyContext(fDisplay, fContext); + fContext = EGL_NO_CONTEXT; + } + + if (EGL_NO_SURFACE != fSurface) { + eglDestroySurface(fDisplay, fSurface); + fSurface = EGL_NO_SURFACE; + } + + if (EGL_NO_DISPLAY != fDisplay) { + eglTerminate(fDisplay); + fDisplay = EGL_NO_DISPLAY; + } +#endif // SK_ANGLE +#endif // SK_SUPPORT_GPU +} + +static SkKey winToskKey(WPARAM vk) { + static const struct { + WPARAM fVK; + SkKey fKey; + } gPair[] = { + { VK_BACK, kBack_SkKey }, + { VK_CLEAR, kBack_SkKey }, + { VK_RETURN, kOK_SkKey }, + { VK_UP, kUp_SkKey }, + { VK_DOWN, kDown_SkKey }, + { VK_LEFT, kLeft_SkKey }, + { VK_RIGHT, kRight_SkKey } + }; + for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) { + if (gPair[i].fVK == vk) { + return gPair[i].fKey; + } + } + return kNONE_SkKey; +} + +static unsigned getModifiers(UINT message) { + return 0; // TODO +} + +bool SkOSWindow::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { + switch (message) { + case WM_KEYDOWN: { + SkKey key = winToskKey(wParam); + if (kNONE_SkKey != key) { + this->handleKey(key); + return true; + } + } break; + case WM_KEYUP: { + SkKey key = winToskKey(wParam); + if (kNONE_SkKey != key) { + this->handleKeyUp(key); + return true; + } + } break; + case WM_UNICHAR: + this->handleChar((SkUnichar) wParam); + return true; + case WM_CHAR: { + this->handleChar(SkUTF8_ToUnichar((char*)&wParam)); + return true; + } break; + case WM_SIZE: { + INT width = LOWORD(lParam); + INT height = HIWORD(lParam); + this->resize(width, height); + break; + } + case WM_PAINT: { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hWnd, &ps); + this->doPaint(hdc); + EndPaint(hWnd, &ps); + return true; + } break; + + case WM_TIMER: { + RECT* rect = (RECT*)wParam; + InvalidateRect(hWnd, rect, FALSE); + KillTimer(hWnd, (UINT_PTR)rect); + delete rect; + return true; + } break; + + case WM_LBUTTONDOWN: + this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), + Click::kDown_State, NULL, getModifiers(message)); + return true; + + case WM_MOUSEMOVE: + this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), + Click::kMoved_State, NULL, getModifiers(message)); + return true; + + case WM_LBUTTONUP: + this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), + Click::kUp_State, NULL, getModifiers(message)); + return true; + + case WM_EVENT_CALLBACK: + if (SkEvent::ProcessEvent()) { + post_skwinevent(); + } + return true; + } + return false; +} + +void SkOSWindow::doPaint(void* ctx) { + this->update(NULL); + + if (kNone_BackEndType == fAttached) + { + HDC hdc = (HDC)ctx; + const SkBitmap& bitmap = this->getBitmap(); + + BITMAPINFO bmi; + memset(&bmi, 0, sizeof(bmi)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = bitmap.width(); + bmi.bmiHeader.biHeight = -bitmap.height(); // top-down image + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + + // + // Do the SetDIBitsToDevice. + // + // TODO(wjmaclean): + // Fix this call to handle SkBitmaps that have rowBytes != width, + // i.e. may have padding at the end of lines. The SkASSERT below + // may be ignored by builds, and the only obviously safe option + // seems to be to copy the bitmap to a temporary (contiguous) + // buffer before passing to SetDIBitsToDevice(). + SkASSERT(bitmap.width() * bitmap.bytesPerPixel() == bitmap.rowBytes()); + bitmap.lockPixels(); + int ret = SetDIBitsToDevice(hdc, + 0, 0, + bitmap.width(), bitmap.height(), + 0, 0, + 0, bitmap.height(), + bitmap.getPixels(), + &bmi, + DIB_RGB_COLORS); + (void)ret; // we're ignoring potential failures for now. + bitmap.unlockPixels(); + } +} + +#if 0 +void SkOSWindow::updateSize() +{ + RECT r; + GetWindowRect((HWND)this->getHWND(), &r); + this->resize(r.right - r.left, r.bottom - r.top); +} +#endif + +void SkOSWindow::onHandleInval(const SkIRect& r) { + RECT* rect = new RECT; + rect->left = r.fLeft; + rect->top = r.fTop; + rect->right = r.fRight; + rect->bottom = r.fBottom; + SetTimer((HWND)fHWND, (UINT_PTR)rect, INVALIDATE_DELAY_MS, NULL); +} + +void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu) +{ +} + +void SkOSWindow::onSetTitle(const char title[]){ + SetWindowTextA((HWND)fHWND, title); +} + +enum { + SK_MacReturnKey = 36, + SK_MacDeleteKey = 51, + SK_MacEndKey = 119, + SK_MacLeftKey = 123, + SK_MacRightKey = 124, + SK_MacDownKey = 125, + SK_MacUpKey = 126, + + SK_Mac0Key = 0x52, + SK_Mac1Key = 0x53, + SK_Mac2Key = 0x54, + SK_Mac3Key = 0x55, + SK_Mac4Key = 0x56, + SK_Mac5Key = 0x57, + SK_Mac6Key = 0x58, + SK_Mac7Key = 0x59, + SK_Mac8Key = 0x5b, + SK_Mac9Key = 0x5c +}; + +static SkKey raw2key(uint32_t raw) +{ + static const struct { + uint32_t fRaw; + SkKey fKey; + } gKeys[] = { + { SK_MacUpKey, kUp_SkKey }, + { SK_MacDownKey, kDown_SkKey }, + { SK_MacLeftKey, kLeft_SkKey }, + { SK_MacRightKey, kRight_SkKey }, + { SK_MacReturnKey, kOK_SkKey }, + { SK_MacDeleteKey, kBack_SkKey }, + { SK_MacEndKey, kEnd_SkKey }, + { SK_Mac0Key, k0_SkKey }, + { SK_Mac1Key, k1_SkKey }, + { SK_Mac2Key, k2_SkKey }, + { SK_Mac3Key, k3_SkKey }, + { SK_Mac4Key, k4_SkKey }, + { SK_Mac5Key, k5_SkKey }, + { SK_Mac6Key, k6_SkKey }, + { SK_Mac7Key, k7_SkKey }, + { SK_Mac8Key, k8_SkKey }, + { SK_Mac9Key, k9_SkKey } + }; + + for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++) + if (gKeys[i].fRaw == raw) + return gKeys[i].fKey; + return kNONE_SkKey; +} + +/////////////////////////////////////////////////////////////////////////////////////// + +void SkEvent::SignalNonEmptyQueue() +{ + post_skwinevent(); + //SkDebugf("signal nonempty\n"); +} + +static UINT_PTR gTimer; + +VOID CALLBACK sk_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + SkEvent::ServiceQueueTimer(); + //SkDebugf("timer task fired\n"); +} + +void SkEvent::SignalQueueTimer(SkMSec delay) +{ + if (gTimer) + { + KillTimer(NULL, gTimer); + gTimer = NULL; + } + if (delay) + { + gTimer = SetTimer(NULL, 0, delay, sk_timer_proc); + //SkDebugf("SetTimer of %d returned %d\n", delay, gTimer); + } +} + +#if SK_SUPPORT_GPU + +bool SkOSWindow::attachGL(int msaaSampleCount, AttachmentInfo* info) { + HDC dc = GetDC((HWND)fHWND); + if (NULL == fHGLRC) { + fHGLRC = SkCreateWGLContext(dc, msaaSampleCount, false); + if (NULL == fHGLRC) { + return false; + } + glClearStencil(0); + glClearColor(0, 0, 0, 0); + glStencilMask(0xffffffff); + glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + } + if (wglMakeCurrent(dc, (HGLRC)fHGLRC)) { + // use DescribePixelFormat to get the stencil bit depth. + int pixelFormat = GetPixelFormat(dc); + PIXELFORMATDESCRIPTOR pfd; + DescribePixelFormat(dc, pixelFormat, sizeof(pfd), &pfd); + info->fStencilBits = pfd.cStencilBits; + + // Get sample count if the MSAA WGL extension is present + SkWGLExtensions extensions; + if (extensions.hasExtension(dc, "WGL_ARB_multisample")) { + static const int kSampleCountAttr = SK_WGL_SAMPLES; + extensions.getPixelFormatAttribiv(dc, + pixelFormat, + 0, + 1, + &kSampleCountAttr, + &info->fSampleCount); + } else { + info->fSampleCount = 0; + } + + glViewport(0, 0, + SkScalarRoundToInt(this->width()), + SkScalarRoundToInt(this->height())); + return true; + } + return false; +} + +void SkOSWindow::detachGL() { + wglMakeCurrent(GetDC((HWND)fHWND), 0); + wglDeleteContext((HGLRC)fHGLRC); + fHGLRC = NULL; +} + +void SkOSWindow::presentGL() { + glFlush(); + HDC dc = GetDC((HWND)fHWND); + SwapBuffers(dc); + ReleaseDC((HWND)fHWND, dc); +} + +#if SK_ANGLE +bool create_ANGLE(EGLNativeWindowType hWnd, + int msaaSampleCount, + EGLDisplay* eglDisplay, + EGLContext* eglContext, + EGLSurface* eglSurface, + EGLConfig* eglConfig) { + static const EGLint contextAttribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE, EGL_NONE + }; + static const EGLint configAttribList[] = { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 8, + EGL_STENCIL_SIZE, 8, + EGL_NONE + }; + static const EGLint surfaceAttribList[] = { + EGL_NONE, EGL_NONE + }; + + EGLDisplay display = eglGetDisplay(GetDC(hWnd)); + if (display == EGL_NO_DISPLAY ) { + return false; + } + + // Initialize EGL + EGLint majorVersion, minorVersion; + if (!eglInitialize(display, &majorVersion, &minorVersion)) { + return false; + } + + EGLint numConfigs; + if (!eglGetConfigs(display, NULL, 0, &numConfigs)) { + return false; + } + + // Choose config + bool foundConfig = false; + if (msaaSampleCount) { + static const int kConfigAttribListCnt = + SK_ARRAY_COUNT(configAttribList); + EGLint msaaConfigAttribList[kConfigAttribListCnt + 4]; + memcpy(msaaConfigAttribList, + configAttribList, + sizeof(configAttribList)); + SkASSERT(EGL_NONE == msaaConfigAttribList[kConfigAttribListCnt - 1]); + msaaConfigAttribList[kConfigAttribListCnt - 1] = EGL_SAMPLE_BUFFERS; + msaaConfigAttribList[kConfigAttribListCnt + 0] = 1; + msaaConfigAttribList[kConfigAttribListCnt + 1] = EGL_SAMPLES; + msaaConfigAttribList[kConfigAttribListCnt + 2] = msaaSampleCount; + msaaConfigAttribList[kConfigAttribListCnt + 3] = EGL_NONE; + if (eglChooseConfig(display, configAttribList, eglConfig, 1, &numConfigs)) { + SkASSERT(numConfigs > 0); + foundConfig = true; + } + } + if (!foundConfig) { + if (!eglChooseConfig(display, configAttribList, eglConfig, 1, &numConfigs)) { + return false; + } + } + + // Create a surface + EGLSurface surface = eglCreateWindowSurface(display, *eglConfig, + (EGLNativeWindowType)hWnd, + surfaceAttribList); + if (surface == EGL_NO_SURFACE) { + return false; + } + + // Create a GL context + EGLContext context = eglCreateContext(display, *eglConfig, + EGL_NO_CONTEXT, + contextAttribs ); + if (context == EGL_NO_CONTEXT ) { + return false; + } + + // Make the context current + if (!eglMakeCurrent(display, surface, surface, context)) { + return false; + } + + *eglDisplay = display; + *eglContext = context; + *eglSurface = surface; + return true; +} + +bool SkOSWindow::attachANGLE(int msaaSampleCount, AttachmentInfo* info) { + if (EGL_NO_DISPLAY == fDisplay) { + bool bResult = create_ANGLE((HWND)fHWND, + msaaSampleCount, + &fDisplay, + &fContext, + &fSurface, + &fConfig); + if (false == bResult) { + return false; + } + SkAutoTUnref intf(GrGLCreateANGLEInterface()); + + if (intf) { + ANGLE_GL_CALL(intf, ClearStencil(0)); + ANGLE_GL_CALL(intf, ClearColor(0, 0, 0, 0)); + ANGLE_GL_CALL(intf, StencilMask(0xffffffff)); + ANGLE_GL_CALL(intf, Clear(GL_STENCIL_BUFFER_BIT |GL_COLOR_BUFFER_BIT)); + } + } + if (eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) { + eglGetConfigAttrib(fDisplay, fConfig, EGL_STENCIL_SIZE, &info->fStencilBits); + eglGetConfigAttrib(fDisplay, fConfig, EGL_SAMPLES, &info->fSampleCount); + + SkAutoTUnref intf(GrGLCreateANGLEInterface()); + + if (intf ) { + ANGLE_GL_CALL(intf, Viewport(0, 0, + SkScalarRoundToInt(this->width()), + SkScalarRoundToInt(this->height()))); + } + return true; + } + return false; +} + +void SkOSWindow::detachANGLE() { + eglMakeCurrent(fDisplay, EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT); + + eglDestroyContext(fDisplay, fContext); + fContext = EGL_NO_CONTEXT; + + eglDestroySurface(fDisplay, fSurface); + fSurface = EGL_NO_SURFACE; + + eglTerminate(fDisplay); + fDisplay = EGL_NO_DISPLAY; +} + +void SkOSWindow::presentANGLE() { + SkAutoTUnref intf(GrGLCreateANGLEInterface()); + + if (intf) { + ANGLE_GL_CALL(intf, Flush()); + } + + eglSwapBuffers(fDisplay, fSurface); +} +#endif // SK_ANGLE +#endif // SK_SUPPORT_GPU + +// return true on success +bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo* info) { + + // attach doubles as "windowResize" so we need to allo + // already bound states to pass through again + // TODO: split out the resize functionality +// SkASSERT(kNone_BackEndType == fAttached); + bool result = true; + + switch (attachType) { + case kNone_BackEndType: + // nothing to do + break; +#if SK_SUPPORT_GPU + case kNativeGL_BackEndType: + result = attachGL(msaaSampleCount, info); + break; +#if SK_ANGLE + case kANGLE_BackEndType: + result = attachANGLE(msaaSampleCount, info); + break; +#endif // SK_ANGLE +#endif // SK_SUPPORT_GPU + default: + SkASSERT(false); + result = false; + break; + } + + if (result) { + fAttached = attachType; + } + + return result; +} + +void SkOSWindow::detach() { + switch (fAttached) { + case kNone_BackEndType: + // nothing to do + break; +#if SK_SUPPORT_GPU + case kNativeGL_BackEndType: + detachGL(); + break; +#if SK_ANGLE + case kANGLE_BackEndType: + detachANGLE(); + break; +#endif // SK_ANGLE +#endif // SK_SUPPORT_GPU + default: + SkASSERT(false); + break; + } + fAttached = kNone_BackEndType; +} + +void SkOSWindow::present() { + switch (fAttached) { + case kNone_BackEndType: + // nothing to do + return; +#if SK_SUPPORT_GPU + case kNativeGL_BackEndType: + presentGL(); + break; +#if SK_ANGLE + case kANGLE_BackEndType: + presentANGLE(); + break; +#endif // SK_ANGLE +#endif // SK_SUPPORT_GPU + default: + SkASSERT(false); + break; + } +} + +#endif