Implement TextPath: first step (iOS)
This commit is contained in:
Родитель
1d06134719
Коммит
52dfe21074
|
@ -12,7 +12,7 @@ class Shape extends Component {
|
|||
this.state = this.touchableGetInitialState();
|
||||
}
|
||||
|
||||
extractProps = (props, options) => {
|
||||
extractProps = (props = {}, options) => {
|
||||
let extractedProps = extractProps(props, options);
|
||||
if (extractedProps.touchable && !extractedProps.disabled) {
|
||||
_.assign(extractedProps, {
|
||||
|
|
|
@ -4,6 +4,7 @@ import {TextPathAttributes} from '../lib/attributes';
|
|||
import extractText from '../lib/extract/extractText';
|
||||
import Shape from './Shape';
|
||||
import {pathProps, fontProps} from '../lib/props';
|
||||
import TSpan from './TSpan';
|
||||
|
||||
const idExpReg = /^#(.+)$/;
|
||||
|
||||
|
@ -18,23 +19,29 @@ class TextPath extends Shape {
|
|||
};
|
||||
|
||||
render() {
|
||||
let {props} = this;
|
||||
let matched = props.href.match(idExpReg);
|
||||
let href;
|
||||
let {children, href, ...props} = this.props;
|
||||
if (href) {
|
||||
let matched = href.match(idExpReg);
|
||||
|
||||
if (matched) {
|
||||
href = matched[1];
|
||||
if (matched) {
|
||||
href = matched[1];
|
||||
|
||||
return <RNSVGTextPath
|
||||
href={href}
|
||||
{...this.extractProps({
|
||||
...props,
|
||||
x: null,
|
||||
y: null
|
||||
})}
|
||||
{...extractText({children}, true)}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
|
||||
if (!href) {
|
||||
console.warn('Invalid `href` prop for `TextPath` element, expected a href like `"#id"`, but got: "' + props.href + '"');
|
||||
}
|
||||
|
||||
return <RNSVGTextPath
|
||||
href={href}
|
||||
{...extractText({children: props.children})}
|
||||
/>;
|
||||
console.warn('Invalid `href` prop for `TextPath` element, expected a href like `"#id"`, but got: "' + props.href + '"');
|
||||
return <TSpan>{children}</TSpan>
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const RNSVGTextPath = createReactNativeComponentClass({
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
@interface RNSVGGroup : RNSVGPath <RNSVGContainer>
|
||||
|
||||
- (void)pathRenderLayerTo:(CGContextRef)contex;
|
||||
- (void)renderLayerToWithTransform:(CGContextRef)context transform:(CGAffineTransform)transform;
|
||||
- (void)renderPathTo:(CGContextRef)context;
|
||||
- (void)renderGroupTo:(CGContextRef)context;
|
||||
|
||||
@end
|
||||
|
|
|
@ -12,27 +12,21 @@
|
|||
|
||||
- (void)renderLayerTo:(CGContextRef)context
|
||||
{
|
||||
[self renderLayerToWithTransform:context transform:CGAffineTransformIdentity];
|
||||
[self clip:context];
|
||||
[self renderGroupTo:context];
|
||||
}
|
||||
|
||||
- (void)renderLayerToWithTransform:(CGContextRef)context transform:(CGAffineTransform)transform
|
||||
- (void)renderGroupTo:(CGContextRef)context
|
||||
{
|
||||
RNSVGSvgView* svg = [self getSvgView];
|
||||
[self clip:context];
|
||||
|
||||
CGContextConcatCTM(context, transform);
|
||||
[self traverseSubviews:^(RNSVGNode *node) {
|
||||
if (node.responsible && !svg.responsible) {
|
||||
svg.responsible = YES;
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}];
|
||||
|
||||
[self traverseSubviews:^(RNSVGNode *node) {
|
||||
|
||||
[node mergeProperties:self mergeList:self.attributeList inherited:YES];
|
||||
[node renderTo:context];
|
||||
|
||||
|
||||
if ([node isKindOfClass: [RNSVGRenderable class]]) {
|
||||
RNSVGRenderable *renderable = node;
|
||||
[self concatLayoutBoundingBox:[renderable getLayoutBoundingBox]];
|
||||
|
@ -41,7 +35,7 @@
|
|||
}];
|
||||
}
|
||||
|
||||
- (void)pathRenderLayerTo:(CGContextRef)context
|
||||
- (void)renderPathTo:(CGContextRef)context
|
||||
{
|
||||
[super renderLayerTo:context];
|
||||
}
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "RNSVGPathParser.h"
|
||||
#import "RNSVGRenderable.h"
|
||||
|
||||
@interface RNSVGPath : RNSVGRenderable
|
||||
|
||||
@property (nonatomic, assign) CGPathRef d;
|
||||
@property (nonatomic, strong) RNSVGPathParser *d;
|
||||
|
||||
- (NSArray *)getBezierCurves;
|
||||
|
||||
@end
|
||||
|
|
|
@ -9,26 +9,35 @@
|
|||
#import "RNSVGPath.h"
|
||||
|
||||
@implementation RNSVGPath
|
||||
{
|
||||
CGPathRef _path;
|
||||
}
|
||||
|
||||
- (void)setD:(CGPathRef)d
|
||||
- (void)setD:(RNSVGPathParser *)d
|
||||
{
|
||||
if (d == _d) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self invalidate];
|
||||
CGPathRelease(_d);
|
||||
_d = CGPathRetain(d);
|
||||
_d = d;
|
||||
CGPathRelease(_path);
|
||||
_path = CGPathRetain([d getPath]);
|
||||
}
|
||||
|
||||
- (CGPathRef)getPath:(CGContextRef)context
|
||||
{
|
||||
return self.d;
|
||||
return _path;
|
||||
}
|
||||
|
||||
- (NSArray *)getBezierCurves
|
||||
{
|
||||
return [_d getBezierCurves];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
CGPathRelease(_d);
|
||||
CGPathRelease(_path);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreText/CoreText.h>
|
||||
#import "RNSVGPath.h"
|
||||
#import "RNSVGText.h"
|
||||
|
||||
@interface RNSVGTSpan : RNSVGText
|
||||
|
|
|
@ -10,23 +10,29 @@
|
|||
#import "RNSVGTSpan.h"
|
||||
#import "RNSVGBezierPath.h"
|
||||
#import "RNSVGText.h"
|
||||
#import "RNSVGTextPath.h"
|
||||
|
||||
@implementation RNSVGTSpan
|
||||
{
|
||||
RNSVGBezierPath *_bezierPath;
|
||||
}
|
||||
|
||||
- (void)renderLayerTo:(CGContextRef)context
|
||||
{
|
||||
if (self.content) {
|
||||
[self pathRenderLayerTo:context];
|
||||
[self renderPathTo:context];
|
||||
} else {
|
||||
[super renderLayerTo:context];
|
||||
[self clip:context];
|
||||
[self renderGroupTo:context];
|
||||
}
|
||||
}
|
||||
|
||||
- (CGPathRef)getPath:(CGContextRef)context
|
||||
{
|
||||
if (!self.content) {
|
||||
return [self getTextGroupPath:context];
|
||||
return [self getGroupPath:context];
|
||||
}
|
||||
[self initialTextPath];
|
||||
[self setContextBoundingBox:CGContextGetClipBoundingBox(context)];
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
|
||||
|
@ -49,7 +55,7 @@
|
|||
CTLineRef line = CTLineCreateWithAttributedString(attrString);
|
||||
|
||||
CGMutablePathRef linePath = [self getLinePath:line];
|
||||
CGAffineTransform offset = CGAffineTransformMakeTranslation(0, CTFontGetSize(font));
|
||||
CGAffineTransform offset = CGAffineTransformMakeTranslation(0, _bezierPath ? 0 : CTFontGetSize(font) * 1.1);
|
||||
CGPathAddPath(path, &offset, linePath);
|
||||
|
||||
// clean up
|
||||
|
@ -57,7 +63,6 @@
|
|||
CFRelease(line);
|
||||
CGPathRelease(linePath);
|
||||
[self resetTextPathAttributes];
|
||||
|
||||
return (CGPathRef)CFAutorelease(path);
|
||||
}
|
||||
|
||||
|
@ -81,21 +86,63 @@
|
|||
CTFontRef runFont = CFDictionaryGetValue(attributes, kCTFontAttributeName);
|
||||
|
||||
CGFloat lineStartX;
|
||||
CGFloat lastX;
|
||||
for(CFIndex i = 0; i < runGlyphCount; i++) {
|
||||
RNSVGGlyphPoint computedPoint = [self getComputedGlyphPoint:i glyphOffset:positions[i]];
|
||||
|
||||
if (!i) {
|
||||
lineStartX = computedPoint.x;
|
||||
lastX = lineStartX;
|
||||
}
|
||||
|
||||
CGAffineTransform textPathTransform = [self getTextPathTransform:computedPoint.x];
|
||||
|
||||
if (!textPathTransform.a || !textPathTransform.d) {
|
||||
return path;
|
||||
}
|
||||
|
||||
CGAffineTransform transform = CGAffineTransformTranslate(upsideDown, computedPoint.x, -computedPoint.y);
|
||||
CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyphs[i], nil);
|
||||
CGAffineTransform transform;
|
||||
|
||||
if (_bezierPath) {
|
||||
transform = CGAffineTransformScale(textPathTransform, 1.0, -1.0);
|
||||
} else {
|
||||
transform = CGAffineTransformTranslate(upsideDown, computedPoint.x, -computedPoint.y);
|
||||
}
|
||||
|
||||
CGPathAddPath(path, &transform, letter);
|
||||
lastX += CGPathGetBoundingBox(letter).size.width;
|
||||
CGPathRelease(letter);
|
||||
}
|
||||
|
||||
[self getTextRoot].lastX = lineStartX + CGPathGetBoundingBox(path).size.width;
|
||||
[self getTextRoot].lastX = lastX;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
- (void)initialTextPath
|
||||
{
|
||||
__block RNSVGBezierPath *bezierPath;
|
||||
[self traverseTextSuperviews:^(__kindof RNSVGText *node) {
|
||||
if ([node class] == [RNSVGTextPath class]) {
|
||||
RNSVGTextPath *textPath = node;
|
||||
bezierPath = [node getBezierPath];
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}];
|
||||
|
||||
_bezierPath = bezierPath;
|
||||
}
|
||||
|
||||
- (CGAffineTransform)getTextPathTransform:(CGFloat)distance
|
||||
{
|
||||
if (_bezierPath) {
|
||||
return [_bezierPath transformAtDistance:distance];
|
||||
}
|
||||
|
||||
return CGAffineTransformIdentity;
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -27,7 +27,9 @@
|
|||
- (CTFontRef)getComputedFont;
|
||||
- (RNSVGGlyphPoint)getComputedGlyphPoint:(NSUInteger *)index glyphOffset:(CGPoint)glyphOffset;
|
||||
- (RNSVGText *)getTextRoot;
|
||||
- (CGPathRef)getTextGroupPath:(CGContextRef)context;
|
||||
- (CGAffineTransform)getTextPathTransform:(CGFloat)distance;
|
||||
- (CGPathRef)getGroupPath:(CGContextRef)context;
|
||||
- (void)resetTextPathAttributes;
|
||||
- (void)traverseTextSuperviews:(BOOL (^)(__kindof RNSVGText *node))block;
|
||||
|
||||
@end
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
#import "RNSVGText.h"
|
||||
#import "RNSVGBezierPath.h"
|
||||
#import "RNSVGTextPath.h"
|
||||
#import <React/RCTFont.h>
|
||||
#import <CoreText/CoreText.h>
|
||||
|
||||
|
@ -24,33 +24,39 @@
|
|||
|
||||
- (void)renderLayerTo:(CGContextRef)context
|
||||
{
|
||||
[self clip:context];
|
||||
CGContextSaveGState(context);
|
||||
CGAffineTransform transform = CGAffineTransformMakeTranslation([self getShift:context path:nil], 0);
|
||||
[super renderLayerToWithTransform:context transform:transform];
|
||||
CGContextConcatCTM(context, transform);
|
||||
[self renderGroupTo:context];
|
||||
[self resetTextPathAttributes];
|
||||
CGContextRestoreGState(context);
|
||||
}
|
||||
|
||||
- (CGPathRef)getPath:(CGContextRef)context
|
||||
{
|
||||
CGMutablePathRef shape = [self getTextGroupPath:context];
|
||||
CGAffineTransform translation = CGAffineTransformMakeTranslation([self getShift:context path:shape], 0);
|
||||
CGMutablePathRef path = CGPathCreateCopyByTransformingPath(shape, &translation);
|
||||
return (CGPathRef)CFAutorelease(path);
|
||||
CGPathRef path = [self getGroupPath:context];
|
||||
CGAffineTransform transform = CGAffineTransformMakeTranslation([self getShift:context path:path], 0);
|
||||
CGPathRef transformedPath = CGPathCreateCopyByTransformingPath(path, &transform);
|
||||
|
||||
// check memory leaks here
|
||||
//CGPathRelease(path);
|
||||
return (CGPathRef)CFAutorelease(transformedPath);
|
||||
}
|
||||
|
||||
- (CGPathRef)getTextGroupPath:(CGContextRef)context
|
||||
- (CGPathRef)getGroupPath:(CGContextRef)context
|
||||
{
|
||||
CGPathRef path = [super getPath:context];
|
||||
CGPathRef groupPath = [super getPath:context];
|
||||
[self resetTextPathAttributes];
|
||||
return path;
|
||||
return groupPath;
|
||||
}
|
||||
|
||||
- (CGFloat)getShift:(CGContextRef)context path:(CGPathRef)path
|
||||
{
|
||||
if (!path) {
|
||||
path = [self getTextGroupPath:context];
|
||||
if (path == nil) {
|
||||
path = [self getGroupPath:context];
|
||||
}
|
||||
|
||||
|
||||
CGFloat width = CGRectGetWidth(CGPathGetBoundingBox(path));
|
||||
|
||||
switch ([self getComputedTextAnchor]) {
|
||||
|
@ -74,7 +80,6 @@
|
|||
child = [child.subviews objectAtIndex:0];
|
||||
}
|
||||
}
|
||||
|
||||
return anchor;
|
||||
}
|
||||
|
||||
|
@ -112,7 +117,7 @@
|
|||
- (CTFontRef)getComputedFont
|
||||
{
|
||||
NSMutableDictionary *fontDict = [[NSMutableDictionary alloc] init];
|
||||
[self traverseTextSuperviews:^(RNSVGText *node) {
|
||||
[self traverseTextSuperviews:^(__kindof RNSVGText *node) {
|
||||
return [self extendFontFromInheritedFont:fontDict inheritedFont:node.font];
|
||||
}];
|
||||
|
||||
|
@ -132,38 +137,44 @@
|
|||
}
|
||||
fontFamily = fontFamilyFound ? fontFamily : nil;
|
||||
|
||||
return (__bridge CTFontRef)[RCTFont updateFont:nil withFamily:fontFamily size:fontDict[@"fontSize"] weight:fontDict[@"fontWeight"] style:fontDict[@"fontStyle"] variant:nil scaleMultiplier:1.0];
|
||||
return (__bridge CTFontRef)[RCTFont updateFont:nil
|
||||
withFamily:fontFamily
|
||||
size:fontDict[@"fontSize"]
|
||||
weight:fontDict[@"fontWeight"]
|
||||
style:fontDict[@"fontStyle"]
|
||||
variant:nil scaleMultiplier:1.0];
|
||||
}
|
||||
|
||||
- (RNSVGGlyphPoint)getComputedGlyphPoint:(NSUInteger *)index glyphOffset:(CGPoint)glyphOffset
|
||||
{
|
||||
RNSVGGlyphPoint __block point;
|
||||
__block RNSVGGlyphPoint point;
|
||||
point.isDeltaXSet = point.isDeltaYSet = point.isPositionXSet = point.isPositionYSet = NO;
|
||||
|
||||
[self traverseTextSuperviews:^(RNSVGText *node) {
|
||||
NSUInteger index = node.lastIndex;
|
||||
|
||||
if (!point.isPositionXSet && node.positionX && !index) {
|
||||
point.positionX = [self getWidthRelatedValue:node.positionX];
|
||||
point.isPositionXSet = YES;
|
||||
[self traverseTextSuperviews:^(__kindof RNSVGText *node) {
|
||||
if ([node class] != [RNSVGTextPath class]) {
|
||||
NSUInteger index = node.lastIndex;
|
||||
|
||||
if (!point.isPositionXSet && node.positionX && !index) {
|
||||
point.positionX = [self getWidthRelatedValue:node.positionX];
|
||||
point.isPositionXSet = YES;
|
||||
}
|
||||
|
||||
if (!point.isDeltaXSet && node.deltaX.count > index) {
|
||||
point.deltaX = [[node.deltaX objectAtIndex:index] floatValue];
|
||||
point.isDeltaXSet = YES;
|
||||
}
|
||||
|
||||
if (!point.isPositionYSet && node.positionY && !index) {
|
||||
point.positionY = [self getHeightRelatedValue:node.positionY];
|
||||
point.isPositionYSet = YES;
|
||||
}
|
||||
|
||||
if (!point.isDeltaYSet && node.deltaY.count > index) {
|
||||
point.deltaY = [[node.deltaY objectAtIndex:index] floatValue];
|
||||
point.isDeltaYSet = YES;
|
||||
}
|
||||
node.lastIndex++;
|
||||
}
|
||||
|
||||
if (!point.isDeltaXSet && node.deltaX.count > index) {
|
||||
point.deltaX = [[node.deltaX objectAtIndex:index] floatValue];
|
||||
point.isDeltaXSet = YES;
|
||||
}
|
||||
|
||||
if (!point.isPositionYSet && node.positionY && !index) {
|
||||
point.positionY = [self getHeightRelatedValue:node.positionY];
|
||||
point.isPositionYSet = YES;
|
||||
}
|
||||
|
||||
if (!point.isDeltaYSet && node.deltaY.count > index) {
|
||||
point.deltaY = [[node.deltaY objectAtIndex:index] floatValue];
|
||||
point.isDeltaYSet = YES;
|
||||
}
|
||||
|
||||
node.lastIndex++;
|
||||
return YES;
|
||||
}];
|
||||
|
||||
|
@ -192,14 +203,16 @@
|
|||
|
||||
point.x = lastX + glyphOffset.x;
|
||||
point.y = lastY + glyphOffset.y;
|
||||
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
|
||||
- (void)traverseTextSuperviews:(BOOL (^)(__kindof RNSVGText *node))block
|
||||
{
|
||||
RNSVGText *targetView = self;
|
||||
block(targetView);
|
||||
block(self);
|
||||
|
||||
while (targetView && [targetView class] != [RNSVGText class]) {
|
||||
if (![targetView isKindOfClass:[RNSVGText class]]) {
|
||||
//todo: throw exception here
|
||||
|
|
|
@ -8,11 +8,13 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreText/CoreText.h>
|
||||
#import "RNSVGPath.h"
|
||||
#import "RNSVGText.h"
|
||||
#import "RNSVGBezierPath.h"
|
||||
|
||||
@interface RNSVGTextPath : RNSVGText
|
||||
|
||||
@property (nonatomic, strong) NSString *href;
|
||||
|
||||
- (RNSVGBezierPath *)getBezierPath;
|
||||
|
||||
@end
|
||||
|
|
|
@ -10,14 +10,30 @@
|
|||
#import "RNSVGTextPath.h"
|
||||
#import "RNSVGBezierPath.h"
|
||||
|
||||
@class RNSVGText;
|
||||
@implementation RNSVGTextPath
|
||||
|
||||
- (void)renderLayerTo:(CGContextRef)context
|
||||
{
|
||||
[self renderGroupTo:context];
|
||||
}
|
||||
|
||||
- (CGPathRef)getPath:(CGContextRef)context
|
||||
{
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
return [self getGroupPath:context];
|
||||
}
|
||||
|
||||
return (CGPathRef)CFAutorelease(path);
|
||||
- (RNSVGBezierPath *)getBezierPath
|
||||
{
|
||||
RNSVGSvgView *svg = [self getSvgView];
|
||||
RNSVGNode *template = [svg getDefinedTemplate:self.href];
|
||||
|
||||
if ([template class] != [RNSVGPath class]) {
|
||||
// warning about this.
|
||||
return nil;
|
||||
}
|
||||
|
||||
RNSVGPath *path = template;
|
||||
return [[RNSVGBezierPath alloc] initWithBezierCurves:[path getBezierCurves]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -14,13 +14,14 @@
|
|||
#import "RNSVGCGFCRule.h"
|
||||
#import "RNSVGVBMOS.h"
|
||||
#import "RNSVGTextAnchor.h"
|
||||
#import "RNSVGPathParser.h"
|
||||
|
||||
@class RNSVGBrush;
|
||||
|
||||
@interface RCTConvert (RNSVG)
|
||||
|
||||
+ (RNSVGTextAnchor)RNSVGTextAnchor:(id)json;
|
||||
+ (CGPathRef)CGPath:(NSString *)d;
|
||||
+ (RNSVGPathParser *)CGPath:(NSString *)d;
|
||||
+ (CTTextAlignment)CTTextAlignment:(id)json;
|
||||
+ (RNSVGCGFCRule)RNSVGCGFCRule:(id)json;
|
||||
+ (RNSVGVBMOS)RNSVGVBMOS:(id)json;
|
||||
|
@ -28,7 +29,6 @@
|
|||
+ (RNSVGBrush *)RNSVGBrush:(id)json;
|
||||
|
||||
|
||||
+ (NSArray *)RNSVGBezier:(id)json;
|
||||
+ (CGRect)CGRect:(id)json offset:(NSUInteger)offset;
|
||||
+ (CGColorRef)CGColor:(id)json offset:(NSUInteger)offset;
|
||||
+ (CGGradientRef)CGGradient:(id)json offset:(NSUInteger)offset;
|
||||
|
|
|
@ -15,13 +15,12 @@
|
|||
#import "RNSVGCGFCRule.h"
|
||||
#import "RNSVGVBMOS.h"
|
||||
#import <React/RCTFont.h>
|
||||
#import "RNSVGPathParser.h"
|
||||
|
||||
@implementation RCTConvert (RNSVG)
|
||||
|
||||
+ (CGPathRef)CGPath:(NSString *)d
|
||||
+ (RNSVGPathParser *)CGPath:(NSString *)d
|
||||
{
|
||||
return [[[RNSVGPathParser alloc] initWithPathString: d] getPath];
|
||||
return [[RNSVGPathParser alloc] initWithPathString: d];
|
||||
}
|
||||
|
||||
RCT_ENUM_CONVERTER(RNSVGCGFCRule, (@{
|
||||
|
|
|
@ -6,12 +6,13 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface RNSVGPathParser : NSObject
|
||||
|
||||
- (instancetype) initWithPathString:(NSString *)d;
|
||||
- (CGPathRef)getPath;
|
||||
- (NSArray *)getBezierCurves;
|
||||
|
||||
@end
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
NSString* _d;
|
||||
NSString* _originD;
|
||||
NSRegularExpression* _pathRegularExpression;
|
||||
NSMutableArray<NSArray *>* _bezierCurves;
|
||||
NSValue *_lastStartPoint;
|
||||
double _penX;
|
||||
double _penY;
|
||||
double _penDownX;
|
||||
|
@ -39,8 +41,9 @@
|
|||
{
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
NSArray<NSTextCheckingResult *>* results = [_pathRegularExpression matchesInString:_d options:0 range:NSMakeRange(0, [_d length])];
|
||||
|
||||
_bezierCurves = [[NSMutableArray alloc] init];
|
||||
int count = [results count];
|
||||
|
||||
if (count) {
|
||||
NSUInteger i = 0;
|
||||
#define NEXT_VALUE [self getNextValue:results[i++]]
|
||||
|
@ -117,6 +120,15 @@
|
|||
return (CGPathRef)CFAutorelease(path);
|
||||
}
|
||||
|
||||
- (NSArray *)getBezierCurves
|
||||
{
|
||||
if (!_bezierCurves) {
|
||||
CGPathRelease([self getPath]);
|
||||
}
|
||||
|
||||
return [_bezierCurves copy];
|
||||
}
|
||||
|
||||
- (NSString *)getNextValue:(NSTextCheckingResult *)result
|
||||
{
|
||||
if (!result) {
|
||||
|
@ -145,6 +157,9 @@
|
|||
_pivotX = _penX = x;
|
||||
_pivotY = _penY = y;
|
||||
CGPathMoveToPoint(path, nil, x, y);
|
||||
|
||||
_lastStartPoint = [NSValue valueWithCGPoint: CGPointMake(x, y)];
|
||||
[_bezierCurves addObject: @[_lastStartPoint]];
|
||||
}
|
||||
|
||||
- (void)line:(CGPathRef)path x:(double)x y:(double)y
|
||||
|
@ -157,6 +172,13 @@
|
|||
_pivotX = _penX = x;
|
||||
_pivotY = _penY = y;
|
||||
CGPathAddLineToPoint(path, nil, x, y);
|
||||
|
||||
NSValue * destination = [NSValue valueWithCGPoint:CGPointMake(x, y)];
|
||||
[_bezierCurves addObject: @[
|
||||
destination,
|
||||
_lastStartPoint,
|
||||
destination
|
||||
]];
|
||||
}
|
||||
|
||||
- (void)curve:(CGPathRef)path c1x:(double)c1x c1y:(double)c1y c2x:(double)c2x c2y:(double)c2y ex:(double)ex ey:(double)ey
|
||||
|
@ -182,6 +204,13 @@
|
|||
_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:(CGPathRef)path c1x:(double)c1x c1y:(double)c1y ex:(double)ex ey:(double)ey
|
||||
|
@ -302,11 +331,7 @@
|
|||
_penX = _pivotX = x;
|
||||
_penY = _pivotY = y;
|
||||
|
||||
if (rx != ry || rad != 0) {
|
||||
[self arcToBezier:path cx:cx cy:cy rx:rx ry:ry sa:sa ea:ea clockwise:clockwise rad:rad];
|
||||
} else {
|
||||
CGPathAddArc(path, nil, cx, cy, rx, sa, ea, !clockwise);
|
||||
}
|
||||
[self arcToBezier:path cx:cx cy:cy rx:rx ry:ry sa:sa ea:ea clockwise:clockwise rad:rad];
|
||||
}
|
||||
|
||||
- (void)arcToBezier:(CGPathRef)path cx:(double)cx cy:(double)cy rx:(double)rx ry:(double)ry sa:(double)sa ea:(double)ea clockwise:(BOOL)clockwise rad:(double)rad
|
||||
|
@ -364,6 +389,7 @@
|
|||
_penY = _penDownY;
|
||||
_penDownSet = NO;
|
||||
CGPathCloseSubpath(path);
|
||||
[_bezierCurves addObject: @[]];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -98,9 +98,9 @@ const TextAttributes = merge({
|
|||
positionY: true
|
||||
}, RenderableAttributes);
|
||||
|
||||
const TextPathAttributes = {
|
||||
const TextPathAttributes = merge({
|
||||
href: true
|
||||
};
|
||||
}, RenderableAttributes);
|
||||
|
||||
const TSpanAttibutes = merge({
|
||||
content: true
|
||||
|
|
|
@ -79,7 +79,7 @@ function parseDelta(delta) {
|
|||
}
|
||||
}
|
||||
|
||||
export default function(props, isText) {
|
||||
export default function(props, container) {
|
||||
const {
|
||||
x,
|
||||
y,
|
||||
|
@ -95,7 +95,7 @@ export default function(props, isText) {
|
|||
let content = null;
|
||||
|
||||
if (typeof children === 'string') {
|
||||
if (isText) {
|
||||
if (container) {
|
||||
children = <TSpan>{children}</TSpan>;
|
||||
} else {
|
||||
content = children;
|
||||
|
|
Загрузка…
Ссылка в новой задаче