• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
post_skwinevent(HWND hwnd)43 void post_skwinevent(HWND hwnd)
44 {
45     PostMessage(hwnd, WM_EVENT_CALLBACK, 0, 0);
46 }
47 
48 SkTHashMap<void*, SkOSWindow*> SkOSWindow::gHwndToOSWindowMap;
49 
SkOSWindow(const void * winInit)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 
~SkOSWindow()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 
winToskKey(WPARAM vk)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 
getModifiers(UINT message)116 static unsigned getModifiers(UINT message) {
117     return 0;   // TODO
118 }
119 
wndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)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 
doPaint(void * ctx)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         bitmap.lockPixels();
211         int ret = SetDIBitsToDevice(hdc,
212             0, 0,
213             bitmap.width(), bitmap.height(),
214             0, 0,
215             0, bitmap.height(),
216             bitmap.getPixels(),
217             &bmi,
218             DIB_RGB_COLORS);
219         (void)ret; // we're ignoring potential failures for now.
220         bitmap.unlockPixels();
221     }
222 }
223 
updateSize()224 void SkOSWindow::updateSize()
225 {
226     RECT    r;
227     GetWindowRect((HWND)fHWND, &r);
228     this->resize(r.right - r.left, r.bottom - r.top);
229 }
230 
onHandleInval(const SkIRect & r)231 void SkOSWindow::onHandleInval(const SkIRect& r) {
232     RECT rect;
233     rect.left    = r.fLeft;
234     rect.top     = r.fTop;
235     rect.right   = r.fRight;
236     rect.bottom  = r.fBottom;
237     InvalidateRect((HWND)fHWND, &rect, FALSE);
238 }
239 
onAddMenu(const SkOSMenu * sk_menu)240 void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu)
241 {
242 }
243 
onSetTitle(const char title[])244 void SkOSWindow::onSetTitle(const char title[]){
245     SetWindowTextA((HWND)fHWND, title);
246 }
247 
248 enum {
249     SK_MacReturnKey     = 36,
250     SK_MacDeleteKey     = 51,
251     SK_MacEndKey        = 119,
252     SK_MacLeftKey       = 123,
253     SK_MacRightKey      = 124,
254     SK_MacDownKey       = 125,
255     SK_MacUpKey         = 126,
256 
257     SK_Mac0Key          = 0x52,
258     SK_Mac1Key          = 0x53,
259     SK_Mac2Key          = 0x54,
260     SK_Mac3Key          = 0x55,
261     SK_Mac4Key          = 0x56,
262     SK_Mac5Key          = 0x57,
263     SK_Mac6Key          = 0x58,
264     SK_Mac7Key          = 0x59,
265     SK_Mac8Key          = 0x5b,
266     SK_Mac9Key          = 0x5c
267 };
268 
raw2key(uint32_t raw)269 static SkKey raw2key(uint32_t raw)
270 {
271     static const struct {
272         uint32_t  fRaw;
273         SkKey   fKey;
274     } gKeys[] = {
275         { SK_MacUpKey,      kUp_SkKey       },
276         { SK_MacDownKey,    kDown_SkKey     },
277         { SK_MacLeftKey,    kLeft_SkKey     },
278         { SK_MacRightKey,   kRight_SkKey    },
279         { SK_MacReturnKey,  kOK_SkKey       },
280         { SK_MacDeleteKey,  kBack_SkKey     },
281         { SK_MacEndKey,     kEnd_SkKey      },
282         { SK_Mac0Key,       k0_SkKey        },
283         { SK_Mac1Key,       k1_SkKey        },
284         { SK_Mac2Key,       k2_SkKey        },
285         { SK_Mac3Key,       k3_SkKey        },
286         { SK_Mac4Key,       k4_SkKey        },
287         { SK_Mac5Key,       k5_SkKey        },
288         { SK_Mac6Key,       k6_SkKey        },
289         { SK_Mac7Key,       k7_SkKey        },
290         { SK_Mac8Key,       k8_SkKey        },
291         { SK_Mac9Key,       k9_SkKey        }
292     };
293 
294     for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++)
295         if (gKeys[i].fRaw == raw)
296             return gKeys[i].fKey;
297     return kNONE_SkKey;
298 }
299 
300 ///////////////////////////////////////////////////////////////////////////////////////
301 
SignalNonEmptyQueue()302 void SkEvent::SignalNonEmptyQueue()
303 {
304     SkOSWindow::ForAllWindows([](void* hWND, SkOSWindow**) {
305         post_skwinevent((HWND)hWND);
306     });
307 }
308 
309 static UINT_PTR gTimer;
310 
sk_timer_proc(HWND hwnd,UINT uMsg,UINT_PTR idEvent,DWORD dwTime)311 VOID CALLBACK sk_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
312 {
313     SkEvent::ServiceQueueTimer();
314     //SkDebugf("timer task fired\n");
315 }
316 
SignalQueueTimer(SkMSec delay)317 void SkEvent::SignalQueueTimer(SkMSec delay)
318 {
319     if (gTimer)
320     {
321         KillTimer(NULL, gTimer);
322         gTimer = NULL;
323     }
324     if (delay)
325     {
326         gTimer = SetTimer(NULL, 0, delay, sk_timer_proc);
327         //SkDebugf("SetTimer of %d returned %d\n", delay, gTimer);
328     }
329 }
330 
331 #if SK_SUPPORT_GPU
332 
attachGL(int msaaSampleCount,bool deepColor,AttachmentInfo * info)333 bool SkOSWindow::attachGL(int msaaSampleCount, bool deepColor, AttachmentInfo* info) {
334     HDC dc = GetDC((HWND)fHWND);
335     if (NULL == fHGLRC) {
336         fHGLRC = SkCreateWGLContext(dc, msaaSampleCount, deepColor,
337                 kGLPreferCompatibilityProfile_SkWGLContextRequest);
338         if (NULL == fHGLRC) {
339             return false;
340         }
341         glClearStencil(0);
342         glClearColor(0, 0, 0, 0);
343         glStencilMask(0xffffffff);
344         glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
345     }
346     if (wglMakeCurrent(dc, (HGLRC)fHGLRC)) {
347         // use DescribePixelFormat to get the stencil and color bit depth.
348         int pixelFormat = GetPixelFormat(dc);
349         PIXELFORMATDESCRIPTOR pfd;
350         DescribePixelFormat(dc, pixelFormat, sizeof(pfd), &pfd);
351         info->fStencilBits = pfd.cStencilBits;
352         // pfd.cColorBits includes alpha, so it will be 32 in 8/8/8/8 and 10/10/10/2
353         info->fColorBits = pfd.cRedBits + pfd.cGreenBits + pfd.cBlueBits;
354 
355         // Get sample count if the MSAA WGL extension is present
356         SkWGLExtensions extensions;
357         if (extensions.hasExtension(dc, "WGL_ARB_multisample")) {
358             static const int kSampleCountAttr = SK_WGL_SAMPLES;
359             extensions.getPixelFormatAttribiv(dc,
360                                               pixelFormat,
361                                               0,
362                                               1,
363                                               &kSampleCountAttr,
364                                               &info->fSampleCount);
365         } else {
366             info->fSampleCount = 0;
367         }
368 
369         glViewport(0, 0,
370                    SkScalarRoundToInt(this->width()),
371                    SkScalarRoundToInt(this->height()));
372         return true;
373     }
374     return false;
375 }
376 
detachGL()377 void SkOSWindow::detachGL() {
378     wglMakeCurrent(GetDC((HWND)fHWND), 0);
379     wglDeleteContext((HGLRC)fHGLRC);
380     fHGLRC = NULL;
381 }
382 
presentGL()383 void SkOSWindow::presentGL() {
384     HDC dc = GetDC((HWND)fHWND);
385     SwapBuffers(dc);
386     ReleaseDC((HWND)fHWND, dc);
387 }
388 
389 #if SK_ANGLE
390 
get_angle_egl_display(void * nativeDisplay)391 static void* get_angle_egl_display(void* nativeDisplay) {
392     PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
393     eglGetPlatformDisplayEXT =
394         (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
395 
396     // We expect ANGLE to support this extension
397     if (!eglGetPlatformDisplayEXT) {
398         return EGL_NO_DISPLAY;
399     }
400 
401     EGLDisplay display = EGL_NO_DISPLAY;
402     // Try for an ANGLE D3D11 context, fall back to D3D9, and finally GL.
403     EGLint attribs[3][3] = {
404         {
405             EGL_PLATFORM_ANGLE_TYPE_ANGLE,
406             EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
407             EGL_NONE
408         },
409         {
410             EGL_PLATFORM_ANGLE_TYPE_ANGLE,
411             EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE,
412             EGL_NONE
413         },
414     };
415     for (int i = 0; i < 3 && display == EGL_NO_DISPLAY; ++i) {
416         display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,nativeDisplay, attribs[i]);
417     }
418     return display;
419 }
420 
421 struct ANGLEAssembleContext {
ANGLEAssembleContextANGLEAssembleContext422     ANGLEAssembleContext() {
423         fEGL = GetModuleHandle("libEGL.dll");
424         fGL = GetModuleHandle("libGLESv2.dll");
425     }
426 
isValidANGLEAssembleContext427     bool isValid() const { return SkToBool(fEGL) && SkToBool(fGL); }
428 
429     HMODULE fEGL;
430     HMODULE fGL;
431 };
432 
angle_get_gl_proc(void * ctx,const char name[])433 static GrGLFuncPtr angle_get_gl_proc(void* ctx, const char name[]) {
434     const ANGLEAssembleContext& context = *reinterpret_cast<const ANGLEAssembleContext*>(ctx);
435     GrGLFuncPtr proc = (GrGLFuncPtr) GetProcAddress(context.fGL, name);
436     if (proc) {
437         return proc;
438     }
439     proc = (GrGLFuncPtr) GetProcAddress(context.fEGL, name);
440     if (proc) {
441         return proc;
442     }
443     return eglGetProcAddress(name);
444 }
445 
get_angle_gl_interface()446 static const GrGLInterface* get_angle_gl_interface() {
447     ANGLEAssembleContext context;
448     if (!context.isValid()) {
449         return nullptr;
450     }
451     return GrGLAssembleGLESInterface(&context, angle_get_gl_proc);
452 }
453 
create_ANGLE(EGLNativeWindowType hWnd,int msaaSampleCount,EGLDisplay * eglDisplay,EGLContext * eglContext,EGLSurface * eglSurface,EGLConfig * eglConfig)454 bool create_ANGLE(EGLNativeWindowType hWnd,
455                   int msaaSampleCount,
456                   EGLDisplay* eglDisplay,
457                   EGLContext* eglContext,
458                   EGLSurface* eglSurface,
459                   EGLConfig* eglConfig) {
460     static const EGLint contextAttribs[] = {
461         EGL_CONTEXT_CLIENT_VERSION, 2,
462         EGL_NONE, EGL_NONE
463     };
464     static const EGLint configAttribList[] = {
465         EGL_RED_SIZE,       8,
466         EGL_GREEN_SIZE,     8,
467         EGL_BLUE_SIZE,      8,
468         EGL_ALPHA_SIZE,     8,
469         EGL_DEPTH_SIZE,     8,
470         EGL_STENCIL_SIZE,   8,
471         EGL_NONE
472     };
473     static const EGLint surfaceAttribList[] = {
474         EGL_NONE, EGL_NONE
475     };
476 
477     EGLDisplay display = get_angle_egl_display(GetDC(hWnd));
478 
479     if (EGL_NO_DISPLAY == display) {
480         SkDebugf("Could not create ANGLE egl display!\n");
481         return false;
482     }
483 
484     // Initialize EGL
485     EGLint majorVersion, minorVersion;
486     if (!eglInitialize(display, &majorVersion, &minorVersion)) {
487        return false;
488     }
489 
490     EGLint numConfigs;
491     if (!eglGetConfigs(display, NULL, 0, &numConfigs)) {
492        return false;
493     }
494 
495     // Choose config
496     bool foundConfig = false;
497     if (msaaSampleCount) {
498         static const int kConfigAttribListCnt =
499                                 SK_ARRAY_COUNT(configAttribList);
500         EGLint msaaConfigAttribList[kConfigAttribListCnt + 4];
501         memcpy(msaaConfigAttribList,
502                configAttribList,
503                sizeof(configAttribList));
504         SkASSERT(EGL_NONE == msaaConfigAttribList[kConfigAttribListCnt - 1]);
505         msaaConfigAttribList[kConfigAttribListCnt - 1] = EGL_SAMPLE_BUFFERS;
506         msaaConfigAttribList[kConfigAttribListCnt + 0] = 1;
507         msaaConfigAttribList[kConfigAttribListCnt + 1] = EGL_SAMPLES;
508         msaaConfigAttribList[kConfigAttribListCnt + 2] = msaaSampleCount;
509         msaaConfigAttribList[kConfigAttribListCnt + 3] = EGL_NONE;
510         if (eglChooseConfig(display, msaaConfigAttribList, eglConfig, 1, &numConfigs)) {
511             SkASSERT(numConfigs > 0);
512             foundConfig = true;
513         }
514     }
515     if (!foundConfig) {
516         if (!eglChooseConfig(display, configAttribList, eglConfig, 1, &numConfigs)) {
517            return false;
518         }
519     }
520 
521     // Create a surface
522     EGLSurface surface = eglCreateWindowSurface(display, *eglConfig,
523                                                 (EGLNativeWindowType)hWnd,
524                                                 surfaceAttribList);
525     if (surface == EGL_NO_SURFACE) {
526        return false;
527     }
528 
529     // Create a GL context
530     EGLContext context = eglCreateContext(display, *eglConfig,
531                                           EGL_NO_CONTEXT,
532                                           contextAttribs );
533     if (context == EGL_NO_CONTEXT ) {
534        return false;
535     }
536 
537     // Make the context current
538     if (!eglMakeCurrent(display, surface, surface, context)) {
539        return false;
540     }
541 
542     *eglDisplay = display;
543     *eglContext = context;
544     *eglSurface = surface;
545     return true;
546 }
547 
attachANGLE(int msaaSampleCount,AttachmentInfo * info)548 bool SkOSWindow::attachANGLE(int msaaSampleCount, AttachmentInfo* info) {
549     if (EGL_NO_DISPLAY == fDisplay) {
550         bool bResult = create_ANGLE((HWND)fHWND,
551                                     msaaSampleCount,
552                                     &fDisplay,
553                                     &fContext,
554                                     &fSurface,
555                                     &fConfig);
556         if (false == bResult) {
557             return false;
558         }
559         fANGLEInterface.reset(get_angle_gl_interface());
560         if (!fANGLEInterface) {
561             this->detachANGLE();
562             return false;
563         }
564         GL_CALL(fANGLEInterface, ClearStencil(0));
565         GL_CALL(fANGLEInterface, ClearColor(0, 0, 0, 0));
566         GL_CALL(fANGLEInterface, StencilMask(0xffffffff));
567         GL_CALL(fANGLEInterface, Clear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT));
568     }
569     if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
570         this->detachANGLE();
571         return false;
572     }
573     eglGetConfigAttrib(fDisplay, fConfig, EGL_STENCIL_SIZE, &info->fStencilBits);
574     eglGetConfigAttrib(fDisplay, fConfig, EGL_SAMPLES, &info->fSampleCount);
575 
576     GL_CALL(fANGLEInterface, Viewport(0, 0, SkScalarRoundToInt(this->width()),
577                                       SkScalarRoundToInt(this->height())));
578     return true;
579 }
580 
detachANGLE()581 void SkOSWindow::detachANGLE() {
582     fANGLEInterface.reset(nullptr);
583     eglMakeCurrent(fDisplay, EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT);
584 
585     eglDestroyContext(fDisplay, fContext);
586     fContext = EGL_NO_CONTEXT;
587 
588     eglDestroySurface(fDisplay, fSurface);
589     fSurface = EGL_NO_SURFACE;
590 
591     eglTerminate(fDisplay);
592     fDisplay = EGL_NO_DISPLAY;
593 }
594 
presentANGLE()595 void SkOSWindow::presentANGLE() {
596     GL_CALL(fANGLEInterface, Flush());
597 
598     eglSwapBuffers(fDisplay, fSurface);
599 }
600 #endif // SK_ANGLE
601 
602 #endif // SK_SUPPORT_GPU
603 
604 // return true on success
attach(SkBackEndTypes attachType,int msaaSampleCount,bool deepColor,AttachmentInfo * info)605 bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor,
606                         AttachmentInfo* info) {
607 
608     // attach doubles as "windowResize" so we need to allo
609     // already bound states to pass through again
610     // TODO: split out the resize functionality
611 //    SkASSERT(kNone_BackEndType == fAttached);
612     bool result = true;
613 
614     switch (attachType) {
615     case kNone_BackEndType:
616         // nothing to do
617         break;
618 #if SK_SUPPORT_GPU
619     case kNativeGL_BackEndType:
620         result = attachGL(msaaSampleCount, deepColor, info);
621         break;
622 #if SK_ANGLE
623     case kANGLE_BackEndType:
624         result = attachANGLE(msaaSampleCount, info);
625         break;
626 #endif // SK_ANGLE
627 #endif // SK_SUPPORT_GPU
628     default:
629         SkASSERT(false);
630         result = false;
631         break;
632     }
633 
634     if (result) {
635         fAttached = attachType;
636     }
637 
638     return result;
639 }
640 
release()641 void SkOSWindow::release() {
642     switch (fAttached) {
643     case kNone_BackEndType:
644         // nothing to do
645         break;
646 #if SK_SUPPORT_GPU
647     case kNativeGL_BackEndType:
648         detachGL();
649         break;
650 #if SK_ANGLE
651     case kANGLE_BackEndType:
652         detachANGLE();
653         break;
654 #endif // SK_ANGLE
655 #endif // SK_SUPPORT_GPU
656     default:
657         SkASSERT(false);
658         break;
659     }
660     fAttached = kNone_BackEndType;
661 }
662 
present()663 void SkOSWindow::present() {
664     switch (fAttached) {
665     case kNone_BackEndType:
666         // nothing to do
667         return;
668 #if SK_SUPPORT_GPU
669     case kNativeGL_BackEndType:
670         presentGL();
671         break;
672 #if SK_ANGLE
673     case kANGLE_BackEndType:
674         presentANGLE();
675         break;
676 #endif // SK_ANGLE
677 #endif // SK_SUPPORT_GPU
678     default:
679         SkASSERT(false);
680         break;
681     }
682 }
683 
makeFullscreen()684 bool SkOSWindow::makeFullscreen() {
685     if (fFullscreen) {
686         return true;
687     }
688 #if SK_SUPPORT_GPU
689     if (fHGLRC) {
690         this->detachGL();
691     }
692 #endif // SK_SUPPORT_GPU
693     // This is hacked together from various sources on the web. It can certainly be improved and be
694     // made more robust.
695 
696     // Save current window/resolution information. We do this in case we ever implement switching
697     // back to windowed mode.
698     fSavedWindowState.fZoomed = SkToBool(IsZoomed((HWND)fHWND));
699     if (fSavedWindowState.fZoomed) {
700         SendMessage((HWND)fHWND, WM_SYSCOMMAND, SC_RESTORE, 0);
701     }
702     fSavedWindowState.fStyle = GetWindowLong((HWND)fHWND, GWL_STYLE);
703     fSavedWindowState.fExStyle = GetWindowLong((HWND)fHWND, GWL_EXSTYLE);
704     GetWindowRect((HWND)fHWND, &fSavedWindowState.fRect);
705     DEVMODE currScreenSettings;
706     memset(&currScreenSettings,0,sizeof(currScreenSettings));
707     currScreenSettings.dmSize = sizeof(currScreenSettings);
708     EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &currScreenSettings);
709     fSavedWindowState.fScreenWidth = currScreenSettings.dmPelsWidth;
710     fSavedWindowState.fScreenHeight = currScreenSettings.dmPelsHeight;
711     fSavedWindowState.fScreenBits = currScreenSettings.dmBitsPerPel;
712     fSavedWindowState.fHWND = fHWND;
713 
714     // Try different sizes to find an allowed setting? Use ChangeDisplaySettingsEx?
715     static const int kWidth = 1280;
716     static const int kHeight = 1024;
717     DEVMODE newScreenSettings;
718     memset(&newScreenSettings, 0, sizeof(newScreenSettings));
719     newScreenSettings.dmSize = sizeof(newScreenSettings);
720     newScreenSettings.dmPelsWidth    = kWidth;
721     newScreenSettings.dmPelsHeight   = kHeight;
722     newScreenSettings.dmBitsPerPel   = 32;
723     newScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
724     if (ChangeDisplaySettings(&newScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
725         return false;
726     }
727     RECT WindowRect;
728     WindowRect.left = 0;
729     WindowRect.right = kWidth;
730     WindowRect.top = 0;
731     WindowRect.bottom = kHeight;
732     ShowCursor(FALSE);
733     AdjustWindowRectEx(&WindowRect, WS_POPUP, FALSE, WS_EX_APPWINDOW);
734     HWND fsHWND = CreateWindowEx(
735         WS_EX_APPWINDOW,
736         fWinInit.fClass,
737         NULL,
738         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
739         0, 0, WindowRect.right-WindowRect.left, WindowRect.bottom-WindowRect.top,
740         NULL,
741         NULL,
742         fWinInit.fInstance,
743         NULL
744     );
745     if (!fsHWND) {
746         return false;
747     }
748     // Hide the old window and set the entry in the global mapping for this SkOSWindow to the
749     // new HWND.
750     ShowWindow((HWND)fHWND, SW_HIDE);
751     gHwndToOSWindowMap.remove(fHWND);
752     fHWND = fsHWND;
753     gHwndToOSWindowMap.set(fHWND, this);
754     this->updateSize();
755 
756     fFullscreen = true;
757     return true;
758 }
759 
setVsync(bool enable)760 void SkOSWindow::setVsync(bool enable) {
761     SkWGLExtensions wgl;
762     wgl.swapInterval(enable ? 1 : 0);
763 }
764 
closeWindow()765 void SkOSWindow::closeWindow() {
766     DestroyWindow((HWND)fHWND);
767     if (fFullscreen) {
768         DestroyWindow((HWND)fSavedWindowState.fHWND);
769     }
770     gHwndToOSWindowMap.remove(fHWND);
771 }
772 #endif
773