blob: 92a357db19ffb53fe4c77788e5a860763855d493 [file] [log] [blame]
bsalomon@google.comf75b84e2011-09-29 14:58:28 +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
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00009#import "SkNSView.h"
yangsu@google.com12d177d2011-08-01 17:07:12 +000010#include "SkCanvas.h"
yangsu@google.com12d177d2011-08-01 17:07:12 +000011#include "SkCGUtils.h"
12#include "SkEvent.h"
yangsu@google.com12d177d2011-08-01 17:07:12 +000013
14//#define FORCE_REDRAW
15@implementation SkNSView
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000016@synthesize fWind, fTitle, fOptionsDelegate;
17
18#if SK_SUPPORT_GPU
19@synthesize fGLContext;
20#endif
yangsu@google.com12d177d2011-08-01 17:07:12 +000021
22- (id)initWithCoder:(NSCoder*)coder {
23 if ((self = [super initWithCoder:coder])) {
yangsu@google.coma8540412011-08-30 14:40:49 +000024 self = [self initWithDefaults];
25 [self setUpWindow];
yangsu@google.com12d177d2011-08-01 17:07:12 +000026 }
27 return self;
28}
29
30- (id)initWithFrame:(NSRect)frameRect {
caryclark@google.com679ab312012-06-06 12:04:00 +000031 if ((self = [super initWithFrame:frameRect])) {
yangsu@google.coma8540412011-08-30 14:40:49 +000032 self = [self initWithDefaults];
33 [self setUpWindow];
yangsu@google.com12d177d2011-08-01 17:07:12 +000034 }
35 return self;
36}
37
yangsu@google.coma8540412011-08-30 14:40:49 +000038- (id)initWithDefaults {
yangsu@google.com12d177d2011-08-01 17:07:12 +000039 fRedrawRequestPending = false;
yangsu@google.coma8540412011-08-30 14:40:49 +000040 fWind = NULL;
yangsu@google.com12d177d2011-08-01 17:07:12 +000041 return self;
42}
43
yangsu@google.coma8540412011-08-30 14:40:49 +000044- (void)setUpWindow {
45 if (NULL != fWind) {
46 fWind->setVisibleP(true);
caryclark@google.com679ab312012-06-06 12:04:00 +000047 fWind->resize((int) self.frame.size.width, (int) self.frame.size.height,
yangsu@google.coma8540412011-08-30 14:40:49 +000048 SkBitmap::kARGB_8888_Config);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000049 [self attach:SkOSWindow::kNone_BackEndType withMSAASampleCount:0];
yangsu@google.coma8540412011-08-30 14:40:49 +000050 }
51}
52
yangsu@google.com12d177d2011-08-01 17:07:12 +000053-(BOOL) isFlipped {
54 return YES;
55}
56
57- (BOOL)acceptsFirstResponder {
58 return YES;
59}
60
suyang1bb3f4a82011-10-10 16:38:58 +000061- (void)resizeSkView:(NSSize)newSize {
62 if (NULL != fWind && (fWind->width() != newSize.width || fWind->height() != newSize.height)) {
caryclark@google.com679ab312012-06-06 12:04:00 +000063 fWind->resize((int) newSize.width, (int) newSize.height);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000064#if SK_SUPPORT_GPU
suyang1bb3f4a82011-10-10 16:38:58 +000065 glClear(GL_STENCIL_BUFFER_BIT);
66 [fGLContext update];
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000067#endif
yangsu@google.com12d177d2011-08-01 17:07:12 +000068 }
yangsu@google.com12d177d2011-08-01 17:07:12 +000069}
70
suyang1bb3f4a82011-10-10 16:38:58 +000071- (void) setFrameSize:(NSSize)newSize {
72 [super setFrameSize:newSize];
73 [self resizeSkView:newSize];
74}
75
yangsu@google.com12d177d2011-08-01 17:07:12 +000076- (void)dealloc {
77 delete fWind;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000078#if SK_SUPPORT_GPU
yangsu@google.com12d177d2011-08-01 17:07:12 +000079 self.fGLContext = nil;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000080#endif
yangsu@google.com12d177d2011-08-01 17:07:12 +000081 self.fTitle = nil;
yangsu@google.com12d177d2011-08-01 17:07:12 +000082 [super dealloc];
83}
84
suyang1bb3f4a82011-10-10 16:38:58 +000085////////////////////////////////////////////////////////////////////////////////
yangsu@google.com12d177d2011-08-01 17:07:12 +000086
yangsu@google.comf3493f02011-08-08 15:12:05 +000087- (void)drawSkia {
yangsu@google.com12d177d2011-08-01 17:07:12 +000088 fRedrawRequestPending = false;
yangsu@google.coma8540412011-08-30 14:40:49 +000089 if (NULL != fWind) {
90 SkCanvas canvas(fWind->getBitmap());
91 fWind->draw(&canvas);
yangsu@google.com12d177d2011-08-01 17:07:12 +000092#ifdef FORCE_REDRAW
yangsu@google.coma8540412011-08-30 14:40:49 +000093 fWind->inval(NULL);
yangsu@google.com12d177d2011-08-01 17:07:12 +000094#endif
yangsu@google.coma8540412011-08-30 14:40:49 +000095 }
yangsu@google.com12d177d2011-08-01 17:07:12 +000096}
97
yangsu@google.comf3493f02011-08-08 15:12:05 +000098- (void)setSkTitle:(const char *)title {
99 self.fTitle = [NSString stringWithUTF8String:title];
100 [[self window] setTitle:self.fTitle];
101}
102
103- (BOOL)onHandleEvent:(const SkEvent&)evt {
104 return false;
105}
106
107#include "SkOSMenu.h"
108- (void)onAddMenu:(const SkOSMenu*)menu {
109 [self.fOptionsDelegate view:self didAddMenu:menu];
110}
111
112- (void)onUpdateMenu:(const SkOSMenu*)menu {
113 [self.fOptionsDelegate view:self didUpdateMenu:menu];
114}
115
116- (void)postInvalWithRect:(const SkIRect*)r {
117 if (!fRedrawRequestPending) {
118 fRedrawRequestPending = true;
yangsu@google.coma8540412011-08-30 14:40:49 +0000119 [self setNeedsDisplay:YES];
yangsu@google.comf3493f02011-08-08 15:12:05 +0000120 [self performSelector:@selector(drawSkia) withObject:nil afterDelay:0];
121 }
yangsu@google.com12d177d2011-08-01 17:07:12 +0000122}
123///////////////////////////////////////////////////////////////////////////////
124
125#include "SkKey.h"
126enum {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000127 SK_MacReturnKey = 36,
128 SK_MacDeleteKey = 51,
129 SK_MacEndKey = 119,
130 SK_MacLeftKey = 123,
131 SK_MacRightKey = 124,
132 SK_MacDownKey = 125,
133 SK_MacUpKey = 126,
yangsu@google.com12d177d2011-08-01 17:07:12 +0000134 SK_Mac0Key = 0x52,
135 SK_Mac1Key = 0x53,
136 SK_Mac2Key = 0x54,
137 SK_Mac3Key = 0x55,
138 SK_Mac4Key = 0x56,
139 SK_Mac5Key = 0x57,
140 SK_Mac6Key = 0x58,
141 SK_Mac7Key = 0x59,
142 SK_Mac8Key = 0x5b,
143 SK_Mac9Key = 0x5c
144};
145
146static SkKey raw2key(UInt32 raw)
147{
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000148 static const struct {
149 UInt32 fRaw;
150 SkKey fKey;
151 } gKeys[] = {
152 { SK_MacUpKey, kUp_SkKey },
153 { SK_MacDownKey, kDown_SkKey },
154 { SK_MacLeftKey, kLeft_SkKey },
155 { SK_MacRightKey, kRight_SkKey },
156 { SK_MacReturnKey, kOK_SkKey },
157 { SK_MacDeleteKey, kBack_SkKey },
158 { SK_MacEndKey, kEnd_SkKey },
yangsu@google.com12d177d2011-08-01 17:07:12 +0000159 { SK_Mac0Key, k0_SkKey },
160 { SK_Mac1Key, k1_SkKey },
161 { SK_Mac2Key, k2_SkKey },
162 { SK_Mac3Key, k3_SkKey },
yangsu@google.comf3493f02011-08-08 15:12:05 +0000163 { SK_Mac4Key, k4_SkKey },
yangsu@google.com12d177d2011-08-01 17:07:12 +0000164 { SK_Mac5Key, k5_SkKey },
165 { SK_Mac6Key, k6_SkKey },
166 { SK_Mac7Key, k7_SkKey },
167 { SK_Mac8Key, k8_SkKey },
168 { SK_Mac9Key, k9_SkKey }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000169 };
yangsu@google.com12d177d2011-08-01 17:07:12 +0000170
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000171 for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++)
172 if (gKeys[i].fRaw == raw)
173 return gKeys[i].fKey;
174 return kNONE_SkKey;
yangsu@google.com12d177d2011-08-01 17:07:12 +0000175}
176
177- (void)keyDown:(NSEvent *)event {
yangsu@google.com849ad5a2011-08-30 15:27:57 +0000178 if (NULL == fWind)
yangsu@google.coma8540412011-08-30 14:40:49 +0000179 return;
180
yangsu@google.com12d177d2011-08-01 17:07:12 +0000181 SkKey key = raw2key([event keyCode]);
182 if (kNONE_SkKey != key)
183 fWind->handleKey(key);
184 else{
185 unichar c = [[event characters] characterAtIndex:0];
186 fWind->handleChar((SkUnichar)c);
187 }
188}
189
190- (void)keyUp:(NSEvent *)event {
yangsu@google.com849ad5a2011-08-30 15:27:57 +0000191 if (NULL == fWind)
yangsu@google.coma8540412011-08-30 14:40:49 +0000192 return;
193
yangsu@google.com12d177d2011-08-01 17:07:12 +0000194 SkKey key = raw2key([event keyCode]);
195 if (kNONE_SkKey != key)
196 fWind->handleKeyUp(key);
caryclark@google.com679ab312012-06-06 12:04:00 +0000197 // else
198 // unichar c = [[event characters] characterAtIndex:0];
yangsu@google.com12d177d2011-08-01 17:07:12 +0000199}
200
201- (void)mouseDown:(NSEvent *)event {
202 NSPoint p = [event locationInWindow];
yangsu@google.coma8540412011-08-30 14:40:49 +0000203 if ([self mouse:p inRect:[self bounds]] && NULL != fWind) {
yangsu@google.com12d177d2011-08-01 17:07:12 +0000204 NSPoint loc = [self convertPoint:p fromView:nil];
caryclark@google.com679ab312012-06-06 12:04:00 +0000205 fWind->handleClick((int) loc.x, (int) loc.y, SkView::Click::kDown_State, self);
yangsu@google.com12d177d2011-08-01 17:07:12 +0000206 }
207}
208
209- (void)mouseDragged:(NSEvent *)event {
210 NSPoint p = [event locationInWindow];
yangsu@google.coma8540412011-08-30 14:40:49 +0000211 if ([self mouse:p inRect:[self bounds]] && NULL != fWind) {
yangsu@google.com12d177d2011-08-01 17:07:12 +0000212 NSPoint loc = [self convertPoint:p fromView:nil];
caryclark@google.com679ab312012-06-06 12:04:00 +0000213 fWind->handleClick((int) loc.x, (int) loc.y, SkView::Click::kMoved_State, self);
yangsu@google.com12d177d2011-08-01 17:07:12 +0000214 }
215}
216
suyang1bb3f4a82011-10-10 16:38:58 +0000217- (void)mouseMoved:(NSEvent *)event {
218 NSPoint p = [event locationInWindow];
219 if ([self mouse:p inRect:[self bounds]] && NULL != fWind) {
220 NSPoint loc = [self convertPoint:p fromView:nil];
caryclark@google.com679ab312012-06-06 12:04:00 +0000221 fWind->handleClick((int) loc.x, (int) loc.y, SkView::Click::kMoved_State, self);
suyang1bb3f4a82011-10-10 16:38:58 +0000222 }
223}
224
yangsu@google.com12d177d2011-08-01 17:07:12 +0000225- (void)mouseUp:(NSEvent *)event {
226 NSPoint p = [event locationInWindow];
yangsu@google.coma8540412011-08-30 14:40:49 +0000227 if ([self mouse:p inRect:[self bounds]] && NULL != fWind) {
yangsu@google.com12d177d2011-08-01 17:07:12 +0000228 NSPoint loc = [self convertPoint:p fromView:nil];
caryclark@google.com679ab312012-06-06 12:04:00 +0000229 fWind->handleClick((int) loc.x, (int) loc.y, SkView::Click::kUp_State, self);
yangsu@google.com12d177d2011-08-01 17:07:12 +0000230 }
231}
232
yangsu@google.com12d177d2011-08-01 17:07:12 +0000233///////////////////////////////////////////////////////////////////////////////
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000234#if SK_SUPPORT_GPU
yangsu@google.com12d177d2011-08-01 17:07:12 +0000235#include <OpenGL/OpenGL.h>
bsalomon@google.comed164832012-04-03 18:06:20 +0000236namespace {
bsalomon@google.com11959252012-04-06 20:13:38 +0000237CGLContextObj createGLContext(int msaaSampleCount) {
yangsu@google.com12d177d2011-08-01 17:07:12 +0000238 GLint major, minor;
yangsu@google.com12d177d2011-08-01 17:07:12 +0000239 CGLGetVersion(&major, &minor);
yangsu@google.com12d177d2011-08-01 17:07:12 +0000240
bsalomon@google.com11959252012-04-06 20:13:38 +0000241 static const CGLPixelFormatAttribute attributes[] = {
242 kCGLPFAStencilSize, (CGLPixelFormatAttribute) 8,
yangsu@google.com12d177d2011-08-01 17:07:12 +0000243 kCGLPFAAccelerated,
244 kCGLPFADoubleBuffer,
245 (CGLPixelFormatAttribute)0
246 };
247
248 CGLPixelFormatObj format;
bsalomon@google.com11959252012-04-06 20:13:38 +0000249 GLint npix = 0;
250 if (msaaSampleCount > 0) {
251 static int kAttributeCount = SK_ARRAY_COUNT(attributes);
252 CGLPixelFormatAttribute msaaAttributes[kAttributeCount + 5];
253 memcpy(msaaAttributes, attributes, sizeof(attributes));
254 SkASSERT(0 == msaaAttributes[kAttributeCount - 1]);
255 msaaAttributes[kAttributeCount - 1] = kCGLPFASampleBuffers;
256 msaaAttributes[kAttributeCount + 0] = (CGLPixelFormatAttribute)1;
257 msaaAttributes[kAttributeCount + 1] = kCGLPFAMultisample;
258 msaaAttributes[kAttributeCount + 2] = kCGLPFASamples;
259 msaaAttributes[kAttributeCount + 3] =
260 (CGLPixelFormatAttribute)msaaSampleCount;
261 msaaAttributes[kAttributeCount + 4] = (CGLPixelFormatAttribute)0;
262 CGLChoosePixelFormat(msaaAttributes, &format, &npix);
263 }
264 if (!npix) {
265 CGLChoosePixelFormat(attributes, &format, &npix);
266 }
yangsu@google.com12d177d2011-08-01 17:07:12 +0000267
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000268 CGLContextObj ctx;
yangsu@google.com12d177d2011-08-01 17:07:12 +0000269 CGLCreateContext(format, NULL, &ctx);
yangsu@google.com12d177d2011-08-01 17:07:12 +0000270 CGLDestroyPixelFormat(format);
271
272 static const GLint interval = 1;
273 CGLSetParameter(ctx, kCGLCPSwapInterval, &interval);
274 CGLSetCurrentContext(ctx);
275 return ctx;
276}
bsalomon@google.comed164832012-04-03 18:06:20 +0000277}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000278#endif
yangsu@google.com12d177d2011-08-01 17:07:12 +0000279
280- (void)viewDidMoveToWindow {
281 [super viewDidMoveToWindow];
282
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000283#if SK_SUPPORT_GPU
yangsu@google.com12d177d2011-08-01 17:07:12 +0000284 //Attaching view to fGLContext requires that the view to be part of a window,
285 //and that the NSWindow instance must have a CoreGraphics counterpart (or
286 //it must NOT be deferred or should have been on screen at least once)
287 if ([fGLContext view] != self && nil != self.window) {
288 [fGLContext setView:self];
yangsu@google.com12d177d2011-08-01 17:07:12 +0000289 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000290#endif
yangsu@google.com12d177d2011-08-01 17:07:12 +0000291}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000292- (bool)attach:(SkOSWindow::SkBackEndTypes)attachType withMSAASampleCount:(int) sampleCount {
293#if SK_SUPPORT_GPU
294 if (SkOSWindow::kNativeGL_BackEndType == attachType) {
295 [self setWantsLayer:NO];
296 self.layer = nil;
297 if (nil == fGLContext) {
298 CGLContextObj ctx = createGLContext(sampleCount);
299 fGLContext = [[NSOpenGLContext alloc] initWithCGLContextObj:ctx];
300 CGLReleaseContext(ctx);
301 if (NULL == fGLContext) {
302 return false;
303 }
304 [fGLContext setView:self];
caryclark@google.com4ee8aea2011-11-23 14:54:19 +0000305 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000306
307 [fGLContext makeCurrentContext];
308
309 glViewport(0, 0, (int) self.bounds.size.width, (int) self.bounds.size.width);
310 glClearColor(0, 0, 0, 0);
311 glClearStencil(0);
312 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
313 return true;
caryclark@google.com4ee8aea2011-11-23 14:54:19 +0000314 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000315#endif
316 if (SkOSWindow::kNone_BackEndType == attachType) {
317 [self detach];
318 [self setLayer:[CALayer layer]];
319 [self setWantsLayer:YES];
320 return true;
321 }
322 return false;
yangsu@google.com12d177d2011-08-01 17:07:12 +0000323}
324
robertphillips@google.comd5b05ef2012-04-02 20:19:28 +0000325- (void)detach {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000326#if SK_SUPPORT_GPU
bsalomon@google.comed164832012-04-03 18:06:20 +0000327 [fGLContext release];
328 fGLContext = nil;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000329#endif
yangsu@google.com12d177d2011-08-01 17:07:12 +0000330}
331
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000332#include "SkCGUtils.h"
333
robertphillips@google.comd5b05ef2012-04-02 20:19:28 +0000334- (void)present {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000335#if SK_SUPPORT_GPU
bsalomon@google.comed164832012-04-03 18:06:20 +0000336 if (nil != fGLContext) {
337 [fGLContext flushBuffer];
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000338 return;
bsalomon@google.comed164832012-04-03 18:06:20 +0000339 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000340#endif
341 const SkBitmap& bmp = fWind->getBitmap();
342 SkASSERT(self.layer);
343 // FIXME: This causes the layer to flicker during animation. Making a copy of the CGImage does
344 // not help.
345 CGImageRef img = SkCreateCGImageRef(bmp);
346 self.layer.contents = (id) img;
347 CGImageRelease(img);
yangsu@google.com12d177d2011-08-01 17:07:12 +0000348}
robertphillips@google.comd5b05ef2012-04-02 20:19:28 +0000349@end