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