summaryrefslogtreecommitdiffstats
path: root/gfx/skia/skia/src/views/win/SkOSWindow_win.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/skia/skia/src/views/win/SkOSWindow_win.cpp')
-rw-r--r--gfx/skia/skia/src/views/win/SkOSWindow_win.cpp772
1 files changed, 772 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/views/win/SkOSWindow_win.cpp b/gfx/skia/skia/src/views/win/SkOSWindow_win.cpp
new file mode 100644
index 000000000..983b253c5
--- /dev/null
+++ b/gfx/skia/skia/src/views/win/SkOSWindow_win.cpp
@@ -0,0 +1,772 @@
+/*
+ * 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 "SkLeanWindows.h"
+
+#include <GL/gl.h>
+#include <WindowsX.h>
+#include "win/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/GrGLAssembleInterface.h"
+#include "gl/GrGLInterface.h"
+#include "GLES2/gl2.h"
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#endif // SK_ANGLE
+
+const int kDefaultWindowWidth = 500;
+const int kDefaultWindowHeight = 500;
+
+#define GL_CALL(IFACE, X) \
+ SkASSERT(IFACE); \
+ do { \
+ (IFACE)->fFunctions.f##X; \
+ } while (false)
+
+#define WM_EVENT_CALLBACK (WM_USER+0)
+
+void post_skwinevent(HWND hwnd)
+{
+ PostMessage(hwnd, WM_EVENT_CALLBACK, 0, 0);
+}
+
+SkTHashMap<void*, SkOSWindow*> SkOSWindow::gHwndToOSWindowMap;
+
+SkOSWindow::SkOSWindow(const void* winInit) {
+ fWinInit = *(const WindowInit*)winInit;
+
+ fHWND = CreateWindow(fWinInit.fClass, NULL, WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, 0, kDefaultWindowWidth, kDefaultWindowHeight, NULL, NULL,
+ fWinInit.fInstance, NULL);
+ gHwndToOSWindowMap.set(fHWND, this);
+#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;
+ fFullscreen = false;
+}
+
+SkOSWindow::~SkOSWindow() {
+#if SK_SUPPORT_GPU
+ if (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
+ this->closeWindow();
+}
+
+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: {
+ const uint16_t* c = reinterpret_cast<uint16_t*>(&wParam);
+ this->handleChar(SkUTF16_NextUnichar(&c));
+ 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_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(hWnd);
+ }
+ 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();
+ }
+}
+
+void SkOSWindow::updateSize()
+{
+ RECT r;
+ GetWindowRect((HWND)fHWND, &r);
+ this->resize(r.right - r.left, r.bottom - r.top);
+}
+
+void SkOSWindow::onHandleInval(const SkIRect& r) {
+ RECT rect;
+ rect.left = r.fLeft;
+ rect.top = r.fTop;
+ rect.right = r.fRight;
+ rect.bottom = r.fBottom;
+ InvalidateRect((HWND)fHWND, &rect, FALSE);
+}
+
+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()
+{
+ SkOSWindow::ForAllWindows([](void* hWND, SkOSWindow**) {
+ post_skwinevent((HWND)hWND);
+ });
+}
+
+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, bool deepColor, AttachmentInfo* info) {
+ HDC dc = GetDC((HWND)fHWND);
+ if (NULL == fHGLRC) {
+ fHGLRC = SkCreateWGLContext(dc, msaaSampleCount, deepColor,
+ kGLPreferCompatibilityProfile_SkWGLContextRequest);
+ 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 and color bit depth.
+ int pixelFormat = GetPixelFormat(dc);
+ PIXELFORMATDESCRIPTOR pfd;
+ DescribePixelFormat(dc, pixelFormat, sizeof(pfd), &pfd);
+ info->fStencilBits = pfd.cStencilBits;
+ // pfd.cColorBits includes alpha, so it will be 32 in 8/8/8/8 and 10/10/10/2
+ info->fColorBits = pfd.cRedBits + pfd.cGreenBits + pfd.cBlueBits;
+
+ // 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() {
+ HDC dc = GetDC((HWND)fHWND);
+ SwapBuffers(dc);
+ ReleaseDC((HWND)fHWND, dc);
+}
+
+#if SK_ANGLE
+
+static void* get_angle_egl_display(void* nativeDisplay) {
+ PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
+ eglGetPlatformDisplayEXT =
+ (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
+
+ // We expect ANGLE to support this extension
+ if (!eglGetPlatformDisplayEXT) {
+ return EGL_NO_DISPLAY;
+ }
+
+ EGLDisplay display = EGL_NO_DISPLAY;
+ // Try for an ANGLE D3D11 context, fall back to D3D9, and finally GL.
+ EGLint attribs[3][3] = {
+ {
+ EGL_PLATFORM_ANGLE_TYPE_ANGLE,
+ EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+ EGL_NONE
+ },
+ {
+ EGL_PLATFORM_ANGLE_TYPE_ANGLE,
+ EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE,
+ EGL_NONE
+ },
+ };
+ for (int i = 0; i < 3 && display == EGL_NO_DISPLAY; ++i) {
+ display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,nativeDisplay, attribs[i]);
+ }
+ return display;
+}
+
+struct ANGLEAssembleContext {
+ ANGLEAssembleContext() {
+ fEGL = GetModuleHandle("libEGL.dll");
+ fGL = GetModuleHandle("libGLESv2.dll");
+ }
+
+ bool isValid() const { return SkToBool(fEGL) && SkToBool(fGL); }
+
+ HMODULE fEGL;
+ HMODULE fGL;
+};
+
+static GrGLFuncPtr angle_get_gl_proc(void* ctx, const char name[]) {
+ const ANGLEAssembleContext& context = *reinterpret_cast<const ANGLEAssembleContext*>(ctx);
+ GrGLFuncPtr proc = (GrGLFuncPtr) GetProcAddress(context.fGL, name);
+ if (proc) {
+ return proc;
+ }
+ proc = (GrGLFuncPtr) GetProcAddress(context.fEGL, name);
+ if (proc) {
+ return proc;
+ }
+ return eglGetProcAddress(name);
+}
+
+static const GrGLInterface* get_angle_gl_interface() {
+ ANGLEAssembleContext context;
+ if (!context.isValid()) {
+ return nullptr;
+ }
+ return GrGLAssembleGLESInterface(&context, angle_get_gl_proc);
+}
+
+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 = get_angle_egl_display(GetDC(hWnd));
+
+ if (EGL_NO_DISPLAY == display) {
+ SkDebugf("Could not create ANGLE egl display!\n");
+ 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, msaaConfigAttribList, 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;
+ }
+ fANGLEInterface.reset(get_angle_gl_interface());
+ if (!fANGLEInterface) {
+ this->detachANGLE();
+ return false;
+ }
+ GL_CALL(fANGLEInterface, ClearStencil(0));
+ GL_CALL(fANGLEInterface, ClearColor(0, 0, 0, 0));
+ GL_CALL(fANGLEInterface, StencilMask(0xffffffff));
+ GL_CALL(fANGLEInterface, Clear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT));
+ }
+ if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
+ this->detachANGLE();
+ return false;
+ }
+ eglGetConfigAttrib(fDisplay, fConfig, EGL_STENCIL_SIZE, &info->fStencilBits);
+ eglGetConfigAttrib(fDisplay, fConfig, EGL_SAMPLES, &info->fSampleCount);
+
+ GL_CALL(fANGLEInterface, Viewport(0, 0, SkScalarRoundToInt(this->width()),
+ SkScalarRoundToInt(this->height())));
+ return true;
+}
+
+void SkOSWindow::detachANGLE() {
+ fANGLEInterface.reset(nullptr);
+ 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() {
+ GL_CALL(fANGLEInterface, Flush());
+
+ eglSwapBuffers(fDisplay, fSurface);
+}
+#endif // SK_ANGLE
+
+#endif // SK_SUPPORT_GPU
+
+// return true on success
+bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor,
+ 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, deepColor, 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::release() {
+ 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;
+ }
+}
+
+bool SkOSWindow::makeFullscreen() {
+ if (fFullscreen) {
+ return true;
+ }
+#if SK_SUPPORT_GPU
+ if (fHGLRC) {
+ this->detachGL();
+ }
+#endif // SK_SUPPORT_GPU
+ // This is hacked together from various sources on the web. It can certainly be improved and be
+ // made more robust.
+
+ // Save current window/resolution information. We do this in case we ever implement switching
+ // back to windowed mode.
+ fSavedWindowState.fZoomed = SkToBool(IsZoomed((HWND)fHWND));
+ if (fSavedWindowState.fZoomed) {
+ SendMessage((HWND)fHWND, WM_SYSCOMMAND, SC_RESTORE, 0);
+ }
+ fSavedWindowState.fStyle = GetWindowLong((HWND)fHWND, GWL_STYLE);
+ fSavedWindowState.fExStyle = GetWindowLong((HWND)fHWND, GWL_EXSTYLE);
+ GetWindowRect((HWND)fHWND, &fSavedWindowState.fRect);
+ DEVMODE currScreenSettings;
+ memset(&currScreenSettings,0,sizeof(currScreenSettings));
+ currScreenSettings.dmSize = sizeof(currScreenSettings);
+ EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &currScreenSettings);
+ fSavedWindowState.fScreenWidth = currScreenSettings.dmPelsWidth;
+ fSavedWindowState.fScreenHeight = currScreenSettings.dmPelsHeight;
+ fSavedWindowState.fScreenBits = currScreenSettings.dmBitsPerPel;
+ fSavedWindowState.fHWND = fHWND;
+
+ // Try different sizes to find an allowed setting? Use ChangeDisplaySettingsEx?
+ static const int kWidth = 1280;
+ static const int kHeight = 1024;
+ DEVMODE newScreenSettings;
+ memset(&newScreenSettings, 0, sizeof(newScreenSettings));
+ newScreenSettings.dmSize = sizeof(newScreenSettings);
+ newScreenSettings.dmPelsWidth = kWidth;
+ newScreenSettings.dmPelsHeight = kHeight;
+ newScreenSettings.dmBitsPerPel = 32;
+ newScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
+ if (ChangeDisplaySettings(&newScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
+ return false;
+ }
+ RECT WindowRect;
+ WindowRect.left = 0;
+ WindowRect.right = kWidth;
+ WindowRect.top = 0;
+ WindowRect.bottom = kHeight;
+ ShowCursor(FALSE);
+ AdjustWindowRectEx(&WindowRect, WS_POPUP, FALSE, WS_EX_APPWINDOW);
+ HWND fsHWND = CreateWindowEx(
+ WS_EX_APPWINDOW,
+ fWinInit.fClass,
+ NULL,
+ WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
+ 0, 0, WindowRect.right-WindowRect.left, WindowRect.bottom-WindowRect.top,
+ NULL,
+ NULL,
+ fWinInit.fInstance,
+ NULL
+ );
+ if (!fsHWND) {
+ return false;
+ }
+ // Hide the old window and set the entry in the global mapping for this SkOSWindow to the
+ // new HWND.
+ ShowWindow((HWND)fHWND, SW_HIDE);
+ gHwndToOSWindowMap.remove(fHWND);
+ fHWND = fsHWND;
+ gHwndToOSWindowMap.set(fHWND, this);
+ this->updateSize();
+
+ fFullscreen = true;
+ return true;
+}
+
+void SkOSWindow::setVsync(bool enable) {
+ SkWGLExtensions wgl;
+ wgl.swapInterval(enable ? 1 : 0);
+}
+
+void SkOSWindow::closeWindow() {
+ DestroyWindow((HWND)fHWND);
+ if (fFullscreen) {
+ DestroyWindow((HWND)fSavedWindowState.fHWND);
+ }
+ gHwndToOSWindowMap.remove(fHWND);
+}
+#endif