Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 #include "SkTypes.h"
      8 
      9 #if defined(SK_BUILD_FOR_WIN)
     10 
     11 #include "SkLeanWindows.h"
     12 
     13 #include <GL/gl.h>
     14 #include <WindowsX.h>
     15 #include "win/SkWGL.h"
     16 #include "SkWindow.h"
     17 #include "SkCanvas.h"
     18 #include "SkOSMenu.h"
     19 #include "SkTime.h"
     20 #include "SkUtils.h"
     21 
     22 #include "SkGraphics.h"
     23 
     24 #if SK_ANGLE
     25 #include "gl/GrGLAssembleInterface.h"
     26 #include "gl/GrGLInterface.h"
     27 #include "GLES2/gl2.h"
     28 #include <EGL/egl.h>
     29 #include <EGL/eglext.h>
     30 #endif // SK_ANGLE
     31 
     32 const int kDefaultWindowWidth = 500;
     33 const int kDefaultWindowHeight = 500;
     34 
     35 #define GL_CALL(IFACE, X)                                 \
     36     SkASSERT(IFACE);                                      \
     37     do {                                                  \
     38         (IFACE)->fFunctions.f##X;                         \
     39     } while (false)
     40 
     41 #define WM_EVENT_CALLBACK (WM_USER+0)
     42 
     43 void post_skwinevent(HWND hwnd)
     44 {
     45     PostMessage(hwnd, WM_EVENT_CALLBACK, 0, 0);
     46 }
     47 
     48 SkTHashMap<void*, SkOSWindow*> SkOSWindow::gHwndToOSWindowMap;
     49 
     50 SkOSWindow::SkOSWindow(const void* winInit) {
     51     fWinInit = *(const WindowInit*)winInit;
     52 
     53     fHWND = CreateWindow(fWinInit.fClass, NULL, WS_OVERLAPPEDWINDOW,
     54                          CW_USEDEFAULT, 0, kDefaultWindowWidth, kDefaultWindowHeight, NULL, NULL,
     55                          fWinInit.fInstance, NULL);
     56     gHwndToOSWindowMap.set(fHWND, this);
     57 #if SK_SUPPORT_GPU
     58 #if SK_ANGLE
     59     fDisplay = EGL_NO_DISPLAY;
     60     fContext = EGL_NO_CONTEXT;
     61     fSurface = EGL_NO_SURFACE;
     62 #endif
     63 
     64     fHGLRC = NULL;
     65 #endif
     66     fAttached = kNone_BackEndType;
     67     fFullscreen = false;
     68 }
     69 
     70 SkOSWindow::~SkOSWindow() {
     71 #if SK_SUPPORT_GPU
     72     if (fHGLRC) {
     73         wglDeleteContext((HGLRC)fHGLRC);
     74     }
     75 #if SK_ANGLE
     76     if (EGL_NO_CONTEXT != fContext) {
     77         eglDestroyContext(fDisplay, fContext);
     78         fContext = EGL_NO_CONTEXT;
     79     }
     80 
     81     if (EGL_NO_SURFACE != fSurface) {
     82         eglDestroySurface(fDisplay, fSurface);
     83         fSurface = EGL_NO_SURFACE;
     84     }
     85 
     86     if (EGL_NO_DISPLAY != fDisplay) {
     87         eglTerminate(fDisplay);
     88         fDisplay = EGL_NO_DISPLAY;
     89     }
     90 #endif // SK_ANGLE
     91 #endif // SK_SUPPORT_GPU
     92     this->closeWindow();
     93 }
     94 
     95 static SkKey winToskKey(WPARAM vk) {
     96     static const struct {
     97         WPARAM    fVK;
     98         SkKey    fKey;
     99     } gPair[] = {
    100         { VK_BACK,    kBack_SkKey },
    101         { VK_CLEAR,    kBack_SkKey },
    102         { VK_RETURN, kOK_SkKey },
    103         { VK_UP,     kUp_SkKey },
    104         { VK_DOWN,     kDown_SkKey },
    105         { VK_LEFT,     kLeft_SkKey },
    106         { VK_RIGHT,     kRight_SkKey }
    107     };
    108     for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
    109         if (gPair[i].fVK == vk) {
    110             return gPair[i].fKey;
    111         }
    112     }
    113     return kNONE_SkKey;
    114 }
    115 
    116 static unsigned getModifiers(UINT message) {
    117     return 0;   // TODO
    118 }
    119 
    120 bool SkOSWindow::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    121     switch (message) {
    122         case WM_KEYDOWN: {
    123             SkKey key = winToskKey(wParam);
    124             if (kNONE_SkKey != key) {
    125                 this->handleKey(key);
    126                 return true;
    127             }
    128         } break;
    129         case WM_KEYUP: {
    130             SkKey key = winToskKey(wParam);
    131             if (kNONE_SkKey != key) {
    132                 this->handleKeyUp(key);
    133                 return true;
    134             }
    135         } break;
    136         case WM_UNICHAR:
    137             this->handleChar((SkUnichar) wParam);
    138             return true;
    139         case WM_CHAR: {
    140             const uint16_t* c = reinterpret_cast<uint16_t*>(&wParam);
    141             this->handleChar(SkUTF16_NextUnichar(&c));
    142             return true;
    143         } break;
    144         case WM_SIZE: {
    145             INT width = LOWORD(lParam);
    146             INT height = HIWORD(lParam);
    147             this->resize(width, height);
    148             break;
    149         }
    150         case WM_PAINT: {
    151             PAINTSTRUCT ps;
    152             HDC hdc = BeginPaint(hWnd, &ps);
    153             this->doPaint(hdc);
    154             EndPaint(hWnd, &ps);
    155             return true;
    156             } break;
    157 
    158         case WM_LBUTTONDOWN:
    159             this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),
    160                               Click::kDown_State, NULL, getModifiers(message));
    161             return true;
    162 
    163         case WM_MOUSEMOVE:
    164             this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),
    165                               Click::kMoved_State, NULL, getModifiers(message));
    166             return true;
    167 
    168         case WM_LBUTTONUP:
    169             this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),
    170                               Click::kUp_State, NULL, getModifiers(message));
    171             return true;
    172 
    173         case WM_EVENT_CALLBACK:
    174             if (SkEvent::ProcessEvent()) {
    175                 post_skwinevent(hWnd);
    176             }
    177             return true;
    178     }
    179     return false;
    180 }
    181 
    182 void SkOSWindow::doPaint(void* ctx) {
    183     this->update(NULL);
    184 
    185     if (kNone_BackEndType == fAttached)
    186     {
    187         HDC hdc = (HDC)ctx;
    188         const SkBitmap& bitmap = this->getBitmap();
    189 
    190         BITMAPINFO bmi;
    191         memset(&bmi, 0, sizeof(bmi));
    192         bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
    193         bmi.bmiHeader.biWidth       = bitmap.width();
    194         bmi.bmiHeader.biHeight      = -bitmap.height(); // top-down image
    195         bmi.bmiHeader.biPlanes      = 1;
    196         bmi.bmiHeader.biBitCount    = 32;
    197         bmi.bmiHeader.biCompression = BI_RGB;
    198         bmi.bmiHeader.biSizeImage   = 0;
    199 
    200         //
    201         // Do the SetDIBitsToDevice.
    202         //
    203         // TODO(wjmaclean):
    204         //       Fix this call to handle SkBitmaps that have rowBytes != width,
    205         //       i.e. may have padding at the end of lines. The SkASSERT below
    206         //       may be ignored by builds, and the only obviously safe option
    207         //       seems to be to copy the bitmap to a temporary (contiguous)
    208         //       buffer before passing to SetDIBitsToDevice().
    209         SkASSERT(bitmap.width() * bitmap.bytesPerPixel() == bitmap.rowBytes());
    210         int ret = SetDIBitsToDevice(hdc,
    211             0, 0,
    212             bitmap.width(), bitmap.height(),
    213             0, 0,
    214             0, bitmap.height(),
    215             bitmap.getPixels(),
    216             &bmi,
    217             DIB_RGB_COLORS);
    218         (void)ret; // we're ignoring potential failures for now.
    219     }
    220 }
    221 
    222 void SkOSWindow::updateSize()
    223 {
    224     RECT    r;
    225     GetWindowRect((HWND)fHWND, &r);
    226     this->resize(r.right - r.left, r.bottom - r.top);
    227 }
    228 
    229 void SkOSWindow::onHandleInval(const SkIRect& r) {
    230     RECT rect;
    231     rect.left    = r.fLeft;
    232     rect.top     = r.fTop;
    233     rect.right   = r.fRight;
    234     rect.bottom  = r.fBottom;
    235     InvalidateRect((HWND)fHWND, &rect, FALSE);
    236 }
    237 
    238 void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu)
    239 {
    240 }
    241 
    242 void SkOSWindow::onSetTitle(const char title[]){
    243     SetWindowTextA((HWND)fHWND, title);
    244 }
    245 
    246 enum {
    247     SK_MacReturnKey     = 36,
    248     SK_MacDeleteKey     = 51,
    249     SK_MacEndKey        = 119,
    250     SK_MacLeftKey       = 123,
    251     SK_MacRightKey      = 124,
    252     SK_MacDownKey       = 125,
    253     SK_MacUpKey         = 126,
    254 
    255     SK_Mac0Key          = 0x52,
    256     SK_Mac1Key          = 0x53,
    257     SK_Mac2Key          = 0x54,
    258     SK_Mac3Key          = 0x55,
    259     SK_Mac4Key          = 0x56,
    260     SK_Mac5Key          = 0x57,
    261     SK_Mac6Key          = 0x58,
    262     SK_Mac7Key          = 0x59,
    263     SK_Mac8Key          = 0x5b,
    264     SK_Mac9Key          = 0x5c
    265 };
    266 
    267 static SkKey raw2key(uint32_t raw)
    268 {
    269     static const struct {
    270         uint32_t  fRaw;
    271         SkKey   fKey;
    272     } gKeys[] = {
    273         { SK_MacUpKey,      kUp_SkKey       },
    274         { SK_MacDownKey,    kDown_SkKey     },
    275         { SK_MacLeftKey,    kLeft_SkKey     },
    276         { SK_MacRightKey,   kRight_SkKey    },
    277         { SK_MacReturnKey,  kOK_SkKey       },
    278         { SK_MacDeleteKey,  kBack_SkKey     },
    279         { SK_MacEndKey,     kEnd_SkKey      },
    280         { SK_Mac0Key,       k0_SkKey        },
    281         { SK_Mac1Key,       k1_SkKey        },
    282         { SK_Mac2Key,       k2_SkKey        },
    283         { SK_Mac3Key,       k3_SkKey        },
    284         { SK_Mac4Key,       k4_SkKey        },
    285         { SK_Mac5Key,       k5_SkKey        },
    286         { SK_Mac6Key,       k6_SkKey        },
    287         { SK_Mac7Key,       k7_SkKey        },
    288         { SK_Mac8Key,       k8_SkKey        },
    289         { SK_Mac9Key,       k9_SkKey        }
    290     };
    291 
    292     for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++)
    293         if (gKeys[i].fRaw == raw)
    294             return gKeys[i].fKey;
    295     return kNONE_SkKey;
    296 }
    297 
    298 ///////////////////////////////////////////////////////////////////////////////////////
    299 
    300 void SkEvent::SignalNonEmptyQueue()
    301 {
    302     SkOSWindow::ForAllWindows([](void* hWND, SkOSWindow**) {
    303         post_skwinevent((HWND)hWND);
    304     });
    305 }
    306 
    307 static UINT_PTR gTimer;
    308 
    309 VOID CALLBACK sk_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
    310 {
    311     SkEvent::ServiceQueueTimer();
    312     //SkDebugf("timer task fired\n");
    313 }
    314 
    315 void SkEvent::SignalQueueTimer(SkMSec delay)
    316 {
    317     if (gTimer)
    318     {
    319         KillTimer(NULL, gTimer);
    320         gTimer = NULL;
    321     }
    322     if (delay)
    323     {
    324         gTimer = SetTimer(NULL, 0, delay, sk_timer_proc);
    325         //SkDebugf("SetTimer of %d returned %d\n", delay, gTimer);
    326     }
    327 }
    328 
    329 #if SK_SUPPORT_GPU
    330 
    331 bool SkOSWindow::attachGL(int msaaSampleCount, bool deepColor, AttachmentInfo* info) {
    332     HDC dc = GetDC((HWND)fHWND);
    333     if (NULL == fHGLRC) {
    334         fHGLRC = SkCreateWGLContext(dc, msaaSampleCount, deepColor,
    335                 kGLPreferCompatibilityProfile_SkWGLContextRequest);
    336         if (NULL == fHGLRC) {
    337             return false;
    338         }
    339         glClearStencil(0);
    340         glClearColor(0, 0, 0, 0);
    341         glStencilMask(0xffffffff);
    342         glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    343     }
    344     if (wglMakeCurrent(dc, (HGLRC)fHGLRC)) {
    345         // use DescribePixelFormat to get the stencil and color bit depth.
    346         int pixelFormat = GetPixelFormat(dc);
    347         PIXELFORMATDESCRIPTOR pfd;
    348         DescribePixelFormat(dc, pixelFormat, sizeof(pfd), &pfd);
    349         info->fStencilBits = pfd.cStencilBits;
    350         // pfd.cColorBits includes alpha, so it will be 32 in 8/8/8/8 and 10/10/10/2
    351         info->fColorBits = pfd.cRedBits + pfd.cGreenBits + pfd.cBlueBits;
    352 
    353         // Get sample count if the MSAA WGL extension is present
    354         SkWGLExtensions extensions;
    355         if (extensions.hasExtension(dc, "WGL_ARB_multisample")) {
    356             static const int kSampleCountAttr = SK_WGL_SAMPLES;
    357             extensions.getPixelFormatAttribiv(dc,
    358                                               pixelFormat,
    359                                               0,
    360                                               1,
    361                                               &kSampleCountAttr,
    362                                               &info->fSampleCount);
    363         } else {
    364             info->fSampleCount = 0;
    365         }
    366 
    367         glViewport(0, 0,
    368                    SkScalarRoundToInt(this->width()),
    369                    SkScalarRoundToInt(this->height()));
    370         return true;
    371     }
    372     return false;
    373 }
    374 
    375 void SkOSWindow::detachGL() {
    376     wglMakeCurrent(GetDC((HWND)fHWND), 0);
    377     wglDeleteContext((HGLRC)fHGLRC);
    378     fHGLRC = NULL;
    379 }
    380 
    381 void SkOSWindow::presentGL() {
    382     HDC dc = GetDC((HWND)fHWND);
    383     SwapBuffers(dc);
    384     ReleaseDC((HWND)fHWND, dc);
    385 }
    386 
    387 #if SK_ANGLE
    388 
    389 static void* get_angle_egl_display(void* nativeDisplay) {
    390     PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
    391     eglGetPlatformDisplayEXT =
    392         (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
    393 
    394     // We expect ANGLE to support this extension
    395     if (!eglGetPlatformDisplayEXT) {
    396         return EGL_NO_DISPLAY;
    397     }
    398 
    399     EGLDisplay display = EGL_NO_DISPLAY;
    400     // Try for an ANGLE D3D11 context, fall back to D3D9, and finally GL.
    401     EGLint attribs[3][3] = {
    402         {
    403             EGL_PLATFORM_ANGLE_TYPE_ANGLE,
    404             EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
    405             EGL_NONE
    406         },
    407         {
    408             EGL_PLATFORM_ANGLE_TYPE_ANGLE,
    409             EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE,
    410             EGL_NONE
    411         },
    412     };
    413     for (int i = 0; i < 3 && display == EGL_NO_DISPLAY; ++i) {
    414         display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,nativeDisplay, attribs[i]);
    415     }
    416     return display;
    417 }
    418 
    419 struct ANGLEAssembleContext {
    420     ANGLEAssembleContext() {
    421         fEGL = GetModuleHandle("libEGL.dll");
    422         fGL = GetModuleHandle("libGLESv2.dll");
    423     }
    424 
    425     bool isValid() const { return SkToBool(fEGL) && SkToBool(fGL); }
    426 
    427     HMODULE fEGL;
    428     HMODULE fGL;
    429 };
    430 
    431 static GrGLFuncPtr angle_get_gl_proc(void* ctx, const char name[]) {
    432     const ANGLEAssembleContext& context = *reinterpret_cast<const ANGLEAssembleContext*>(ctx);
    433     GrGLFuncPtr proc = (GrGLFuncPtr) GetProcAddress(context.fGL, name);
    434     if (proc) {
    435         return proc;
    436     }
    437     proc = (GrGLFuncPtr) GetProcAddress(context.fEGL, name);
    438     if (proc) {
    439         return proc;
    440     }
    441     return eglGetProcAddress(name);
    442 }
    443 
    444 static const GrGLInterface* get_angle_gl_interface() {
    445     ANGLEAssembleContext context;
    446     if (!context.isValid()) {
    447         return nullptr;
    448     }
    449     return GrGLAssembleGLESInterface(&context, angle_get_gl_proc);
    450 }
    451 
    452 bool create_ANGLE(EGLNativeWindowType hWnd,
    453                   int msaaSampleCount,
    454                   EGLDisplay* eglDisplay,
    455                   EGLContext* eglContext,
    456                   EGLSurface* eglSurface,
    457                   EGLConfig* eglConfig) {
    458     static const EGLint contextAttribs[] = {
    459         EGL_CONTEXT_CLIENT_VERSION, 2,
    460         EGL_NONE, EGL_NONE
    461     };
    462     static const EGLint configAttribList[] = {
    463         EGL_RED_SIZE,       8,
    464         EGL_GREEN_SIZE,     8,
    465         EGL_BLUE_SIZE,      8,
    466         EGL_ALPHA_SIZE,     8,
    467         EGL_DEPTH_SIZE,     8,
    468         EGL_STENCIL_SIZE,   8,
    469         EGL_NONE
    470     };
    471     static const EGLint surfaceAttribList[] = {
    472         EGL_NONE, EGL_NONE
    473     };
    474 
    475     EGLDisplay display = get_angle_egl_display(GetDC(hWnd));
    476 
    477     if (EGL_NO_DISPLAY == display) {
    478         SkDebugf("Could not create ANGLE egl display!\n");
    479         return false;
    480     }
    481 
    482     // Initialize EGL
    483     EGLint majorVersion, minorVersion;
    484     if (!eglInitialize(display, &majorVersion, &minorVersion)) {
    485        return false;
    486     }
    487 
    488     EGLint numConfigs;
    489     if (!eglGetConfigs(display, NULL, 0, &numConfigs)) {
    490        return false;
    491     }
    492 
    493     // Choose config
    494     bool foundConfig = false;
    495     if (msaaSampleCount) {
    496         static const int kConfigAttribListCnt =
    497                                 SK_ARRAY_COUNT(configAttribList);
    498         EGLint msaaConfigAttribList[kConfigAttribListCnt + 4];
    499         memcpy(msaaConfigAttribList,
    500                configAttribList,
    501                sizeof(configAttribList));
    502         SkASSERT(EGL_NONE == msaaConfigAttribList[kConfigAttribListCnt - 1]);
    503         msaaConfigAttribList[kConfigAttribListCnt - 1] = EGL_SAMPLE_BUFFERS;
    504         msaaConfigAttribList[kConfigAttribListCnt + 0] = 1;
    505         msaaConfigAttribList[kConfigAttribListCnt + 1] = EGL_SAMPLES;
    506         msaaConfigAttribList[kConfigAttribListCnt + 2] = msaaSampleCount;
    507         msaaConfigAttribList[kConfigAttribListCnt + 3] = EGL_NONE;
    508         if (eglChooseConfig(display, msaaConfigAttribList, eglConfig, 1, &numConfigs)) {
    509             SkASSERT(numConfigs > 0);
    510             foundConfig = true;
    511         }
    512     }
    513     if (!foundConfig) {
    514         if (!eglChooseConfig(display, configAttribList, eglConfig, 1, &numConfigs)) {
    515            return false;
    516         }
    517     }
    518 
    519     // Create a surface
    520     EGLSurface surface = eglCreateWindowSurface(display, *eglConfig,
    521                                                 (EGLNativeWindowType)hWnd,
    522                                                 surfaceAttribList);
    523     if (surface == EGL_NO_SURFACE) {
    524        return false;
    525     }
    526 
    527     // Create a GL context
    528     EGLContext context = eglCreateContext(display, *eglConfig,
    529                                           EGL_NO_CONTEXT,
    530                                           contextAttribs );
    531     if (context == EGL_NO_CONTEXT ) {
    532        return false;
    533     }
    534 
    535     // Make the context current
    536     if (!eglMakeCurrent(display, surface, surface, context)) {
    537        return false;
    538     }
    539 
    540     *eglDisplay = display;
    541     *eglContext = context;
    542     *eglSurface = surface;
    543     return true;
    544 }
    545 
    546 bool SkOSWindow::attachANGLE(int msaaSampleCount, AttachmentInfo* info) {
    547     if (EGL_NO_DISPLAY == fDisplay) {
    548         bool bResult = create_ANGLE((HWND)fHWND,
    549                                     msaaSampleCount,
    550                                     &fDisplay,
    551                                     &fContext,
    552                                     &fSurface,
    553                                     &fConfig);
    554         if (false == bResult) {
    555             return false;
    556         }
    557         fANGLEInterface.reset(get_angle_gl_interface());
    558         if (!fANGLEInterface) {
    559             this->detachANGLE();
    560             return false;
    561         }
    562         GL_CALL(fANGLEInterface, ClearStencil(0));
    563         GL_CALL(fANGLEInterface, ClearColor(0, 0, 0, 0));
    564         GL_CALL(fANGLEInterface, StencilMask(0xffffffff));
    565         GL_CALL(fANGLEInterface, Clear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT));
    566     }
    567     if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
    568         this->detachANGLE();
    569         return false;
    570     }
    571     eglGetConfigAttrib(fDisplay, fConfig, EGL_STENCIL_SIZE, &info->fStencilBits);
    572     eglGetConfigAttrib(fDisplay, fConfig, EGL_SAMPLES, &info->fSampleCount);
    573 
    574     GL_CALL(fANGLEInterface, Viewport(0, 0, SkScalarRoundToInt(this->width()),
    575                                       SkScalarRoundToInt(this->height())));
    576     return true;
    577 }
    578 
    579 void SkOSWindow::detachANGLE() {
    580     fANGLEInterface.reset(nullptr);
    581     eglMakeCurrent(fDisplay, EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT);
    582 
    583     eglDestroyContext(fDisplay, fContext);
    584     fContext = EGL_NO_CONTEXT;
    585 
    586     eglDestroySurface(fDisplay, fSurface);
    587     fSurface = EGL_NO_SURFACE;
    588 
    589     eglTerminate(fDisplay);
    590     fDisplay = EGL_NO_DISPLAY;
    591 }
    592 
    593 void SkOSWindow::presentANGLE() {
    594     GL_CALL(fANGLEInterface, Flush());
    595 
    596     eglSwapBuffers(fDisplay, fSurface);
    597 }
    598 #endif // SK_ANGLE
    599 
    600 #endif // SK_SUPPORT_GPU
    601 
    602 // return true on success
    603 bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor,
    604                         AttachmentInfo* info) {
    605 
    606     // attach doubles as "windowResize" so we need to allo
    607     // already bound states to pass through again
    608     // TODO: split out the resize functionality
    609 //    SkASSERT(kNone_BackEndType == fAttached);
    610     bool result = true;
    611 
    612     switch (attachType) {
    613     case kNone_BackEndType:
    614         // nothing to do
    615         break;
    616 #if SK_SUPPORT_GPU
    617     case kNativeGL_BackEndType:
    618         result = attachGL(msaaSampleCount, deepColor, info);
    619         break;
    620 #if SK_ANGLE
    621     case kANGLE_BackEndType:
    622         result = attachANGLE(msaaSampleCount, info);
    623         break;
    624 #endif // SK_ANGLE
    625 #endif // SK_SUPPORT_GPU
    626     default:
    627         SkASSERT(false);
    628         result = false;
    629         break;
    630     }
    631 
    632     if (result) {
    633         fAttached = attachType;
    634     }
    635 
    636     return result;
    637 }
    638 
    639 void SkOSWindow::release() {
    640     switch (fAttached) {
    641     case kNone_BackEndType:
    642         // nothing to do
    643         break;
    644 #if SK_SUPPORT_GPU
    645     case kNativeGL_BackEndType:
    646         detachGL();
    647         break;
    648 #if SK_ANGLE
    649     case kANGLE_BackEndType:
    650         detachANGLE();
    651         break;
    652 #endif // SK_ANGLE
    653 #endif // SK_SUPPORT_GPU
    654     default:
    655         SkASSERT(false);
    656         break;
    657     }
    658     fAttached = kNone_BackEndType;
    659 }
    660 
    661 void SkOSWindow::present() {
    662     switch (fAttached) {
    663     case kNone_BackEndType:
    664         // nothing to do
    665         return;
    666 #if SK_SUPPORT_GPU
    667     case kNativeGL_BackEndType:
    668         presentGL();
    669         break;
    670 #if SK_ANGLE
    671     case kANGLE_BackEndType:
    672         presentANGLE();
    673         break;
    674 #endif // SK_ANGLE
    675 #endif // SK_SUPPORT_GPU
    676     default:
    677         SkASSERT(false);
    678         break;
    679     }
    680 }
    681 
    682 bool SkOSWindow::makeFullscreen() {
    683     if (fFullscreen) {
    684         return true;
    685     }
    686 #if SK_SUPPORT_GPU
    687     if (fHGLRC) {
    688         this->detachGL();
    689     }
    690 #endif // SK_SUPPORT_GPU
    691     // This is hacked together from various sources on the web. It can certainly be improved and be
    692     // made more robust.
    693 
    694     // Save current window/resolution information. We do this in case we ever implement switching
    695     // back to windowed mode.
    696     fSavedWindowState.fZoomed = SkToBool(IsZoomed((HWND)fHWND));
    697     if (fSavedWindowState.fZoomed) {
    698         SendMessage((HWND)fHWND, WM_SYSCOMMAND, SC_RESTORE, 0);
    699     }
    700     fSavedWindowState.fStyle = GetWindowLong((HWND)fHWND, GWL_STYLE);
    701     fSavedWindowState.fExStyle = GetWindowLong((HWND)fHWND, GWL_EXSTYLE);
    702     GetWindowRect((HWND)fHWND, &fSavedWindowState.fRect);
    703     DEVMODE currScreenSettings;
    704     memset(&currScreenSettings,0,sizeof(currScreenSettings));
    705     currScreenSettings.dmSize = sizeof(currScreenSettings);
    706     EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &currScreenSettings);
    707     fSavedWindowState.fScreenWidth = currScreenSettings.dmPelsWidth;
    708     fSavedWindowState.fScreenHeight = currScreenSettings.dmPelsHeight;
    709     fSavedWindowState.fScreenBits = currScreenSettings.dmBitsPerPel;
    710     fSavedWindowState.fHWND = fHWND;
    711 
    712     // Try different sizes to find an allowed setting? Use ChangeDisplaySettingsEx?
    713     static const int kWidth = 1280;
    714     static const int kHeight = 1024;
    715     DEVMODE newScreenSettings;
    716     memset(&newScreenSettings, 0, sizeof(newScreenSettings));
    717     newScreenSettings.dmSize = sizeof(newScreenSettings);
    718     newScreenSettings.dmPelsWidth    = kWidth;
    719     newScreenSettings.dmPelsHeight   = kHeight;
    720     newScreenSettings.dmBitsPerPel   = 32;
    721     newScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
    722     if (ChangeDisplaySettings(&newScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
    723         return false;
    724     }
    725     RECT WindowRect;
    726     WindowRect.left = 0;
    727     WindowRect.right = kWidth;
    728     WindowRect.top = 0;
    729     WindowRect.bottom = kHeight;
    730     ShowCursor(FALSE);
    731     AdjustWindowRectEx(&WindowRect, WS_POPUP, FALSE, WS_EX_APPWINDOW);
    732     HWND fsHWND = CreateWindowEx(
    733         WS_EX_APPWINDOW,
    734         fWinInit.fClass,
    735         NULL,
    736         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
    737         0, 0, WindowRect.right-WindowRect.left, WindowRect.bottom-WindowRect.top,
    738         NULL,
    739         NULL,
    740         fWinInit.fInstance,
    741         NULL
    742     );
    743     if (!fsHWND) {
    744         return false;
    745     }
    746     // Hide the old window and set the entry in the global mapping for this SkOSWindow to the
    747     // new HWND.
    748     ShowWindow((HWND)fHWND, SW_HIDE);
    749     gHwndToOSWindowMap.remove(fHWND);
    750     fHWND = fsHWND;
    751     gHwndToOSWindowMap.set(fHWND, this);
    752     this->updateSize();
    753 
    754     fFullscreen = true;
    755     return true;
    756 }
    757 
    758 void SkOSWindow::setVsync(bool enable) {
    759     SkWGLExtensions wgl;
    760     wgl.swapInterval(enable ? 1 : 0);
    761 }
    762 
    763 void SkOSWindow::closeWindow() {
    764     DestroyWindow((HWND)fHWND);
    765     if (fFullscreen) {
    766         DestroyWindow((HWND)fSavedWindowState.fHWND);
    767     }
    768     gHwndToOSWindowMap.remove(fHWND);
    769 }
    770 #endif
    771