1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/views/mac/SkNSView.mm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,420 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2011 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 +#import "SkNSView.h" 1.13 +#include "SkCanvas.h" 1.14 +#include "SkCGUtils.h" 1.15 +#include "SkEvent.h" 1.16 +SK_COMPILE_ASSERT(SK_SUPPORT_GPU, not_implemented_for_non_gpu_build); 1.17 +#include <OpenGL/gl.h> 1.18 + 1.19 +//#define FORCE_REDRAW 1.20 +// Can be dropped when we no longer support 10.6. 1.21 +#define RETINA_API_AVAILABLE (defined(MAC_OS_X_VERSION_10_7) && \ 1.22 + MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7) 1.23 +@implementation SkNSView 1.24 +@synthesize fWind, fTitle, fOptionsDelegate, fGLContext; 1.25 + 1.26 +- (id)initWithCoder:(NSCoder*)coder { 1.27 + if ((self = [super initWithCoder:coder])) { 1.28 + self = [self initWithDefaults]; 1.29 + [self setUpWindow]; 1.30 + } 1.31 + return self; 1.32 +} 1.33 + 1.34 +- (id)initWithFrame:(NSRect)frameRect { 1.35 + if ((self = [super initWithFrame:frameRect])) { 1.36 + self = [self initWithDefaults]; 1.37 + [self setUpWindow]; 1.38 + } 1.39 + return self; 1.40 +} 1.41 + 1.42 +- (id)initWithDefaults { 1.43 +#if RETINA_API_AVAILABLE 1.44 + [self setWantsBestResolutionOpenGLSurface:YES]; 1.45 +#endif 1.46 + fRedrawRequestPending = false; 1.47 + fWind = NULL; 1.48 + return self; 1.49 +} 1.50 + 1.51 +- (void)setUpWindow { 1.52 + [[NSNotificationCenter defaultCenter] addObserver:self 1.53 + selector:@selector(backingPropertiesChanged:) 1.54 + name:@"NSWindowDidChangeBackingPropertiesNotification" 1.55 + object:[self window]]; 1.56 + if (NULL != fWind) { 1.57 + fWind->setVisibleP(true); 1.58 + NSSize size = self.frame.size; 1.59 +#if RETINA_API_AVAILABLE 1.60 + size = [self convertSizeToBacking:self.frame.size]; 1.61 +#endif 1.62 + fWind->resize((int) size.width, (int) size.height, 1.63 + kPMColor_SkColorType); 1.64 + } 1.65 +} 1.66 + 1.67 +-(BOOL) isFlipped { 1.68 + return YES; 1.69 +} 1.70 + 1.71 +- (BOOL)acceptsFirstResponder { 1.72 + return YES; 1.73 +} 1.74 + 1.75 +- (float)scaleFactor { 1.76 + NSWindow *window = [self window]; 1.77 +#if RETINA_API_AVAILABLE 1.78 + if (window) { 1.79 + return [window backingScaleFactor]; 1.80 + } 1.81 + return [[NSScreen mainScreen] backingScaleFactor]; 1.82 +#else 1.83 + if (window) { 1.84 + return [window userSpaceScaleFactor]; 1.85 + } 1.86 + return [[NSScreen mainScreen] userSpaceScaleFactor]; 1.87 +#endif 1.88 +} 1.89 + 1.90 +- (void)backingPropertiesChanged:(NSNotification *)notification { 1.91 + CGFloat oldBackingScaleFactor = (CGFloat)[ 1.92 + [notification.userInfo objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue 1.93 + ]; 1.94 + CGFloat newBackingScaleFactor = [self scaleFactor]; 1.95 + if (oldBackingScaleFactor == newBackingScaleFactor) { 1.96 + return; 1.97 + } 1.98 + 1.99 + // TODO: need a better way to force a refresh (that works). 1.100 + // [fGLContext update] does not appear to update if the point size has not changed, 1.101 + // even if the backing size has changed. 1.102 + [self setFrameSize:NSMakeSize(self.frame.size.width + 1, self.frame.size.height + 1)]; 1.103 +} 1.104 + 1.105 +- (void)resizeSkView:(NSSize)newSize { 1.106 +#if RETINA_API_AVAILABLE 1.107 + newSize = [self convertSizeToBacking:newSize]; 1.108 +#endif 1.109 + if (NULL != fWind && 1.110 + (fWind->width() != newSize.width || 1.111 + fWind->height() != newSize.height)) 1.112 + { 1.113 + fWind->resize((int) newSize.width, (int) newSize.height); 1.114 + if (NULL != fGLContext) { 1.115 + glClear(GL_STENCIL_BUFFER_BIT); 1.116 + [fGLContext update]; 1.117 + } 1.118 + } 1.119 +} 1.120 + 1.121 +- (void) setFrameSize:(NSSize)newSize { 1.122 + [super setFrameSize:newSize]; 1.123 + [self resizeSkView:newSize]; 1.124 +} 1.125 + 1.126 +- (void)dealloc { 1.127 + delete fWind; 1.128 + self.fGLContext = nil; 1.129 + self.fTitle = nil; 1.130 + [super dealloc]; 1.131 +} 1.132 + 1.133 +//////////////////////////////////////////////////////////////////////////////// 1.134 + 1.135 +- (void)drawSkia { 1.136 + fRedrawRequestPending = false; 1.137 + if (NULL != fWind) { 1.138 + SkAutoTUnref<SkCanvas> canvas(fWind->createCanvas()); 1.139 + fWind->draw(canvas); 1.140 +#ifdef FORCE_REDRAW 1.141 + fWind->inval(NULL); 1.142 +#endif 1.143 + } 1.144 +} 1.145 + 1.146 +- (void)setSkTitle:(const char *)title { 1.147 + self.fTitle = [NSString stringWithUTF8String:title]; 1.148 + [[self window] setTitle:self.fTitle]; 1.149 +} 1.150 + 1.151 +- (BOOL)onHandleEvent:(const SkEvent&)evt { 1.152 + return false; 1.153 +} 1.154 + 1.155 +#include "SkOSMenu.h" 1.156 +- (void)onAddMenu:(const SkOSMenu*)menu { 1.157 + [self.fOptionsDelegate view:self didAddMenu:menu]; 1.158 +} 1.159 + 1.160 +- (void)onUpdateMenu:(const SkOSMenu*)menu { 1.161 + [self.fOptionsDelegate view:self didUpdateMenu:menu]; 1.162 +} 1.163 + 1.164 +- (void)postInvalWithRect:(const SkIRect*)r { 1.165 + if (!fRedrawRequestPending) { 1.166 + fRedrawRequestPending = true; 1.167 + [self setNeedsDisplay:YES]; 1.168 + [self performSelector:@selector(drawSkia) withObject:nil afterDelay:0]; 1.169 + } 1.170 +} 1.171 +/////////////////////////////////////////////////////////////////////////////// 1.172 + 1.173 +#include "SkKey.h" 1.174 +enum { 1.175 + SK_MacReturnKey = 36, 1.176 + SK_MacDeleteKey = 51, 1.177 + SK_MacEndKey = 119, 1.178 + SK_MacLeftKey = 123, 1.179 + SK_MacRightKey = 124, 1.180 + SK_MacDownKey = 125, 1.181 + SK_MacUpKey = 126, 1.182 + SK_Mac0Key = 0x52, 1.183 + SK_Mac1Key = 0x53, 1.184 + SK_Mac2Key = 0x54, 1.185 + SK_Mac3Key = 0x55, 1.186 + SK_Mac4Key = 0x56, 1.187 + SK_Mac5Key = 0x57, 1.188 + SK_Mac6Key = 0x58, 1.189 + SK_Mac7Key = 0x59, 1.190 + SK_Mac8Key = 0x5b, 1.191 + SK_Mac9Key = 0x5c 1.192 +}; 1.193 + 1.194 +static SkKey raw2key(UInt32 raw) 1.195 +{ 1.196 + static const struct { 1.197 + UInt32 fRaw; 1.198 + SkKey fKey; 1.199 + } gKeys[] = { 1.200 + { SK_MacUpKey, kUp_SkKey }, 1.201 + { SK_MacDownKey, kDown_SkKey }, 1.202 + { SK_MacLeftKey, kLeft_SkKey }, 1.203 + { SK_MacRightKey, kRight_SkKey }, 1.204 + { SK_MacReturnKey, kOK_SkKey }, 1.205 + { SK_MacDeleteKey, kBack_SkKey }, 1.206 + { SK_MacEndKey, kEnd_SkKey }, 1.207 + { SK_Mac0Key, k0_SkKey }, 1.208 + { SK_Mac1Key, k1_SkKey }, 1.209 + { SK_Mac2Key, k2_SkKey }, 1.210 + { SK_Mac3Key, k3_SkKey }, 1.211 + { SK_Mac4Key, k4_SkKey }, 1.212 + { SK_Mac5Key, k5_SkKey }, 1.213 + { SK_Mac6Key, k6_SkKey }, 1.214 + { SK_Mac7Key, k7_SkKey }, 1.215 + { SK_Mac8Key, k8_SkKey }, 1.216 + { SK_Mac9Key, k9_SkKey } 1.217 + }; 1.218 + 1.219 + for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++) 1.220 + if (gKeys[i].fRaw == raw) 1.221 + return gKeys[i].fKey; 1.222 + return kNONE_SkKey; 1.223 +} 1.224 + 1.225 +- (void)keyDown:(NSEvent *)event { 1.226 + if (NULL == fWind) 1.227 + return; 1.228 + 1.229 + SkKey key = raw2key([event keyCode]); 1.230 + if (kNONE_SkKey != key) 1.231 + fWind->handleKey(key); 1.232 + else{ 1.233 + unichar c = [[event characters] characterAtIndex:0]; 1.234 + fWind->handleChar((SkUnichar)c); 1.235 + } 1.236 +} 1.237 + 1.238 +- (void)keyUp:(NSEvent *)event { 1.239 + if (NULL == fWind) 1.240 + return; 1.241 + 1.242 + SkKey key = raw2key([event keyCode]); 1.243 + if (kNONE_SkKey != key) 1.244 + fWind->handleKeyUp(key); 1.245 + // else 1.246 + // unichar c = [[event characters] characterAtIndex:0]; 1.247 +} 1.248 + 1.249 +static const struct { 1.250 + unsigned fNSModifierMask; 1.251 + unsigned fSkModifierMask; 1.252 +} gModifierMasks[] = { 1.253 + { NSAlphaShiftKeyMask, kShift_SkModifierKey }, 1.254 + { NSShiftKeyMask, kShift_SkModifierKey }, 1.255 + { NSControlKeyMask, kControl_SkModifierKey }, 1.256 + { NSAlternateKeyMask, kOption_SkModifierKey }, 1.257 + { NSCommandKeyMask, kCommand_SkModifierKey }, 1.258 +}; 1.259 + 1.260 +static unsigned convertNSModifiersToSk(NSUInteger nsModi) { 1.261 + unsigned skModi = 0; 1.262 + for (size_t i = 0; i < SK_ARRAY_COUNT(gModifierMasks); ++i) { 1.263 + if (nsModi & gModifierMasks[i].fNSModifierMask) { 1.264 + skModi |= gModifierMasks[i].fSkModifierMask; 1.265 + } 1.266 + } 1.267 + return skModi; 1.268 +} 1.269 + 1.270 +- (void)mouseDown:(NSEvent *)event { 1.271 + NSPoint p = [event locationInWindow]; 1.272 + unsigned modi = convertNSModifiersToSk([event modifierFlags]); 1.273 + 1.274 + if ([self mouse:p inRect:[self bounds]] && NULL != fWind) { 1.275 + NSPoint loc = [self convertPoint:p fromView:nil]; 1.276 +#if RETINA_API_AVAILABLE 1.277 + loc = [self convertPointToBacking:loc]; //y-up 1.278 + loc.y = -loc.y; 1.279 +#endif 1.280 + fWind->handleClick((int) loc.x, (int) loc.y, 1.281 + SkView::Click::kDown_State, self, modi); 1.282 + } 1.283 +} 1.284 + 1.285 +- (void)mouseDragged:(NSEvent *)event { 1.286 + NSPoint p = [event locationInWindow]; 1.287 + unsigned modi = convertNSModifiersToSk([event modifierFlags]); 1.288 + 1.289 + if ([self mouse:p inRect:[self bounds]] && NULL != fWind) { 1.290 + NSPoint loc = [self convertPoint:p fromView:nil]; 1.291 +#if RETINA_API_AVAILABLE 1.292 + loc = [self convertPointToBacking:loc]; //y-up 1.293 + loc.y = -loc.y; 1.294 +#endif 1.295 + fWind->handleClick((int) loc.x, (int) loc.y, 1.296 + SkView::Click::kMoved_State, self, modi); 1.297 + } 1.298 +} 1.299 + 1.300 +- (void)mouseMoved:(NSEvent *)event { 1.301 + NSPoint p = [event locationInWindow]; 1.302 + unsigned modi = convertNSModifiersToSk([event modifierFlags]); 1.303 + 1.304 + if ([self mouse:p inRect:[self bounds]] && NULL != fWind) { 1.305 + NSPoint loc = [self convertPoint:p fromView:nil]; 1.306 +#if RETINA_API_AVAILABLE 1.307 + loc = [self convertPointToBacking:loc]; //y-up 1.308 + loc.y = -loc.y; 1.309 +#endif 1.310 + fWind->handleClick((int) loc.x, (int) loc.y, 1.311 + SkView::Click::kMoved_State, self, modi); 1.312 + } 1.313 +} 1.314 + 1.315 +- (void)mouseUp:(NSEvent *)event { 1.316 + NSPoint p = [event locationInWindow]; 1.317 + unsigned modi = convertNSModifiersToSk([event modifierFlags]); 1.318 + 1.319 + if ([self mouse:p inRect:[self bounds]] && NULL != fWind) { 1.320 + NSPoint loc = [self convertPoint:p fromView:nil]; 1.321 +#if RETINA_API_AVAILABLE 1.322 + loc = [self convertPointToBacking:loc]; //y-up 1.323 + loc.y = -loc.y; 1.324 +#endif 1.325 + fWind->handleClick((int) loc.x, (int) loc.y, 1.326 + SkView::Click::kUp_State, self, modi); 1.327 + } 1.328 +} 1.329 + 1.330 +/////////////////////////////////////////////////////////////////////////////// 1.331 +#include <OpenGL/OpenGL.h> 1.332 + 1.333 +namespace { 1.334 +CGLContextObj createGLContext(int msaaSampleCount) { 1.335 + GLint major, minor; 1.336 + CGLGetVersion(&major, &minor); 1.337 + 1.338 + static const CGLPixelFormatAttribute attributes[] = { 1.339 + kCGLPFAStencilSize, (CGLPixelFormatAttribute) 8, 1.340 + kCGLPFAAccelerated, 1.341 + kCGLPFADoubleBuffer, 1.342 + (CGLPixelFormatAttribute)0 1.343 + }; 1.344 + 1.345 + CGLPixelFormatObj format; 1.346 + GLint npix = 0; 1.347 + if (msaaSampleCount > 0) { 1.348 + static int kAttributeCount = SK_ARRAY_COUNT(attributes); 1.349 + CGLPixelFormatAttribute msaaAttributes[kAttributeCount + 5]; 1.350 + memcpy(msaaAttributes, attributes, sizeof(attributes)); 1.351 + SkASSERT(0 == msaaAttributes[kAttributeCount - 1]); 1.352 + msaaAttributes[kAttributeCount - 1] = kCGLPFASampleBuffers; 1.353 + msaaAttributes[kAttributeCount + 0] = (CGLPixelFormatAttribute)1; 1.354 + msaaAttributes[kAttributeCount + 1] = kCGLPFAMultisample; 1.355 + msaaAttributes[kAttributeCount + 2] = kCGLPFASamples; 1.356 + msaaAttributes[kAttributeCount + 3] = 1.357 + (CGLPixelFormatAttribute)msaaSampleCount; 1.358 + msaaAttributes[kAttributeCount + 4] = (CGLPixelFormatAttribute)0; 1.359 + CGLChoosePixelFormat(msaaAttributes, &format, &npix); 1.360 + } 1.361 + if (!npix) { 1.362 + CGLChoosePixelFormat(attributes, &format, &npix); 1.363 + } 1.364 + CGLContextObj ctx; 1.365 + CGLCreateContext(format, NULL, &ctx); 1.366 + CGLDestroyPixelFormat(format); 1.367 + 1.368 + static const GLint interval = 1; 1.369 + CGLSetParameter(ctx, kCGLCPSwapInterval, &interval); 1.370 + CGLSetCurrentContext(ctx); 1.371 + return ctx; 1.372 +} 1.373 +} 1.374 + 1.375 +- (void)viewDidMoveToWindow { 1.376 + [super viewDidMoveToWindow]; 1.377 + 1.378 + //Attaching view to fGLContext requires that the view to be part of a window, 1.379 + //and that the NSWindow instance must have a CoreGraphics counterpart (or 1.380 + //it must NOT be deferred or should have been on screen at least once) 1.381 + if ([fGLContext view] != self && nil != self.window) { 1.382 + [fGLContext setView:self]; 1.383 + } 1.384 +} 1.385 +- (bool)attach:(SkOSWindow::SkBackEndTypes)attachType 1.386 + withMSAASampleCount:(int) sampleCount 1.387 + andGetInfo:(SkOSWindow::AttachmentInfo*) info { 1.388 + if (nil == fGLContext) { 1.389 + CGLContextObj ctx = createGLContext(sampleCount); 1.390 + fGLContext = [[NSOpenGLContext alloc] initWithCGLContextObj:ctx]; 1.391 + CGLReleaseContext(ctx); 1.392 + if (NULL == fGLContext) { 1.393 + return false; 1.394 + } 1.395 + [fGLContext setView:self]; 1.396 + } 1.397 + 1.398 + [fGLContext makeCurrentContext]; 1.399 + CGLPixelFormatObj format = CGLGetPixelFormat((CGLContextObj)[fGLContext CGLContextObj]); 1.400 + CGLDescribePixelFormat(format, 0, kCGLPFASamples, &info->fSampleCount); 1.401 + CGLDescribePixelFormat(format, 0, kCGLPFAStencilSize, &info->fStencilBits); 1.402 + NSSize size = self.bounds.size; 1.403 +#if RETINA_API_AVAILABLE 1.404 + size = [self convertSizeToBacking:size]; 1.405 +#endif 1.406 + glViewport(0, 0, (int) size.width, (int) size.height); 1.407 + glClearColor(0, 0, 0, 0); 1.408 + glClearStencil(0); 1.409 + glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 1.410 + return true; 1.411 +} 1.412 + 1.413 +- (void)detach { 1.414 + [fGLContext release]; 1.415 + fGLContext = nil; 1.416 +} 1.417 + 1.418 +- (void)present { 1.419 + if (nil != fGLContext) { 1.420 + [fGLContext flushBuffer]; 1.421 + } 1.422 +} 1.423 +@end