blob: 1014ffe04dcaec7750df14d78dc63d785edc10c9 [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
robertphillips@google.com5b5bba32012-09-24 14:20:00 +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"
bsalomon@google.com2e401732012-08-03 19:25:10 +000013SK_COMPILE_ASSERT(SK_SUPPORT_GPU, not_implemented_for_non_gpu_build);
commit-bot@chromium.org6a180792014-01-15 21:39:18 +000014#include <OpenGL/gl.h>
yangsu@google.com12d177d2011-08-01 17:07:12 +000015
16//#define FORCE_REDRAW
bungeman@google.comb20a1b52013-06-28 16:44:55 +000017// 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)
yangsu@google.com12d177d2011-08-01 17:07:12 +000020@implementation SkNSView
bsalomon@google.com2e401732012-08-03 19:25:10 +000021@synthesize fWind, fTitle, fOptionsDelegate, fGLContext;
yangsu@google.com12d177d2011-08-01 17:07:12 +000022
23- (id)initWithCoder:(NSCoder*)coder {
24 if ((self = [super initWithCoder:coder])) {
yangsu@google.coma8540412011-08-30 14:40:49 +000025 self = [self initWithDefaults];
26 [self setUpWindow];
yangsu@google.com12d177d2011-08-01 17:07:12 +000027 }
28 return self;
29}
30
31- (id)initWithFrame:(NSRect)frameRect {
caryclark@google.com679ab312012-06-06 12:04:00 +000032 if ((self = [super initWithFrame:frameRect])) {
yangsu@google.coma8540412011-08-30 14:40:49 +000033 self = [self initWithDefaults];
34 [self setUpWindow];
yangsu@google.com12d177d2011-08-01 17:07:12 +000035 }
36 return self;
37}
38
yangsu@google.coma8540412011-08-30 14:40:49 +000039- (id)initWithDefaults {
bungeman@google.comb20a1b52013-06-28 16:44:55 +000040#if RETINA_API_AVAILABLE
41 [self setWantsBestResolutionOpenGLSurface:YES];
42#endif
yangsu@google.com12d177d2011-08-01 17:07:12 +000043 fRedrawRequestPending = false;
yangsu@google.coma8540412011-08-30 14:40:49 +000044 fWind = NULL;
yangsu@google.com12d177d2011-08-01 17:07:12 +000045 return self;
46}
47
yangsu@google.coma8540412011-08-30 14:40:49 +000048- (void)setUpWindow {
bungeman@google.comb20a1b52013-06-28 16:44:55 +000049 [[NSNotificationCenter defaultCenter] addObserver:self
50 selector:@selector(backingPropertiesChanged:)
51 name:@"NSWindowDidChangeBackingPropertiesNotification"
52 object:[self window]];
yangsu@google.coma8540412011-08-30 14:40:49 +000053 if (NULL != fWind) {
54 fWind->setVisibleP(true);
bungeman@google.comb20a1b52013-06-28 16:44:55 +000055 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,
commit-bot@chromium.org757ebd22014-04-10 22:36:34 +000060 kPMColor_SkColorType);
yangsu@google.coma8540412011-08-30 14:40:49 +000061 }
62}
63
yangsu@google.com12d177d2011-08-01 17:07:12 +000064-(BOOL) isFlipped {
65 return YES;
66}
67
68- (BOOL)acceptsFirstResponder {
69 return YES;
70}
71
bungeman@google.comb20a1b52013-06-28 16:44:55 +000072- (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 {
bungeman@google.com44fb1fa2013-06-28 17:21:35 +000088 CGFloat oldBackingScaleFactor = (CGFloat)[
bungeman@google.comb20a1b52013-06-28 16:44:55 +000089 [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
suyang1bb3f4a82011-10-10 16:38:58 +0000102- (void)resizeSkView:(NSSize)newSize {
bungeman@google.comb20a1b52013-06-28 16:44:55 +0000103#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 {
caryclark@google.com679ab312012-06-06 12:04:00 +0000110 fWind->resize((int) newSize.width, (int) newSize.height);
caryclark@google.com594dd3c2012-09-24 19:33:57 +0000111 if (NULL != fGLContext) {
112 glClear(GL_STENCIL_BUFFER_BIT);
bungeman@google.comb20a1b52013-06-28 16:44:55 +0000113 [fGLContext update];
caryclark@google.com594dd3c2012-09-24 19:33:57 +0000114 }
yangsu@google.com12d177d2011-08-01 17:07:12 +0000115 }
yangsu@google.com12d177d2011-08-01 17:07:12 +0000116}
117
suyang1bb3f4a82011-10-10 16:38:58 +0000118- (void) setFrameSize:(NSSize)newSize {
119 [super setFrameSize:newSize];
120 [self resizeSkView:newSize];
121}
122
yangsu@google.com12d177d2011-08-01 17:07:12 +0000123- (void)dealloc {
124 delete fWind;
125 self.fGLContext = nil;
126 self.fTitle = nil;
yangsu@google.com12d177d2011-08-01 17:07:12 +0000127 [super dealloc];
128}
129
suyang1bb3f4a82011-10-10 16:38:58 +0000130////////////////////////////////////////////////////////////////////////////////
yangsu@google.com12d177d2011-08-01 17:07:12 +0000131
yangsu@google.comf3493f02011-08-08 15:12:05 +0000132- (void)drawSkia {
yangsu@google.com12d177d2011-08-01 17:07:12 +0000133 fRedrawRequestPending = false;
yangsu@google.coma8540412011-08-30 14:40:49 +0000134 if (NULL != fWind) {
reed@google.com5957f472012-10-01 20:31:56 +0000135 SkAutoTUnref<SkCanvas> canvas(fWind->createCanvas());
136 fWind->draw(canvas);
yangsu@google.com12d177d2011-08-01 17:07:12 +0000137#ifdef FORCE_REDRAW
yangsu@google.coma8540412011-08-30 14:40:49 +0000138 fWind->inval(NULL);
yangsu@google.com12d177d2011-08-01 17:07:12 +0000139#endif
yangsu@google.coma8540412011-08-30 14:40:49 +0000140 }
yangsu@google.com12d177d2011-08-01 17:07:12 +0000141}
142
yangsu@google.comf3493f02011-08-08 15:12:05 +0000143- (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;
yangsu@google.coma8540412011-08-30 14:40:49 +0000164 [self setNeedsDisplay:YES];
yangsu@google.comf3493f02011-08-08 15:12:05 +0000165 [self performSelector:@selector(drawSkia) withObject:nil afterDelay:0];
166 }
yangsu@google.com12d177d2011-08-01 17:07:12 +0000167}
168///////////////////////////////////////////////////////////////////////////////
169
170#include "SkKey.h"
171enum {
bsalomon@google.com2e401732012-08-03 19:25:10 +0000172 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,
yangsu@google.com12d177d2011-08-01 17:07:12 +0000179 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
191static SkKey raw2key(UInt32 raw)
192{
bsalomon@google.com2e401732012-08-03 19:25:10 +0000193 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 },
yangsu@google.com12d177d2011-08-01 17:07:12 +0000204 { SK_Mac0Key, k0_SkKey },
205 { SK_Mac1Key, k1_SkKey },
206 { SK_Mac2Key, k2_SkKey },
207 { SK_Mac3Key, k3_SkKey },
yangsu@google.comf3493f02011-08-08 15:12:05 +0000208 { SK_Mac4Key, k4_SkKey },
yangsu@google.com12d177d2011-08-01 17:07:12 +0000209 { SK_Mac5Key, k5_SkKey },
210 { SK_Mac6Key, k6_SkKey },
211 { SK_Mac7Key, k7_SkKey },
212 { SK_Mac8Key, k8_SkKey },
213 { SK_Mac9Key, k9_SkKey }
bsalomon@google.com2e401732012-08-03 19:25:10 +0000214 };
yangsu@google.com12d177d2011-08-01 17:07:12 +0000215
bsalomon@google.com2e401732012-08-03 19:25:10 +0000216 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;
yangsu@google.com12d177d2011-08-01 17:07:12 +0000220}
221
222- (void)keyDown:(NSEvent *)event {
yangsu@google.com849ad5a2011-08-30 15:27:57 +0000223 if (NULL == fWind)
yangsu@google.coma8540412011-08-30 14:40:49 +0000224 return;
225
yangsu@google.com12d177d2011-08-01 17:07:12 +0000226 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 {
yangsu@google.com849ad5a2011-08-30 15:27:57 +0000236 if (NULL == fWind)
yangsu@google.coma8540412011-08-30 14:40:49 +0000237 return;
238
yangsu@google.com12d177d2011-08-01 17:07:12 +0000239 SkKey key = raw2key([event keyCode]);
240 if (kNONE_SkKey != key)
241 fWind->handleKeyUp(key);
caryclark@google.com679ab312012-06-06 12:04:00 +0000242 // else
243 // unichar c = [[event characters] characterAtIndex:0];
yangsu@google.com12d177d2011-08-01 17:07:12 +0000244}
245
reed@google.com4d5c26d2013-01-08 16:17:50 +0000246static 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
257static 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
yangsu@google.com12d177d2011-08-01 17:07:12 +0000267- (void)mouseDown:(NSEvent *)event {
268 NSPoint p = [event locationInWindow];
reed@google.com4d5c26d2013-01-08 16:17:50 +0000269 unsigned modi = convertNSModifiersToSk([event modifierFlags]);
270
yangsu@google.coma8540412011-08-30 14:40:49 +0000271 if ([self mouse:p inRect:[self bounds]] && NULL != fWind) {
yangsu@google.com12d177d2011-08-01 17:07:12 +0000272 NSPoint loc = [self convertPoint:p fromView:nil];
bungeman@google.comb20a1b52013-06-28 16:44:55 +0000273#if RETINA_API_AVAILABLE
274 loc = [self convertPointToBacking:loc]; //y-up
275 loc.y = -loc.y;
276#endif
reed@google.com4d5c26d2013-01-08 16:17:50 +0000277 fWind->handleClick((int) loc.x, (int) loc.y,
278 SkView::Click::kDown_State, self, modi);
yangsu@google.com12d177d2011-08-01 17:07:12 +0000279 }
280}
281
282- (void)mouseDragged:(NSEvent *)event {
283 NSPoint p = [event locationInWindow];
reed@google.com4d5c26d2013-01-08 16:17:50 +0000284 unsigned modi = convertNSModifiersToSk([event modifierFlags]);
285
yangsu@google.coma8540412011-08-30 14:40:49 +0000286 if ([self mouse:p inRect:[self bounds]] && NULL != fWind) {
yangsu@google.com12d177d2011-08-01 17:07:12 +0000287 NSPoint loc = [self convertPoint:p fromView:nil];
bungeman@google.comb20a1b52013-06-28 16:44:55 +0000288#if RETINA_API_AVAILABLE
289 loc = [self convertPointToBacking:loc]; //y-up
290 loc.y = -loc.y;
291#endif
reed@google.com4d5c26d2013-01-08 16:17:50 +0000292 fWind->handleClick((int) loc.x, (int) loc.y,
293 SkView::Click::kMoved_State, self, modi);
yangsu@google.com12d177d2011-08-01 17:07:12 +0000294 }
295}
296
suyang1bb3f4a82011-10-10 16:38:58 +0000297- (void)mouseMoved:(NSEvent *)event {
298 NSPoint p = [event locationInWindow];
reed@google.com4d5c26d2013-01-08 16:17:50 +0000299 unsigned modi = convertNSModifiersToSk([event modifierFlags]);
300
suyang1bb3f4a82011-10-10 16:38:58 +0000301 if ([self mouse:p inRect:[self bounds]] && NULL != fWind) {
302 NSPoint loc = [self convertPoint:p fromView:nil];
bungeman@google.comb20a1b52013-06-28 16:44:55 +0000303#if RETINA_API_AVAILABLE
304 loc = [self convertPointToBacking:loc]; //y-up
305 loc.y = -loc.y;
306#endif
reed@google.com4d5c26d2013-01-08 16:17:50 +0000307 fWind->handleClick((int) loc.x, (int) loc.y,
308 SkView::Click::kMoved_State, self, modi);
suyang1bb3f4a82011-10-10 16:38:58 +0000309 }
310}
311
yangsu@google.com12d177d2011-08-01 17:07:12 +0000312- (void)mouseUp:(NSEvent *)event {
313 NSPoint p = [event locationInWindow];
reed@google.com4d5c26d2013-01-08 16:17:50 +0000314 unsigned modi = convertNSModifiersToSk([event modifierFlags]);
315
yangsu@google.coma8540412011-08-30 14:40:49 +0000316 if ([self mouse:p inRect:[self bounds]] && NULL != fWind) {
yangsu@google.com12d177d2011-08-01 17:07:12 +0000317 NSPoint loc = [self convertPoint:p fromView:nil];
bungeman@google.comb20a1b52013-06-28 16:44:55 +0000318#if RETINA_API_AVAILABLE
319 loc = [self convertPointToBacking:loc]; //y-up
320 loc.y = -loc.y;
321#endif
reed@google.com4d5c26d2013-01-08 16:17:50 +0000322 fWind->handleClick((int) loc.x, (int) loc.y,
323 SkView::Click::kUp_State, self, modi);
yangsu@google.com12d177d2011-08-01 17:07:12 +0000324 }
325}
326
yangsu@google.com12d177d2011-08-01 17:07:12 +0000327///////////////////////////////////////////////////////////////////////////////
328#include <OpenGL/OpenGL.h>
bsalomon@google.com2e401732012-08-03 19:25:10 +0000329
bsalomon@google.comed164832012-04-03 18:06:20 +0000330namespace {
bsalomon@google.com11959252012-04-06 20:13:38 +0000331CGLContextObj createGLContext(int msaaSampleCount) {
yangsu@google.com12d177d2011-08-01 17:07:12 +0000332 GLint major, minor;
yangsu@google.com12d177d2011-08-01 17:07:12 +0000333 CGLGetVersion(&major, &minor);
yangsu@google.com12d177d2011-08-01 17:07:12 +0000334
bsalomon@google.com11959252012-04-06 20:13:38 +0000335 static const CGLPixelFormatAttribute attributes[] = {
336 kCGLPFAStencilSize, (CGLPixelFormatAttribute) 8,
yangsu@google.com12d177d2011-08-01 17:07:12 +0000337 kCGLPFAAccelerated,
338 kCGLPFADoubleBuffer,
339 (CGLPixelFormatAttribute)0
340 };
341
342 CGLPixelFormatObj format;
bsalomon@google.com11959252012-04-06 20:13:38 +0000343 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 }
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000361 CGLContextObj ctx;
yangsu@google.com12d177d2011-08-01 17:07:12 +0000362 CGLCreateContext(format, NULL, &ctx);
yangsu@google.com12d177d2011-08-01 17:07:12 +0000363 CGLDestroyPixelFormat(format);
364
365 static const GLint interval = 1;
366 CGLSetParameter(ctx, kCGLCPSwapInterval, &interval);
367 CGLSetCurrentContext(ctx);
368 return ctx;
369}
bsalomon@google.comed164832012-04-03 18:06:20 +0000370}
yangsu@google.com12d177d2011-08-01 17:07:12 +0000371
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];
yangsu@google.com12d177d2011-08-01 17:07:12 +0000380 }
381}
bsalomon@google.com2e401732012-08-03 19:25:10 +0000382- (bool)attach:(SkOSWindow::SkBackEndTypes)attachType
bsalomon@google.com64cc8102013-03-05 20:06:05 +0000383 withMSAASampleCount:(int) sampleCount
384 andGetInfo:(SkOSWindow::AttachmentInfo*) info {
bsalomon@google.com2e401732012-08-03 19:25:10 +0000385 if (nil == fGLContext) {
386 CGLContextObj ctx = createGLContext(sampleCount);
387 fGLContext = [[NSOpenGLContext alloc] initWithCGLContextObj:ctx];
388 CGLReleaseContext(ctx);
389 if (NULL == fGLContext) {
390 return false;
caryclark@google.com4ee8aea2011-11-23 14:54:19 +0000391 }
bsalomon@google.com2e401732012-08-03 19:25:10 +0000392 [fGLContext setView:self];
caryclark@google.com4ee8aea2011-11-23 14:54:19 +0000393 }
bsalomon@google.com64cc8102013-03-05 20:06:05 +0000394
bsalomon@google.com2e401732012-08-03 19:25:10 +0000395 [fGLContext makeCurrentContext];
bsalomon@google.com64cc8102013-03-05 20:06:05 +0000396 CGLPixelFormatObj format = CGLGetPixelFormat((CGLContextObj)[fGLContext CGLContextObj]);
397 CGLDescribePixelFormat(format, 0, kCGLPFASamples, &info->fSampleCount);
398 CGLDescribePixelFormat(format, 0, kCGLPFAStencilSize, &info->fStencilBits);
bungeman@google.comb20a1b52013-06-28 16:44:55 +0000399 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);
bsalomon@google.com2e401732012-08-03 19:25:10 +0000404 glClearColor(0, 0, 0, 0);
405 glClearStencil(0);
406 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
407 return true;
yangsu@google.com12d177d2011-08-01 17:07:12 +0000408}
409
robertphillips@google.comd5b05ef2012-04-02 20:19:28 +0000410- (void)detach {
bsalomon@google.comed164832012-04-03 18:06:20 +0000411 [fGLContext release];
412 fGLContext = nil;
yangsu@google.com12d177d2011-08-01 17:07:12 +0000413}
414
robertphillips@google.comd5b05ef2012-04-02 20:19:28 +0000415- (void)present {
bsalomon@google.comed164832012-04-03 18:06:20 +0000416 if (nil != fGLContext) {
417 [fGLContext flushBuffer];
418 }
yangsu@google.com12d177d2011-08-01 17:07:12 +0000419}
robertphillips@google.comd5b05ef2012-04-02 20:19:28 +0000420@end