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