Skip to content

Commit 78c4f20

Browse files
committed
feat(ios): implement getTotalLength and getPointAtLength
1 parent 203e53b commit 78c4f20

File tree

8 files changed

+320
-265
lines changed

8 files changed

+320
-265
lines changed

android/src/main/java/com/horcrux/svg/RNSVGRenderableManager.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ public void run() {
5252
} else {
5353
successCallback.invoke(false);
5454
}
55-
return;
5655
} else {
5756
float scale = svg.mScale;
5857
src[0] *= scale;

ios/RNSVG.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@
6767
947F38102148119A00677F2A /* RNSVGMaskManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 947F380E2148119A00677F2A /* RNSVGMaskManager.m */; };
6868
9482DEFA23460EC800FC486E /* RNSVGContextBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 9482DEF823460EC700FC486E /* RNSVGContextBrush.m */; };
6969
9482DEFB23460EC800FC486E /* RNSVGContextBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 9482DEF823460EC700FC486E /* RNSVGContextBrush.m */; };
70+
9482DF02234680A200FC486E /* RNSVGPathMeasure.m in Sources */ = {isa = PBXBuildFile; fileRef = 9482DF00234680A200FC486E /* RNSVGPathMeasure.m */; };
71+
9482DF03234680A200FC486E /* RNSVGPathMeasure.m in Sources */ = {isa = PBXBuildFile; fileRef = 9482DF00234680A200FC486E /* RNSVGPathMeasure.m */; };
7072
9494C4D81F473BA700D5BCFD /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9494C4D71F473BA700D5BCFD /* QuartzCore.framework */; };
7173
9494C4DA1F473BCB00D5BCFD /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9494C4D91F473BCB00D5BCFD /* CoreText.framework */; };
7274
9494C4DC1F473BD900D5BCFD /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9494C4DB1F473BD900D5BCFD /* CoreGraphics.framework */; };
@@ -261,6 +263,8 @@
261263
947F380E2148119A00677F2A /* RNSVGMaskManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGMaskManager.m; sourceTree = "<group>"; };
262264
9482DEF823460EC700FC486E /* RNSVGContextBrush.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGContextBrush.m; sourceTree = "<group>"; };
263265
9482DEF923460EC800FC486E /* RNSVGContextBrush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGContextBrush.h; sourceTree = "<group>"; };
266+
9482DF00234680A200FC486E /* RNSVGPathMeasure.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGPathMeasure.m; path = Utils/RNSVGPathMeasure.m; sourceTree = "<group>"; };
267+
9482DF01234680A200FC486E /* RNSVGPathMeasure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGPathMeasure.h; path = Utils/RNSVGPathMeasure.h; sourceTree = "<group>"; };
264268
9494C4D71F473BA700D5BCFD /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
265269
9494C4D91F473BCB00D5BCFD /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; };
266270
9494C4DB1F473BD900D5BCFD /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
@@ -482,6 +486,8 @@
482486
1039D29A1CE7212C001E90A8 /* Utils */ = {
483487
isa = PBXGroup;
484488
children = (
489+
9482DF01234680A200FC486E /* RNSVGPathMeasure.h */,
490+
9482DF00234680A200FC486E /* RNSVGPathMeasure.m */,
485491
94A178FD2344097B00693CB3 /* RNSVGMarkerPosition.h */,
486492
94A178FE2344097B00693CB3 /* RNSVGMarkerPosition.m */,
487493
94696EE92235A7F200C1D558 /* RNSVGVectorEffect.h */,
@@ -608,6 +614,7 @@
608614
9482DEFA23460EC800FC486E /* RNSVGContextBrush.m in Sources */,
609615
0CF68B071AF0549300FF9E5C /* RNSVGRenderable.m in Sources */,
610616
1039D2891CE71EB7001E90A8 /* RNSVGGroup.m in Sources */,
617+
9482DF02234680A200FC486E /* RNSVGPathMeasure.m in Sources */,
611618
10ED4A9E1CF0656A0078BC02 /* RNSVGClipPathManager.m in Sources */,
612619
10BEC1C61D3F7BD300FDCB19 /* RNSVGPainter.m in Sources */,
613620
10ED4AA21CF078830078BC02 /* RNSVGNode.m in Sources */,
@@ -674,6 +681,7 @@
674681
9482DEFB23460EC800FC486E /* RNSVGContextBrush.m in Sources */,
675682
A361E77D1EB0C33D00646005 /* RNSVGGroup.m in Sources */,
676683
A361E77E1EB0C33D00646005 /* RNSVGClipPathManager.m in Sources */,
684+
9482DF03234680A200FC486E /* RNSVGPathMeasure.m in Sources */,
677685
A361E77F1EB0C33D00646005 /* RNSVGPainter.m in Sources */,
678686
A361E7801EB0C33D00646005 /* RNSVGNode.m in Sources */,
679687
A361E7811EB0C33D00646005 /* RNSVGClipPath.m in Sources */,

ios/Text/RNSVGTSpan.m

Lines changed: 15 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#import "RNSVGText.h"
1010
#import "RNSVGTextPath.h"
1111
#import "RNSVGTextProperties.h"
12+
#import "RNSVGPathMeasure.h"
1213
#import "RNSVGFontData.h"
1314

1415
static NSCharacterSet *RNSVGTSpan_separators = nil;
@@ -38,18 +39,14 @@ - (void)drawTextInRect:(CGRect) rect
3839
@implementation RNSVGTSpan
3940
{
4041
CGFloat startOffset;
41-
CGFloat _pathLength;
4242
RNSVGTextPath *textPath;
43-
NSArray *lengths;
44-
NSArray *lines;
45-
NSUInteger lineCount;
46-
BOOL isClosed;
4743
NSMutableArray *emoji;
4844
NSMutableArray *emojiTransform;
4945
CGFloat cachedAdvance;
5046
CTFontRef fontRef;
5147
CGFloat firstX;
5248
CGFloat firstY;
49+
RNSVGPathMeasure *measure;
5350
}
5451

5552
- (id)init
@@ -62,6 +59,7 @@ - (id)init
6259

6360
emoji = [NSMutableArray arrayWithCapacity:0];
6461
emojiTransform = [NSMutableArray arrayWithCapacity:0];
62+
measure = [[RNSVGPathMeasure alloc]init];
6563

6664
return self;
6765
}
@@ -476,7 +474,7 @@ vertical alternates (OpenType feature: vert) must be enabled.
476474

477475
int side = 1;
478476
CGFloat startOfRendering = 0;
479-
CGFloat endOfRendering = _pathLength;
477+
CGFloat endOfRendering = measure.pathLength;
480478
CGFloat fontSize = [gc getFontSize];
481479
//bool sharpMidLine = false;
482480
if (hasTextPath) {
@@ -541,13 +539,13 @@ For the start (end) value, the text is rendered from the start (end) of the line
541539
the path is reached.
542540
*/
543541
CGFloat absoluteStartOffset = [RNSVGPropHelper fromRelative:textPath.startOffset
544-
relative:_pathLength
542+
relative:measure.pathLength
545543
fontSize:fontSize];
546544
offset += absoluteStartOffset;
547-
if (isClosed) {
548-
CGFloat halfPathDistance = _pathLength / 2;
545+
if (measure.isClosed) {
546+
CGFloat halfPathDistance = measure.pathLength / 2;
549547
startOfRendering = absoluteStartOffset + (textAnchor == RNSVGTextAnchorMiddle ? -halfPathDistance : 0);
550-
endOfRendering = startOfRendering + _pathLength;
548+
endOfRendering = startOfRendering + measure.pathLength;
551549
}
552550
/*
553551
RNSVGTextPathSpacing spacing = textPath.getSpacing();
@@ -958,39 +956,10 @@ A negative value is an error (see Error processing).
958956
continue;
959957
}
960958

961-
// Investigation suggests binary search is faster at lineCount >= 16
962-
// https://gist.github.com/msand/4c7993319425f9d7933be58ad9ada1a4
963-
NSUInteger i = lineCount < 16 ?
964-
[lengths
965-
indexOfObjectPassingTest:^(NSNumber* length, NSUInteger index, BOOL * _Nonnull stop) {
966-
BOOL contains = midPoint <= [length doubleValue];
967-
return contains;
968-
}]
969-
:
970-
[lengths
971-
indexOfObject:[NSNumber numberWithDouble:midPoint]
972-
inSortedRange:NSMakeRange(0, lineCount)
973-
options:NSBinarySearchingInsertionIndex
974-
usingComparator:^(NSNumber* obj1, NSNumber* obj2) {
975-
return [obj1 compare:obj2];
976-
}];
977-
978-
CGFloat totalLength = (CGFloat)[lengths[i] doubleValue];
979-
CGFloat prevLength = i == 0 ? 0 : (CGFloat)[lengths[i - 1] doubleValue];
980-
981-
CGFloat length = totalLength - prevLength;
982-
CGFloat percent = (midPoint - prevLength) / length;
983-
984-
NSArray * points = [lines objectAtIndex: i];
985-
CGPoint p1 = [[points objectAtIndex: 0] CGPointValue];
986-
CGPoint p2 = [[points objectAtIndex: 1] CGPointValue];
987-
988-
CGFloat ldx = p2.x - p1.x;
989-
CGFloat ldy = p2.y - p1.y;
990-
CGFloat angle = atan2(ldy, ldx);
991-
992-
CGFloat px = p1.x + ldx * percent;
993-
CGFloat py = p1.y + ldy * percent;
959+
CGFloat angle;
960+
CGFloat px;
961+
CGFloat py;
962+
[measure getPosAndTan:&angle midPoint:midPoint px:&px py:&py];
994963

995964
transform = CGAffineTransformConcat(CGAffineTransformMakeTranslation(px, py), transform);
996965
transform = CGAffineTransformConcat(CGAffineTransformMakeRotation(angle + r), transform);
@@ -1061,24 +1030,18 @@ + (CGFloat)getTextAnchorOffset:(RNSVGTextAnchor)textAnchor width:(CGFloat) width
10611030

10621031
- (void)setupTextPath:(CGContextRef)context
10631032
{
1064-
lines = nil;
1065-
lengths = nil;
10661033
textPath = nil;
10671034
RNSVGText *parent = (RNSVGText*)[self superview];
1068-
10691035
while (parent) {
10701036
if ([parent class] == [RNSVGTextPath class]) {
10711037
textPath = (RNSVGTextPath*) parent;
1072-
[textPath getPathLength:&_pathLength
1073-
lineCount:&lineCount
1074-
lengths:&lengths
1075-
lines:&lines
1076-
isClosed:&isClosed];
1038+
RNSVGNode *template = [self.svgView getDefinedTemplate:textPath.href];
1039+
CGPathRef path = [template getPath:nil];
1040+
[measure extractPathData:path];
10771041
break;
10781042
} else if (![parent isKindOfClass:[RNSVGText class]]) {
10791043
break;
10801044
}
1081-
10821045
parent = (RNSVGText*)[parent superview];
10831046
}
10841047
}

ios/Text/RNSVGTextPath.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,4 @@
2020
@property (nonatomic, strong) NSString *spacing;
2121
@property (nonatomic, strong) RNSVGLength *startOffset;
2222

23-
- (void)getPathLength:(CGFloat*)length lineCount:(NSUInteger*)lineCount lengths:(NSArray* __strong *)lengths lines:(NSArray* __strong *)lines isClosed:(BOOL*)isClosed;
24-
25-
2623
@end

0 commit comments

Comments
 (0)