[bugfix] Fix calling toDataUrl early and with options

Enable calling toDataUrl as soon as you get a ref to the svg root.
Fix invalidation and rendering with options for width and height.
This commit is contained in:
Mikael Sand
2019-03-11 02:43:06 +02:00
parent 74b0e3d99f
commit 6bd27dfeba
7 changed files with 98 additions and 15 deletions
@@ -101,8 +101,19 @@ public class SvgView extends ReactViewGroup implements ReactCompoundView, ReactC
if (mBitmap == null) {
mBitmap = drawOutput();
}
if (mBitmap != null)
if (mBitmap != null) {
canvas.drawBitmap(mBitmap, 0, 0, null);
if (toDataUrlTask != null) {
toDataUrlTask.run();
toDataUrlTask = null;
}
}
}
private Runnable toDataUrlTask = null;
void setToDataUrlTask(Runnable task) {
toDataUrlTask = task;
}
@Override
@@ -138,6 +149,10 @@ public class SvgView extends ReactViewGroup implements ReactCompoundView, ReactC
private boolean mRendered = false;
int mTintColor = 0;
boolean isRendered() {
return mRendered;
}
private void clearChildCache() {
if (!mRendered) {
return;
@@ -298,7 +313,10 @@ public class SvgView extends ReactViewGroup implements ReactCompoundView, ReactC
getHeight(),
Bitmap.Config.ARGB_8888);
clearChildCache();
drawChildren(new Canvas(bitmap));
clearChildCache();
this.invalidate();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
bitmap.recycle();
@@ -312,7 +330,10 @@ public class SvgView extends ReactViewGroup implements ReactCompoundView, ReactC
height,
Bitmap.Config.ARGB_8888);
clearChildCache();
drawChildren(new Canvas(bitmap));
clearChildCache();
this.invalidate();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
bitmap.recycle();
@@ -28,9 +28,19 @@ class SvgViewManager extends ReactViewManager {
private static final String REACT_CLASS = "RNSVGSvgView";
private static final SparseArray<SvgView> mTagToSvgView = new SparseArray<>();
private static final SparseArray<Runnable> mTagToRunnable = new SparseArray<>();
static void setSvgView(int tag, SvgView svg) {
mTagToSvgView.put(tag, svg);
Runnable task = mTagToRunnable.get(tag);
if (task != null) {
task.run();
mTagToRunnable.delete(tag);
}
}
static void runWhenViewIsAvailable(int tag, Runnable task) {
mTagToRunnable.put(tag, task);
}
static @Nullable SvgView getSvgViewByTag(int tag) {
@@ -25,12 +25,33 @@ class SvgViewModule extends ReactContextBaseJavaModule {
return "RNSVGSvgViewManager";
}
@ReactMethod
public void toDataURL(int tag, ReadableMap options, Callback successCallback) {
static public void toDataURL(final int tag, final ReadableMap options, final Callback successCallback, final int attempt) {
SvgView svg = SvgViewManager.getSvgViewByTag(tag);
if (svg != null) {
if (svg == null) {
SvgViewManager.runWhenViewIsAvailable(tag, new Runnable() {
@Override
public void run() {
SvgView svg = SvgViewManager.getSvgViewByTag(tag);
if (svg == null) { // Should never happen
return;
}
svg.setToDataUrlTask(new Runnable() {
@Override
public void run() {
toDataURL(tag, options, successCallback, attempt + 1);
}
});
}
});
} else if (!svg.isRendered()) {
svg.setToDataUrlTask(new Runnable() {
@Override
public void run() {
toDataURL(tag, options, successCallback, attempt + 1);
}
});
} else {
if (options != null) {
successCallback.invoke(
svg.toDataURL(
@@ -43,4 +64,9 @@ class SvgViewModule extends ReactContextBaseJavaModule {
}
}
}
@ReactMethod
public void toDataURL(int tag, ReadableMap options, Callback successCallback) {
toDataURL(tag, options, successCallback, 0);
}
}
+1 -1
View File
@@ -52,7 +52,7 @@
- (NSString *)getDataURL;
- (NSString *)getDataURLwithBounds:(CGSize)bounds;
- (NSString *)getDataURLwithBounds:(CGRect)bounds;
- (CGRect)getContextBounds;
+9 -3
View File
@@ -250,17 +250,23 @@
- (NSString *)getDataURL
{
UIGraphicsBeginImageContextWithOptions(_boundingBox.size, NO, 0);
[self clearChildCache];
[self drawRect:_boundingBox];
[self clearChildCache];
[self invalidate];
NSData *imageData = UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext());
NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
UIGraphicsEndImageContext();
return base64;
}
- (NSString *)getDataURLwithBounds:(CGSize)bounds
- (NSString *)getDataURLwithBounds:(CGRect)bounds
{
UIGraphicsBeginImageContextWithOptions(bounds, NO, 0);
[self drawRect:_boundingBox];
UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0);
[self clearChildCache];
[self drawRect:bounds];
[self clearChildCache];
[self invalidate];
NSData *imageData = UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext());
NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
UIGraphicsEndImageContext();
+2
View File
@@ -251,6 +251,7 @@
94241669213B0DB800088E93 /* RNSVGPattern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNSVGPattern.h; sourceTree = "<group>"; };
9424166A213B2FF100088E93 /* RNSVGPatternManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNSVGPatternManager.h; sourceTree = "<group>"; };
9424166C213B302600088E93 /* RNSVGPatternManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNSVGPatternManager.m; sourceTree = "<group>"; };
94696EE92235A7F200C1D558 /* RNSVGVectorEffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGVectorEffect.h; path = Utils/RNSVGVectorEffect.h; sourceTree = "<group>"; };
947F3809214810B800677F2A /* RNSVGMask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGMask.h; path = Elements/RNSVGMask.h; sourceTree = "<group>"; };
947F380A214810DC00677F2A /* RNSVGMask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGMask.m; path = Elements/RNSVGMask.m; sourceTree = "<group>"; };
947F380D2148118300677F2A /* RNSVGMaskManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGMaskManager.h; sourceTree = "<group>"; };
@@ -463,6 +464,7 @@
1039D29A1CE7212C001E90A8 /* Utils */ = {
isa = PBXGroup;
children = (
94696EE92235A7F200C1D558 /* RNSVGVectorEffect.h */,
B56895A920352B36004DBF1E /* RNSVGBezierElement.h */,
B56895A820352B35004DBF1E /* RNSVGBezierElement.m */,
7F69160D1E3703D800DA6EDC /* RNSVGUnits.h */,
+24 -6
View File
@@ -8,6 +8,7 @@
#import <React/RCTBridge.h>
#import <React/RCTUIManager.h>
#import <React/RCTUIManagerUtils.h>
#import "RNSVGSvgViewManager.h"
#import "RNSVGSvgView.h"
@@ -30,15 +31,15 @@ RCT_EXPORT_VIEW_PROPERTY(align, NSString)
RCT_EXPORT_VIEW_PROPERTY(meetOrSlice, RNSVGVBMOS)
RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
RCT_EXPORT_METHOD(toDataURL:(nonnull NSNumber *)reactTag options:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback)
{
- (void)toDataURL:(nonnull NSNumber *)reactTag options:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback attempt:(int)attempt {
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
__kindof UIView *view = viewRegistry[reactTag];
NSString * b64;
if ([view isKindOfClass:[RNSVGSvgView class]]) {
RNSVGSvgView *svg = view;
if (options == nil) {
RNSVGSvgView *svg = view;
callback(@[[svg getDataURL]]);
b64 = [svg getDataURL];
} else {
id width = [options objectForKey:@"width"];
id height = [options objectForKey:@"height"];
@@ -52,13 +53,30 @@ RCT_EXPORT_METHOD(toDataURL:(nonnull NSNumber *)reactTag options:(NSDictionary *
NSNumber* h = height;
NSInteger hi = (NSInteger)[h intValue];
CGSize bounds = CGSizeMake(wi, hi);
callback(@[[svg getDataURLwithBounds:bounds]]);
CGRect bounds = CGRectMake(0, 0, wi, hi);
b64 = [svg getDataURLwithBounds:bounds];
}
} else {
RCTLogError(@"Invalid svg returned frin registry, expecting RNSVGSvgView, got: %@", view);
return;
}
if (b64) {
callback(@[b64]);
} else if (attempt < 1) {
void (^retryBlock)(void) = ^{
[self toDataURL:reactTag options:options callback:callback attempt:(attempt + 1)];
};
RCTExecuteOnUIManagerQueue(retryBlock);
} else {
callback(@[]);
}
}];
}
RCT_EXPORT_METHOD(toDataURL:(nonnull NSNumber *)reactTag options:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback)
{
[self toDataURL:reactTag options:options callback:callback attempt:0];
}
@end