[iOS] Cache node/group paths. Simpler memory handling, needs testing.

This commit is contained in:
Mikael Sand
2019-01-12 21:28:46 +02:00
parent d52b1ade6d
commit a25f05da47
8 changed files with 104 additions and 85 deletions
+7 -1
View File
@@ -122,6 +122,10 @@
- (CGPathRef)getPath:(CGContextRef)context
{
CGPathRef cached = self.path;
if (cached) {
return cached;
}
CGMutablePathRef __block path = CGPathCreateMutable();
[self traverseSubviews:^(RNSVGNode *node) {
if ([node isKindOfClass:[RNSVGNode class]]) {
@@ -131,7 +135,9 @@
return YES;
}];
return (CGPathRef)CFAutorelease(path);
cached = CGPathRetain(path);
self.path = cached;
return cached;
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
+12 -13
View File
@@ -51,18 +51,17 @@
// Do nothing, as subviews are inserted by insertReactSubview:
}
- (void)releaseCachedPath
- (void)clearChildCache
{
if (!rendered) {
return;
}
rendered = false;
for (UIView *node in self.subviews) {
for (__kindof RNSVGNode *node in self.subviews) {
if ([node isKindOfClass:[RNSVGNode class]]) {
RNSVGNode *n = (RNSVGNode *)node;
[n releaseCachedPath];
[node clearChildCache];
}
};
}
}
- (void)invalidate
@@ -77,7 +76,7 @@
}
[self invalidate];
[self releaseCachedPath];
[self clearChildCache];
_minX = minX;
}
@@ -88,7 +87,7 @@
}
[self invalidate];
[self releaseCachedPath];
[self clearChildCache];
_minY = minY;
}
@@ -99,7 +98,7 @@
}
[self invalidate];
[self releaseCachedPath];
[self clearChildCache];
_vbWidth = vbWidth;
}
@@ -110,7 +109,7 @@
}
[self invalidate];
[self releaseCachedPath];
[self clearChildCache];
_vbHeight = vbHeight;
}
@@ -121,7 +120,7 @@
}
[self invalidate];
[self releaseCachedPath];
[self clearChildCache];
_bbWidth = bbWidth;
}
@@ -132,7 +131,7 @@
}
[self invalidate];
[self releaseCachedPath];
[self clearChildCache];
_bbHeight = bbHeight;
}
@@ -143,7 +142,7 @@
}
[self invalidate];
[self releaseCachedPath];
[self clearChildCache];
_align = align;
}
@@ -154,7 +153,7 @@
}
[self invalidate];
[self releaseCachedPath];
[self clearChildCache];
_meetOrSlice = meetOrSlice;
}
+1
View File
@@ -74,6 +74,7 @@
- (void)renderTo:(CGContextRef)context rect:(CGRect)rect
{
self.dirty = false;
// Do not render Symbol
}
+3 -1
View File
@@ -37,6 +37,8 @@ extern CGFloat const RNSVG_DEFAULT_FONT_SIZE;
@property (nonatomic, assign) CGAffineTransform invmatrix;
@property (nonatomic, assign) CGAffineTransform invTransform;
@property (nonatomic, assign) BOOL active;
@property (nonatomic, assign) BOOL dirty;
@property (nonatomic, assign) BOOL merging;
@property (nonatomic, assign) CGPathRef path;
@property (nonatomic, assign) CGRect clientRect;
@property (nonatomic, copy) RCTDirectEventBlock onLayout;
@@ -112,6 +114,6 @@ extern CGFloat const RNSVG_DEFAULT_FONT_SIZE;
- (void)traverseSubviews:(BOOL (^)(__kindof UIView *node))block;
- (void)releaseCachedPath;
- (void)clearChildCache;
@end
+34 -14
View File
@@ -38,6 +38,8 @@ CGFloat const RNSVG_DEFAULT_FONT_SIZE = 12;
self.opacity = 1;
self.transforms = CGAffineTransformIdentity;
self.invTransform = CGAffineTransformIdentity;
_merging = false;
_dirty = false;
}
return self;
}
@@ -62,6 +64,10 @@ CGFloat const RNSVG_DEFAULT_FONT_SIZE = 12;
- (void)invalidate
{
if (_dirty || _merging) {
return;
}
_dirty = true;
id<RNSVGContainer> container = (id<RNSVGContainer>)self.superview;
[container invalidate];
[self clearPath];
@@ -72,9 +78,33 @@ CGFloat const RNSVG_DEFAULT_FONT_SIZE = 12;
- (void)clearPath
{
if (_path) {
CGPathRelease(_path);
_path = nil;
self.path = nil;
}
- (void)clearChildCache
{
[self clearPath];
for (__kindof RNSVGNode *node in self.subviews) {
if ([node isKindOfClass:[RNSVGNode class]]) {
[node clearChildCache];
}
}
}
- (void)clearParentCache
{
RNSVGNode* node = self;
while (node != nil) {
UIView* parent = [node superview];
if (![parent isKindOfClass:[RNSVGNode class]]) {
return;
}
node = (RNSVGNode*)parent;
if (!node.path) {
return;
}
[node clearPath];
}
}
@@ -239,6 +269,7 @@ CGFloat const RNSVG_DEFAULT_FONT_SIZE = 12;
- (void)renderTo:(CGContextRef)context rect:(CGRect)rect
{
self.dirty = false;
// abstract
}
@@ -511,17 +542,6 @@ 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
{
CGPathRelease(_cachedClipPath);
+28 -10
View File
@@ -19,6 +19,7 @@
NSArray<RNSVGLength *> *_sourceStrokeDashArray;
CGFloat *_strokeDashArrayData;
CGPathRef _strokePath;
CGPathRef _srcHitPath;
CGPathRef _hitArea;
}
@@ -36,7 +37,11 @@
- (void)invalidate
{
_sourceStrokeDashArray = nil;
if (self.dirty || self.merging) {
return;
}
[super invalidate];
self.dirty = true;
}
- (void)setFill:(RNSVGBrush *)fill
@@ -166,6 +171,7 @@ UInt32 saturate(CGFloat value) {
- (void)renderTo:(CGContextRef)context rect:(CGRect)rect
{
self.dirty = false;
// This needs to be painted on a layer before being composited.
CGContextSaveGState(context);
CGContextConcatCTM(context, self.matrix);
@@ -290,12 +296,16 @@ UInt32 saturate(CGFloat value) {
return;
}
if (!self.path) {
self.path = CGPathRetain(CFAutorelease(CGPathCreateCopy([self getPath:context])));
[self setHitArea:self.path];
CGPathRef path = self.path;
if (!path) {
path = [self getPath:context];
if (!self.path) {
self.path = CGPathRetain(path);
}
[self setHitArea:path];
}
const CGRect fillBounds = CGPathGetBoundingBox(self.path);
const CGRect fillBounds = CGPathGetBoundingBox(path);
const CGRect strokeBounds = CGPathGetBoundingBox(_strokePath);
const CGRect pathBounding = CGRectUnion(fillBounds, strokeBounds);
@@ -334,7 +344,7 @@ UInt32 saturate(CGFloat value) {
mode = evenodd ? kCGPathEOFill : kCGPathFill;
} else {
CGContextSaveGState(context);
CGContextAddPath(context, self.path);
CGContextAddPath(context, path);
CGContextClip(context);
[self.fill paint:context
opacity:self.fillOpacity
@@ -365,7 +375,7 @@ UInt32 saturate(CGFloat value) {
}
if (!fillColor) {
CGContextAddPath(context, self.path);
CGContextAddPath(context, path);
CGContextReplacePathWithStrokedPath(context);
CGContextClip(context);
}
@@ -384,12 +394,12 @@ UInt32 saturate(CGFloat value) {
} else if (!strokeColor) {
// draw fill
if (fillColor) {
CGContextAddPath(context, self.path);
CGContextAddPath(context, path);
CGContextDrawPath(context, mode);
}
// draw stroke
CGContextAddPath(context, self.path);
CGContextAddPath(context, path);
CGContextReplacePathWithStrokedPath(context);
CGContextClip(context);
@@ -402,15 +412,19 @@ UInt32 saturate(CGFloat value) {
}
}
CGContextAddPath(context, self.path);
CGContextAddPath(context, path);
CGContextDrawPath(context, mode);
}
- (void)setHitArea:(CGPathRef)path
{
if (_srcHitPath == path) {
return;
}
_srcHitPath = path;
CGPathRelease(_hitArea);
CGPathRelease(_strokePath);
_hitArea = CGPathRetain(CFAutorelease(CGPathCreateCopy(path)));
_hitArea = CGPathCreateCopy(path);
_strokePath = nil;
if (self.stroke && self.strokeWidth) {
// Add stroke to hitArea
@@ -474,6 +488,7 @@ UInt32 saturate(CGFloat value) {
- (void)mergeProperties:(__kindof RNSVGRenderable *)target
{
self.merging = true;
NSArray<NSString *> *targetAttributeList = [target getAttributeList];
if (targetAttributeList.count == 0) {
@@ -493,16 +508,19 @@ UInt32 saturate(CGFloat value) {
_lastMergedList = targetAttributeList;
_attributeList = [attributeList copy];
self.merging = false;
}
- (void)resetProperties
{
self.merging = true;
for (NSString *key in _lastMergedList) {
[self setValue:[_originProperties valueForKey:key] forKey:key];
}
_lastMergedList = nil;
_attributeList = _propList;
self.merging = false;
}
@end
+5 -17
View File
@@ -17,7 +17,6 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI;
@implementation RNSVGTSpan
{
CGFloat startOffset;
CGPathRef _cache;
CGFloat _pathLength;
RNSVGTextPath *textPath;
NSArray *lengths;
@@ -56,22 +55,11 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI;
}
}
- (void)releaseCachedPath
{
CGPathRelease(_cache);
_cache = nil;
self.path = nil;
}
- (void)dealloc
{
CGPathRelease(_cache);
}
- (CGPathRef)getPath:(CGContextRef)context
{
if (_cache) {
return _cache;
CGPathRef path = self.path;
if (path) {
return path;
}
NSString *text = self.content;
@@ -83,9 +71,9 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI;
[self pushGlyphContext];
CGPathRef path = [self getLinePath:text context:context];
path = [self getLinePath:text context:context];
_cache = CGPathRetain(CFAutorelease(CGPathCreateCopy(path)));
self.path = CGPathRetain(path);
[self popGlyphContext];
+14 -29
View File
@@ -18,30 +18,15 @@
RNSVGGlyphContext *_glyphContext;
NSString *_alignmentBaseline;
NSString *_baselineShift;
BOOL _merging;
}
- (void)invalidate
{
if (_merging) {
if (self.dirty || self.merging) {
return;
}
[super invalidate];
[self releaseCachedPath];
}
- (void)mergeProperties:(__kindof RNSVGRenderable *)target
{
_merging = true;
[super mergeProperties:target];
_merging = false;
}
- (void)resetProperties
{
_merging = true;
[super resetProperties];
_merging = false;
[self clearChildCache];
}
- (void)setTextLength:(RNSVGLength *)textLength
@@ -130,14 +115,8 @@
[self clip:context];
CGContextSaveGState(context);
[self setupGlyphContext:context];
CGPathRef path = [self getGroupPath:context];
[self renderGroupTo:context rect:rect];
CGContextRestoreGState(context);
CGPathRef transformedPath = CGPathCreateCopy(path);
[self setHitArea:transformedPath];
CGPathRelease(transformedPath);
}
- (void)setupGlyphContext:(CGContextRef)context
@@ -150,19 +129,25 @@
- (CGPathRef)getGroupPath:(CGContextRef)context
{
CGPathRef path = self.path;
if (path) {
return path;
}
[self pushGlyphContext];
CGPathRef groupPath = [super getPath:context];
path = [super getPath:context];
[self popGlyphContext];
return groupPath;
self.path = path;
return path;
}
- (CGPathRef)getPath:(CGContextRef)context
{
CGPathRef path = self.path;
if (path) {
return path;
}
[self setupGlyphContext:context];
CGPathRef groupPath = [self getGroupPath:context];
return (CGPathRef)CFAutorelease(CGPathCreateCopy(groupPath));
return [self getGroupPath:context];
}
- (void)renderGroupTo:(CGContextRef)context rect:(CGRect)rect