Merge pull request #558 from msand/tailormade_distance_along_path

Implement tailor made data structure and logic for text on a path, and various bugfixes.
This commit is contained in:
Mikael Sand
2018-01-17 19:50:40 +02:00
committed by GitHub
22 changed files with 863 additions and 807 deletions
@@ -160,7 +160,7 @@ class ImageShadowNode extends RenderableShadowNode {
@Override
protected Path getPath(Canvas canvas, Paint paint) {
Path path = new Path();
path.addRect(new RectF(getRect()), Path.Direction.CW);
path.addRect(getRect(), Path.Direction.CW);
return path;
}
@@ -187,51 +187,37 @@ class ImageShadowNode extends RenderableShadowNode {
}
@Nonnull
private Rect getRect() {
private RectF getRect() {
double x = relativeOnWidth(mX);
double y = relativeOnHeight(mY);
double w = relativeOnWidth(mW);
double h = relativeOnHeight(mH);
if (w == 0) {
w = mImageWidth * mScale;
}
if (h == 0) {
h = mImageHeight * mScale;
}
return new Rect((int) x, (int) y, (int) (x + w), (int) (y + h));
return new RectF((float)x, (float)y, (float)(x + w), (float)(y + h));
}
private void doRender(Canvas canvas, Paint paint, Bitmap bitmap, float opacity) {
// apply viewBox transform on Image render.
Rect rect = getRect();
float rectWidth = (float)rect.width();
float rectHeight = (float)rect.height();
float rectX = (float)rect.left;
float rectY = (float)rect.top;
float canvasLeft = getCanvasLeft();
float canvasTop = getCanvasTop();
if (mImageWidth == 0 || mImageHeight == 0) {
mImageWidth = bitmap.getWidth();
mImageHeight = bitmap.getHeight();
}
RectF renderRect = new RectF(0, 0, mImageWidth, mImageHeight);
RectF renderRect = getRect();
RectF vbRect = new RectF(0, 0, mImageWidth, mImageHeight);
RectF eRect = new RectF(canvasLeft, canvasTop, (rectWidth / mScale) + canvasLeft, (rectHeight / mScale) + canvasTop);
Matrix transform = ViewBox.getTransform(vbRect, eRect, mAlign, mMeetOrSlice);
Matrix transform = ViewBox.getTransform(vbRect, renderRect, mAlign, mMeetOrSlice);
transform.mapRect(vbRect);
Matrix translation = new Matrix();
transform.mapRect(renderRect);
if (mMatrix != null) {
translation.postConcat(mMatrix);
//mMatrix.mapRect(renderRect);
mMatrix.mapRect(vbRect);
}
float dx = rectX / mScale + canvasLeft;
float dy = rectY / mScale + canvasTop;
translation.postTranslate(dx, dy);
translation.postScale(mScale, mScale);
translation.mapRect(renderRect);
Path clip = new Path();
Path clipPath = getClipPath(canvas, paint);
Path path = getPath(canvas, paint);
if (clipPath != null) {
@@ -256,7 +242,7 @@ class ImageShadowNode extends RenderableShadowNode {
Paint alphaPaint = new Paint();
alphaPaint.setAlpha((int) (opacity * 255));
canvas.drawBitmap(bitmap, null, renderRect, alphaPaint);
canvas.drawBitmap(bitmap, null, vbRect, alphaPaint);
}
private void tryRender(ImageRequest request, Canvas canvas, Paint paint, float opacity) {
@@ -726,7 +726,7 @@ class TSpanShadowNode extends TextShadowNode {
double spacing = wordSpace + letterSpacing;
double advance = charWidth + spacing;
double x = gc.nextX(kerning + advance);
double x = gc.nextX(alreadyRenderedGraphemeCluster ? 0 : kerning + advance);
double y = gc.nextY();
double dx = gc.nextDeltaX();
double dy = gc.nextDeltaY();
+23 -32
View File
@@ -96,55 +96,46 @@
- (void)renderLayerTo:(CGContextRef)context
{
CGRect rect = [self getRect:context];
// add hit area
CGPathRef hitArea = CGPathCreateWithRect(rect, nil);
[self setHitArea:hitArea];
CGPathRelease(hitArea);
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0, rect.size.height + 2 * rect.origin.y);
CGContextScaleCTM(context, 1, -1);
// add hit area
CGRect hitArea = [self getHitArea];
CGPathRef hitAreaPath = CGPathCreateWithRect(hitArea, nil);
[self setHitArea:hitAreaPath];
CGPathRelease(hitAreaPath);
// apply viewBox transform on Image render.
CGRect renderRect = CGRectMake(0, 0, _imageSize.width, _imageSize.height);
CGFloat rectWidth = CGRectGetWidth(rect);
CGFloat rectHeight = CGRectGetHeight(rect);
CGFloat rectX = CGRectGetMinX(rect);
CGFloat rectY = CGRectGetMinY(rect);
CGFloat canvasLeft = [self getContextLeft];
CGFloat canvasTop = [self getContextTop];
CGRect eRect = CGRectMake(canvasLeft, canvasTop, rectWidth, rectHeight);
CGRect vbRect = CGRectMake(0, 0, CGRectGetWidth(renderRect), CGRectGetHeight(renderRect));
CGAffineTransform transform = [RNSVGViewBox getTransform:vbRect eRect:eRect align:self.align meetOrSlice:self.meetOrSlice];
renderRect = CGRectApplyAffineTransform(renderRect, transform);
CGFloat dx = rectX + canvasLeft;
CGFloat dy = rectY + canvasTop;
renderRect = CGRectApplyAffineTransform(renderRect, CGAffineTransformMakeTranslation(dx, dy));
CGRect imageBounds = CGRectMake(0, 0, _imageSize.width, _imageSize.height);
CGAffineTransform viewbox = [RNSVGViewBox getTransform:imageBounds eRect:hitArea align:self.align meetOrSlice:self.meetOrSlice];
CGContextTranslateCTM(context, 0, hitArea.size.height);
CGContextScaleCTM(context, 1, -1);
[self clip:context];
CGContextClipToRect(context, rect);
CGContextDrawImage(context, renderRect, _image);
CGContextClipToRect(context, hitArea);
CGContextConcatCTM(context, viewbox);
CGContextDrawImage(context, imageBounds, _image);
CGContextRestoreGState(context);
}
- (CGRect)getRect:(CGContextRef)context
- (CGRect)getHitArea
{
CGFloat x = [self relativeOnWidth:self.x];
CGFloat y = [self relativeOnHeight:self.y];
CGFloat width = [self relativeOnWidth:self.width];
CGFloat height = [self relativeOnHeight:self.height];
if (width == 0) {
width = _imageSize.width;
}
if (height == 0) {
height = _imageSize.height;
}
return CGRectMake(x, y, width, height);
}
- (CGPathRef)getPath:(CGContextRef)context
{
return (CGPathRef)CFAutorelease(CGPathCreateWithRect([self getRect:context], nil));
return (CGPathRef)CFAutorelease(CGPathCreateWithRect([self getHitArea], nil));
}
@end
-2
View File
@@ -14,6 +14,4 @@
@property (nonatomic, strong) RNSVGPathParser *d;
- (NSArray *)getBezierCurves;
@end
-5
View File
@@ -30,11 +30,6 @@
return _path;
}
- (NSArray *)getBezierCurves
{
return [_d getBezierCurves];
}
- (void)dealloc
{
CGPathRelease(_path);
+6 -100
View File
@@ -49,14 +49,12 @@
7F08CE9B1E23476900650F83 /* RNSVGTSpanManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F08CE991E23476900650F83 /* RNSVGTSpanManager.m */; };
7F08CEA01E23479700650F83 /* RNSVGTextPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F08CE9D1E23479700650F83 /* RNSVGTextPath.m */; };
7F08CEA11E23479700650F83 /* RNSVGTSpan.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F08CE9F1E23479700650F83 /* RNSVGTSpan.m */; };
7F4BB50A1FB1E50000663D5F /* QuartzBookPack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F4BB5051FB1DEC300663D5F /* QuartzBookPack.framework */; };
7F9CDAFA1E1F809C00E0C805 /* RNSVGPathParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F9CDAF91E1F809C00E0C805 /* RNSVGPathParser.m */; };
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 */; };
945A8AF81F4CE3E8004BBF6B /* AlignmentBaseline.m in Sources */ = {isa = PBXBuildFile; fileRef = 945A8AF71F4CE3E8004BBF6B /* AlignmentBaseline.m */; };
945A8AF91F4CE3E8004BBF6B /* AlignmentBaseline.m in Sources */ = {isa = PBXBuildFile; fileRef = 945A8AF71F4CE3E8004BBF6B /* AlignmentBaseline.m */; };
9494C47A1F47116800D5BCFD /* PerformanceBezier.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9494C4771F4710FE00D5BCFD /* PerformanceBezier.framework */; };
9494C4D81F473BA700D5BCFD /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9494C4D71F473BA700D5BCFD /* QuartzCore.framework */; };
9494C4DA1F473BCB00D5BCFD /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9494C4D91F473BCB00D5BCFD /* CoreText.framework */; };
9494C4DC1F473BD900D5BCFD /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9494C4DB1F473BD900D5BCFD /* CoreGraphics.framework */; };
@@ -89,6 +87,7 @@
9494C5471F4C44DD00D5BCFD /* TextPathSide.m in Sources */ = {isa = PBXBuildFile; fileRef = 9494C5361F4C44DD00D5BCFD /* TextPathSide.m */; };
9494C5481F4C44DD00D5BCFD /* TextPathSpacing.m in Sources */ = {isa = PBXBuildFile; fileRef = 9494C5371F4C44DD00D5BCFD /* TextPathSpacing.m */; };
9494C5491F4C44DD00D5BCFD /* TextPathSpacing.m in Sources */ = {isa = PBXBuildFile; fileRef = 9494C5371F4C44DD00D5BCFD /* TextPathSpacing.m */; };
94C70B1A1FF6B1C0004DFD49 /* BezierElement.m in Sources */ = {isa = PBXBuildFile; fileRef = 94C70B171FF6B1C0004DFD49 /* BezierElement.m */; };
A361E76E1EB0C33D00646005 /* RNSVGTextManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D331CE74E3100887C2B /* RNSVGTextManager.m */; };
A361E76F1EB0C33D00646005 /* RNSVGImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2841CE71EB7001E90A8 /* RNSVGImage.m */; };
A361E7701EB0C33D00646005 /* RNSVGRect.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D471CE74E3D00887C2B /* RNSVGRect.m */; };
@@ -137,37 +136,6 @@
A361E79D1EB0C33D00646005 /* RNSVGDefsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1023B48C1D3DDCCE0051496D /* RNSVGDefsManager.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
7F4BB5041FB1DEC300663D5F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 7F4BB4FF1FB1DEC300663D5F /* QuartzBookPack.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 7F917B141FB1D5E900A75AA4;
remoteInfo = QuartzBookPack;
};
7F4BB5061FB1DEC300663D5F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 7F4BB4FF1FB1DEC300663D5F /* QuartzBookPack.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 7F917B1D1FB1D5E900A75AA4;
remoteInfo = QuartzBookPackTests;
};
9494C4761F4710FE00D5BCFD /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 9494C4711F4710FE00D5BCFD /* PerformanceBezier.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 66F2EBE31A8DC05100D536E9;
remoteInfo = PerformanceBezier;
};
9494C4781F4710FE00D5BCFD /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 9494C4711F4710FE00D5BCFD /* PerformanceBezier.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 66B9D28C1A8D5FDE00CAC341;
remoteInfo = PerformanceBezierTests;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
0CF68ABF1AF0540F00FF9E5C /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
@@ -280,8 +248,6 @@
7F08CE9D1E23479700650F83 /* RNSVGTextPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGTextPath.m; path = Text/RNSVGTextPath.m; sourceTree = "<group>"; };
7F08CE9E1E23479700650F83 /* RNSVGTSpan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGTSpan.h; path = Text/RNSVGTSpan.h; sourceTree = "<group>"; };
7F08CE9F1E23479700650F83 /* RNSVGTSpan.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGTSpan.m; path = Text/RNSVGTSpan.m; sourceTree = "<group>"; };
7F08CEA31E23481F00650F83 /* RNSVGTextAnchor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGTextAnchor.h; path = Utils/RNSVGTextAnchor.h; sourceTree = "<group>"; };
7F4BB4FF1FB1DEC300663D5F /* QuartzBookPack.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = QuartzBookPack.xcodeproj; path = QuartzBookPack/QuartzBookPack.xcodeproj; sourceTree = "<group>"; };
7F69160D1E3703D800DA6EDC /* RNSVGUnits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGUnits.h; path = Utils/RNSVGUnits.h; sourceTree = "<group>"; };
7F9CDAF81E1F809C00E0C805 /* RNSVGPathParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGPathParser.h; path = Utils/RNSVGPathParser.h; sourceTree = "<group>"; };
7F9CDAF91E1F809C00E0C805 /* RNSVGPathParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGPathParser.m; path = Utils/RNSVGPathParser.m; sourceTree = "<group>"; };
@@ -293,7 +259,6 @@
7FC260D31E34A12A00A39833 /* RNSVGSymbolManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGSymbolManager.m; sourceTree = "<group>"; };
945A8AF71F4CE3E8004BBF6B /* AlignmentBaseline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AlignmentBaseline.m; path = Text/AlignmentBaseline.m; sourceTree = "<group>"; };
945A8AFA1F4CE41E004BBF6B /* AlignmentBaseline.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AlignmentBaseline.h; path = Text/AlignmentBaseline.h; sourceTree = "<group>"; };
9494C4711F4710FE00D5BCFD /* PerformanceBezier.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = PerformanceBezier.xcodeproj; path = PerformanceBezier/PerformanceBezier.xcodeproj; sourceTree = "<group>"; };
9494C4D71F473BA700D5BCFD /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
9494C4D91F473BCB00D5BCFD /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; };
9494C4DB1F473BD900D5BCFD /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
@@ -326,6 +291,8 @@
9494C5351F4C44DD00D5BCFD /* TextPathMidLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TextPathMidLine.m; path = Text/TextPathMidLine.m; sourceTree = "<group>"; };
9494C5361F4C44DD00D5BCFD /* TextPathSide.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TextPathSide.m; path = Text/TextPathSide.m; sourceTree = "<group>"; };
9494C5371F4C44DD00D5BCFD /* TextPathSpacing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TextPathSpacing.m; path = Text/TextPathSpacing.m; sourceTree = "<group>"; };
94C70B151FF6B1BF004DFD49 /* BezierElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BezierElement.h; path = Utils/BezierElement.h; sourceTree = "<group>"; };
94C70B171FF6B1C0004DFD49 /* BezierElement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BezierElement.m; path = Utils/BezierElement.m; sourceTree = "<group>"; };
94DDAC5C1F3D024300EED511 /* libRNSVG-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRNSVG-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
@@ -334,14 +301,12 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
7F4BB50A1FB1E50000663D5F /* QuartzBookPack.framework in Frameworks */,
9494C4E01F473BED00D5BCFD /* Accelerate.framework in Frameworks */,
9494C4D81F473BA700D5BCFD /* QuartzCore.framework in Frameworks */,
9494C4DA1F473BCB00D5BCFD /* CoreText.framework in Frameworks */,
9494C4DC1F473BD900D5BCFD /* CoreGraphics.framework in Frameworks */,
9494C4DE1F473BDD00D5BCFD /* UIKit.framework in Frameworks */,
9494C4E21F473BF500D5BCFD /* Foundation.framework in Frameworks */,
9494C47A1F47116800D5BCFD /* PerformanceBezier.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -358,8 +323,6 @@
0CF68AB81AF0540F00FF9E5C = {
isa = PBXGroup;
children = (
7F4BB4FF1FB1DEC300663D5F /* QuartzBookPack.xcodeproj */,
9494C4711F4710FE00D5BCFD /* PerformanceBezier.xcodeproj */,
1039D29A1CE7212C001E90A8 /* Utils */,
1039D2801CE71DCF001E90A8 /* Elements */,
1039D27F1CE71D9B001E90A8 /* Text */,
@@ -532,10 +495,11 @@
1039D29A1CE7212C001E90A8 /* Utils */ = {
isa = PBXGroup;
children = (
94C70B151FF6B1BF004DFD49 /* BezierElement.h */,
94C70B171FF6B1C0004DFD49 /* BezierElement.m */,
7F69160D1E3703D800DA6EDC /* RNSVGUnits.h */,
10ABC7381D43982B006CCF6E /* RNSVGVBMOS.h */,
10ABC7371D439779006CCF6E /* RNSVGCGFCRule.h */,
7F08CEA31E23481F00650F83 /* RNSVGTextAnchor.h */,
7FC260CC1E3499BC00A39833 /* RNSVGViewBox.h */,
7FC260CD1E3499BC00A39833 /* RNSVGViewBox.m */,
1039D29E1CE72177001E90A8 /* RNSVGCGFloatArray.h */,
@@ -549,15 +513,6 @@
name = Utils;
sourceTree = "<group>";
};
7F4BB5001FB1DEC300663D5F /* Products */ = {
isa = PBXGroup;
children = (
7F4BB5051FB1DEC300663D5F /* QuartzBookPack.framework */,
7F4BB5071FB1DEC300663D5F /* QuartzBookPackTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
9494C2B31F46139600D5BCFD /* Frameworks */ = {
isa = PBXGroup;
children = (
@@ -571,15 +526,6 @@
name = Frameworks;
sourceTree = "<group>";
};
9494C4721F4710FE00D5BCFD /* Products */ = {
isa = PBXGroup;
children = (
9494C4771F4710FE00D5BCFD /* PerformanceBezier.framework */,
9494C4791F4710FE00D5BCFD /* PerformanceBezierTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -640,16 +586,6 @@
mainGroup = 0CF68AB81AF0540F00FF9E5C;
productRefGroup = 0CF68AC21AF0540F00FF9E5C /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = 9494C4721F4710FE00D5BCFD /* Products */;
ProjectRef = 9494C4711F4710FE00D5BCFD /* PerformanceBezier.xcodeproj */;
},
{
ProductGroup = 7F4BB5001FB1DEC300663D5F /* Products */;
ProjectRef = 7F4BB4FF1FB1DEC300663D5F /* QuartzBookPack.xcodeproj */;
},
);
projectRoot = "";
targets = (
0CF68AC01AF0540F00FF9E5C /* RNSVG */,
@@ -658,37 +594,6 @@
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
7F4BB5051FB1DEC300663D5F /* QuartzBookPack.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = QuartzBookPack.framework;
remoteRef = 7F4BB5041FB1DEC300663D5F /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
7F4BB5071FB1DEC300663D5F /* QuartzBookPackTests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = QuartzBookPackTests.xctest;
remoteRef = 7F4BB5061FB1DEC300663D5F /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
9494C4771F4710FE00D5BCFD /* PerformanceBezier.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework.static;
path = PerformanceBezier.framework;
remoteRef = 9494C4761F4710FE00D5BCFD /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
9494C4791F4710FE00D5BCFD /* PerformanceBezierTests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = PerformanceBezierTests.xctest;
remoteRef = 9494C4781F4710FE00D5BCFD /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXSourcesBuildPhase section */
0CF68ABD1AF0540F00FF9E5C /* Sources */ = {
isa = PBXSourcesBuildPhase;
@@ -734,6 +639,7 @@
9494C5251F4B605F00D5BCFD /* GlyphContext.m in Sources */,
10BA0D481CE74E3D00887C2B /* RNSVGCircle.m in Sources */,
9494C5401F4C44DD00D5BCFD /* TextLengthAdjust.m in Sources */,
94C70B1A1FF6B1C0004DFD49 /* BezierElement.m in Sources */,
10BA0D351CE74E3100887C2B /* RNSVGEllipseManager.m in Sources */,
1039D2A01CE72177001E90A8 /* RCTConvert+RNSVG.m in Sources */,
9494C4FF1F4B5BE800D5BCFD /* FontData.m in Sources */,
-1
View File
@@ -6,7 +6,6 @@
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <PerformanceBezier/PerformanceBezier.h>
#import <Foundation/Foundation.h>
#import <CoreText/CoreText.h>
#import "RNSVGText.h"
+491 -525
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -8,7 +8,6 @@
#import <Foundation/Foundation.h>
#import "RNSVGGroup.h"
#import "RNSVGTextAnchor.h"
#import "AlignmentBaseline.h"
@interface RNSVGText : RNSVGGroup
+2 -1
View File
@@ -19,6 +19,7 @@
@property (nonatomic, strong) NSString *spacing;
@property (nonatomic, strong) NSString *startOffset;
- (RNSVGPath *)getPath;
- (void)getPathLength:(CGFloat*)length lineCount:(NSUInteger*)lineCount lengths:(NSArray* __strong *)lengths lines:(NSArray* __strong *)lines isClosed:(BOOL*)isClosed;
@end
+198 -14
View File
@@ -8,28 +8,212 @@
#import "RNSVGTextPath.h"
#import "BezierElement.h"
/* Some Bezier logic from PerformanceBezier */
/*
## License
<a rel="license" href="http://creativecommons.org/licenses/by/3.0/us/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/3.0/us/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/3.0/us/">Creative Commons Attribution 3.0 United States License</a>.
For attribution, please include:
1. Mention original author "Adam Wulf for Loose Leaf app"
2. Link to https://getlooseleaf.com/opensource/
3. Link to https://github.com/adamwulf/PerformanceBezier
*/
static CGFloat idealFlatness = .01;
/**
* returns the distance between two points
*/
CGFloat distance(CGPoint p1, CGPoint p2)
{
CGFloat dx = p2.x - p1.x;
CGFloat dy = p2.y - p1.y;
return hypot(dx, dy);
}
// Subdivide a Bézier (specific division)
/*
* (c) 2004 Alastair J. Houghton
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. The name of the author of this software may not be used to endorse
* or promote products derived from the software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY DIRECT, INDIRECT,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
void subdivideBezierAtT(const CGPoint bez[4], CGPoint bez1[4], CGPoint bez2[4], CGFloat t)
{
CGPoint q;
CGFloat mt = 1 - t;
bez1[0].x = bez[0].x;
bez1[0].y = bez[0].y;
bez2[3].x = bez[3].x;
bez2[3].y = bez[3].y;
q.x = mt * bez[1].x + t * bez[2].x;
q.y = mt * bez[1].y + t * bez[2].y;
bez1[1].x = mt * bez[0].x + t * bez[1].x;
bez1[1].y = mt * bez[0].y + t * bez[1].y;
bez2[2].x = mt * bez[2].x + t * bez[3].x;
bez2[2].y = mt * bez[2].y + t * bez[3].y;
bez1[2].x = mt * bez1[1].x + t * q.x;
bez1[2].y = mt * bez1[1].y + t * q.y;
bez2[1].x = mt * q.x + t * bez2[2].x;
bez2[1].y = mt * q.y + t * bez2[2].y;
bez1[3].x = bez2[0].x = mt * bez1[2].x + t * bez2[1].x;
bez1[3].y = bez2[0].y = mt * bez1[2].y + t * bez2[1].y;
}
void addLine(CGPoint *last, const CGPoint *next, NSMutableArray *lines, CGFloat *length, NSMutableArray *lengths) {
NSArray *line = @[[NSValue valueWithCGPoint:*last], [NSValue valueWithCGPoint:*next]];
[lines addObject:line];
*length += distance(*last, *next);
[lengths addObject:[NSNumber numberWithDouble:*length]];
*last = *next;
}
@implementation RNSVGTextPath
{
CGPathRef _path;
NSMutableArray *lengths;
NSMutableArray *lines;
NSUInteger lineCount;
CGFloat length;
BOOL isClosed;
}
- (void)getPathLength:(CGFloat*)lengthP lineCount:(NSUInteger*)lineCountP lengths:(NSArray* __strong *)lengthsP lines:(NSArray* __strong *)linesP isClosed:(BOOL*)isClosedP
{
RNSVGSvgView *svg = [self getSvgView];
RNSVGNode *template = [svg getDefinedTemplate:self.href];
CGPathRef path = [template getPath:nil];
if (_path != path) {
_path = path;
CGPoint origin = CGPointMake (0.0, 0.0);
CGPoint last = CGPointMake (0.0, 0.0);
lengths = [NSMutableArray array];
lines = [NSMutableArray array];
isClosed = NO;
lineCount = 0;
length = 0;
NSArray *elements = [BezierElement elementsFromCGPath:path];
for (BezierElement *element in elements) {
switch (element.elementType)
{
case kCGPathElementMoveToPoint:
origin = last = element.point;
break;
case kCGPathElementAddLineToPoint: {
CGPoint next = element.point;
addLine(&last, &next, lines, &length, lengths);
lineCount++;
break;
}
case kCGPathElementAddQuadCurveToPoint:
case kCGPathElementAddCurveToPoint:
{
// handle both curve types gracefully
CGPoint curveTo = element.point;
CGPoint ctrl1 = element.controlPoint1;
CGPoint ctrl2 = element.elementType == kCGPathElementAddQuadCurveToPoint ? ctrl1 : element.controlPoint2;
// this is the bezier for our current element
CGPoint bezier[4] = { last, ctrl1, ctrl2, curveTo };
NSValue *arr = [NSValue valueWithBytes:&bezier objCType:@encode(CGPoint[4])];
NSMutableArray *curves = [NSMutableArray arrayWithObjects:arr, nil];
for (NSInteger curveIndex = 0; curveIndex >= 0; curveIndex--) {
CGPoint bez[4];
[curves[curveIndex] getValue:&bez];
[curves removeLastObject];
// calculate the error rate of the curve vs
// a line segment between the start and end points
CGPoint ctrl1 = bez[1];
CGPoint ctrl2 = bez[2];
CGPoint next = bez[3];
CGFloat polyLen =
distance(last, ctrl1) +
distance(ctrl1, ctrl2) +
distance(ctrl2, next);
CGFloat chordLen = distance(last, next);
CGFloat error = polyLen - chordLen;
// if the error is less than our accepted level of error
// then add a line, else, split the curve in half
if (error <= idealFlatness) {
addLine(&last, &next, lines, &length, lengths);
lineCount++;
} else {
CGPoint bez1[4], bez2[4];
subdivideBezierAtT(bez, bez1, bez2, .5);
[curves addObject:[NSValue valueWithBytes:&bez2 objCType:@encode(CGPoint[4])]];
[curves addObject:[NSValue valueWithBytes:&bez1 objCType:@encode(CGPoint[4])]];
curveIndex += 2;
}
}
break;
}
case kCGPathElementCloseSubpath: {
CGPoint next = origin;
addLine(&last, &next, lines, &length, lengths);
lineCount++;
isClosed = YES;
break;
}
default:
break;
}
}
}
*lineCountP = lineCount;
*isClosedP = isClosed;
*lengthsP = lengths;
*lengthP = length;
*linesP = lines;
}
- (void)renderLayerTo:(CGContextRef)context
{
[self renderGroupTo:context];
}
- (RNSVGPath *)getPath
{
RNSVGSvgView *svg = [self getSvgView];
RNSVGNode *template = [svg getDefinedTemplate:self.href];
if ([template class] != [RNSVGPath class]) {
// warning about this.
return nil;
}
RNSVGPath *path = (RNSVGPath *)template;
return path;
}
- (CGPathRef)getPath:(CGContextRef)context
{
return [self getGroupPath:context];
+25
View File
@@ -0,0 +1,25 @@
/*
Erica Sadun, http://ericasadun.com
https://github.com/erica/iOS-Drawing/tree/master/C08/Quartz%20Book%20Pack/Bezier
*/
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#define NULLPOINT CGRectNull.origin
@interface BezierElement : NSObject
// Element storage
@property (nonatomic, assign) CGPathElementType elementType;
@property (nonatomic, assign) CGPoint point;
@property (nonatomic, assign) CGPoint controlPoint1;
@property (nonatomic, assign) CGPoint controlPoint2;
// Instance creation
+ (instancetype) elementWithPathElement: (CGPathElement) element;
+ (NSArray *) elementsFromCGPath:(CGPathRef)path;
@end;
+77
View File
@@ -0,0 +1,77 @@
/*
Erica Sadun, http://ericasadun.com
https://github.com/erica/iOS-Drawing/tree/master/C08/Quartz%20Book%20Pack/Bezier
*/
#import "BezierElement.h"
#pragma mark - Bezier Element -
@implementation BezierElement
- (instancetype) init
{
self = [super init];
if (self)
{
_elementType = kCGPathElementMoveToPoint;
_point = NULLPOINT;
_controlPoint1 = NULLPOINT;
_controlPoint2 = NULLPOINT;
}
return self;
}
+ (instancetype) elementWithPathElement: (CGPathElement) element
{
BezierElement *newElement = [[self alloc] init];
newElement.elementType = element.type;
switch (newElement.elementType)
{
case kCGPathElementCloseSubpath:
break;
case kCGPathElementMoveToPoint:
case kCGPathElementAddLineToPoint:
{
newElement.point = element.points[0];
break;
}
case kCGPathElementAddQuadCurveToPoint:
{
newElement.point = element.points[1];
newElement.controlPoint1 = element.points[0];
break;
}
case kCGPathElementAddCurveToPoint:
{
newElement.point = element.points[2];
newElement.controlPoint1 = element.points[0];
newElement.controlPoint2 = element.points[1];
break;
}
default:
break;
}
return newElement;
}
// Convert one element to BezierElement and save to array
void GetBezierElements(void *info, const CGPathElement *element)
{
NSMutableArray *bezierElements = (__bridge NSMutableArray *)info;
if (element)
[bezierElements addObject:[BezierElement elementWithPathElement:*element]];
}
// Retrieve array of component elements
+ (NSArray *) elementsFromCGPath:(CGPathRef)path
{
NSMutableArray *elements = [NSMutableArray array];
CGPathApply(path, (__bridge void *)elements, GetBezierElements);
return elements;
}
@end
-2
View File
@@ -13,7 +13,6 @@
#import <React/RCTConvert.h>
#import "RNSVGCGFCRule.h"
#import "RNSVGVBMOS.h"
#import "RNSVGTextAnchor.h"
#import "RNSVGUnits.h"
#import "RNSVGPathParser.h"
@@ -21,7 +20,6 @@
@interface RCTConvert (RNSVG)
+ (RNSVGTextAnchor)RNSVGTextAnchor:(id)json;
+ (RNSVGCGFCRule)RNSVGCGFCRule:(id)json;
+ (RNSVGVBMOS)RNSVGVBMOS:(id)json;
+ (RNSVGUnits)RNSVGUnits:(id)json;
-7
View File
@@ -26,13 +26,6 @@ RCT_ENUM_CONVERTER(RNSVGVBMOS, (@{
@"none": @(kRNSVGVBMOSNone)
}), kRNSVGVBMOSMeet, intValue)
RCT_ENUM_CONVERTER(RNSVGTextAnchor, (@{
@"auto": @(kRNSVGTextAnchorAuto),
@"start": @(kRNSVGTextAnchorStart),
@"middle": @(kRNSVGTextAnchorMiddle),
@"end": @(kRNSVGTextAnchorEnd)
}), kRNSVGTextAnchorAuto, intValue)
RCT_ENUM_CONVERTER(RNSVGUnits, (@{
@"objectBoundingBox": @(kRNSVGUnitsObjectBoundingBox),
@"userSpaceOnUse": @(kRNSVGUnitsUserSpaceOnUse),
-1
View File
@@ -13,6 +13,5 @@
- (instancetype) initWithPathString:(NSString *)d;
- (CGPathRef)getPath;
- (NSArray *)getBezierCurves;
@end
+8 -33
View File
@@ -9,14 +9,13 @@
#import "RNSVGPathParser.h"
#import <React/RCTLog.h>
#import "math.h"
#import "BezierElement.h"
@implementation RNSVGPathParser
{
NSString* _d;
NSString* _originD;
NSRegularExpression* _pathRegularExpression;
NSMutableArray<NSArray *>* _bezierCurves;
NSValue *_lastStartPoint;
float _penX;
float _penY;
float _penDownX;
@@ -42,7 +41,6 @@
{
CGMutablePathRef path = CGPathCreateMutable();
NSArray<NSTextCheckingResult *>* results = [_pathRegularExpression matchesInString:_d options:0 range:NSMakeRange(0, [_d length])];
_bezierCurves = [[NSMutableArray alloc] init];
unsigned long count = [results count];
if (count) {
@@ -121,15 +119,6 @@
return (CGPathRef)CFAutorelease(path);
}
- (NSArray *)getBezierCurves
{
if (!_bezierCurves) {
CGPathRelease([self getPath]);
}
return [_bezierCurves copy];
}
- (NSString *)getNextValue:(NSTextCheckingResult *)result
{
if (!result) {
@@ -158,9 +147,6 @@
_pivotX = _penX = x;
_pivotY = _penY = y;
CGPathMoveToPoint(path, nil, x, y);
_lastStartPoint = [NSValue valueWithCGPoint: CGPointMake(x, y)];
[_bezierCurves addObject: @[_lastStartPoint]];
}
- (void)line:(CGMutablePathRef)path x:(float)x y:(float)y
@@ -173,9 +159,6 @@
_pivotX = _penX = x;
_pivotY = _penY = y;
CGPathAddLineToPoint(path, nil, x, y);
NSValue * destination = [NSValue valueWithCGPoint:CGPointMake(x, y)];
[_bezierCurves addObject: @[destination, destination, destination]];
}
- (void)curve:(CGMutablePathRef)path c1x:(float)c1x c1y:(float)c1y c2x:(float)c2x c2y:(float)c2y ex:(float)ex ey:(float)ey
@@ -201,12 +184,6 @@
_penX = ex;
_penY = ey;
CGPathAddCurveToPoint(path, nil, c1x, c1y, c2x, c2y, ex, ey);
[_bezierCurves addObject: @[
[NSValue valueWithCGPoint:CGPointMake(c1x, c1y)],
[NSValue valueWithCGPoint:CGPointMake(c2x, c2y)],
[NSValue valueWithCGPoint:CGPointMake(ex, ey)]
]];
}
- (void)smoothCurve:(CGMutablePathRef)path c1x:(float)c1x c1y:(float)c1y ex:(float)ex ey:(float)ey
@@ -367,14 +344,13 @@
float cp2x = x + k * y;
float cp2y = y - k * x;
CGPathAddCurveToPoint(path,
nil,
cx + xx * cp1x + yx * cp1y,
cy + xy * cp1x + yy * cp1y,
cx + xx * cp2x + yx * cp2y,
cy + xy * cp2x + yy * cp2y,
cx + xx * x + yx * y,
cy + xy * x + yy * y);
float c1x = cx + xx * cp1x + yx * cp1y;
float c1y = cy + xy * cp1x + yy * cp1y;
float c2x = cx + xx * cp2x + yx * cp2y;
float c2y = cy + xy * cp2x + yy * cp2y;
float ex = cx + xx * x + yx * y;
float ey = cy + xy * x + yy * y;
CGPathAddCurveToPoint(path, nil, c1x, c1y, c2x, c2y, ex, ey);
}
}
@@ -385,7 +361,6 @@
_penY = _penDownY;
_penDownSet = NO;
CGPathCloseSubpath(path);
[_bezierCurves addObject: @[_lastStartPoint, _lastStartPoint, _lastStartPoint]];
}
}
-14
View File
@@ -1,14 +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.
*/
typedef CF_ENUM(int32_t, RNSVGTextAnchor) {
kRNSVGTextAnchorAuto,
kRNSVGTextAnchorStart,
kRNSVGTextAnchorMiddle,
kRNSVGTextAnchorEnd
};
-1
View File
@@ -9,7 +9,6 @@
#import "RNSVGTSpanManager.h"
#import "RNSVGTSpan.h"
#import "RNSVGTextAnchor.h"
#import "RCTConvert+RNSVG.h"
@implementation RNSVGTSpanManager
+17 -17
View File
@@ -16,7 +16,7 @@ function transformToMatrix(props, transform) {
const transformParser = peg.generate(`
{
const deg2rad = Math.PI / 180;
var deg2rad = Math.PI / 180;
/*
@@ -26,15 +26,15 @@ const transformParser = peg.generate(`
*/
function multiply_matrices(l, r) {
const [al, cl, el, bl, dl, fl] = l;
const [ar, cr, er, br, dr, fr] = r;
var [al, cl, el, bl, dl, fl] = l;
var [ar, cr, er, br, dr, fr] = r;
const a = al * ar + cl * br;
const c = al * cr + cl * dr;
const e = al * er + cl * fr + el;
const b = bl * ar + dl * br;
const d = bl * cr + dl * dr;
const f = bl * er + dl * fr + fl;
var a = al * ar + cl * br;
var c = al * cr + cl * dr;
var e = al * er + cl * fr + el;
var b = bl * ar + dl * br;
var d = bl * cr + dl * dr;
var f = bl * er + dl * fr + fl;
return [a, c, e, b, d, f];
}
@@ -44,7 +44,7 @@ transformList
= wsp* ts:transforms? wsp* { return ts; }
transforms
= t:transform commaWsp+ ts:transforms
= t:transform commaWsp* ts:transforms
{
return multiply_matrices(t, ts);
}
@@ -94,10 +94,10 @@ scale
rotate
= "rotate" wsp* "(" wsp* angle:number c:commaWspTwoNumbers? wsp* ")"
{
const cos = Math.cos(deg2rad * angle);
const sin = Math.sin(deg2rad * angle);
var cos = Math.cos(deg2rad * angle);
var sin = Math.sin(deg2rad * angle);
if (c !== null) {
const [x, y] = c;
var [x, y] = c;
return [
cos, -sin, cos * -x + -sin * -y + x,
sin, cos, sin * -x + cos * -y + y
@@ -147,15 +147,15 @@ integerConstant
= ds:digitSequence { return ds.join(""); }
floatingPointConstant
= fractionalConstant exponent?
/ digitSequence exponent
= f:(fractionalConstant exponent?) { return f.join(""); }
/ d:(digitSequence exponent) { return d.join(""); }
fractionalConstant "fractionalConstant"
fractionalConstant "fractionalConstant"
= d1:digitSequence? "." d2:digitSequence { return [d1 ? d1.join("") : null, ".", d2.join("")].join(""); }
/ d:digitSequence "." { return d.join(""); }
exponent
= [eE] sign? digitSequence
= e:([eE] sign? digitSequence) { return [e[0], e[1], e[2].join("")].join(""); }
sign
= [+-]
+1 -2
View File
@@ -19,8 +19,7 @@
"gradient"
],
"scripts": {
"lint": "eslint ./",
"postinstall": "node scripts/install.js"
"lint": "eslint ./"
},
"peerDependencies": {
"react-native": ">=0.50.0",
-20
View File
@@ -1,20 +0,0 @@
var path = require('path');
var ghdownload = require('github-download');
function downloadSubModuleFromGithub(user, repo, callback) {
var dist = path.join(process.cwd(), 'ios/' + repo);
console.log('\r\n Start downloading ' + repo + ' to `' + dist + '`');
ghdownload({user: user, repo: repo, ref: 'master'}, dist)
.on('end', function() {
console.log('Download ' + repo + ' library success!');
callback && callback();
})
.on('error', function (err) {
console.error('Download ' + repo + ' library from github failed with err:', err);
});
}
downloadSubModuleFromGithub('adamwulf', 'PerformanceBezier', function () {
downloadSubModuleFromGithub('magicismight', 'QuartzBookPack');
});