From d4336bfb107f48b3d9a9981cde9f62882b4fee2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= Date: Mon, 30 Nov 2015 14:53:07 +0100 Subject: [PATCH] simplify impl of capture(). Fixes #33 --- ios/GLCanvas.h | 3 ++- ios/GLCanvas.m | 34 +++++++++++++++---------- ios/GLCanvasManager.m | 32 +++++++++++------------ ios/RNGL.xcodeproj/project.pbxproj | 4 +-- src/GLCanvas.js | 41 ++++++------------------------ 5 files changed, 47 insertions(+), 67 deletions(-) diff --git a/ios/GLCanvas.h b/ios/GLCanvas.h index 6532981..3ddd672 100644 --- a/ios/GLCanvas.h +++ b/ios/GLCanvas.h @@ -7,7 +7,6 @@ @property (nonatomic) BOOL opaque; @property (nonatomic) BOOL autoRedraw; @property (nonatomic) BOOL eventsThrough; -@property (nonatomic) int captureNextFrameId; @property (nonatomic) BOOL visibleContent; @property (nonatomic) NSNumber *nbContentTextures; @property (nonatomic) NSNumber *renderId; @@ -18,4 +17,6 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge; +- (void) capture:(RCTResponseSenderBlock)callback; + @end diff --git a/ios/GLCanvas.m b/ios/GLCanvas.m index a06e967..ce52c30 100644 --- a/ios/GLCanvas.m +++ b/ios/GLCanvas.m @@ -33,6 +33,8 @@ NSString* srcResource (id res) RCTBridge *_bridge; GLRenderData *_renderData; + + NSMutableArray *_captureListeners; NSArray *_contentTextures; NSDictionary *_images; // This caches the currently used images (imageSrc -> GLReactImage) @@ -47,9 +49,7 @@ NSString* srcResource (id res) BOOL _preloadingDone; NSTimer *animationTimer; - - int _lastCaptureId; - + BOOL _needSync; } @@ -59,8 +59,8 @@ NSString* srcResource (id res) _bridge = bridge; _images = @{}; _preloaded = [[NSMutableArray alloc] init]; + _captureListeners = [[NSMutableArray alloc] init]; _preloadingDone = false; - _lastCaptureId = 0; self.context = [bridge.rnglContext getContext]; self.contentScaleFactor = RCTScreenScale(); } @@ -71,6 +71,12 @@ RCT_NOT_IMPLEMENTED(-init) //// Props Setters +- (void) capture:(RCTResponseSenderBlock)callback +{ + [_captureListeners addObject:callback]; + [self setNeedsDisplay]; +} + -(void)setImagesToPreload:(NSArray *)imagesToPreload { if (_preloadingDone) return; @@ -139,12 +145,6 @@ RCT_NOT_IMPLEMENTED(-init) _nbContentTextures = nbContentTextures; } -- (void)setCaptureNextFrameId:(int)captureNextFrameId -{ - _captureNextFrameId = captureNextFrameId; - [self setNeedsDisplay]; -} - //// Sync methods (called from props setters) - (void) syncEventsThrough @@ -322,9 +322,12 @@ RCT_NOT_IMPLEMENTED(-init) else { [self render]; _deferredRendering = false; - if (_captureNextFrameId > _lastCaptureId) { - _lastCaptureId ++; - int id = _lastCaptureId; + + unsigned long nbCaptureListeners = [_captureListeners count]; + if (nbCaptureListeners > 0) { + NSArray *listeners = _captureListeners; + _captureListeners = [[NSMutableArray alloc] init]; + dispatch_async(dispatch_get_main_queue(), ^{ // snapshot not allowed in render tick. defer it. if (!weakSelf) return; UIImage *frameImage = [weakSelf snapshot]; @@ -332,7 +335,10 @@ RCT_NOT_IMPLEMENTED(-init) NSString *frame = [NSString stringWithFormat:@"data:image/png;base64,%@", [frameData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]]; - [weakSelf dispatchOnCapture:frame withId:id]; + for (int i = 0; i < nbCaptureListeners; i++) { + RCTResponseSenderBlock listener = listeners[i]; + listener(@[[NSNull null], frame]); + } }); } } diff --git a/ios/GLCanvasManager.m b/ios/GLCanvasManager.m index 5ca3543..0ca4404 100644 --- a/ios/GLCanvasManager.m +++ b/ios/GLCanvasManager.m @@ -1,6 +1,8 @@ #import "GLCanvasManager.h" #import "GLCanvas.h" #import "RCTConvert+GLData.h" +#import "RCTSparseArray.h" +#import "RCTUIManager.h" #import "RCTLog.h" #import @@ -21,7 +23,6 @@ RCT_EXPORT_VIEW_PROPERTY(opaque, BOOL); RCT_EXPORT_VIEW_PROPERTY(autoRedraw, BOOL); RCT_EXPORT_VIEW_PROPERTY(eventsThrough, BOOL); RCT_EXPORT_VIEW_PROPERTY(visibleContent, BOOL); -RCT_EXPORT_VIEW_PROPERTY(captureNextFrameId, int); RCT_EXPORT_VIEW_PROPERTY(data, GLData); RCT_EXPORT_VIEW_PROPERTY(renderId, NSNumber); RCT_EXPORT_VIEW_PROPERTY(imagesToPreload, NSArray); @@ -29,22 +30,19 @@ RCT_EXPORT_VIEW_PROPERTY(onLoad, BOOL); RCT_EXPORT_VIEW_PROPERTY(onProgress, BOOL); RCT_EXPORT_VIEW_PROPERTY(onChange, BOOL); -/* TODO - - RCT_EXPORT_METHOD(capture: - (nonnull NSNumber *)reactTag - callback:(RCTResponseSenderBlock)callback) - { - - UIView *view = [self.bridge.uiManager viewForReactTag:reactTag]; - if ([view isKindOfClass:[GLCanvas class]]) { - [((GLCanvas*)view) capture: callback]; - } - else { - callback(@[@"view is not a GLCanvas"]); - } - } - */ +RCT_EXPORT_METHOD(capture: (nonnull NSNumber *)reactTag callback:(RCTResponseSenderBlock)callback) +{ + [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { + GLCanvas *view = viewRegistry[reactTag]; + if (![view isKindOfClass:[GLCanvas class]]) { + RCTLog(@"expecting UIView, got: %@", view); + callback(@[@"view is not a GLCanvas"]); + } + else { + [view capture:callback]; + } + }]; +} - (UIView *)view { diff --git a/ios/RNGL.xcodeproj/project.pbxproj b/ios/RNGL.xcodeproj/project.pbxproj index 99e80ce..4c89e07 100644 --- a/ios/RNGL.xcodeproj/project.pbxproj +++ b/ios/RNGL.xcodeproj/project.pbxproj @@ -34,9 +34,9 @@ /* Begin PBXFileReference section */ 346089BA1BEFD0A500C90DB5 /* GLCanvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLCanvas.h; sourceTree = ""; }; - 346089BB1BEFD0A500C90DB5 /* GLCanvas.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLCanvas.m; sourceTree = ""; }; + 346089BB1BEFD0A500C90DB5 /* GLCanvas.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = GLCanvas.m; sourceTree = ""; tabWidth = 2; }; 346089BC1BEFD0A500C90DB5 /* GLCanvasManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLCanvasManager.h; sourceTree = ""; }; - 346089BD1BEFD0A500C90DB5 /* GLCanvasManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLCanvasManager.m; sourceTree = ""; }; + 346089BD1BEFD0A500C90DB5 /* GLCanvasManager.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = GLCanvasManager.m; sourceTree = ""; tabWidth = 2; }; 346089BE1BEFD0A500C90DB5 /* GLData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLData.h; sourceTree = ""; }; 346089BF1BEFD0A500C90DB5 /* GLData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLData.m; sourceTree = ""; }; 346089C01BEFD0A500C90DB5 /* GLFBO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLFBO.h; sourceTree = ""; }; diff --git a/src/GLCanvas.js b/src/GLCanvas.js index 2cb43e7..6b5e347 100644 --- a/src/GLCanvas.js +++ b/src/GLCanvas.js @@ -2,7 +2,8 @@ const React = require("react-native"); const { Component, - requireNativeComponent + requireNativeComponent, + NativeModules: { GLCanvasManager } } = React; const GLCanvasNative = requireNativeComponent("GLCanvas", GLCanvas); @@ -10,47 +11,21 @@ const GLCanvasNative = requireNativeComponent("GLCanvas", GLCanvas); class GLCanvas extends Component { constructor (props) { super(props); - this.state = { - captureNextFrameId: 0 // the current id to send to the ObjC part. - }; - this._captureId = 1; // track the current id to use for captures. it get incremented when the frame is obtained. - this._captureListeners = { [this._captureId]: [] }; // callbacks by capture id - - this._needsCapture = false; - this.handleCapture = this.handleCapture.bind(this); - this.onCaptureFrame = this.onCaptureFrame.bind(this); } captureFrame (cb) { - this._captureListeners[this._captureId].push(cb); - this.requestCapture(); - } - onCaptureFrame ({ nativeEvent: {frame, id} }) { - if (id in this._captureListeners) { - this._captureListeners[id].forEach(listener => listener(frame)); - delete this._captureListeners[id]; - } - this._captureId ++; - this._captureListeners[this._captureId] = []; - } - requestCapture () { - if (this._needsCapture) return; - this._needsCapture = true; - requestAnimationFrame(this.handleCapture); - } - handleCapture () { - if (!this._needsCapture) return; - this._needsCapture = false; - this.setState({ captureNextFrameId: this._captureId }); + GLCanvasManager.capture( + React.findNodeHandle(this.refs.native), + (error, frame) => { + if (error) console.error(error); // eslint-disable-line no-console + else cb(frame); + }); } render () { const { width, height, ...restProps } = this.props; - const { captureNextFrameId } = this.state; return ; } } -- 2.26.2