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