Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / views / mac / SkNSView.mm
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
9 #import "SkNSView.h"
10 #include "SkCanvas.h"
11 #include "SkCGUtils.h"
12 #include "SkEvent.h"
13 SK_COMPILE_ASSERT(SK_SUPPORT_GPU, not_implemented_for_non_gpu_build);
14 #include <OpenGL/gl.h>
15
16 //#define FORCE_REDRAW
17 // Can be dropped when we no longer support 10.6.
18 #define RETINA_API_AVAILABLE (defined(MAC_OS_X_VERSION_10_7) && \
19                               MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
20 @implementation SkNSView
21 @synthesize fWind, fTitle, fOptionsDelegate, fGLContext;
22
23 - (id)initWithCoder:(NSCoder*)coder {
24     if ((self = [super initWithCoder:coder])) {
25         self = [self initWithDefaults];
26         [self setUpWindow];
27     }
28     return self;
29 }
30
31 - (id)initWithFrame:(NSRect)frameRect {
32     if ((self = [super initWithFrame:frameRect])) {
33         self = [self initWithDefaults];
34         [self setUpWindow];
35     }
36     return self;
37 }
38
39 - (id)initWithDefaults {
40 #if RETINA_API_AVAILABLE
41     [self setWantsBestResolutionOpenGLSurface:YES];
42 #endif
43     fRedrawRequestPending = false;
44     fWind = NULL;
45     return self;
46 }
47
48 - (void)setUpWindow {
49     [[NSNotificationCenter defaultCenter] addObserver:self
50                                           selector:@selector(backingPropertiesChanged:)
51                                           name:@"NSWindowDidChangeBackingPropertiesNotification"
52                                           object:[self window]];
53     if (NULL != fWind) {
54         fWind->setVisibleP(true);
55         NSSize size = self.frame.size;
56 #if RETINA_API_AVAILABLE
57         size = [self convertSizeToBacking:self.frame.size];
58 #endif
59         fWind->resize((int) size.width, (int) size.height,
60                       kN32_SkColorType);
61     }
62 }
63
64 -(BOOL) isFlipped {
65     return YES;
66 }
67
68 - (BOOL)acceptsFirstResponder {
69     return YES;
70 }
71
72 - (float)scaleFactor {
73     NSWindow *window = [self window];
74 #if RETINA_API_AVAILABLE
75     if (window) {
76         return [window backingScaleFactor];
77     }
78     return [[NSScreen mainScreen] backingScaleFactor];
79 #else
80     if (window) {
81         return [window userSpaceScaleFactor];
82     }
83     return [[NSScreen mainScreen] userSpaceScaleFactor];
84 #endif
85 }
86
87 - (void)backingPropertiesChanged:(NSNotification *)notification {
88     CGFloat oldBackingScaleFactor = (CGFloat)[
89         [notification.userInfo objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue
90     ];
91     CGFloat newBackingScaleFactor = [self scaleFactor];
92     if (oldBackingScaleFactor == newBackingScaleFactor) {
93         return;
94     }
95     
96     // TODO: need a better way to force a refresh (that works).
97     // [fGLContext update] does not appear to update if the point size has not changed,
98     // even if the backing size has changed.
99     [self setFrameSize:NSMakeSize(self.frame.size.width + 1, self.frame.size.height + 1)];
100 }
101
102 - (void)resizeSkView:(NSSize)newSize {
103 #if RETINA_API_AVAILABLE
104     newSize = [self convertSizeToBacking:newSize];
105 #endif
106     if (NULL != fWind &&
107             (fWind->width()  != newSize.width ||
108              fWind->height() != newSize.height))
109     {
110         fWind->resize((int) newSize.width, (int) newSize.height);
111         if (NULL != fGLContext) {
112             glClear(GL_STENCIL_BUFFER_BIT);
113             [fGLContext update];
114         }
115     }
116 }
117
118 - (void) setFrameSize:(NSSize)newSize {
119     [super setFrameSize:newSize];
120     [self resizeSkView:newSize];
121 }
122
123 - (void)dealloc {
124     delete fWind;
125     self.fGLContext = nil;
126     self.fTitle = nil;
127     [super dealloc];
128 }
129
130 ////////////////////////////////////////////////////////////////////////////////
131
132 - (void)drawSkia {
133     fRedrawRequestPending = false;
134     if (NULL != fWind) {
135         SkAutoTUnref<SkCanvas> canvas(fWind->createCanvas());
136         fWind->draw(canvas);
137 #ifdef FORCE_REDRAW
138         fWind->inval(NULL);
139 #endif
140     }
141 }
142
143 - (void)setSkTitle:(const char *)title {
144     self.fTitle = [NSString stringWithUTF8String:title];
145     [[self window] setTitle:self.fTitle];
146 }
147
148 - (BOOL)onHandleEvent:(const SkEvent&)evt {
149     return false;
150 }
151
152 #include "SkOSMenu.h"
153 - (void)onAddMenu:(const SkOSMenu*)menu {
154     [self.fOptionsDelegate view:self didAddMenu:menu];
155 }
156
157 - (void)onUpdateMenu:(const SkOSMenu*)menu {
158     [self.fOptionsDelegate view:self didUpdateMenu:menu];
159 }
160
161 - (void)postInvalWithRect:(const SkIRect*)r {
162     if (!fRedrawRequestPending) {
163         fRedrawRequestPending = true;
164         [self setNeedsDisplay:YES];
165         [self performSelector:@selector(drawSkia) withObject:nil afterDelay:0];
166     }
167 }
168 ///////////////////////////////////////////////////////////////////////////////
169
170 #include "SkKey.h"
171 enum {
172         SK_MacReturnKey         = 36,
173         SK_MacDeleteKey         = 51,
174         SK_MacEndKey            = 119,
175         SK_MacLeftKey           = 123,
176         SK_MacRightKey          = 124,
177         SK_MacDownKey           = 125,
178         SK_MacUpKey                     = 126,
179     SK_Mac0Key          = 0x52,
180     SK_Mac1Key          = 0x53,
181     SK_Mac2Key          = 0x54,
182     SK_Mac3Key          = 0x55,
183     SK_Mac4Key          = 0x56,
184     SK_Mac5Key          = 0x57,
185     SK_Mac6Key          = 0x58,
186     SK_Mac7Key          = 0x59,
187     SK_Mac8Key          = 0x5b,
188     SK_Mac9Key          = 0x5c
189 };
190
191 static SkKey raw2key(UInt32 raw)
192 {
193         static const struct {
194                 UInt32  fRaw;
195                 SkKey   fKey;
196         } gKeys[] = {
197                 { SK_MacUpKey,          kUp_SkKey               },
198                 { SK_MacDownKey,        kDown_SkKey             },
199                 { SK_MacLeftKey,        kLeft_SkKey             },
200                 { SK_MacRightKey,   kRight_SkKey        },
201                 { SK_MacReturnKey,  kOK_SkKey           },
202                 { SK_MacDeleteKey,  kBack_SkKey         },
203                 { SK_MacEndKey,         kEnd_SkKey              },
204         { SK_Mac0Key,       k0_SkKey        },
205         { SK_Mac1Key,       k1_SkKey        },
206         { SK_Mac2Key,       k2_SkKey        },
207         { SK_Mac3Key,       k3_SkKey        },
208         { SK_Mac4Key,       k4_SkKey        },
209         { SK_Mac5Key,       k5_SkKey        },
210         { SK_Mac6Key,       k6_SkKey        },
211         { SK_Mac7Key,       k7_SkKey        },
212         { SK_Mac8Key,       k8_SkKey        },
213         { SK_Mac9Key,       k9_SkKey        }
214         };
215     
216         for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++)
217                 if (gKeys[i].fRaw == raw)
218                         return gKeys[i].fKey;
219         return kNONE_SkKey;
220 }
221
222 - (void)keyDown:(NSEvent *)event {
223     if (NULL == fWind)
224         return;
225     
226     SkKey key = raw2key([event keyCode]);
227     if (kNONE_SkKey != key)
228         fWind->handleKey(key);
229     else{
230         unichar c = [[event characters] characterAtIndex:0];
231         fWind->handleChar((SkUnichar)c);
232     }
233 }
234
235 - (void)keyUp:(NSEvent *)event {
236     if (NULL == fWind)
237         return;
238     
239     SkKey key = raw2key([event keyCode]);
240     if (kNONE_SkKey != key)
241         fWind->handleKeyUp(key);
242  // else
243  //     unichar c = [[event characters] characterAtIndex:0];
244 }
245
246 static const struct {
247     unsigned    fNSModifierMask;
248     unsigned    fSkModifierMask;
249 } gModifierMasks[] = {
250     { NSAlphaShiftKeyMask,  kShift_SkModifierKey },
251     { NSShiftKeyMask,       kShift_SkModifierKey },
252     { NSControlKeyMask,     kControl_SkModifierKey },
253     { NSAlternateKeyMask,   kOption_SkModifierKey },
254     { NSCommandKeyMask,     kCommand_SkModifierKey },
255 };
256
257 static unsigned convertNSModifiersToSk(NSUInteger nsModi) {
258     unsigned skModi = 0;
259     for (size_t i = 0; i < SK_ARRAY_COUNT(gModifierMasks); ++i) {
260         if (nsModi & gModifierMasks[i].fNSModifierMask) {
261             skModi |= gModifierMasks[i].fSkModifierMask;
262         }
263     }
264     return skModi;
265 }
266
267 - (void)mouseDown:(NSEvent *)event {
268     NSPoint p = [event locationInWindow];
269     unsigned modi = convertNSModifiersToSk([event modifierFlags]);
270
271     if ([self mouse:p inRect:[self bounds]] && NULL != fWind) {
272         NSPoint loc = [self convertPoint:p fromView:nil];
273 #if RETINA_API_AVAILABLE
274         loc = [self convertPointToBacking:loc]; //y-up
275         loc.y = -loc.y;
276 #endif
277         fWind->handleClick((int) loc.x, (int) loc.y,
278                            SkView::Click::kDown_State, self, modi);
279     }
280 }
281
282 - (void)mouseDragged:(NSEvent *)event {
283     NSPoint p = [event locationInWindow];
284     unsigned modi = convertNSModifiersToSk([event modifierFlags]);
285
286     if ([self mouse:p inRect:[self bounds]] && NULL != fWind) {
287         NSPoint loc = [self convertPoint:p fromView:nil];
288 #if RETINA_API_AVAILABLE
289         loc = [self convertPointToBacking:loc]; //y-up
290         loc.y = -loc.y;
291 #endif
292         fWind->handleClick((int) loc.x, (int) loc.y,
293                            SkView::Click::kMoved_State, self, modi);
294     }
295 }
296
297 - (void)mouseMoved:(NSEvent *)event {
298     NSPoint p = [event locationInWindow];
299     unsigned modi = convertNSModifiersToSk([event modifierFlags]);
300     
301     if ([self mouse:p inRect:[self bounds]] && NULL != fWind) {
302         NSPoint loc = [self convertPoint:p fromView:nil];
303 #if RETINA_API_AVAILABLE
304         loc = [self convertPointToBacking:loc]; //y-up
305         loc.y = -loc.y;
306 #endif
307         fWind->handleClick((int) loc.x, (int) loc.y,
308                            SkView::Click::kMoved_State, self, modi);
309     }
310 }
311
312 - (void)mouseUp:(NSEvent *)event {
313     NSPoint p = [event locationInWindow];
314     unsigned modi = convertNSModifiersToSk([event modifierFlags]);
315     
316     if ([self mouse:p inRect:[self bounds]] && NULL != fWind) {
317         NSPoint loc = [self convertPoint:p fromView:nil];
318 #if RETINA_API_AVAILABLE
319         loc = [self convertPointToBacking:loc]; //y-up
320         loc.y = -loc.y;
321 #endif
322         fWind->handleClick((int) loc.x, (int) loc.y,
323                            SkView::Click::kUp_State, self, modi);
324     }
325 }
326
327 ///////////////////////////////////////////////////////////////////////////////
328 #include <OpenGL/OpenGL.h>
329
330 namespace { 
331 CGLContextObj createGLContext(int msaaSampleCount) {
332     GLint major, minor;
333     CGLGetVersion(&major, &minor);
334     
335     static const CGLPixelFormatAttribute attributes[] = {
336         kCGLPFAStencilSize, (CGLPixelFormatAttribute) 8,
337         kCGLPFAAccelerated,
338         kCGLPFADoubleBuffer,
339         (CGLPixelFormatAttribute)0
340     };
341     
342     CGLPixelFormatObj format;
343     GLint npix = 0;
344     if (msaaSampleCount > 0) {
345         static int kAttributeCount = SK_ARRAY_COUNT(attributes);
346         CGLPixelFormatAttribute msaaAttributes[kAttributeCount + 5];
347         memcpy(msaaAttributes, attributes, sizeof(attributes));
348         SkASSERT(0 == msaaAttributes[kAttributeCount - 1]);
349         msaaAttributes[kAttributeCount - 1] = kCGLPFASampleBuffers;
350         msaaAttributes[kAttributeCount + 0] = (CGLPixelFormatAttribute)1;
351         msaaAttributes[kAttributeCount + 1] = kCGLPFAMultisample;
352         msaaAttributes[kAttributeCount + 2] = kCGLPFASamples;
353         msaaAttributes[kAttributeCount + 3] =
354                                     (CGLPixelFormatAttribute)msaaSampleCount;
355         msaaAttributes[kAttributeCount + 4] = (CGLPixelFormatAttribute)0;
356         CGLChoosePixelFormat(msaaAttributes, &format, &npix);
357     }
358     if (!npix) {
359         CGLChoosePixelFormat(attributes, &format, &npix);
360     }
361     CGLContextObj ctx;
362     CGLCreateContext(format, NULL, &ctx);
363     CGLDestroyPixelFormat(format);
364     
365     static const GLint interval = 1;
366     CGLSetParameter(ctx, kCGLCPSwapInterval, &interval);
367     CGLSetCurrentContext(ctx);
368     return ctx;
369 }
370 }
371
372 - (void)viewDidMoveToWindow {
373     [super viewDidMoveToWindow];
374     
375     //Attaching view to fGLContext requires that the view to be part of a window,
376     //and that the NSWindow instance must have a CoreGraphics counterpart (or 
377     //it must NOT be deferred or should have been on screen at least once)
378     if ([fGLContext view] != self && nil != self.window) {
379         [fGLContext setView:self];
380     }
381 }
382 - (bool)attach:(SkOSWindow::SkBackEndTypes)attachType
383         withMSAASampleCount:(int) sampleCount
384         andGetInfo:(SkOSWindow::AttachmentInfo*) info {
385     if (nil == fGLContext) {
386         CGLContextObj ctx = createGLContext(sampleCount);
387         fGLContext = [[NSOpenGLContext alloc] initWithCGLContextObj:ctx];
388         CGLReleaseContext(ctx);
389         if (NULL == fGLContext) {
390             return false;
391         }
392         [fGLContext setView:self];
393     }
394
395     [fGLContext makeCurrentContext];
396     CGLPixelFormatObj format = CGLGetPixelFormat((CGLContextObj)[fGLContext CGLContextObj]);
397     CGLDescribePixelFormat(format, 0, kCGLPFASamples, &info->fSampleCount);
398     CGLDescribePixelFormat(format, 0, kCGLPFAStencilSize, &info->fStencilBits);
399     NSSize size = self.bounds.size;
400 #if RETINA_API_AVAILABLE
401     size = [self convertSizeToBacking:size];
402 #endif
403     glViewport(0, 0, (int) size.width, (int) size.height);
404     glClearColor(0, 0, 0, 0);
405     glClearStencil(0);
406     glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
407     return true;
408 }
409
410 - (void)detach {
411     [fGLContext release];
412     fGLContext = nil;
413 }
414
415 - (void)present {
416     if (nil != fGLContext) {
417         [fGLContext flushBuffer];
418     }
419 }
420 @end