From 04887af278c49a0fa3b7956d2992fb2e71efd279 Mon Sep 17 00:00:00 2001 From: Mikael Sand Date: Tue, 29 Aug 2017 02:34:56 +0300 Subject: [PATCH] Implement kerning, ligatures, etc., and cleanup; in ios. Implement hasGlyph ligature helper. Export view property setters for: text: textLength, baselineShift, lengthAdjust, alignmentBaseline, textPath: side, method, midLine, spacing. Attempt to fix alignmentBaseline and baselineShift, but both properties are nil at all times, I must be missing something. --- ios/Elements/RNSVGGroup.h | 2 - ios/Elements/RNSVGGroup.m | 10 - ios/RNSVG.xcodeproj/project.pbxproj | 16 - ios/RNSVGNode.m | 2 - ios/Text/RNSVGBezierTransformer.h | 19 - ios/Text/RNSVGBezierTransformer.m | 147 ---- ios/Text/RNSVGGlyphContext.h | 26 - ios/Text/RNSVGGlyphContext.m | 205 ----- ios/Text/RNSVGTSpan.m | 953 ++++++++++++------------ ios/Text/RNSVGText.h | 1 - ios/Text/RNSVGText.m | 21 - ios/Text/RNSVGTextPath.h | 2 - ios/Text/RNSVGTextPath.m | 9 - ios/ViewManagers/RNSVGTextManager.m | 4 + ios/ViewManagers/RNSVGTextPathManager.m | 4 + 15 files changed, 505 insertions(+), 916 deletions(-) delete mode 100644 ios/Text/RNSVGBezierTransformer.h delete mode 100644 ios/Text/RNSVGBezierTransformer.m delete mode 100644 ios/Text/RNSVGGlyphContext.h delete mode 100644 ios/Text/RNSVGGlyphContext.m diff --git a/ios/Elements/RNSVGGroup.h b/ios/Elements/RNSVGGroup.h index 11576f0a..2db11ec4 100644 --- a/ios/Elements/RNSVGGroup.h +++ b/ios/Elements/RNSVGGroup.h @@ -13,7 +13,6 @@ #import "RNSVGSvgView.h" #import "RNSVGPath.h" #import "GlyphContext.h" -#import "RNSVGGlyphContext.h" @interface RNSVGGroup : RNSVGPath @@ -22,7 +21,6 @@ - (void)renderPathTo:(CGContextRef)context; - (void)renderGroupTo:(CGContextRef)context; -- (RNSVGGlyphContext *)getRNSVGGlyphContext; - (GlyphContext *)getGlyphContext; - (void)pushGlyphContext; - (void)popGlyphContext; diff --git a/ios/Elements/RNSVGGroup.m b/ios/Elements/RNSVGGroup.m index 0515048b..ed1649c2 100644 --- a/ios/Elements/RNSVGGroup.m +++ b/ios/Elements/RNSVGGroup.m @@ -11,7 +11,6 @@ @implementation RNSVGGroup { GlyphContext *_glyphContext; - RNSVGGlyphContext *_RNSVGGlyphContext; } - (void)renderLayerTo:(CGContextRef)context @@ -52,17 +51,10 @@ CGFloat width = CGRectGetWidth(clipBounds); CGFloat height = CGRectGetHeight(clipBounds); - _RNSVGGlyphContext = [[RNSVGGlyphContext alloc] initWithDimensions:width - height:height]; _glyphContext = [[GlyphContext alloc] initWithScale:1 width:width height:height]; } -- (RNSVGGlyphContext *)getRNSVGGlyphContext -{ - return _RNSVGGlyphContext; -} - - (GlyphContext *)getGlyphContext { return _glyphContext; @@ -70,13 +62,11 @@ - (void)pushGlyphContext { - //[[[self getTextRoot] getRNSVGGlyphContext] pushContext:self.font]; [[[self getTextRoot] getGlyphContext] pushContextWithRNSVGGroup:self font:self.font]; } - (void)popGlyphContext { - //[[[self getTextRoot] getRNSVGGlyphContext] popContext]; [[[self getTextRoot] getGlyphContext] popContext]; } diff --git a/ios/RNSVG.xcodeproj/project.pbxproj b/ios/RNSVG.xcodeproj/project.pbxproj index c39b9c65..8157a368 100644 --- a/ios/RNSVG.xcodeproj/project.pbxproj +++ b/ios/RNSVG.xcodeproj/project.pbxproj @@ -14,7 +14,6 @@ 1023B4901D3DF4C40051496D /* RNSVGDefs.m in Sources */ = {isa = PBXBuildFile; fileRef = 1023B48F1D3DF4C40051496D /* RNSVGDefs.m */; }; 1023B4931D3DF5060051496D /* RNSVGUse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1023B4921D3DF5060051496D /* RNSVGUse.m */; }; 1023B4961D3DF57D0051496D /* RNSVGUseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1023B4951D3DF57D0051496D /* RNSVGUseManager.m */; }; - 103371321D41C5C90028AF13 /* RNSVGBezierTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 103371311D41C5C90028AF13 /* RNSVGBezierTransformer.m */; }; 1039D2891CE71EB7001E90A8 /* RNSVGGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2821CE71EB7001E90A8 /* RNSVGGroup.m */; }; 1039D28A1CE71EB7001E90A8 /* RNSVGImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2841CE71EB7001E90A8 /* RNSVGImage.m */; }; 1039D28B1CE71EB7001E90A8 /* RNSVGPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2861CE71EB7001E90A8 /* RNSVGPath.m */; }; @@ -54,7 +53,6 @@ 7FC260CE1E3499BC00A39833 /* RNSVGViewBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FC260CD1E3499BC00A39833 /* RNSVGViewBox.m */; }; 7FC260D11E34A12000A39833 /* RNSVGSymbol.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FC260D01E34A12000A39833 /* RNSVGSymbol.m */; }; 7FC260D41E34A12A00A39833 /* RNSVGSymbolManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FC260D31E34A12A00A39833 /* RNSVGSymbolManager.m */; }; - 7FFC4EA41E24E5AD00AD5BE5 /* RNSVGGlyphContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FFC4EA31E24E5AD00AD5BE5 /* RNSVGGlyphContext.m */; }; 945A8AE11F4CBFD1004BBF6B /* Drawing-Text.m in Sources */ = {isa = PBXBuildFile; fileRef = 945A8ADF1F4CBFD1004BBF6B /* Drawing-Text.m */; }; 945A8AE21F4CBFD1004BBF6B /* UIBezierPath+Text.m in Sources */ = {isa = PBXBuildFile; fileRef = 945A8AE01F4CBFD1004BBF6B /* UIBezierPath+Text.m */; }; 945A8AE41F4CC01D004BBF6B /* UIBezierPath+Elements.m in Sources */ = {isa = PBXBuildFile; fileRef = 945A8AE31F4CC01D004BBF6B /* UIBezierPath+Elements.m */; }; @@ -108,7 +106,6 @@ A361E7711EB0C33D00646005 /* RNSVGCircleManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D1D1CE74E3100887C2B /* RNSVGCircleManager.m */; }; A361E7721EB0C33D00646005 /* RNSVGLinearGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BEC1B91D3F66F500FDCB19 /* RNSVGLinearGradient.m */; }; A361E7731EB0C33D00646005 /* RNSVGPercentageConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2AF1CE72F27001E90A8 /* RNSVGPercentageConverter.m */; }; - A361E7741EB0C33D00646005 /* RNSVGGlyphContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FFC4EA31E24E5AD00AD5BE5 /* RNSVGGlyphContext.m */; }; A361E7751EB0C33D00646005 /* RNSVGEllipse.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D431CE74E3D00887C2B /* RNSVGEllipse.m */; }; A361E7761EB0C33D00646005 /* RNSVGPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2861CE71EB7001E90A8 /* RNSVGPath.m */; }; A361E7771EB0C33D00646005 /* RNSVGTextPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F08CE9D1E23479700650F83 /* RNSVGTextPath.m */; }; @@ -125,7 +122,6 @@ A361E7821EB0C33D00646005 /* RNSVGSvgViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D311CE74E3100887C2B /* RNSVGSvgViewManager.m */; }; A361E7831EB0C33D00646005 /* RNSVGSolidColorBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF41AF0549300FF9E5C /* RNSVGSolidColorBrush.m */; }; A361E7841EB0C33D00646005 /* RNSVGPathManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D291CE74E3100887C2B /* RNSVGPathManager.m */; }; - A361E7851EB0C33D00646005 /* RNSVGBezierTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 103371311D41C5C90028AF13 /* RNSVGBezierTransformer.m */; }; A361E7861EB0C33D00646005 /* RNSVGRenderableManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D2D1CE74E3100887C2B /* RNSVGRenderableManager.m */; }; A361E7871EB0C33D00646005 /* RNSVGRadialGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BEC1BB1D3F66F500FDCB19 /* RNSVGRadialGradient.m */; }; A361E7881EB0C33D00646005 /* RNSVGRadialGradientManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BEC1C11D3F680F00FDCB19 /* RNSVGRadialGradientManager.m */; }; @@ -206,8 +202,6 @@ 1023B4921D3DF5060051496D /* RNSVGUse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGUse.m; path = Elements/RNSVGUse.m; sourceTree = ""; }; 1023B4941D3DF57D0051496D /* RNSVGUseManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGUseManager.h; sourceTree = ""; }; 1023B4951D3DF57D0051496D /* RNSVGUseManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGUseManager.m; sourceTree = ""; }; - 103371311D41C5C90028AF13 /* RNSVGBezierTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGBezierTransformer.m; path = Text/RNSVGBezierTransformer.m; sourceTree = ""; }; - 103371331D41D3400028AF13 /* RNSVGBezierTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGBezierTransformer.h; path = Text/RNSVGBezierTransformer.h; sourceTree = ""; }; 1039D2811CE71EB7001E90A8 /* RNSVGGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGGroup.h; path = Elements/RNSVGGroup.h; sourceTree = ""; }; 1039D2821CE71EB7001E90A8 /* RNSVGGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGGroup.m; path = Elements/RNSVGGroup.m; sourceTree = ""; }; 1039D2831CE71EB7001E90A8 /* RNSVGImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGImage.h; path = Elements/RNSVGImage.h; sourceTree = ""; }; @@ -293,8 +287,6 @@ 7FC260D01E34A12000A39833 /* RNSVGSymbol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGSymbol.m; path = Elements/RNSVGSymbol.m; sourceTree = ""; }; 7FC260D21E34A12A00A39833 /* RNSVGSymbolManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGSymbolManager.h; sourceTree = ""; }; 7FC260D31E34A12A00A39833 /* RNSVGSymbolManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGSymbolManager.m; sourceTree = ""; }; - 7FFC4EA21E24E52500AD5BE5 /* RNSVGGlyphContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNSVGGlyphContext.h; path = Text/RNSVGGlyphContext.h; sourceTree = ""; }; - 7FFC4EA31E24E5AD00AD5BE5 /* RNSVGGlyphContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGGlyphContext.m; path = Text/RNSVGGlyphContext.m; sourceTree = ""; }; 945A8ADD1F4CB7F9004BBF6B /* QuartzBookPack */ = {isa = PBXFileReference; lastKnownFileType = folder; path = QuartzBookPack; sourceTree = ""; }; 945A8ADF1F4CBFD1004BBF6B /* Drawing-Text.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "Drawing-Text.m"; path = "QuartzBookPack/TextDrawing/Drawing-Text.m"; sourceTree = ""; }; 945A8AE01F4CBFD1004BBF6B /* UIBezierPath+Text.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "UIBezierPath+Text.m"; path = "QuartzBookPack/TextDrawing/UIBezierPath+Text.m"; sourceTree = ""; }; @@ -506,10 +498,6 @@ 9494C51A1F4B605F00D5BCFD /* GlyphContext.m */, 9494C4EF1F4B5BE700D5BCFD /* PropHelper.h */, 9494C4F01F4B5BE700D5BCFD /* PropHelper.m */, - 103371331D41D3400028AF13 /* RNSVGBezierTransformer.h */, - 103371311D41C5C90028AF13 /* RNSVGBezierTransformer.m */, - 7FFC4EA21E24E52500AD5BE5 /* RNSVGGlyphContext.h */, - 7FFC4EA31E24E5AD00AD5BE5 /* RNSVGGlyphContext.m */, 1039D28F1CE71EC2001E90A8 /* RNSVGText.h */, 1039D2901CE71EC2001E90A8 /* RNSVGText.m */, 7F08CE9C1E23479700650F83 /* RNSVGTextPath.h */, @@ -718,7 +706,6 @@ 10BEC1BC1D3F66F500FDCB19 /* RNSVGLinearGradient.m in Sources */, 9494C5461F4C44DD00D5BCFD /* TextPathSide.m in Sources */, 1039D2B01CE72F27001E90A8 /* RNSVGPercentageConverter.m in Sources */, - 7FFC4EA41E24E5AD00AD5BE5 /* RNSVGGlyphContext.m in Sources */, 9494C53C1F4C44DD00D5BCFD /* TextAnchor.m in Sources */, 10BA0D491CE74E3D00887C2B /* RNSVGEllipse.m in Sources */, 9494C5051F4B5BE800D5BCFD /* FontWeight.m in Sources */, @@ -740,7 +727,6 @@ 10BA0D3E1CE74E3100887C2B /* RNSVGSvgViewManager.m in Sources */, 0CF68B0F1AF0549300FF9E5C /* RNSVGSolidColorBrush.m in Sources */, 10BA0D3A1CE74E3100887C2B /* RNSVGPathManager.m in Sources */, - 103371321D41C5C90028AF13 /* RNSVGBezierTransformer.m in Sources */, 10BA0D3C1CE74E3100887C2B /* RNSVGRenderableManager.m in Sources */, 10BEC1BD1D3F66F500FDCB19 /* RNSVGRadialGradient.m in Sources */, 10BEC1C31D3F680F00FDCB19 /* RNSVGRadialGradientManager.m in Sources */, @@ -786,7 +772,6 @@ A361E7711EB0C33D00646005 /* RNSVGCircleManager.m in Sources */, A361E7721EB0C33D00646005 /* RNSVGLinearGradient.m in Sources */, A361E7731EB0C33D00646005 /* RNSVGPercentageConverter.m in Sources */, - A361E7741EB0C33D00646005 /* RNSVGGlyphContext.m in Sources */, 9494C53F1F4C44DD00D5BCFD /* TextDecoration.m in Sources */, A361E7751EB0C33D00646005 /* RNSVGEllipse.m in Sources */, A361E7761EB0C33D00646005 /* RNSVGPath.m in Sources */, @@ -809,7 +794,6 @@ A361E7831EB0C33D00646005 /* RNSVGSolidColorBrush.m in Sources */, 9494C5391F4C44DD00D5BCFD /* FontStyle.m in Sources */, A361E7841EB0C33D00646005 /* RNSVGPathManager.m in Sources */, - A361E7851EB0C33D00646005 /* RNSVGBezierTransformer.m in Sources */, A361E7861EB0C33D00646005 /* RNSVGRenderableManager.m in Sources */, A361E7871EB0C33D00646005 /* RNSVGRadialGradient.m in Sources */, 945A8AF91F4CE3E8004BBF6B /* AlignmentBaseline.m in Sources */, diff --git a/ios/RNSVGNode.m b/ios/RNSVGNode.m index 6c11764b..a9679be0 100644 --- a/ios/RNSVGNode.m +++ b/ios/RNSVGNode.m @@ -10,14 +10,12 @@ #import "RNSVGContainer.h" #import "RNSVGClipPath.h" #import "RNSVGGroup.h" -#import "RNSVGGlyphContext.h" #import "GlyphContext.h" @implementation RNSVGNode { RNSVGGroup *_textRoot; GlyphContext *glyphContext; - RNSVGGlyphContext *RNSVGGlyphContext; BOOL _transparent; CGPathRef _cachedClipPath; RNSVGSvgView *_svgView; diff --git a/ios/Text/RNSVGBezierTransformer.h b/ios/Text/RNSVGBezierTransformer.h deleted file mode 100644 index f8995577..00000000 --- a/ios/Text/RNSVGBezierTransformer.h +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2015-present, Horcrux. - * All rights reserved. - * - * This source code is licensed under the MIT-style license found in the - * LICENSE file in the root directory of this source tree. - */ - - -#import - -@interface RNSVGBezierTransformer : NSObject - -- (instancetype)initWithBezierCurvesAndStartOffset:(NSArray *)bezierCurves startOffset:(CGFloat)startOffset; -- (CGAffineTransform)getTransformAtDistance:(CGFloat)distance; -- (BOOL)hasReachedEnd; -- (BOOL)hasReachedStart; - -@end diff --git a/ios/Text/RNSVGBezierTransformer.m b/ios/Text/RNSVGBezierTransformer.m deleted file mode 100644 index d8efd142..00000000 --- a/ios/Text/RNSVGBezierTransformer.m +++ /dev/null @@ -1,147 +0,0 @@ -/** - * Copyright (c) 2015-present, Horcrux. - * All rights reserved. - * - * This source code is licensed under the MIT-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -/** - * based on CurvyText by iosptl: https://github.com/iosptl/ios7ptl/blob/master/ch21-Text/CurvyText/CurvyText/CurvyTextView.m - */ - -#import "RNSVGBezierTransformer.h" - -@implementation RNSVGBezierTransformer -{ - NSArray *_bezierCurves; - int _currentBezierIndex; - CGFloat _startOffset; - CGFloat _lastOffset; - CGFloat _lastRecord; - CGFloat _lastDistance; - CGPoint _lastPoint; - CGPoint _P0; - CGPoint _P1; - CGPoint _P2; - CGPoint _P3; - BOOL _reachedEnd; - BOOL _reachedStart; -} - -- (instancetype)initWithBezierCurvesAndStartOffset:(NSArray *)bezierCurves startOffset:(CGFloat)startOffset -{ - if (self = [super init]) { - _bezierCurves = bezierCurves; - _currentBezierIndex = _lastOffset = _lastRecord = _lastDistance = 0; - _startOffset = startOffset; - [self setControlPoints]; - } - return self; -} - -static CGFloat calculateBezier(CGFloat t, CGFloat P0, CGFloat P1, CGFloat P2, CGFloat P3) { - return (1-t)*(1-t)*(1-t)*P0+3*(1-t)*(1-t)*t*P1+3*(1-t)*t*t*P2+t*t*t*P3; -} - -- (CGPoint)pointAtOffset:(CGFloat)t { - CGFloat x = calculateBezier(t, _P0.x, _P1.x, _P2.x, _P3.x); - CGFloat y = calculateBezier(t, _P0.y, _P1.y, _P2.y, _P3.y); - return CGPointMake(x, y); -} - -static CGFloat calculateBezierPrime(CGFloat t, CGFloat P0, CGFloat P1, CGFloat P2, CGFloat P3) { - return -3*(1-t)*(1-t)*P0+(3*(1-t)*(1-t)*P1)-(6*t*(1-t)*P1)-(3*t*t*P2)+(6*t*(1-t)*P2)+3*t*t*P3; -} - -- (CGFloat)angleAtOffset:(CGFloat)t { - CGFloat dx = calculateBezierPrime(t, _P0.x, _P1.x, _P2.x, _P3.x); - CGFloat dy = calculateBezierPrime(t, _P0.y, _P1.y, _P2.y, _P3.y); - return atan2(dy, dx); -} - -static CGFloat calculateDistance(CGPoint a, CGPoint b) { - return hypot(a.x - b.x, a.y - b.y); -} - -// Simplistic routine to find the offset along Bezier that is -// `distance` away from `point`. `offset` is the offset used to -// generate `point`, and saves us the trouble of recalculating it -// This routine just walks forward until it finds a point at least -// `distance` away. Good optimizations here would reduce the number -// of guesses, but this is tricky since if we go too far out, the -// curve might loop back on leading to incorrect results. Tuning -// kStep is good start. -- (CGFloat)offsetAtDistance:(CGFloat)distance - fromPoint:(CGPoint)point - offset:(CGFloat)offset { - - const CGFloat kStep = 0.001; // 0.0001 - 0.001 work well - CGFloat newDistance = 0; - CGFloat newOffset = offset + kStep; - while (newDistance <= distance && newOffset < 1.0) { - newOffset += kStep; - newDistance = calculateDistance(point, [self pointAtOffset:newOffset]); - } - - _lastDistance = newDistance; - return newOffset; -} - -- (void)setControlPoints -{ - NSArray *bezier = [_bezierCurves objectAtIndex:_currentBezierIndex++]; - - // set start point - if (bezier.count == 1) { - _lastPoint = _P0 = [[bezier objectAtIndex:0] CGPointValue]; - [self setControlPoints]; - } else if (bezier.count == 3) { - _P1 = [[bezier objectAtIndex:0] CGPointValue]; - _P2 = [[bezier objectAtIndex:1] CGPointValue]; - _P3 = [[bezier objectAtIndex:2] CGPointValue]; - } -} - - -- (CGAffineTransform)getTransformAtDistance:(CGFloat)distance -{ - distance += _startOffset; - _reachedStart = distance >= 0; - if (_reachedEnd || !_reachedStart) { - return CGAffineTransformIdentity; - } - - CGFloat offset = [self offsetAtDistance:distance - _lastRecord - fromPoint:_lastPoint - offset:_lastOffset]; - - if (offset < 1) { - CGPoint glyphPoint = [self pointAtOffset:offset]; - _lastOffset = offset; - _lastPoint = glyphPoint; - _lastRecord = distance; - return CGAffineTransformRotate(CGAffineTransformMakeTranslation(glyphPoint.x, glyphPoint.y), [self angleAtOffset:offset]); - } else if (_bezierCurves.count == _currentBezierIndex) { - _reachedEnd = YES; - return CGAffineTransformIdentity; - } else { - _lastOffset = 0; - _lastPoint = _P0 = _P3; - _lastRecord += _lastDistance; - [self setControlPoints]; - return [self getTransformAtDistance:distance - _startOffset]; - } -} - -- (BOOL)hasReachedEnd -{ - return _reachedEnd; -} - -- (BOOL)hasReachedStart -{ - return _reachedStart; -} - -@end diff --git a/ios/Text/RNSVGGlyphContext.h b/ios/Text/RNSVGGlyphContext.h deleted file mode 100644 index 8fb0cf3b..00000000 --- a/ios/Text/RNSVGGlyphContext.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2015-present, Horcrux. - * All rights reserved. - * - * This source code is licensed under the MIT-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#import -#import -#import "RNSVGPercentageConverter.h" - -@interface RNSVGGlyphContext : NSObject - -- (instancetype)initWithDimensions:(CGFloat)width height:(CGFloat)height; - -- (CGFloat)getWidth; -- (CGFloat)getHeight; -- (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; -- (CGPoint)getNextGlyphPoint:(CGPoint)offset glyphWidth:(CGFloat)glyphWidth; - -@end diff --git a/ios/Text/RNSVGGlyphContext.m b/ios/Text/RNSVGGlyphContext.m deleted file mode 100644 index b51d8cff..00000000 --- a/ios/Text/RNSVGGlyphContext.m +++ /dev/null @@ -1,205 +0,0 @@ -/** - * Copyright (c) 2015-present, Horcrux. - * All rights reserved. - * - * This source code is licensed under the MIT-style license found in the - * LICENSE file in the root directory of this source tree. - */ - - -#import "RNSVGGlyphContext.h" -#import "RNSVGPercentageConverter.h" -#import -#import "RNSVGNode.h" - -@implementation RNSVGGlyphContext -{ - NSMutableArray *_fontContext; - NSMutableArray *_locationContext; - NSMutableArray *_deltaXContext; - NSMutableArray *_deltaYContext; - NSMutableArray *_xContext; - CGPoint _currentLocation; - CGFloat _width; - CGFloat _height; - CGFloat _fontSize; -} - -- (instancetype)initWithDimensions:(CGFloat)width height:(CGFloat)height -{ - if (self = [super init]) { - _width = width; - _height = height; - _fontContext = [[NSMutableArray alloc] init]; - _locationContext = [[NSMutableArray alloc] init]; - _deltaXContext = [[NSMutableArray alloc] init]; - _deltaYContext = [[NSMutableArray alloc] init]; - _xContext = [[NSMutableArray alloc] init]; - _currentLocation = CGPointZero; - _fontSize = DEFAULT_FONT_SIZE; - } - return self; -} - -- (CGFloat) getWidth -{ - return _width; -} - -- (CGFloat) getHeight { - return _height; -} - -- (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; - - if (positionX) { - location.x = [RNSVGPercentageConverter stringToFloat:[positionX firstObject] relative:_width offset:0]; - } - - if (positionY) { - location.y = [RNSVGPercentageConverter stringToFloat:[positionY firstObject] relative:_height offset:0]; - } - - [_locationContext addObject:[NSValue valueWithCGPoint:location]]; - [_fontContext addObject:font ? font : @{}]; - [_deltaXContext addObject:deltaX ? deltaX : @[]]; - [_deltaYContext addObject:deltaY ? deltaY : @[]]; - [_xContext addObject:[NSNumber numberWithFloat:location.x]]; - _currentLocation = location; -} - -- (void)popContext -{ - NSNumber *x = [_xContext lastObject]; - [_fontContext removeLastObject]; - [_locationContext removeLastObject]; - [_deltaXContext removeLastObject]; - [_deltaYContext removeLastObject]; - [_xContext removeLastObject]; - - if (_xContext.count) { - [_xContext replaceObjectAtIndex:_xContext.count - 1 withObject:x]; - } - - if (_locationContext.count) { - _currentLocation = [[_locationContext lastObject] CGPointValue]; - _currentLocation.x = [x floatValue]; - [_locationContext replaceObjectAtIndex:_locationContext.count - 1 - withObject:[NSValue valueWithCGPoint:_currentLocation]]; - } -} - -- (CGPoint)getNextGlyphPoint:(CGPoint)offset glyphWidth:(CGFloat)glyphWidth -{ - CGPoint currentLocation = _currentLocation; - NSNumber *dx = [self getNextDelta:_deltaXContext]; - currentLocation.x += [dx floatValue]; - - NSNumber *dy = [self getNextDelta:_deltaYContext]; - currentLocation.y += [dy floatValue]; - - for (NSUInteger i = 0; i < _locationContext.count; i++) { - CGPoint point = [[_locationContext objectAtIndex:i] CGPointValue]; - point.x += [dx floatValue]; - point.y += [dy floatValue]; - [_locationContext replaceObjectAtIndex:i withObject:[NSValue valueWithCGPoint:point]]; - } - - _currentLocation = currentLocation; - NSNumber *x = [NSNumber numberWithFloat:currentLocation.x + offset.x + glyphWidth]; - [_xContext replaceObjectAtIndex:_xContext.count - 1 withObject:x]; - return CGPointMake(currentLocation.x + offset.x, currentLocation.y + offset.y); -} - -- (NSNumber *)getNextDelta:(NSMutableArray *)deltaContext -{ - NSNumber *value; - NSUInteger index = deltaContext.count; - for (NSArray *delta in [deltaContext reverseObjectEnumerator]) { - index--; - if (value == nil) { - value = [delta firstObject]; - } - - if (delta.count) { - NSMutableArray *mutableDelta = [delta mutableCopy]; - [mutableDelta removeObjectAtIndex:0]; - [deltaContext replaceObjectAtIndex:index withObject:[mutableDelta copy]]; - } - } - - return value; -} - -- (CTFontRef)getGlyphFont -{ - NSString *fontFamily; - NSNumber *fontSize; - NSString *fontWeight; - NSString *fontStyle; - NSNumberFormatter *f = [[NSNumberFormatter alloc] init]; - f.numberStyle = NSNumberFormatterDecimalStyle; - - for (NSDictionary *font in [_fontContext reverseObjectEnumerator]) { - if (!fontFamily) { - fontFamily = font[@"fontFamily"]; - } - - if (fontSize == nil) { - fontSize = [f numberFromString:font[@"fontSize"]]; - } - - if (!fontWeight) { - fontWeight = font[@"fontWeight"]; - } - if (!fontStyle) { - fontStyle = font[@"fontStyle"]; - } - - if (fontFamily && fontSize && fontWeight && fontStyle) { - break; - } - } - - BOOL fontFamilyFound = NO; - NSArray *supportedFontFamilyNames = [UIFont familyNames]; - - if ([supportedFontFamilyNames containsObject:fontFamily]) { - fontFamilyFound = YES; - } else { - for (NSString *fontFamilyName in supportedFontFamilyNames) { - if ([[UIFont fontNamesForFamilyName: fontFamilyName] containsObject:fontFamily]) { - fontFamilyFound = YES; - break; - } - } - } - fontFamily = fontFamilyFound ? fontFamily : nil; - - return (__bridge CTFontRef)[RCTFont updateFont:nil - withFamily:fontFamily - size:fontSize - weight:fontWeight - style:fontStyle - variant:nil - scaleMultiplier:1.0]; -} - -@end diff --git a/ios/Text/RNSVGTSpan.m b/ios/Text/RNSVGTSpan.m index 6cddf9d7..79b519ae 100644 --- a/ios/Text/RNSVGTSpan.m +++ b/ios/Text/RNSVGTSpan.m @@ -7,7 +7,6 @@ */ #import #import "RNSVGTSpan.h" -#import "RNSVGBezierTransformer.h" #import "RNSVGText.h" #import "RNSVGTextPath.h" #import "UIBezierPath+Text.h" @@ -15,13 +14,13 @@ @implementation RNSVGTSpan { - RNSVGBezierTransformer *_bezierTransformer; CGFloat startOffset; UIBezierPath *_path; CGPathRef _cache; CGFloat pathLength; RNSVGTextPath * textPath; RNSVGPath * textPathPath; + bool isClosed; } - (void)setContent:(NSString *)content @@ -103,6 +102,10 @@ GlyphContext* gc = [[self getTextRoot] getGlyphContext]; FontData* font = [gc getFont]; NSUInteger n = str.length; + bool ligature[n]; + for (int i = 0; i < n; i++){ + ligature[i] = NO; + } /* * * Three properties affect the space between characters and words: @@ -122,7 +125,7 @@ * or decrease the space between typographic character units in order to justify text. * * */ - // TODO double kerning = font->kerning; + double kerning = font->kerning; double wordSpacing = font->wordSpacing; double letterSpacing = font->letterSpacing; bool autoKerning = !font->manualKerning; @@ -174,7 +177,7 @@ user agents should not apply optional ligatures. https://www.w3.org/TR/css-text-3/#letter-spacing-property */ - // TODO bool allowOptionalLigatures = letterSpacing == 0 && font->fontVariantLigatures == FontVariantLigaturesNormal; + bool allowOptionalLigatures = letterSpacing == 0 && font->fontVariantLigatures == FontVariantLigaturesNormal; /* For OpenType fonts, discretionary ligatures include those enabled by @@ -233,437 +236,8 @@ vertical alternates (OpenType feature: vert) must be enabled. */ // OpenType.js font data - // TODO NSDictionary * fontData = font->fontData; + NSDictionary * fontData = font->fontData; - /* - float advances[] = new float[length]; - paint.getTextWidths(line, advances); - */ - - /* - This would give both advances and textMeasure in one call / looping over the text - double textMeasure = paint.getTextRunAdvances(line, 0, length, 0, length, true, advances, 0); - */ - /* - Determine the startpoint-on-the-path for the first glyph using attribute ‘startOffset’ - and property text-anchor. - - For text-anchor:start, startpoint-on-the-path is the point - on the path which represents the point on the path which is ‘startOffset’ distance - along the path from the start of the path, calculated using the user agent's distance - along the path algorithm. - - For text-anchor:middle, startpoint-on-the-path is the point - on the path which represents the point on the path which is [ ‘startOffset’ minus half - of the total advance values for all of the glyphs in the ‘textPath’ element ] distance - along the path from the start of the path, calculated using the user agent's distance - along the path algorithm. - - For text-anchor:end, startpoint-on-the-path is the point on - the path which represents the point on the path which is [ ‘startOffset’ minus the - total advance values for all of the glyphs in the ‘textPath’ element ]. - - Before rendering the first glyph, the horizontal component of the startpoint-on-the-path - is adjusted to take into account various horizontal alignment text properties and - attributes, such as a ‘dx’ attribute value on a ‘tspan’ element. - */ - enum TextAnchor textAnchor = font->textAnchor; - CGRect textBounds = CTLineGetBoundsWithOptions(line, 0); - double textMeasure = CGRectGetWidth(textBounds); - double offset = getTextAnchorOffset(textAnchor, textMeasure); - - bool hasTextPath = _path != nil; - bool isClosed = false; - - int side = 1; - double startOfRendering = 0; - double endOfRendering = pathLength; - double fontSize = [gc getFontSize]; - bool sharpMidLine = false; - if (hasTextPath) { - sharpMidLine = TextPathMidLineFromString([textPath midLine]) == TextPathMidLineSharp; - /* - Name - side - Value - left | right - initial value - left - Animatable - yes - - Determines the side of the path the text is placed on - (relative to the path direction). - - Specifying a value of right effectively reverses the path. - - Added in SVG 2 to allow text either inside or outside closed subpaths - and basic shapes (e.g. rectangles, circles, and ellipses). - - Adding 'side' was resolved at the Sydney (2015) meeting. - */ - side = TextPathSideFromString([textPath side]) == TextPathSideRight ? -1 : 1; - /* - Name - startOffset - Value - | | - initial value - 0 - Animatable - yes - - An offset from the start of the path for the initial current text position, - calculated using the user agent's distance along the path algorithm, - after converting the path to the ‘textPath’ element's coordinate system. - - If a other than a percentage is given, then the ‘startOffset’ - represents a distance along the path measured in the current user coordinate - system for the ‘textPath’ element. - - If a percentage is given, then the ‘startOffset’ represents a percentage - distance along the entire path. Thus, startOffset="0%" indicates the start - point of the path and startOffset="100%" indicates the end point of the path. - - Negative values and values larger than the path length (e.g. 150%) are allowed. - - Any typographic characters with mid-points that are not on the path are not rendered - - For paths consisting of a single closed subpath (including an equivalent path for a - basic shape), typographic characters are rendered along one complete circuit of the - path. The text is aligned as determined by the text-anchor property to a position - along the path set by the ‘startOffset’ attribute. - - For the start (end) value, the text is rendered from the start (end) of the line - until the initial position along the path is reached again. - - For the middle, the text is rendered from the middle point in both directions until - a point on the path equal distance in both directions from the initial position on - the path is reached. - */ - double absoluteStartOffset = [PropHelper fromRelativeWithNSString:textPath.startOffset - relative:pathLength - offset:0 - scale:1 - fontSize:fontSize]; - offset += absoluteStartOffset; - if (isClosed) { - double halfPathDistance = pathLength / 2; - startOfRendering = absoluteStartOffset + (textAnchor == TextAnchorMiddle ? -halfPathDistance : 0); - endOfRendering = startOfRendering + pathLength; - } - /* - TextPathSpacing spacing = textPath.getSpacing(); - if (spacing == TextPathSpacing.auto) { - // Hmm, what to do here? - // https://svgwg.org/svg2-draft/text.html#TextPathElementSpacingAttribute - } - */ - } - - /* - Name - method - Value - align | stretch - initial value - align - Animatable - yes - Indicates the method by which text should be rendered along the path. - - A value of align indicates that the typographic character should be rendered using - simple 2×3 matrix transformations such that there is no stretching/warping of the - typographic characters. Typically, supplemental rotation, scaling and translation - transformations are done for each typographic characters to be rendered. - - As a result, with align, in fonts where the typographic characters are designed to be - connected (e.g., cursive fonts), the connections may not align properly when text is - rendered along a path. - - A value of stretch indicates that the typographic character outlines will be converted - into paths, and then all end points and control points will be adjusted to be along the - perpendicular vectors from the path, thereby stretching and possibly warping the glyphs. - - With this approach, connected typographic characters, such as in cursive scripts, - will maintain their connections. (Non-vertical straight path segments should be - converted to Bézier curves in such a way that horizontal straight paths have an - (approximately) constant offset from the path along which the typographic characters - are rendered.) - - TODO implement stretch - */ - - /* - Name Value Initial value Animatable - textLength | | See below yes - - The author's computation of the total sum of all of the advance values that correspond - to character data within this element, including the advance value on the glyph - (horizontal or vertical), the effect of properties letter-spacing and word-spacing and - adjustments due to attributes ‘dx’ and ‘dy’ on this ‘text’ or ‘tspan’ element or any - descendants. This value is used to calibrate the user agent's own calculations with - that of the author. - - The purpose of this attribute is to allow the author to achieve exact alignment, - in visual rendering order after any bidirectional reordering, for the first and - last rendered glyphs that correspond to this element; thus, for the last rendered - character (in visual rendering order after any bidirectional reordering), - any supplemental inter-character spacing beyond normal glyph advances are ignored - (in most cases) when the user agent determines the appropriate amount to expand/compress - the text string to fit within a length of ‘textLength’. - - If attribute ‘textLength’ is specified on a given element and also specified on an - ancestor, the adjustments on all character data within this element are controlled by - the value of ‘textLength’ on this element exclusively, with the possible side-effect - that the adjustment ratio for the contents of this element might be different than the - adjustment ratio used for other content that shares the same ancestor. The user agent - must assume that the total advance values for the other content within that ancestor is - the difference between the advance value on that ancestor and the advance value for - this element. - - This attribute is not intended for use to obtain effects such as shrinking or - expanding text. - - A negative value is an error (see Error processing). - - The ‘textLength’ attribute is only applied when the wrapping area is not defined by the - TODO shape-inside or the inline-size properties. It is also not applied for any ‘text’ or - TODO ‘tspan’ element that has forced line breaks (due to a white-space value of pre or - pre-line). - - If the attribute is not specified anywhere within a ‘text’ element, the effect is as if - the author's computation exactly matched the value calculated by the user agent; - thus, no advance adjustments are made. - */ - double scaleSpacingAndGlyphs = 1; - NSString *mTextLength = [self textLength]; - enum TextLengthAdjust mLengthAdjust = TextLengthAdjustFromString([self lengthAdjust]); - // TODO canvasWidth - double canvasWidth = 0; - if (mTextLength != nil) { - double author = [PropHelper fromRelativeWithNSString:mTextLength - relative:canvasWidth - offset:0 - scale:1 - fontSize:fontSize]; - if (author < 0) { - NSException *e = [NSException - exceptionWithName:@"NegativeTextLength" - reason:@"Negative textLength value" - userInfo:nil]; - @throw e; - } - switch (mLengthAdjust) { - default: - case TextLengthAdjustSpacing: - letterSpacing += (author - textMeasure) / (n - 1); - break; - case TextLengthAdjustSpacingAndGlyphs: - scaleSpacingAndGlyphs = author / textMeasure; - break; - } - } - double scaledDirection = scaleSpacingAndGlyphs * side; - - /* - https://developer.mozilla.org/en/docs/Web/CSS/vertical-align - https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6bsln.html - https://www.microsoft.com/typography/otspec/base.htm - http://apike.ca/prog_svg_text_style.html - https://www.w3schools.com/tags/canvas_textbaseline.asp - http://vanseodesign.com/web-design/svg-text-baseline-alignment/ - https://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align - https://tympanus.net/codrops/css_reference/vertical-align/ - - https://svgwg.org/svg2-draft/text.html#AlignmentBaselineProperty - 11.10.2.6. The ‘alignment-baseline’ property - - This property is defined in the CSS Line Layout Module 3 specification. See 'alignment-baseline'. [css-inline-3] - https://drafts.csswg.org/css-inline/#propdef-alignment-baseline - - The vertical-align property shorthand should be preferred in new content. - - SVG 2 introduces some changes to the definition of this property. - In particular: the values 'auto', 'before-edge', and 'after-edge' have been removed. - For backwards compatibility, 'text-before-edge' should be mapped to 'text-top' and - 'text-after-edge' should be mapped to 'text-bottom'. - - Neither 'text-before-edge' nor 'text-after-edge' should be used with the vertical-align property. - */ - //Paint.FontMetrics fm = paint.getFontMetrics(); - double top = 0;//-fm.top; - double bottom = 0;//fm.bottom; - double ascenderHeight = 0;//-fm.ascent; - double descenderDepth = 0;//fm.descent; - double totalHeight = top + bottom; - double baselineShift = 0; - NSString *baselineShiftString = [self baselineShift]; - enum AlignmentBaseline baseline = AlignmentBaselineFromString([self alignmentBaseline]); - if (baseline != AlignmentBaselineBaseline) { - // TODO alignment-baseline, test / verify behavior - // TODO get per glyph baselines from font baseline table, for high-precision alignment - switch (baseline) { - // https://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling - default: - case AlignmentBaselineBaseline: - // Use the dominant baseline choice of the parent. - // Match the box’s corresponding baseline to that of its parent. - baselineShift = 0; - break; - - case AlignmentBaselineTextBottom: - case AlignmentBaselineAfterEdge: - case AlignmentBaselineTextAfterEdge: - // Match the bottom of the box to the bottom of the parent’s content area. - // text-after-edge = text-bottom - // text-after-edge = descender depth - baselineShift = -descenderDepth; - break; - - case AlignmentBaselineAlphabetic: - // Match the box’s alphabetic baseline to that of its parent. - // alphabetic = 0 - baselineShift = 0; - break; - - case AlignmentBaselineIdeographic: - // Match the box’s ideographic character face under-side baseline to that of its parent. - // ideographic = descender depth - baselineShift = -descenderDepth; - break; - - case AlignmentBaselineMiddle: - // Align the vertical midpoint of the box with the baseline of the parent box plus half the x-height of the parent. TODO - // middle = x height / 2 - //Rect bounds = new Rect(); - // this will just retrieve the bounding rect for 'x' - //paint.getTextBounds("x", 0, 1, bounds); - //int xHeight = bounds.height(); - //baselineShift = xHeight / 2; - break; - - case AlignmentBaselineCentral: - // Match the box’s central baseline to the central baseline of its parent. - // central = (ascender height - descender depth) / 2 - baselineShift = (ascenderHeight - descenderDepth) / 2; - break; - - case AlignmentBaselineMathematical: - // Match the box’s mathematical baseline to that of its parent. - // Hanging and mathematical baselines - // There are no obvious formulas to calculate the position of these baselines. - // At the time of writing FOP puts the hanging baseline at 80% of the ascender - // height and the mathematical baseline at 50%. - baselineShift = 0.5 * ascenderHeight; - break; - - case AlignmentBaselineHanging: - baselineShift = 0.8 * ascenderHeight; - break; - - case AlignmentBaselineTextTop: - case AlignmentBaselineBeforeEdge: - case AlignmentBaselineTextBeforeEdge: - // Match the top of the box to the top of the parent’s content area. - // text-before-edge = text-top - // text-before-edge = ascender height - baselineShift = ascenderHeight; - break; - - case AlignmentBaselineBottom: - // Align the top of the aligned subtree with the top of the line box. - baselineShift = bottom; - break; - - case AlignmentBaselineCenter: - // Align the center of the aligned subtree with the center of the line box. - baselineShift = totalHeight / 2; - break; - - case AlignmentBaselineTop: - // Align the bottom of the aligned subtree with the bottom of the line box. - baselineShift = top; - break; - } - /* - 2.2.2. Alignment Shift: baseline-shift longhand - - This property specifies by how much the box is shifted up from its alignment point. - It does not apply when alignment-baseline is top or bottom. - - Authors should use the vertical-align shorthand instead of this property. - - Values have the following meanings: - - - Raise (positive value) or lower (negative value) by the specified length. - - Raise (positive value) or lower (negative value) by the specified percentage of the line-height. - TODO sub - Lower by the offset appropriate for subscripts of the parent’s box. - (The UA should use the parent’s font data to find this offset whenever possible.) - TODO super - Raise by the offset appropriate for superscripts of the parent’s box. - (The UA should use the parent’s font data to find this offset whenever possible.) - - User agents may additionally support the keyword baseline as computing to 0 - if is necessary for them to support legacy SVG content. - Issue: We would prefer to remove this, - and are looking for feedback from SVG user agents as to whether it’s necessary. - - https://www.w3.org/TR/css-inline-3/#propdef-baseline-shift - */ - if (baselineShiftString != nil) { - switch (baseline) { - case AlignmentBaselineTop: - case AlignmentBaselineBottom: - break; - - default: - if ([baselineShiftString isEqualToString:@"sub"]) { - // TODO - /* - if (fontData != nil && fontData.hasKey("tables") && fontData.hasKey("unitsPerEm")) { - int unitsPerEm = fontData.getInt("unitsPerEm"); - ReadableMap tables = fontData.getMap("tables"); - if (tables.hasKey("os2")) { - ReadableMap os2 = tables.getMap("os2"); - if (os2.hasKey("ySubscriptYOffset")) { - double subOffset = os2.getDouble("ySubscriptYOffset"); - baselineShift += fontSize * subOffset / unitsPerEm; - } - } - } - */ - } else if ([baselineShiftString isEqualToString:@"super"]) { - // TODO - /* - if (fontData != nil && fontData.hasKey("tables") && fontData.hasKey("unitsPerEm")) { - int unitsPerEm = fontData.getInt("unitsPerEm"); - ReadableMap tables = fontData.getMap("tables"); - if (tables.hasKey("os2")) { - ReadableMap os2 = tables.getMap("os2"); - if (os2.hasKey("ySuperscriptYOffset")) { - double superOffset = os2.getDouble("ySuperscriptYOffset"); - baselineShift -= fontSize * superOffset / unitsPerEm; - } - } - } - */ - } else if ([baselineShiftString isEqualToString:@"baseline"]) { - } else { - baselineShift -= [PropHelper fromRelativeWithNSString:baselineShiftString - relative:fontSize - offset:0 - scale:1 - fontSize:fontSize]; - - } - break; - } - } - } double tau = 2 * M_PI; double radToDeg = 360 / tau; @@ -672,25 +246,441 @@ CTRunRef run = CFArrayGetValueAtIndex(runs, r); CFIndex runGlyphCount = CTRunGetGlyphCount(run); - CGSize glyph_advances[runGlyphCount]; - //CGPoint positions[runGlyphCount]; + CGSize advances[runGlyphCount]; CGGlyph glyphs[runGlyphCount]; - // Grab the glyphs, positions, and font + // Grab the glyphs and font CTRunGetGlyphs(run, CFRangeMake(0, 0), glyphs); - //CTRunGetPositions(run, CFRangeMake(0, 0), positions); CTFontRef runFont = CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName); - CTFontGetAdvancesForGlyphs(runFont, kCTFontOrientationHorizontal, glyphs, glyph_advances, runGlyphCount); + CTFontGetAdvancesForGlyphs(runFont, kCTFontOrientationHorizontal, glyphs, advances, runGlyphCount); + /* + Determine the startpoint-on-the-path for the first glyph using attribute ‘startOffset’ + and property text-anchor. + + For text-anchor:start, startpoint-on-the-path is the point + on the path which represents the point on the path which is ‘startOffset’ distance + along the path from the start of the path, calculated using the user agent's distance + along the path algorithm. + + For text-anchor:middle, startpoint-on-the-path is the point + on the path which represents the point on the path which is [ ‘startOffset’ minus half + of the total advance values for all of the glyphs in the ‘textPath’ element ] distance + along the path from the start of the path, calculated using the user agent's distance + along the path algorithm. + + For text-anchor:end, startpoint-on-the-path is the point on + the path which represents the point on the path which is [ ‘startOffset’ minus the + total advance values for all of the glyphs in the ‘textPath’ element ]. + + Before rendering the first glyph, the horizontal component of the startpoint-on-the-path + is adjusted to take into account various horizontal alignment text properties and + attributes, such as a ‘dx’ attribute value on a ‘tspan’ element. + */ + enum TextAnchor textAnchor = font->textAnchor; + CGRect textBounds = CTLineGetBoundsWithOptions(line, 0); + double textMeasure = CGRectGetWidth(textBounds); + double offset = getTextAnchorOffset(textAnchor, textMeasure); + + bool hasTextPath = _path != nil; + + int side = 1; + double startOfRendering = 0; + double endOfRendering = pathLength; + double fontSize = [gc getFontSize]; + bool sharpMidLine = false; + if (hasTextPath) { + sharpMidLine = TextPathMidLineFromString([textPath midLine]) == TextPathMidLineSharp; + /* + Name + side + Value + left | right + initial value + left + Animatable + yes + + Determines the side of the path the text is placed on + (relative to the path direction). + + Specifying a value of right effectively reverses the path. + + Added in SVG 2 to allow text either inside or outside closed subpaths + and basic shapes (e.g. rectangles, circles, and ellipses). + + Adding 'side' was resolved at the Sydney (2015) meeting. + */ + side = TextPathSideFromString([textPath side]) == TextPathSideRight ? -1 : 1; + /* + Name + startOffset + Value + | | + initial value + 0 + Animatable + yes + + An offset from the start of the path for the initial current text position, + calculated using the user agent's distance along the path algorithm, + after converting the path to the ‘textPath’ element's coordinate system. + + If a other than a percentage is given, then the ‘startOffset’ + represents a distance along the path measured in the current user coordinate + system for the ‘textPath’ element. + + If a percentage is given, then the ‘startOffset’ represents a percentage + distance along the entire path. Thus, startOffset="0%" indicates the start + point of the path and startOffset="100%" indicates the end point of the path. + + Negative values and values larger than the path length (e.g. 150%) are allowed. + + Any typographic characters with mid-points that are not on the path are not rendered + + For paths consisting of a single closed subpath (including an equivalent path for a + basic shape), typographic characters are rendered along one complete circuit of the + path. The text is aligned as determined by the text-anchor property to a position + along the path set by the ‘startOffset’ attribute. + + For the start (end) value, the text is rendered from the start (end) of the line + until the initial position along the path is reached again. + + For the middle, the text is rendered from the middle point in both directions until + a point on the path equal distance in both directions from the initial position on + the path is reached. + */ + double absoluteStartOffset = [PropHelper fromRelativeWithNSString:textPath.startOffset + relative:pathLength + offset:0 + scale:1 + fontSize:fontSize]; + offset += absoluteStartOffset; + if (isClosed) { + double halfPathDistance = pathLength / 2; + startOfRendering = absoluteStartOffset + (textAnchor == TextAnchorMiddle ? -halfPathDistance : 0); + endOfRendering = startOfRendering + pathLength; + } + /* + TextPathSpacing spacing = textPath.getSpacing(); + if (spacing == TextPathSpacing.auto) { + // Hmm, what to do here? + // https://svgwg.org/svg2-draft/text.html#TextPathElementSpacingAttribute + } + */ + } + + /* + Name + method + Value + align | stretch + initial value + align + Animatable + yes + Indicates the method by which text should be rendered along the path. + + A value of align indicates that the typographic character should be rendered using + simple 2×3 matrix transformations such that there is no stretching/warping of the + typographic characters. Typically, supplemental rotation, scaling and translation + transformations are done for each typographic characters to be rendered. + + As a result, with align, in fonts where the typographic characters are designed to be + connected (e.g., cursive fonts), the connections may not align properly when text is + rendered along a path. + + A value of stretch indicates that the typographic character outlines will be converted + into paths, and then all end points and control points will be adjusted to be along the + perpendicular vectors from the path, thereby stretching and possibly warping the glyphs. + + With this approach, connected typographic characters, such as in cursive scripts, + will maintain their connections. (Non-vertical straight path segments should be + converted to Bézier curves in such a way that horizontal straight paths have an + (approximately) constant offset from the path along which the typographic characters + are rendered.) + + TODO implement stretch + */ + + /* + Name Value Initial value Animatable + textLength | | See below yes + + The author's computation of the total sum of all of the advance values that correspond + to character data within this element, including the advance value on the glyph + (horizontal or vertical), the effect of properties letter-spacing and word-spacing and + adjustments due to attributes ‘dx’ and ‘dy’ on this ‘text’ or ‘tspan’ element or any + descendants. This value is used to calibrate the user agent's own calculations with + that of the author. + + The purpose of this attribute is to allow the author to achieve exact alignment, + in visual rendering order after any bidirectional reordering, for the first and + last rendered glyphs that correspond to this element; thus, for the last rendered + character (in visual rendering order after any bidirectional reordering), + any supplemental inter-character spacing beyond normal glyph advances are ignored + (in most cases) when the user agent determines the appropriate amount to expand/compress + the text string to fit within a length of ‘textLength’. + + If attribute ‘textLength’ is specified on a given element and also specified on an + ancestor, the adjustments on all character data within this element are controlled by + the value of ‘textLength’ on this element exclusively, with the possible side-effect + that the adjustment ratio for the contents of this element might be different than the + adjustment ratio used for other content that shares the same ancestor. The user agent + must assume that the total advance values for the other content within that ancestor is + the difference between the advance value on that ancestor and the advance value for + this element. + + This attribute is not intended for use to obtain effects such as shrinking or + expanding text. + + A negative value is an error (see Error processing). + + The ‘textLength’ attribute is only applied when the wrapping area is not defined by the + TODO shape-inside or the inline-size properties. It is also not applied for any ‘text’ or + TODO ‘tspan’ element that has forced line breaks (due to a white-space value of pre or + pre-line). + + If the attribute is not specified anywhere within a ‘text’ element, the effect is as if + the author's computation exactly matched the value calculated by the user agent; + thus, no advance adjustments are made. + */ + double scaleSpacingAndGlyphs = 1; + NSString *mTextLength = [self textLength]; + enum TextLengthAdjust mLengthAdjust = TextLengthAdjustFromString([self lengthAdjust]); + if (mTextLength != nil) { + double author = [PropHelper fromRelativeWithNSString:mTextLength + relative:[gc getWidth] + offset:0 + scale:1 + fontSize:fontSize]; + if (author < 0) { + NSException *e = [NSException + exceptionWithName:@"NegativeTextLength" + reason:@"Negative textLength value" + userInfo:nil]; + @throw e; + } + switch (mLengthAdjust) { + default: + case TextLengthAdjustSpacing: + letterSpacing += (author - textMeasure) / (n - 1); + break; + case TextLengthAdjustSpacingAndGlyphs: + scaleSpacingAndGlyphs = author / textMeasure; + break; + } + } + double scaledDirection = scaleSpacingAndGlyphs * side; + + /* + https://developer.mozilla.org/en/docs/Web/CSS/vertical-align + https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6bsln.html + https://www.microsoft.com/typography/otspec/base.htm + http://apike.ca/prog_svg_text_style.html + https://www.w3schools.com/tags/canvas_textbaseline.asp + http://vanseodesign.com/web-design/svg-text-baseline-alignment/ + https://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align + https://tympanus.net/codrops/css_reference/vertical-align/ + + https://svgwg.org/svg2-draft/text.html#AlignmentBaselineProperty + 11.10.2.6. The ‘alignment-baseline’ property + + This property is defined in the CSS Line Layout Module 3 specification. See 'alignment-baseline'. [css-inline-3] + https://drafts.csswg.org/css-inline/#propdef-alignment-baseline + + The vertical-align property shorthand should be preferred in new content. + + SVG 2 introduces some changes to the definition of this property. + In particular: the values 'auto', 'before-edge', and 'after-edge' have been removed. + For backwards compatibility, 'text-before-edge' should be mapped to 'text-top' and + 'text-after-edge' should be mapped to 'text-bottom'. + + Neither 'text-before-edge' nor 'text-after-edge' should be used with the vertical-align property. + */ + /* + CGRect fontBounds = CTFontGetBoundingBox(fontRef); + double textHeight = CGRectGetHeight(textBounds); + double fontWidth = CGRectGetWidth(textBounds); + CGPoint fontOrigin = fontBounds.origin; + + CGFloat fontMinX = fontOrigin.x; + CGFloat fontMinY = fontOrigin.y; + CGFloat fontMaxX = fontMinX + fontWidth; + CGFloat fontMaxY = fontMinY + textHeight; + */ + // TODO + double descenderDepth = CTFontGetDescent(fontRef); + double bottom = descenderDepth + CTFontGetLeading(fontRef); + double ascenderHeight = CTFontGetAscent(fontRef); + double top = ascenderHeight; + double totalHeight = top + bottom; + double baselineShift = 0; + // TODO, alignmentBaseline and baselineShift are always nil for some reason? + NSString *baselineShiftString = [self baselineShift]; + enum AlignmentBaseline baseline = AlignmentBaselineFromString([self alignmentBaseline]); + if (baseline != AlignmentBaselineBaseline) { + // TODO alignment-baseline, test / verify behavior + // TODO get per glyph baselines from font baseline table, for high-precision alignment + CGFloat xHeight = CTFontGetXHeight(fontRef); + switch (baseline) { + // https://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling + default: + case AlignmentBaselineBaseline: + // Use the dominant baseline choice of the parent. + // Match the box’s corresponding baseline to that of its parent. + baselineShift = 0; + break; + + case AlignmentBaselineTextBottom: + case AlignmentBaselineAfterEdge: + case AlignmentBaselineTextAfterEdge: + // Match the bottom of the box to the bottom of the parent’s content area. + // text-after-edge = text-bottom + // text-after-edge = descender depth + baselineShift = -descenderDepth; + break; + + case AlignmentBaselineAlphabetic: + // Match the box’s alphabetic baseline to that of its parent. + // alphabetic = 0 + baselineShift = 0; + break; + + case AlignmentBaselineIdeographic: + // Match the box’s ideographic character face under-side baseline to that of its parent. + // ideographic = descender depth + baselineShift = -descenderDepth; + break; + + case AlignmentBaselineMiddle: + // Align the vertical midpoint of the box with the baseline of the parent box plus half the x-height of the parent. TODO + // middle = x height / 2 + baselineShift = xHeight / 2; + break; + + case AlignmentBaselineCentral: + // Match the box’s central baseline to the central baseline of its parent. + // central = (ascender height - descender depth) / 2 + baselineShift = (ascenderHeight - descenderDepth) / 2; + break; + + case AlignmentBaselineMathematical: + // Match the box’s mathematical baseline to that of its parent. + // Hanging and mathematical baselines + // There are no obvious formulas to calculate the position of these baselines. + // At the time of writing FOP puts the hanging baseline at 80% of the ascender + // height and the mathematical baseline at 50%. + baselineShift = 0.5 * ascenderHeight; + break; + + case AlignmentBaselineHanging: + baselineShift = 0.8 * ascenderHeight; + break; + + case AlignmentBaselineTextTop: + case AlignmentBaselineBeforeEdge: + case AlignmentBaselineTextBeforeEdge: + // Match the top of the box to the top of the parent’s content area. + // text-before-edge = text-top + // text-before-edge = ascender height + baselineShift = ascenderHeight; + break; + + case AlignmentBaselineBottom: + // Align the top of the aligned subtree with the top of the line box. + baselineShift = bottom; + break; + + case AlignmentBaselineCenter: + // Align the center of the aligned subtree with the center of the line box. + baselineShift = totalHeight / 2; + break; + + case AlignmentBaselineTop: + // Align the bottom of the aligned subtree with the bottom of the line box. + baselineShift = top; + break; + } + /* + 2.2.2. Alignment Shift: baseline-shift longhand + + This property specifies by how much the box is shifted up from its alignment point. + It does not apply when alignment-baseline is top or bottom. + + Authors should use the vertical-align shorthand instead of this property. + + Values have the following meanings: + + + Raise (positive value) or lower (negative value) by the specified length. + + Raise (positive value) or lower (negative value) by the specified percentage of the line-height. + TODO sub + Lower by the offset appropriate for subscripts of the parent’s box. + (The UA should use the parent’s font data to find this offset whenever possible.) + TODO super + Raise by the offset appropriate for superscripts of the parent’s box. + (The UA should use the parent’s font data to find this offset whenever possible.) + + User agents may additionally support the keyword baseline as computing to 0 + if is necessary for them to support legacy SVG content. + Issue: We would prefer to remove this, + and are looking for feedback from SVG user agents as to whether it’s necessary. + + https://www.w3.org/TR/css-inline-3/#propdef-baseline-shift + */ + if (baselineShiftString != nil && fontData != nil) { + switch (baseline) { + case AlignmentBaselineTop: + case AlignmentBaselineBottom: + break; + + default: + if ([baselineShiftString isEqualToString:@"sub"]) { + // TODO + NSDictionary* tables = [fontData objectForKey:@"tables"]; + NSNumber* unitsPerEm = [fontData objectForKey:@"unitsPerEm"]; + NSDictionary* os2 = [tables objectForKey:@"os2"]; + NSNumber* ySubscriptYOffset = [os2 objectForKey:@"ySubscriptYOffset"]; + if (ySubscriptYOffset) { + double subOffset = [ySubscriptYOffset doubleValue]; + baselineShift += fontSize * subOffset / [unitsPerEm doubleValue]; + } + } else if ([baselineShiftString isEqualToString:@"super"]) { + // TODO + NSDictionary* tables = [fontData objectForKey:@"tables"]; + NSNumber* unitsPerEm = [fontData objectForKey:@"unitsPerEm"]; + NSDictionary* os2 = [tables objectForKey:@"os2"]; + NSNumber* ySuperscriptYOffset = [os2 objectForKey:@"ySuperscriptYOffset"]; + if (ySuperscriptYOffset) { + double superOffset = [ySuperscriptYOffset doubleValue]; + baselineShift -= fontSize * superOffset / [unitsPerEm doubleValue]; + } + } else if ([baselineShiftString isEqualToString:@"baseline"]) { + } else { + baselineShift -= [PropHelper fromRelativeWithNSString:baselineShiftString + relative:fontSize + offset:0 + scale:1 + fontSize:fontSize]; + + } + break; + } + } + } + int i = -1; for(CFIndex g = 0; g < runGlyphCount; g++) { - CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyphs[g], nil); + i++; + bool alreadyRenderedGraphemeCluster = ligature[i]; /* Determine the glyph's charwidth (i.e., the amount which the current text position advances horizontally when the glyph is drawn using horizontal text layout). */ - CGFloat charWidth = glyph_advances[g].width * scaleSpacingAndGlyphs; - //CGPoint glyphPoint = [self getGlyphPointFromContext:positions[i] glyphWidth:CGRectGetWidth(CGPathGetBoundingBox(letter))]; + double unkernedAdvance = CTFontGetAdvancesForGlyphs(fontRef, kCTFontOrientationHorizontal, glyphs + g, NULL, 1); + CGFloat charWidth = unkernedAdvance * scaleSpacingAndGlyphs; /* For each subsequent glyph, set a new startpoint-on-the-path as the previous @@ -702,8 +692,8 @@ using the user agent's distance along the path algorithm. */ if (autoKerning) { - // TODO double kerned = advances[index] * scaleSpacingAndGlyphs; - //kerning = kerned - charWidth; + double kerned = advances[g].width * scaleSpacingAndGlyphs; + kerning = kerned - charWidth; } bool isWordSeparator = false; @@ -711,12 +701,34 @@ double spacing = wordSpace + letterSpacing; double advance = charWidth + spacing; - double x = [gc nextXWithDouble:charWidth]; + double x = [gc nextXWithDouble:kerning + charWidth]; double y = [gc nextY]; double dx = [gc nextDeltaX]; double dy = [gc nextDeltaY]; double r = [[gc nextRotation] doubleValue] / radToDeg; + if (alreadyRenderedGraphemeCluster) { + // Skip rendering other grapheme clusters of ligatures (already rendered), + // But, make sure to increment index positions by making gc.next() calls. + continue; + } + + int len = 2; + int nextIndex = i; + CGGlyph glyph = glyphs[g]; + bool hasLigature = false; + while (++nextIndex < n) { + NSString* nextLigature = [str substringWithRange:NSMakeRange(i, len++)]; + bool hasNextLigature = hasGlyph(fontRef, nextLigature, &glyph, allowOptionalLigatures); + if (hasNextLigature) { + ligature[nextIndex] = true; + hasLigature = true; + } else { + break; + } + } + CGPathRef glyphPath = CTFontCreatePathForGlyph(runFont, glyph, nil); + advance *= side; charWidth *= side; double cursor = offset + (x + dx) * side; @@ -759,13 +771,13 @@ transform = CGAffineTransformConcat(CGAffineTransformMakeTranslation(-halfWay, dy + baselineShift), transform); transform = CGAffineTransformConcat(CGAffineTransformMakeTranslation(0, y), transform); } else { - transform = CGAffineTransformMakeTranslation(startPoint, y + dy); + transform = CGAffineTransformMakeTranslation(startPoint, y + dy + baselineShift); transform = CGAffineTransformConcat(CGAffineTransformMakeRotation(r), transform); } transform = CGAffineTransformScale(transform, 1.0, -1.0); - CGPathAddPath(path, &transform, letter); - CGPathRelease(letter); + CGPathAddPath(path, &transform, glyphPath); + CGPathRelease(glyphPath); } } @@ -794,15 +806,14 @@ CGFloat getTextAnchorOffset(enum TextAnchor textAnchor, CGFloat width) _path = nil; textPath = nil; textPathPath = nil; - //_bezierTransformer = nil; [self traverseTextSuperviews:^(__kindof RNSVGText *node) { if ([node class] == [RNSVGTextPath class]) { textPath = (RNSVGTextPath*) node; - //_bezierTransformer = [textPath getBezierTransformer]; textPathPath = [textPath getPath]; _path = [UIBezierPath bezierPathWithCGPath:[textPathPath getPath:nil]]; _path = [_path bezierPathByFlatteningPathAndImmutable:YES]; pathLength = [_path length]; + isClosed = [_path isClosed]; return NO; } return YES; @@ -825,14 +836,44 @@ CGFloat getTextAnchorOffset(enum TextAnchor textAnchor, CGFloat width) } } -- (BOOL)textPathHasReachedEnd +bool hasGlyph(CTFontRef fontRef, NSString * str, CGGlyph* glyph, bool allowOptionalLigatures) { - return [_bezierTransformer hasReachedEnd]; -} + CFStringRef string = (__bridge CFStringRef)str; + CFDictionaryRef attributes; + NSNumber *lig = [NSNumber numberWithInt:allowOptionalLigatures ? 2 : 1]; -- (BOOL)textPathHasReachedStart -{ - return [_bezierTransformer hasReachedStart]; + if (fontRef != nil) { + attributes = (__bridge CFDictionaryRef)@{ + (NSString *)kCTFontAttributeName: (__bridge id)fontRef, + (NSString *)NSLigatureAttributeName: lig + }; + } else { + attributes = (__bridge CFDictionaryRef)@{ + (NSString *)NSLigatureAttributeName: lig + }; + } + + CFAttributedStringRef attrString = CFAttributedStringCreate(kCFAllocatorDefault, string, attributes); + CTLineRef line = CTLineCreateWithAttributedString(attrString); + CFArrayRef runs = CTLineGetGlyphRuns(line); + + CFIndex runEnd = CFArrayGetCount(runs); + if (runEnd > 1) { + return false; + } + CTRunRef run = CFArrayGetValueAtIndex(runs, 0); + CFIndex runGlyphCount = CTRunGetGlyphCount(run); + + CGGlyph glyphs[runGlyphCount]; + CTRunGetGlyphs(run, CFRangeMake(0, 0), glyphs); + + bool hasGlyph = runGlyphCount == 1; + + if (hasGlyph) { + *glyph = glyphs[0]; + } + + return hasGlyph; } @end diff --git a/ios/Text/RNSVGText.h b/ios/Text/RNSVGText.h index b977fc40..e0d3902c 100644 --- a/ios/Text/RNSVGText.h +++ b/ios/Text/RNSVGText.h @@ -25,6 +25,5 @@ - (void)releaseCachedPath; - (CGPathRef)getGroupPath:(CGContextRef)context; - (CTFontRef)getFontFromContext; -- (CGPoint)getGlyphPointFromContext:(CGPoint)offset glyphWidth:(CGFloat)glyphWidth; @end diff --git a/ios/Text/RNSVGText.m b/ios/Text/RNSVGText.m index 328e617b..78e7495a 100644 --- a/ios/Text/RNSVGText.m +++ b/ios/Text/RNSVGText.m @@ -10,14 +10,12 @@ #import "RNSVGTextPath.h" #import #import -#import "RNSVGGlyphContext.h" #import "GlyphContext.h" @implementation RNSVGText { RNSVGText *_textRoot; GlyphContext *_glyphContext; - RNSVGGlyphContext *_RNSVGGlyphContext; } - (void)renderLayerTo:(CGContextRef)context @@ -40,8 +38,6 @@ { _glyphContext = [[GlyphContext alloc] initWithScale:1 width:[self getContextWidth] height:[self getContextHeight]]; - _RNSVGGlyphContext = [[RNSVGGlyphContext alloc] initWithDimensions:[self getContextWidth] - height:[self getContextHeight]]; } // release the cached CGPathRef for RNSVGTSpan @@ -95,11 +91,6 @@ return _textRoot; } -- (RNSVGGlyphContext *)getRNSVGGlyphContext -{ - return _RNSVGGlyphContext; -} - - (GlyphContext *)getGlyphContext { return _glyphContext; @@ -107,12 +98,6 @@ - (void)pushGlyphContext { - /* - [[[self getTextRoot] getRNSVGGlyphContext] pushContext:self.font - deltaX:self.deltaX - deltaY:self.deltaY - positionX:self.positionX - positionY:self.positionY];*/ [[[self getTextRoot] getGlyphContext] pushContextwithRNSVGText:self reset:false font:self.font @@ -125,7 +110,6 @@ - (void)popGlyphContext { - //[[[self getTextRoot] getRNSVGGlyphContext] popContext]; [[[self getTextRoot] getGlyphContext] popContext]; } @@ -134,9 +118,4 @@ return [[[self getTextRoot] getGlyphContext] getGlyphFont]; } -- (CGPoint)getGlyphPointFromContext:(CGPoint)offset glyphWidth:(CGFloat)glyphWidth -{ - return [[[self getTextRoot] getRNSVGGlyphContext] getNextGlyphPoint:(CGPoint)offset glyphWidth:glyphWidth]; -} - @end diff --git a/ios/Text/RNSVGTextPath.h b/ios/Text/RNSVGTextPath.h index 71125673..ec08b7ad 100644 --- a/ios/Text/RNSVGTextPath.h +++ b/ios/Text/RNSVGTextPath.h @@ -9,7 +9,6 @@ #import #import #import "RNSVGText.h" -#import "RNSVGBezierTransformer.h" @interface RNSVGTextPath : RNSVGText @@ -21,6 +20,5 @@ @property (nonatomic, strong) NSString *startOffset; - (RNSVGPath *)getPath; -- (RNSVGBezierTransformer *)getBezierTransformer; @end diff --git a/ios/Text/RNSVGTextPath.m b/ios/Text/RNSVGTextPath.m index 3f28dcfc..310a6b0e 100644 --- a/ios/Text/RNSVGTextPath.m +++ b/ios/Text/RNSVGTextPath.m @@ -8,7 +8,6 @@ #import "RNSVGTextPath.h" -#import "RNSVGBezierTransformer.h" @implementation RNSVGTextPath @@ -31,14 +30,6 @@ return path; } -- (RNSVGBezierTransformer *)getBezierTransformer -{ - RNSVGPath *path = [self getPath]; - CGFloat startOffset = [self relativeOnWidth:self.startOffset]; - return [[RNSVGBezierTransformer alloc] initWithBezierCurvesAndStartOffset:[path getBezierCurves] - startOffset:startOffset]; -} - - (CGPathRef)getPath:(CGContextRef)context { return [self getGroupPath:context]; diff --git a/ios/ViewManagers/RNSVGTextManager.m b/ios/ViewManagers/RNSVGTextManager.m index 74cabcf3..fc154993 100644 --- a/ios/ViewManagers/RNSVGTextManager.m +++ b/ios/ViewManagers/RNSVGTextManager.m @@ -27,5 +27,9 @@ RCT_EXPORT_VIEW_PROPERTY(positionX, NSArray) RCT_EXPORT_VIEW_PROPERTY(positionY, NSArray) RCT_EXPORT_VIEW_PROPERTY(rotate, NSArray) RCT_EXPORT_VIEW_PROPERTY(font, NSDictionary) +RCT_EXPORT_VIEW_PROPERTY(textLength, NSString) +RCT_EXPORT_VIEW_PROPERTY(baselineShift, NSString) +RCT_EXPORT_VIEW_PROPERTY(lengthAdjust, NSString) +RCT_EXPORT_VIEW_PROPERTY(alignmentBaseline, NSString) @end diff --git a/ios/ViewManagers/RNSVGTextPathManager.m b/ios/ViewManagers/RNSVGTextPathManager.m index 3ff778cd..b5efb6a7 100644 --- a/ios/ViewManagers/RNSVGTextPathManager.m +++ b/ios/ViewManagers/RNSVGTextPathManager.m @@ -20,6 +20,10 @@ RCT_EXPORT_MODULE() } RCT_EXPORT_VIEW_PROPERTY(href, NSString) +RCT_EXPORT_VIEW_PROPERTY(side, NSString) +RCT_EXPORT_VIEW_PROPERTY(method, NSString) +RCT_EXPORT_VIEW_PROPERTY(midLine, NSString) +RCT_EXPORT_VIEW_PROPERTY(spacing, NSString) RCT_EXPORT_VIEW_PROPERTY(startOffset, NSString) @end