diff --git a/ios/Elements/RNSVGGroup.h b/ios/Elements/RNSVGGroup.h index ff8fac01..163d8477 100644 --- a/ios/Elements/RNSVGGroup.h +++ b/ios/Elements/RNSVGGroup.h @@ -12,10 +12,16 @@ #import "RNSVGCGFCRule.h" #import "RNSVGSvgView.h" #import "RNSVGPath.h" +#import "RNSVGGlyphContext.h" @interface RNSVGGroup : RNSVGPath +@property (nonatomic, strong) NSDictionary *font; + - (void)renderPathTo:(CGContextRef)context; - (void)renderGroupTo:(CGContextRef)context; +- (RNSVGGlyphContext *)getGlyphContext; +- (void)pushGlyphContext; +- (void)popGlyphContext; @end diff --git a/ios/Elements/RNSVGGroup.m b/ios/Elements/RNSVGGroup.m index d60f7696..d881981c 100644 --- a/ios/Elements/RNSVGGroup.m +++ b/ios/Elements/RNSVGGroup.m @@ -9,15 +9,20 @@ #import "RNSVGGroup.h" @implementation RNSVGGroup +{ + RNSVGGlyphContext *_glyphContext; +} - (void)renderLayerTo:(CGContextRef)context { [self clip:context]; + [self setupGlyphContext:context]; [self renderGroupTo:context]; } - (void)renderGroupTo:(CGContextRef)context { + [self pushGlyphContext]; RNSVGSvgView* svg = [self getSvgView]; [self traverseSubviews:^(RNSVGNode *node) { if (node.responsible && !svg.responsible) { @@ -36,6 +41,28 @@ return YES; }]; + [self popGlyphContext]; +} + +- (void)setupGlyphContext:(CGContextRef)context +{ + _glyphContext = [[RNSVGGlyphContext alloc] initWithDimensions:[self getContextWidth] + height:[self getContextHeight]]; +} + +- (RNSVGGlyphContext *)getGlyphContext +{ + return _glyphContext; +} + +- (void)pushGlyphContext +{ + [[[self getTextRoot] getGlyphContext] pushContext:self.font]; +} + +- (void)popGlyphContext +{ + [[[self getTextRoot] getGlyphContext] popContext]; } - (void)renderPathTo:(CGContextRef)context diff --git a/ios/RNSVGNode.h b/ios/RNSVGNode.h index ef0eb336..fdae8169 100644 --- a/ios/RNSVGNode.h +++ b/ios/RNSVGNode.h @@ -9,6 +9,7 @@ #import #import "RNSVGCGFCRule.h" #import "RNSVGSvgView.h" +@class RNSVGGroup; /** * RNSVG nodes are implemented as base UIViews. They should be implementation for all basic @@ -17,6 +18,14 @@ @interface RNSVGNode : UIView +/* + N[1/Sqrt[2], 36] + The inverse of the square root of 2. + Provide enough digits for the 128-bit IEEE quad (36 significant digits). + */ +extern CGFloat const M_SQRT1_2l; +extern CGFloat const DEFAULT_FONT_SIZE; + @property (nonatomic, strong) NSString *name; @property (nonatomic, assign) CGFloat opacity; @property (nonatomic, assign) RNSVGCGFCRule clipRule; @@ -27,6 +36,9 @@ - (void)invalidate; +- (RNSVGGroup *)getTextRoot; +- (RNSVGGroup *)getParentTextRoot; + - (void)renderTo:(CGContextRef)context; /** @@ -70,6 +82,10 @@ - (CGFloat)relativeOnHeight:(NSString *)length; +- (CGFloat)relativeOnOther:(NSString *)length; + +- (CGFloat)getFontSizeFromContext; + - (CGFloat)getContextWidth; - (CGFloat)getContextHeight; diff --git a/ios/RNSVGNode.m b/ios/RNSVGNode.m index 8371edd2..09ef0e3a 100644 --- a/ios/RNSVGNode.m +++ b/ios/RNSVGNode.m @@ -9,14 +9,21 @@ #import "RNSVGNode.h" #import "RNSVGContainer.h" #import "RNSVGClipPath.h" +#import "RNSVGGroup.h" +#import "RNSVGGlyphContext.h" @implementation RNSVGNode { + RNSVGGroup *_textRoot; + RNSVGGlyphContext *glyphContext; BOOL _transparent; CGPathRef _cachedClipPath; RNSVGSvgView *_svgView; } +CGFloat const M_SQRT1_2l = 0.707106781186547524400844362104849039; +CGFloat const DEFAULT_FONT_SIZE = 12; + - (instancetype)init { if (self = [super init]) { @@ -49,6 +56,53 @@ [container invalidate]; } +- (RNSVGGroup *)getTextRoot +{ + RNSVGNode* node = self; + if (_textRoot == nil) { + while (node != nil) { + if ([node isKindOfClass:[RNSVGGroup class]] && [((RNSVGGroup*) node) getGlyphContext] != nil) { + _textRoot = (RNSVGGroup*)node; + break; + } + + UIView* parent = [node superview]; + + if (![node isKindOfClass:[RNSVGNode class]]) { + node = nil; + } else { + node = (RNSVGNode*)parent; + } + } + } + + return _textRoot; +} + +- (RNSVGGroup *)getParentTextRoot +{ + RNSVGNode* parent = (RNSVGGroup*)[self superview]; + if (![parent isKindOfClass:[RNSVGGroup class]]) { + return nil; + } else { + return [parent getTextRoot]; + } +} + +- (CGFloat)getFontSizeFromContext +{ + RNSVGGroup* root = [self getTextRoot]; + if (root == nil) { + return DEFAULT_FONT_SIZE; + } + + if (glyphContext == nil) { + glyphContext = [root getGlyphContext]; + } + + return [glyphContext getFontSize]; +} + - (void)reactSetInheritedBackgroundColor:(UIColor *)inheritedBackgroundColor { self.backgroundColor = inheritedBackgroundColor; @@ -194,6 +248,15 @@ return [RNSVGPercentageConverter stringToFloat:length relative:[self getContextHeight] offset:0]; } +- (CGFloat)relativeOnOther:(NSString *)length +{ + CGFloat width = [self getContextWidth]; + CGFloat height = [self getContextHeight]; + CGFloat powX = width * width; + CGFloat powY = height * height; + CGFloat r = sqrt(powX + powY) * M_SQRT1_2l; + return [RNSVGPercentageConverter stringToFloat:length relative:r offset:0];} + - (CGFloat)getContextWidth { return CGRectGetWidth([[self getSvgView] getContextBounds]); diff --git a/ios/Text/RNSVGGlyphContext.h b/ios/Text/RNSVGGlyphContext.h index 8fc03bc4..96cbc686 100644 --- a/ios/Text/RNSVGGlyphContext.h +++ b/ios/Text/RNSVGGlyphContext.h @@ -13,6 +13,9 @@ @interface RNSVGGlyphContext : NSObject - (instancetype)initWithDimensions:(CGFloat)width height:(CGFloat)height; + +- (CGFloat)getFontSize; +- (void)pushContext:(NSDictionary *)font; - (void)pushContext:(NSDictionary *)font deltaX:(NSArray *)deltaX deltaY:(NSArray *)deltaY positionX:(NSArray *)positionX positionY:(NSArray *)positionY; - (void)popContext; - (CTFontRef)getGlyphFont; diff --git a/ios/Text/RNSVGGlyphContext.m b/ios/Text/RNSVGGlyphContext.m index 06dbe2a7..7f093f8f 100644 --- a/ios/Text/RNSVGGlyphContext.m +++ b/ios/Text/RNSVGGlyphContext.m @@ -10,6 +10,7 @@ #import "RNSVGGlyphContext.h" #import "RNSVGPercentageConverter.h" #import +#import "RNSVGNode.h" @implementation RNSVGGlyphContext { @@ -21,6 +22,7 @@ CGPoint _currentLocation; CGFloat _width; CGFloat _height; + CGFloat _fontSize; } - (instancetype)initWithDimensions:(CGFloat)width height:(CGFloat)height @@ -34,10 +36,26 @@ _deltaYContext = [[NSMutableArray alloc] init]; _xContext = [[NSMutableArray alloc] init]; _currentLocation = CGPointZero; + _fontSize = DEFAULT_FONT_SIZE; } return self; } +- (CGFloat) getFontSize +{ + return _fontSize; +} + +- (void)pushContext:(NSDictionary *)font +{ + CGPoint location = _currentLocation; + + [_locationContext addObject:[NSValue valueWithCGPoint:location]]; + [_fontContext addObject:font ? font : @{}]; + [_xContext addObject:[NSNumber numberWithFloat:location.x]]; + _currentLocation = location; +} + - (void)pushContext:(NSDictionary *)font deltaX:(NSArray *)deltaX deltaY:(NSArray *)deltaY positionX:(NSArray *)positionX positionY:(NSArray *)positionY { CGPoint location = _currentLocation; diff --git a/ios/Text/RNSVGTSpan.m b/ios/Text/RNSVGTSpan.m index 71903525..af973ee3 100644 --- a/ios/Text/RNSVGTSpan.m +++ b/ios/Text/RNSVGTSpan.m @@ -70,10 +70,17 @@ CTFontRef font = [self getFontFromContext]; // Create a dictionary for this font - CFDictionaryRef attributes = (__bridge CFDictionaryRef)@{ + CFDictionaryRef attributes; + if (font != nil) { + attributes = (__bridge CFDictionaryRef)@{ (NSString *)kCTFontAttributeName: (__bridge id)font, (NSString *)kCTForegroundColorFromContextAttributeName: @YES }; + } else { + attributes = (__bridge CFDictionaryRef)@{ + (NSString *)kCTForegroundColorFromContextAttributeName: @YES + }; + } CFStringRef string = (__bridge CFStringRef)text; CFAttributedStringRef attrString = CFAttributedStringCreate(kCFAllocatorDefault, string, attributes); diff --git a/ios/Text/RNSVGText.h b/ios/Text/RNSVGText.h index b96215e8..aac064a6 100644 --- a/ios/Text/RNSVGText.h +++ b/ios/Text/RNSVGText.h @@ -9,7 +9,6 @@ #import #import "RNSVGGroup.h" #import "RNSVGTextAnchor.h" -#import "RNSVGGlyphContext.h" @interface RNSVGText : RNSVGGroup @@ -18,15 +17,10 @@ @property (nonatomic, strong) NSArray *deltaY; @property (nonatomic, strong) NSArray *positionX; @property (nonatomic, strong) NSArray *positionY; -@property (nonatomic, strong) NSDictionary *font; -- (RNSVGText *)getTextRoot; - (void)releaseCachedPath; - (CGPathRef)getGroupPath:(CGContextRef)context; -- (RNSVGGlyphContext *)getGlyphContext; -- (void)pushGlyphContext; -- (void)popGlyphContext; - (CTFontRef)getFontFromContext; - (CGPoint)getGlyphPointFromContext:(CGPoint)offset glyphWidth:(CGFloat)glyphWidth; diff --git a/ios/Text/RNSVGText.m b/ios/Text/RNSVGText.m index 115cf9ae..27205f6a 100644 --- a/ios/Text/RNSVGText.m +++ b/ios/Text/RNSVGText.m @@ -13,10 +13,6 @@ #import "RNSVGGlyphContext.h" @implementation RNSVGText -{ - RNSVGText *_textRoot; - RNSVGGlyphContext *_glyphContext; -} - (void)setTextAnchor:(RNSVGTextAnchor)textAnchor { @@ -28,7 +24,6 @@ { [self clip:context]; CGContextSaveGState(context); - [self setupGlyphContext:context]; CGPathRef path = [self getGroupPath:context]; CGAffineTransform transform = [self getAlignTransform:path]; @@ -43,12 +38,6 @@ CGPathRelease(transformedPath); } -- (void)setupGlyphContext:(CGContextRef)context -{ - _glyphContext = [[RNSVGGlyphContext alloc] initWithDimensions:[self getContextWidth] - height:[self getContextHeight]]; -} - // release the cached CGPathRef for RNSVGTSpan - (void)releaseCachedPath { @@ -70,7 +59,6 @@ - (CGPathRef)getPath:(CGContextRef)context { - [self setupGlyphContext:context]; CGPathRef groupPath = [self getGroupPath:context]; CGAffineTransform transform = [self getAlignTransform:groupPath]; [self releaseCachedPath]; @@ -117,27 +105,6 @@ return anchor; } -- (RNSVGText *)getTextRoot -{ - if (!_textRoot) { - _textRoot = self; - while (_textRoot && [_textRoot class] != [RNSVGText class]) { - if (![_textRoot isKindOfClass:[RNSVGText class]]) { - //todo: throw exception here - break; - } - _textRoot = (RNSVGText*)[_textRoot superview]; - } - } - - return _textRoot; -} - -- (RNSVGGlyphContext *)getGlyphContext -{ - return _glyphContext; -} - - (void)pushGlyphContext { [[[self getTextRoot] getGlyphContext] pushContext:self.font