blob: 6b26400ca5008a46396778f569ad2cddcaefda8f [file] [log] [blame]
bsalomon@google.com2858b312012-04-02 20:44:38 +00001
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>
bsalomon@google.com2858b312012-04-02 20:44:38 +000013#include <WindowsX.h>
14#include "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/GrGLInterface.h"
25
26#include "GLES2/gl2.h"
27#endif
28
29#define INVALIDATE_DELAY_MS 200
30
31static SkOSWindow* gCurrOSWin;
32static HWND gEventTarget;
33
34#define WM_EVENT_CALLBACK (WM_USER+0)
35
36void post_skwinevent()
37{
38 PostMessage(gEventTarget, WM_EVENT_CALLBACK, 0, 0);
39}
40
41SkOSWindow::SkOSWindow(void* hWnd)
42 : fHWND(hWnd)
43#if SK_ANGLE
44 , fDisplay(EGL_NO_DISPLAY)
45 , fContext(EGL_NO_CONTEXT)
46 , fSurface(EGL_NO_SURFACE)
47#endif
48 , fHGLRC(NULL)
bsalomon@google.com2858b312012-04-02 20:44:38 +000049 , fAttached(kNone_BackEndType) {
50 gEventTarget = (HWND)hWnd;
51}
52
53SkOSWindow::~SkOSWindow() {
bsalomon@google.com2858b312012-04-02 20:44:38 +000054 if (NULL != fHGLRC) {
55 wglDeleteContext((HGLRC)fHGLRC);
56 }
57#if SK_ANGLE
58 if (EGL_NO_CONTEXT != fContext) {
59 eglDestroyContext(fDisplay, fContext);
60 fContext = EGL_NO_CONTEXT;
61 }
62
63 if (EGL_NO_SURFACE != fSurface) {
64 eglDestroySurface(fDisplay, fSurface);
65 fSurface = EGL_NO_SURFACE;
66 }
67
68 if (EGL_NO_DISPLAY != fDisplay) {
69 eglTerminate(fDisplay);
70 fDisplay = EGL_NO_DISPLAY;
71 }
72#endif
73}
74
75static SkKey winToskKey(WPARAM vk) {
76 static const struct {
77 WPARAM fVK;
78 SkKey fKey;
79 } gPair[] = {
80 { VK_BACK, kBack_SkKey },
81 { VK_CLEAR, kBack_SkKey },
82 { VK_RETURN, kOK_SkKey },
83 { VK_UP, kUp_SkKey },
84 { VK_DOWN, kDown_SkKey },
85 { VK_LEFT, kLeft_SkKey },
86 { VK_RIGHT, kRight_SkKey }
87 };
88 for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
89 if (gPair[i].fVK == vk) {
90 return gPair[i].fKey;
91 }
92 }
93 return kNONE_SkKey;
94}
95
96bool SkOSWindow::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
97 switch (message) {
98 case WM_KEYDOWN: {
99 SkKey key = winToskKey(wParam);
100 if (kNONE_SkKey != key) {
101 this->handleKey(key);
102 return true;
103 }
104 } break;
105 case WM_KEYUP: {
106 SkKey key = winToskKey(wParam);
107 if (kNONE_SkKey != key) {
108 this->handleKeyUp(key);
109 return true;
110 }
111 } break;
112 case WM_UNICHAR:
113 this->handleChar(wParam);
114 return true;
115 case WM_CHAR: {
116 this->handleChar(SkUTF8_ToUnichar((char*)&wParam));
117 return true;
118 } break;
119 case WM_SIZE:
120 this->resize(lParam & 0xFFFF, lParam >> 16);
121 break;
122 case WM_PAINT: {
123 PAINTSTRUCT ps;
124 HDC hdc = BeginPaint(hWnd, &ps);
125 this->doPaint(hdc);
126 EndPaint(hWnd, &ps);
127 return true;
128 } break;
129
130 case WM_TIMER: {
131 RECT* rect = (RECT*)wParam;
132 InvalidateRect(hWnd, rect, FALSE);
133 KillTimer(hWnd, (UINT_PTR)rect);
134 delete rect;
135 return true;
136 } break;
137
138 case WM_LBUTTONDOWN:
139 this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), Click::kDown_State);
140 return true;
141
142 case WM_MOUSEMOVE:
143 this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), Click::kMoved_State);
144 return true;
145
146 case WM_LBUTTONUP:
147 this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), Click::kUp_State);
148 return true;
149
150 case WM_EVENT_CALLBACK:
151 if (SkEvent::ProcessEvent()) {
152 post_skwinevent();
153 }
154 return true;
155 }
156 return false;
157}
158
159void SkOSWindow::doPaint(void* ctx) {
160 this->update(NULL);
161
162 if (kNone_BackEndType == fAttached)
163 {
164 HDC hdc = (HDC)ctx;
165 const SkBitmap& bitmap = this->getBitmap();
166
167 BITMAPINFO bmi;
168 memset(&bmi, 0, sizeof(bmi));
169 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
170 bmi.bmiHeader.biWidth = bitmap.width();
171 bmi.bmiHeader.biHeight = -bitmap.height(); // top-down image
172 bmi.bmiHeader.biPlanes = 1;
173 bmi.bmiHeader.biBitCount = 32;
174 bmi.bmiHeader.biCompression = BI_RGB;
175 bmi.bmiHeader.biSizeImage = 0;
176
177 //
178 // Do the SetDIBitsToDevice.
179 //
180 // TODO(wjmaclean):
181 // Fix this call to handle SkBitmaps that have rowBytes != width,
182 // i.e. may have padding at the end of lines. The SkASSERT below
183 // may be ignored by builds, and the only obviously safe option
184 // seems to be to copy the bitmap to a temporary (contiguous)
185 // buffer before passing to SetDIBitsToDevice().
186 SkASSERT(bitmap.width() * bitmap.bytesPerPixel() == bitmap.rowBytes());
187 bitmap.lockPixels();
188 int iRet = SetDIBitsToDevice(hdc,
189 0, 0,
190 bitmap.width(), bitmap.height(),
191 0, 0,
192 0, bitmap.height(),
193 bitmap.getPixels(),
194 &bmi,
195 DIB_RGB_COLORS);
196 bitmap.unlockPixels();
197 }
198}
199
200#if 0
201void SkOSWindow::updateSize()
202{
203 RECT r;
204 GetWindowRect((HWND)this->getHWND(), &r);
205 this->resize(r.right - r.left, r.bottom - r.top);
206}
207#endif
208
209void SkOSWindow::onHandleInval(const SkIRect& r) {
210 RECT* rect = new RECT;
211 rect->left = r.fLeft;
212 rect->top = r.fTop;
213 rect->right = r.fRight;
214 rect->bottom = r.fBottom;
215 SetTimer((HWND)fHWND, (UINT_PTR)rect, INVALIDATE_DELAY_MS, NULL);
216}
217
218void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu)
219{
220}
221
222void SkOSWindow::onSetTitle(const char title[]){
223 SetWindowTextA((HWND)fHWND, title);
224}
225
226enum {
227 SK_MacReturnKey = 36,
228 SK_MacDeleteKey = 51,
229 SK_MacEndKey = 119,
230 SK_MacLeftKey = 123,
231 SK_MacRightKey = 124,
232 SK_MacDownKey = 125,
233 SK_MacUpKey = 126,
234
235 SK_Mac0Key = 0x52,
236 SK_Mac1Key = 0x53,
237 SK_Mac2Key = 0x54,
238 SK_Mac3Key = 0x55,
239 SK_Mac4Key = 0x56,
240 SK_Mac5Key = 0x57,
241 SK_Mac6Key = 0x58,
242 SK_Mac7Key = 0x59,
243 SK_Mac8Key = 0x5b,
244 SK_Mac9Key = 0x5c
245};
246
247static SkKey raw2key(uint32_t raw)
248{
249 static const struct {
250 uint32_t fRaw;
251 SkKey fKey;
252 } gKeys[] = {
253 { SK_MacUpKey, kUp_SkKey },
254 { SK_MacDownKey, kDown_SkKey },
255 { SK_MacLeftKey, kLeft_SkKey },
256 { SK_MacRightKey, kRight_SkKey },
257 { SK_MacReturnKey, kOK_SkKey },
258 { SK_MacDeleteKey, kBack_SkKey },
259 { SK_MacEndKey, kEnd_SkKey },
260 { SK_Mac0Key, k0_SkKey },
261 { SK_Mac1Key, k1_SkKey },
262 { SK_Mac2Key, k2_SkKey },
263 { SK_Mac3Key, k3_SkKey },
264 { SK_Mac4Key, k4_SkKey },
265 { SK_Mac5Key, k5_SkKey },
266 { SK_Mac6Key, k6_SkKey },
267 { SK_Mac7Key, k7_SkKey },
268 { SK_Mac8Key, k8_SkKey },
269 { SK_Mac9Key, k9_SkKey }
270 };
271
272 for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++)
273 if (gKeys[i].fRaw == raw)
274 return gKeys[i].fKey;
275 return kNONE_SkKey;
276}
277
278///////////////////////////////////////////////////////////////////////////////////////
279
280void SkEvent::SignalNonEmptyQueue()
281{
282 post_skwinevent();
283 //SkDebugf("signal nonempty\n");
284}
285
286static UINT_PTR gTimer;
287
288VOID CALLBACK sk_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
289{
290 SkEvent::ServiceQueueTimer();
291 //SkDebugf("timer task fired\n");
292}
293
294void SkEvent::SignalQueueTimer(SkMSec delay)
295{
296 if (gTimer)
297 {
298 KillTimer(NULL, gTimer);
299 gTimer = NULL;
300 }
301 if (delay)
302 {
303 gTimer = SetTimer(NULL, 0, delay, sk_timer_proc);
304 //SkDebugf("SetTimer of %d returned %d\n", delay, gTimer);
305 }
306}
307
308
309#define USE_MSAA 0
310
bsalomon@google.com11959252012-04-06 20:13:38 +0000311HGLRC create_gl(HWND hwnd, int msaaSampleCount) {
bsalomon@google.com2858b312012-04-02 20:44:38 +0000312
313 HDC dc = GetDC(hwnd);
314
315 SkWGLExtensions extensions;
316 if (!extensions.hasExtension(dc, "WGL_ARB_pixel_format")) {
317 return NULL;
318 }
319
320 HDC prevDC = wglGetCurrentDC();
321 HGLRC prevGLRC = wglGetCurrentContext();
322 PIXELFORMATDESCRIPTOR pfd;
323
324 int format = 0;
325
bsalomon@google.com11959252012-04-06 20:13:38 +0000326 static const GLint iAttrs[] = {
bsalomon@google.com2858b312012-04-02 20:44:38 +0000327 SK_WGL_DRAW_TO_WINDOW, TRUE,
328 SK_WGL_DOUBLE_BUFFER, TRUE,
329 SK_WGL_ACCELERATION, SK_WGL_FULL_ACCELERATION,
330 SK_WGL_SUPPORT_OPENGL, TRUE,
331 SK_WGL_COLOR_BITS, 24,
332 SK_WGL_ALPHA_BITS, 8,
333 SK_WGL_STENCIL_BITS, 8,
bsalomon@google.com11959252012-04-06 20:13:38 +0000334 0, 0
bsalomon@google.com2858b312012-04-02 20:44:38 +0000335 };
336
bsalomon@google.com11959252012-04-06 20:13:38 +0000337 GLfloat fAttrs[] = {0, 0};
338
339 if (msaaSampleCount > 0 &&
340 extensions.hasExtension(dc, "WGL_ARB_multisample")) {
341 static const int kIAttrsCount = SK_ARRAY_COUNT(iAttrs);
342 GLint msaaIAttrs[kIAttrsCount + 4];
343 memcpy(msaaIAttrs, iAttrs, sizeof(GLint) * kIAttrsCount);
344 SkASSERT(0 == msaaIAttrs[kIAttrsCount - 2] &&
345 0 == msaaIAttrs[kIAttrsCount - 1]);
346 msaaIAttrs[kIAttrsCount - 2] = SK_WGL_SAMPLE_BUFFERS;
347 msaaIAttrs[kIAttrsCount - 1] = TRUE;
348 msaaIAttrs[kIAttrsCount + 0] = SK_WGL_SAMPLES;
349 msaaIAttrs[kIAttrsCount + 1] = msaaSampleCount;
350 msaaIAttrs[kIAttrsCount + 2] = 0;
351 msaaIAttrs[kIAttrsCount + 3] = 0;
352 GLuint num;
353 int formats[64];
354 extensions.choosePixelFormat(dc, msaaIAttrs, fAttrs, 64, formats, &num);
355 num = min(num,64);
356 for (GLuint i = 0; i < num; ++i) {
357 DescribePixelFormat(dc, formats[i], sizeof(pfd), &pfd);
358 if (SetPixelFormat(dc, formats[i], &pfd)) {
359 format = formats[i];
360 break;
bsalomon@google.com2858b312012-04-02 20:44:38 +0000361 }
362 }
363 }
364
365 if (0 == format) {
bsalomon@google.com2858b312012-04-02 20:44:38 +0000366 GLuint num;
bsalomon@google.com11959252012-04-06 20:13:38 +0000367 extensions.choosePixelFormat(dc, iAttrs, fAttrs, 1, &format, &num);
bsalomon@google.com2858b312012-04-02 20:44:38 +0000368 DescribePixelFormat(dc, format, sizeof(pfd), &pfd);
369 BOOL set = SetPixelFormat(dc, format, &pfd);
370 SkASSERT(TRUE == set);
371 }
372
373 HGLRC glrc = wglCreateContext(dc);
374 SkASSERT(glrc);
375
376 wglMakeCurrent(prevDC, prevGLRC);
377 return glrc;
378}
379
bsalomon@google.com11959252012-04-06 20:13:38 +0000380bool SkOSWindow::attachGL(int msaaSampleCount) {
bsalomon@google.com2858b312012-04-02 20:44:38 +0000381 if (NULL == fHGLRC) {
bsalomon@google.com11959252012-04-06 20:13:38 +0000382 fHGLRC = create_gl((HWND)fHWND, msaaSampleCount);
bsalomon@google.com2858b312012-04-02 20:44:38 +0000383 if (NULL == fHGLRC) {
384 return false;
385 }
386 glClearStencil(0);
387 glClearColor(0, 0, 0, 0);
388 glStencilMask(0xffffffff);
389 glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
390 }
391 if (wglMakeCurrent(GetDC((HWND)fHWND), (HGLRC)fHGLRC)) {
392 glViewport(0, 0, SkScalarRound(this->width()),
393 SkScalarRound(this->height()));
394 return true;
395 }
396 return false;
397}
398
399void SkOSWindow::detachGL() {
400 wglMakeCurrent(GetDC((HWND)fHWND), 0);
401 wglDeleteContext((HGLRC)fHGLRC);
402 fHGLRC = NULL;
403}
404
405void SkOSWindow::presentGL() {
406 glFlush();
407 SwapBuffers(GetDC((HWND)fHWND));
408}
409
410#if SK_ANGLE
bsalomon@google.com11959252012-04-06 20:13:38 +0000411bool create_ANGLE(EGLNativeWindowType hWnd,
412 int msaaSampleCount,
413 EGLDisplay* eglDisplay,
414 EGLContext* eglContext,
415 EGLSurface* eglSurface) {
416 static const EGLint contextAttribs[] = {
417 EGL_CONTEXT_CLIENT_VERSION, 2,
bsalomon@google.com2858b312012-04-02 20:44:38 +0000418 EGL_NONE, EGL_NONE
419 };
bsalomon@google.com11959252012-04-06 20:13:38 +0000420 static const EGLint configAttribList[] = {
bsalomon@google.com2858b312012-04-02 20:44:38 +0000421 EGL_RED_SIZE, 8,
422 EGL_GREEN_SIZE, 8,
423 EGL_BLUE_SIZE, 8,
424 EGL_ALPHA_SIZE, 8,
425 EGL_DEPTH_SIZE, 8,
426 EGL_STENCIL_SIZE, 8,
427 EGL_NONE
428 };
bsalomon@google.com11959252012-04-06 20:13:38 +0000429 static const EGLint surfaceAttribList[] = {
bsalomon@google.com2858b312012-04-02 20:44:38 +0000430 EGL_NONE, EGL_NONE
431 };
432
433 EGLDisplay display = eglGetDisplay(GetDC(hWnd));
434 if (display == EGL_NO_DISPLAY ) {
435 return false;
436 }
437
438 // Initialize EGL
439 EGLint majorVersion, minorVersion;
440 if (!eglInitialize(display, &majorVersion, &minorVersion)) {
441 return false;
442 }
443
444 EGLint numConfigs;
445 if (!eglGetConfigs(display, NULL, 0, &numConfigs)) {
446 return false;
447 }
448
449 // Choose config
450 EGLConfig config;
bsalomon@google.com11959252012-04-06 20:13:38 +0000451 bool foundConfig = false;
452 if (msaaSampleCount) {
453 static const int kConfigAttribListCnt =
454 SK_ARRAY_COUNT(configAttribList);
455 EGLint msaaConfigAttribList[kConfigAttribListCnt + 4];
456 memcpy(msaaConfigAttribList,
457 configAttribList,
458 sizeof(configAttribList));
459 SkASSERT(EGL_NONE == msaaConfigAttribList[kConfigAttribListCnt - 1]);
460 msaaConfigAttribList[kConfigAttribListCnt - 1] = EGL_SAMPLE_BUFFERS;
461 msaaConfigAttribList[kConfigAttribListCnt + 0] = 1;
462 msaaConfigAttribList[kConfigAttribListCnt + 1] = EGL_SAMPLES;
463 msaaConfigAttribList[kConfigAttribListCnt + 2] = msaaSampleCount;
464 msaaConfigAttribList[kConfigAttribListCnt + 3] = EGL_NONE;
465 if (eglChooseConfig(display, configAttribList,
466 &config, 1, &numConfigs)) {
467 SkASSERT(numConfigs > 0);
468 foundConfig = true;
469 }
470 }
471 if (!foundConfig) {
472 if (!eglChooseConfig(display, configAttribList,
473 &config, 1, &numConfigs)) {
474 return false;
475 }
bsalomon@google.com2858b312012-04-02 20:44:38 +0000476 }
477
478 // Create a surface
479 EGLSurface surface = eglCreateWindowSurface(display, config,
480 (EGLNativeWindowType)hWnd,
481 surfaceAttribList);
482 if (surface == EGL_NO_SURFACE) {
483 return false;
484 }
485
486 // Create a GL context
487 EGLContext context = eglCreateContext(display, config,
488 EGL_NO_CONTEXT,
489 contextAttribs );
490 if (context == EGL_NO_CONTEXT ) {
491 return false;
492 }
493
494 // Make the context current
495 if (!eglMakeCurrent(display, surface, surface, context)) {
496 return false;
497 }
498
499 *eglDisplay = display;
500 *eglContext = context;
501 *eglSurface = surface;
502 return true;
503}
504
bsalomon@google.com11959252012-04-06 20:13:38 +0000505bool SkOSWindow::attachANGLE(int msaaSampleCount) {
bsalomon@google.com2858b312012-04-02 20:44:38 +0000506 if (EGL_NO_DISPLAY == fDisplay) {
bsalomon@google.com11959252012-04-06 20:13:38 +0000507 bool bResult = create_ANGLE((HWND)fHWND,
508 msaaSampleCount,
509 &fDisplay,
510 &fContext,
511 &fSurface);
bsalomon@google.com2858b312012-04-02 20:44:38 +0000512 if (false == bResult) {
513 return false;
514 }
515 const GrGLInterface* intf = GrGLCreateANGLEInterface();
516
517 if (intf) {
518 GR_GL_CALL(intf, ClearStencil(0));
519 GR_GL_CALL(intf, ClearColor(0, 0, 0, 0));
520 GR_GL_CALL(intf, StencilMask(0xffffffff));
bsalomon@google.com11959252012-04-06 20:13:38 +0000521 GR_GL_CALL(intf, Clear(GL_STENCIL_BUFFER_BIT |GL_COLOR_BUFFER_BIT));
bsalomon@google.com2858b312012-04-02 20:44:38 +0000522 }
523 }
524 if (eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
525 const GrGLInterface* intf = GrGLCreateANGLEInterface();
526
527 if (intf ) {
528 GR_GL_CALL(intf, Viewport(0, 0, SkScalarRound(this->width()),
529 SkScalarRound(this->height())));
530 }
531 return true;
532 }
533 return false;
534}
535
536void SkOSWindow::detachANGLE() {
537 eglMakeCurrent(fDisplay, EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT);
538
539 eglDestroyContext(fDisplay, fContext);
540 fContext = EGL_NO_CONTEXT;
541
542 eglDestroySurface(fDisplay, fSurface);
543 fSurface = EGL_NO_SURFACE;
544
545 eglTerminate(fDisplay);
546 fDisplay = EGL_NO_DISPLAY;
547}
548
549void SkOSWindow::presentANGLE() {
550 const GrGLInterface* intf = GrGLCreateANGLEInterface();
551
552 if (intf) {
553 GR_GL_CALL(intf, Flush());
554 }
555
556 eglSwapBuffers(fDisplay, fSurface);
557}
558#endif
559
bsalomon@google.com2858b312012-04-02 20:44:38 +0000560// return true on success
bsalomon@google.com11959252012-04-06 20:13:38 +0000561bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount) {
bsalomon@google.com2858b312012-04-02 20:44:38 +0000562
563 // attach doubles as "windowResize" so we need to allo
564 // already bound states to pass through again
565 // TODO: split out the resize functionality
566// SkASSERT(kNone_BackEndType == fAttached);
567 bool result = true;
568
569 switch (attachType) {
570 case kNone_BackEndType:
571 // nothing to do
572 break;
573 case kNativeGL_BackEndType:
bsalomon@google.com11959252012-04-06 20:13:38 +0000574 result = attachGL(msaaSampleCount);
bsalomon@google.com2858b312012-04-02 20:44:38 +0000575 break;
576#if SK_ANGLE
577 case kANGLE_BackEndType:
bsalomon@google.com11959252012-04-06 20:13:38 +0000578 result = attachANGLE(msaaSampleCount);
bsalomon@google.com2858b312012-04-02 20:44:38 +0000579 break;
580#endif
bsalomon@google.com2858b312012-04-02 20:44:38 +0000581 default:
582 SkASSERT(false);
583 result = false;
584 break;
585 }
586
587 if (result) {
588 fAttached = attachType;
589 }
590
591 return result;
592}
593
594void SkOSWindow::detach() {
595 switch (fAttached) {
596 case kNone_BackEndType:
597 // nothing to do
598 break;
599 case kNativeGL_BackEndType:
600 detachGL();
601 break;
602#if SK_ANGLE
603 case kANGLE_BackEndType:
604 detachANGLE();
605 break;
606#endif
bsalomon@google.com2858b312012-04-02 20:44:38 +0000607 default:
608 SkASSERT(false);
609 break;
610 }
611 fAttached = kNone_BackEndType;
612}
613
614void SkOSWindow::present() {
615 switch (fAttached) {
616 case kNone_BackEndType:
617 // nothing to do
618 return;
619 case kNativeGL_BackEndType:
620 presentGL();
621 break;
622#if SK_ANGLE
623 case kANGLE_BackEndType:
624 presentANGLE();
625 break;
626#endif
bsalomon@google.com2858b312012-04-02 20:44:38 +0000627 default:
628 SkASSERT(false);
629 break;
630 }
631}
632
633#endif