Clear cached data in tree when changing properties on root svg element.

Fixes staleness issues when changing width and height.
This commit is contained in:
Mikael Sand
2018-09-13 00:04:43 +03:00
parent c0f51d81a8
commit 7e42a99cf3
8 changed files with 110 additions and 64 deletions
@@ -53,58 +53,82 @@ public class SvgViewShadowNode extends LayoutShadowNode {
private int mMeetOrSlice; private int mMeetOrSlice;
private Matrix mInvViewBoxMatrix = new Matrix(); private Matrix mInvViewBoxMatrix = new Matrix();
private boolean mInvertible = true; private boolean mInvertible = true;
private boolean mRendered = false;
public SvgViewShadowNode() { public SvgViewShadowNode() {
mScale = DisplayMetricsHolder.getScreenDisplayMetrics().density; mScale = DisplayMetricsHolder.getScreenDisplayMetrics().density;
} }
private void releaseCachedPath() {
if (!mRendered) {
return;
}
mRendered = false;
traverseChildren(new VirtualNode.NodeRunnable() {
public void run(ReactShadowNode node) {
if (node instanceof VirtualNode) {
VirtualNode n = ((VirtualNode)node);
n.releaseCachedPath();
}
}
});
}
@ReactProp(name = "minX") @ReactProp(name = "minX")
public void setMinX(float minX) { public void setMinX(float minX) {
mMinX = minX; mMinX = minX;
markUpdated(); markUpdated();
releaseCachedPath();
} }
@ReactProp(name = "minY") @ReactProp(name = "minY")
public void setMinY(float minY) { public void setMinY(float minY) {
mMinY = minY; mMinY = minY;
markUpdated(); markUpdated();
releaseCachedPath();
} }
@ReactProp(name = "vbWidth") @ReactProp(name = "vbWidth")
public void setVbWidth(float vbWidth) { public void setVbWidth(float vbWidth) {
mVbWidth = vbWidth; mVbWidth = vbWidth;
markUpdated(); markUpdated();
releaseCachedPath();
} }
@ReactProp(name = "vbHeight") @ReactProp(name = "vbHeight")
public void setVbHeight(float vbHeight) { public void setVbHeight(float vbHeight) {
mVbHeight = vbHeight; mVbHeight = vbHeight;
markUpdated(); markUpdated();
releaseCachedPath();
} }
@ReactProp(name = "bbWidth") @ReactProp(name = "bbWidth")
public void setVbWidth(String bbWidth) { public void setVbWidth(String bbWidth) {
mbbWidth = bbWidth; mbbWidth = bbWidth;
markUpdated(); markUpdated();
releaseCachedPath();
} }
@ReactProp(name = "bbHeight") @ReactProp(name = "bbHeight")
public void setVbHeight(String bbHeight) { public void setVbHeight(String bbHeight) {
mbbHeight = bbHeight; mbbHeight = bbHeight;
markUpdated(); markUpdated();
releaseCachedPath();
} }
@ReactProp(name = "align") @ReactProp(name = "align")
public void setAlign(String align) { public void setAlign(String align) {
mAlign = align; mAlign = align;
markUpdated(); markUpdated();
releaseCachedPath();
} }
@ReactProp(name = "meetOrSlice") @ReactProp(name = "meetOrSlice")
public void setMeetOrSlice(int meetOrSlice) { public void setMeetOrSlice(int meetOrSlice) {
mMeetOrSlice = meetOrSlice; mMeetOrSlice = meetOrSlice;
markUpdated(); markUpdated();
releaseCachedPath();
} }
@Override @Override
@@ -130,6 +154,7 @@ public class SvgViewShadowNode extends LayoutShadowNode {
} }
Bitmap drawOutput() { Bitmap drawOutput() {
mRendered = true;
float width = getLayoutWidth(); float width = getLayoutWidth();
float height = getLayoutHeight(); float height = getLayoutHeight();
boolean early = Float.isNaN(width) || Float.isNaN(height) || width * height == 0 || (Math.log10(width) + Math.log10(height) > 42); boolean early = Float.isNaN(width) || Float.isNaN(height) || width * height == 0 || (Math.log10(width) + Math.log10(height) > 42);
@@ -185,16 +185,6 @@ class TextShadowNode extends GroupShadowNode {
return mBaselineShift; return mBaselineShift;
} }
void releaseCachedPath() {
traverseChildren(new NodeRunnable() {
public void run(ReactShadowNode node) {
if (node instanceof TextShadowNode) {
((TextShadowNode)node).releaseCachedPath();
}
}
});
}
Path getGroupPath(Canvas canvas, Paint paint) { Path getGroupPath(Canvas canvas, Paint paint) {
pushGlyphContext(); pushGlyphContext();
Path groupPath = super.getPath(canvas, paint); Path groupPath = super.getPath(canvas, paint);
@@ -56,7 +56,7 @@ abstract class VirtualNode extends LayoutShadowNode {
Matrix mMatrix = new Matrix(); Matrix mMatrix = new Matrix();
Matrix mInvMatrix = new Matrix(); Matrix mInvMatrix = new Matrix();
boolean mInvertible = true; boolean mInvertible = true;
RectF mClientRect; private RectF mClientRect;
private int mClipRule; private int mClipRule;
private @Nullable String mClipPath; private @Nullable String mClipPath;
@@ -99,6 +99,10 @@ abstract class VirtualNode extends LayoutShadowNode {
@Override @Override
public void markUpdated() { public void markUpdated() {
super.markUpdated(); super.markUpdated();
clearPath();
}
private void clearPath() {
canvasHeight = -1; canvasHeight = -1;
canvasWidth = -1; canvasWidth = -1;
mRegion = null; mRegion = null;
@@ -106,6 +110,17 @@ abstract class VirtualNode extends LayoutShadowNode {
mBox = null; mBox = null;
} }
void releaseCachedPath() {
clearPath();
traverseChildren(new NodeRunnable() {
public void run(ReactShadowNode node) {
if (node instanceof VirtualNode) {
((VirtualNode)node).releaseCachedPath();
}
}
});
}
@Nullable @Nullable
GroupShadowNode getTextRoot() { GroupShadowNode getTextRoot() {
VirtualNode node = this; VirtualNode node = this;
@@ -156,7 +171,7 @@ abstract class VirtualNode extends LayoutShadowNode {
public abstract void draw(Canvas canvas, Paint paint, float opacity); public abstract void draw(Canvas canvas, Paint paint, float opacity);
public void render(Canvas canvas, Paint paint, float opacity) { public void render(Canvas canvas, Paint paint, float opacity) {
draw(canvas, paint, opacity); draw(canvas, paint, opacity);
}; }
/** /**
* Sets up the transform matrix on the canvas before an element is drawn. * Sets up the transform matrix on the canvas before an element is drawn.
+33 -8
View File
@@ -19,16 +19,18 @@
NSMutableDictionary<NSString *, RNSVGNode *> *_masks; NSMutableDictionary<NSString *, RNSVGNode *> *_masks;
CGAffineTransform _viewBoxTransform; CGAffineTransform _viewBoxTransform;
CGAffineTransform _invviewBoxTransform; CGAffineTransform _invviewBoxTransform;
bool rendered;
} }
- (instancetype)initWithFrame:(CGRect)frame - (instancetype)initWithFrame:(CGRect)frame
{ {
if (self = [super initWithFrame:frame]) { if (self = [super initWithFrame:frame]) {
// This is necessary to ensure that [self setNeedsDisplay] actually triggers // This is necessary to ensure that [self setNeedsDisplay] actually triggers
// a redraw when our parent transitions between hidden and visible. // a redraw when our parent transitions between hidden and visible.
self.contentMode = UIViewContentModeRedraw; self.contentMode = UIViewContentModeRedraw;
} }
return self; rendered = false;
return self;
} }
- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex - (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex
@@ -49,6 +51,20 @@
// Do nothing, as subviews are inserted by insertReactSubview: // Do nothing, as subviews are inserted by insertReactSubview:
} }
- (void)releaseCachedPath
{
if (!rendered) {
return;
}
rendered = false;
for (UIView *node in self.subviews) {
if ([node isKindOfClass:[RNSVGNode class]]) {
RNSVGNode *n = (RNSVGNode *)node;
[n releaseCachedPath];
}
};
}
- (void)invalidate - (void)invalidate
{ {
[self setNeedsDisplay]; [self setNeedsDisplay];
@@ -61,6 +77,7 @@
} }
[self invalidate]; [self invalidate];
[self releaseCachedPath];
_minX = minX; _minX = minX;
} }
@@ -71,6 +88,7 @@
} }
[self invalidate]; [self invalidate];
[self releaseCachedPath];
_minY = minY; _minY = minY;
} }
@@ -81,6 +99,7 @@
} }
[self invalidate]; [self invalidate];
[self releaseCachedPath];
_vbWidth = vbWidth; _vbWidth = vbWidth;
} }
@@ -91,26 +110,29 @@
} }
[self invalidate]; [self invalidate];
[self releaseCachedPath];
_vbHeight = vbHeight; _vbHeight = vbHeight;
} }
- (void)setBBWidth:(NSString *)bbWidth - (void)setBbWidth:(NSString *)bbWidth
{ {
if ([bbWidth isEqualToString:_bbWidth]) { if ([bbWidth isEqualToString:_bbWidth]) {
return; return;
} }
[self invalidate]; [self invalidate];
[self releaseCachedPath];
_bbWidth = bbWidth; _bbWidth = bbWidth;
} }
- (void)setBBHeight:(NSString *)bbHeight - (void)setBbHeight:(NSString *)bbHeight
{ {
if ([bbHeight isEqualToString:_bbHeight]) { if ([bbHeight isEqualToString:_bbHeight]) {
return; return;
} }
[self invalidate]; [self invalidate];
[self releaseCachedPath];
_bbHeight = bbHeight; _bbHeight = bbHeight;
} }
@@ -121,6 +143,7 @@
} }
[self invalidate]; [self invalidate];
[self releaseCachedPath];
_align = align; _align = align;
} }
@@ -131,6 +154,7 @@
} }
[self invalidate]; [self invalidate];
[self releaseCachedPath];
_meetOrSlice = meetOrSlice; _meetOrSlice = meetOrSlice;
} }
@@ -160,6 +184,7 @@
- (void)drawRect:(CGRect)rect - (void)drawRect:(CGRect)rect
{ {
rendered = true;
_clipPaths = nil; _clipPaths = nil;
_templates = nil; _templates = nil;
_painters = nil; _painters = nil;
+2 -4
View File
@@ -91,10 +91,6 @@ extern CGFloat const RNSVG_DEFAULT_FONT_SIZE;
- (CGFloat)getContextHeight; - (CGFloat)getContextHeight;
- (CGFloat)getContextLeft;
- (CGFloat)getContextTop;
/** /**
* save element`s reference into svg element. * save element`s reference into svg element.
*/ */
@@ -106,4 +102,6 @@ extern CGFloat const RNSVG_DEFAULT_FONT_SIZE;
- (void)traverseSubviews:(BOOL (^)(__kindof UIView *node))block; - (void)traverseSubviews:(BOOL (^)(__kindof UIView *node))block;
- (void)releaseCachedPath;
@end @end
+27 -27
View File
@@ -58,6 +58,11 @@ CGFloat const RNSVG_DEFAULT_FONT_SIZE = 12;
{ {
id<RNSVGContainer> container = (id<RNSVGContainer>)self.superview; id<RNSVGContainer> container = (id<RNSVGContainer>)self.superview;
[container invalidate]; [container invalidate];
[self clearPath];
}
- (void)clearPath
{
if (_path) { if (_path) {
CGPathRelease(_path); CGPathRelease(_path);
_path = nil; _path = nil;
@@ -123,7 +128,7 @@ CGFloat const RNSVG_DEFAULT_FONT_SIZE = 12;
if ([name isEqualToString:_name]) { if ([name isEqualToString:_name]) {
return; return;
} }
[self invalidate]; [self invalidate];
_name = name; _name = name;
} }
@@ -338,8 +343,9 @@ CGFloat const RNSVG_DEFAULT_FONT_SIZE = 12;
- (CGFloat)relativeOnOther:(NSString *)length - (CGFloat)relativeOnOther:(NSString *)length
{ {
CGFloat width = [self getContextWidth]; CGRect bounds = [self getContextBounds];
CGFloat height = [self getContextHeight]; CGFloat width = CGRectGetWidth(bounds);
CGFloat height = CGRectGetHeight(bounds);
CGFloat powX = width * width; CGFloat powX = width * width;
CGFloat powY = height * height; CGFloat powY = height * height;
CGFloat r = sqrt(powX + powY) * RNSVG_M_SQRT1_2l; CGFloat r = sqrt(powX + powY) * RNSVG_M_SQRT1_2l;
@@ -350,36 +356,19 @@ CGFloat const RNSVG_DEFAULT_FONT_SIZE = 12;
fontSize:[self getFontSizeFromContext]]; fontSize:[self getFontSizeFromContext]];
} }
- (CGRect)getContextBounds
{
return CGContextGetClipBoundingBox(UIGraphicsGetCurrentContext());
}
- (CGFloat)getContextWidth - (CGFloat)getContextWidth
{ {
RNSVGGroup * root = self.textRoot; return CGRectGetWidth([self getContextBounds]);
RNSVGGlyphContext * gc = [root getGlyphContext];
if (root == nil || gc == nil) {
return CGRectGetWidth([self.svgView getContextBounds]);
} else {
return [gc getWidth];
}
} }
- (CGFloat)getContextHeight - (CGFloat)getContextHeight
{ {
RNSVGGroup * root = self.textRoot; return CGRectGetHeight([self getContextBounds]);
RNSVGGlyphContext * gc = [root getGlyphContext];
if (root == nil || gc == nil) {
return CGRectGetHeight([self.svgView getContextBounds]);
} else {
return [gc getHeight];
}
}
- (CGFloat)getContextLeft
{
return CGRectGetMinX([self.svgView getContextBounds]);
}
- (CGFloat)getContextTop
{
return CGRectGetMinY([self.svgView getContextBounds]);
} }
- (void)parseReference - (void)parseReference
@@ -399,6 +388,17 @@ CGFloat const RNSVG_DEFAULT_FONT_SIZE = 12;
} }
} }
- (void)releaseCachedPath
{
[self clearPath];
[self traverseSubviews:^BOOL(__kindof RNSVGNode *node) {
if ([node isKindOfClass:[RNSVGNode class]]) {
[node releaseCachedPath];
}
return YES;
}];
}
- (void)dealloc - (void)dealloc
{ {
CGPathRelease(_cachedClipPath); CGPathRelease(_cachedClipPath);
-1
View File
@@ -21,7 +21,6 @@
@property (nonatomic, strong) NSArray<NSString *> *positionY; @property (nonatomic, strong) NSArray<NSString *> *positionY;
@property (nonatomic, strong) NSArray<NSString *> *rotate; @property (nonatomic, strong) NSArray<NSString *> *rotate;
- (void)releaseCachedPath;
- (CGPathRef)getGroupPath:(CGContextRef)context; - (CGPathRef)getGroupPath:(CGContextRef)context;
- (CTFontRef)getFontFromContext; - (CTFontRef)getFontFromContext;
+6 -12
View File
@@ -124,18 +124,12 @@
- (void)setupGlyphContext:(CGContextRef)context - (void)setupGlyphContext:(CGContextRef)context
{ {
_glyphContext = [[RNSVGGlyphContext alloc] initWithScale:1 width:[self getContextWidth] CGRect bounds = CGContextGetClipBoundingBox(context);
height:[self getContextHeight]]; CGSize size = bounds.size;
} _glyphContext = [[RNSVGGlyphContext alloc]
initWithScale:1
// release the cached CGPathRef for RNSVGTSpan width:size.width
- (void)releaseCachedPath height:size.height];
{
[self traverseSubviews:^BOOL(__kindof RNSVGNode *node) {
RNSVGText *text = node;
[text releaseCachedPath];
return YES;
}];
} }
- (CGPathRef)getGroupPath:(CGContextRef)context - (CGPathRef)getGroupPath:(CGContextRef)context