mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-05-28 04:55:12 +00:00
finish basic text support on iOS
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
|
||||
- (instancetype)initWithBezierCurves:(NSArray *)bezierCurves
|
||||
{
|
||||
|
||||
if (self = [super init]) {
|
||||
_bezierCurves = bezierCurves;
|
||||
_bezierIndex = 0;
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreText/CoreText.h>
|
||||
#import "RNSVGPath.h"
|
||||
#import "RNSVGTextFrame.h"
|
||||
|
||||
@interface RNSVGSpan : RNSVGPath
|
||||
|
||||
@property (nonatomic, assign) CGFloat *dx;
|
||||
@property (nonatomic, assign) CGFloat *dy;
|
||||
@property (nonatomic, assign) NSString *px;
|
||||
@property (nonatomic, assign) NSString *py;
|
||||
@property (nonatomic, strong) NSString *px;
|
||||
@property (nonatomic, strong) NSString *py;
|
||||
@property (nonatomic, assign) CTFontRef font;
|
||||
@property (nonatomic, strong) NSString *content;
|
||||
|
||||
@end
|
||||
|
||||
+66
-1
@@ -6,17 +6,82 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
|
||||
#import "RNSVGSpan.h"
|
||||
#import "RNSVGBezierPath.h"
|
||||
#import <CoreText/CoreText.h>
|
||||
|
||||
@implementation RNSVGSpan
|
||||
|
||||
- (CGPathRef)getPath:(CGContextRef)context
|
||||
{
|
||||
[self setBoundingBox:CGContextGetClipBoundingBox(context)];
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
|
||||
if (![self.content isEqualToString:@""]) {
|
||||
// Create a dictionary for this font
|
||||
CFDictionaryRef attributes = (__bridge CFDictionaryRef)@{
|
||||
(NSString *)kCTFontAttributeName: (__bridge id)self.font,
|
||||
(NSString *)kCTForegroundColorFromContextAttributeName: @YES
|
||||
};
|
||||
|
||||
CFStringRef string = (__bridge CFStringRef)self.content;
|
||||
CFAttributedStringRef attrString = CFAttributedStringCreate(kCFAllocatorDefault, string, attributes);
|
||||
CTLineRef line = CTLineCreateWithAttributedString(attrString);
|
||||
CFRelease(attrString);
|
||||
|
||||
CGMutablePathRef linePath = [self setLinePath:line];
|
||||
|
||||
// Set up text frame with font metrics
|
||||
CGFloat size = CTFontGetSize(self.font);
|
||||
CGFloat px = self.px ? [self getWidthRelatedValue:self.px] : 0;
|
||||
CGFloat py = self.py ? [self getHeightRelatedValue:self.py] : 0;
|
||||
|
||||
CGAffineTransform offset = CGAffineTransformMakeTranslation(px, size + py);
|
||||
|
||||
CGPathAddPath(path, &offset, linePath);
|
||||
CGPathRelease(linePath);
|
||||
}
|
||||
|
||||
return (CGPathRef)CFAutorelease(path);
|
||||
}
|
||||
|
||||
- (CGMutablePathRef)setLinePath:(CTLineRef)line
|
||||
{
|
||||
CGAffineTransform upsideDown = CGAffineTransformMakeScale(1.0, -1.0);
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
|
||||
CFArrayRef glyphRuns = CTLineGetGlyphRuns(line);
|
||||
CTRunRef run = CFArrayGetValueAtIndex(glyphRuns, 0);
|
||||
|
||||
CFIndex runGlyphCount = CTRunGetGlyphCount(run);
|
||||
CGPoint positions[runGlyphCount];
|
||||
CGGlyph glyphs[runGlyphCount];
|
||||
|
||||
// Grab the glyphs, positions, and font
|
||||
CTRunGetPositions(run, CFRangeMake(0, 0), positions);
|
||||
CTRunGetGlyphs(run, CFRangeMake(0, 0), glyphs);
|
||||
CFDictionaryRef attributes = CTRunGetAttributes(run);
|
||||
|
||||
CTFontRef runFont = CFDictionaryGetValue(attributes, kCTFontAttributeName);
|
||||
|
||||
for(CFIndex i = 0; i < runGlyphCount; ++i) {
|
||||
CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyphs[i], nil);
|
||||
CGPoint point = positions[i];
|
||||
|
||||
if (letter) {
|
||||
CGAffineTransform transform;
|
||||
|
||||
transform = CGAffineTransformTranslate(upsideDown, point.x, point.y);
|
||||
|
||||
|
||||
CGPathAddPath(path, &transform, letter);
|
||||
}
|
||||
|
||||
CGPathRelease(letter);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,10 +7,9 @@
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "RNSVGPath.h"
|
||||
#import "RNSVGTextFrame.h"
|
||||
#import "RNSVGGroup.h"
|
||||
|
||||
@interface RNSVGText : RNSVGRenderable
|
||||
@interface RNSVGText : RNSVGGroup
|
||||
|
||||
@property (nonatomic, assign) CTTextAlignment alignment;
|
||||
@property (nonatomic, copy) NSArray<NSArray *> *path;
|
||||
|
||||
+49
-55
@@ -39,9 +39,56 @@
|
||||
// RNSVGFreeTextFrame(_textFrame);
|
||||
//}
|
||||
|
||||
- (void)renderLayerTo:(CGContextRef)context
|
||||
{
|
||||
CGFloat shift = [self getShift:context path:nil];
|
||||
// translate path by alignment offset
|
||||
CGContextSaveGState(context);
|
||||
CGContextConcatCTM(context, CGAffineTransformMakeTranslation(-shift, 0));
|
||||
[super renderLayerTo:context];
|
||||
CGContextRestoreGState(context);
|
||||
}
|
||||
|
||||
- (CGPathRef)getPath:(CGContextRef)context
|
||||
{
|
||||
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
CGPathRef collection = [super getPath:context];
|
||||
CGFloat shift = [self getShift:context path:collection];
|
||||
|
||||
CGAffineTransform align = CGAffineTransformMakeTranslation(shift, 0);
|
||||
CGPathAddPath(path, &align, collection);
|
||||
CGPathRelease(collection);
|
||||
|
||||
return (CGPathRef)CFAutorelease(path);
|
||||
}
|
||||
|
||||
- (CGFloat)getShift:(CGContextRef)context path:(CGPathRef)path
|
||||
{
|
||||
if (!path) {
|
||||
path = [super getPath:context];
|
||||
}
|
||||
|
||||
CGFloat width = CGPathGetBoundingBox(path).size.width;
|
||||
CGFloat shift;
|
||||
switch (self.alignment) {
|
||||
case kCTTextAlignmentRight:
|
||||
shift = width;
|
||||
break;
|
||||
case kCTTextAlignmentCenter:
|
||||
shift = width / 2;
|
||||
break;
|
||||
default:
|
||||
shift = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return shift;
|
||||
}
|
||||
|
||||
//- (CGPathRef)getPath:(CGContextRef)context
|
||||
//{
|
||||
// CGMutablePathRef path = CGPathCreateMutable();
|
||||
// RNSVGTextFrame frame = self.textFrame;
|
||||
// for (int i = 0; i < frame.count; i++) {
|
||||
// CGFloat shift;
|
||||
@@ -66,59 +113,6 @@
|
||||
// CGPathRelease(line);
|
||||
// }
|
||||
|
||||
return (CGPathRef)CFAutorelease(path);
|
||||
}
|
||||
|
||||
- (CGMutablePathRef)setLinePath:(CTLineRef)line
|
||||
{
|
||||
CGAffineTransform upsideDown = CGAffineTransformMakeScale(1.0, -1.0);
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
|
||||
CFArrayRef glyphRuns = CTLineGetGlyphRuns(line);
|
||||
CTRunRef run = CFArrayGetValueAtIndex(glyphRuns, 0);
|
||||
|
||||
CFIndex runGlyphCount = CTRunGetGlyphCount(run);
|
||||
CGPoint positions[runGlyphCount];
|
||||
CGGlyph glyphs[runGlyphCount];
|
||||
|
||||
// Grab the glyphs, positions, and font
|
||||
CTRunGetPositions(run, CFRangeMake(0, 0), positions);
|
||||
CTRunGetGlyphs(run, CFRangeMake(0, 0), glyphs);
|
||||
CFDictionaryRef attributes = CTRunGetAttributes(run);
|
||||
|
||||
CTFontRef runFont = CFDictionaryGetValue(attributes, kCTFontAttributeName);
|
||||
|
||||
RNSVGBezierPath *bezierPath = [[RNSVGBezierPath alloc] initWithBezierCurves:self.path];
|
||||
|
||||
for(CFIndex i = 0; i < runGlyphCount; ++i) {
|
||||
CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyphs[i], nil);
|
||||
CGPoint point = positions[i];
|
||||
|
||||
if (letter) {
|
||||
CGAffineTransform transform;
|
||||
|
||||
// draw glyphs along path
|
||||
if (self.path) {
|
||||
transform = [bezierPath transformAtDistance:point.x];
|
||||
|
||||
// break loop if line reaches the end of the Path.
|
||||
if (!transform.a || !transform.d) {
|
||||
CGPathRelease(letter);
|
||||
break;
|
||||
}
|
||||
transform = CGAffineTransformScale(transform, 1.0, -1.0);
|
||||
} else {
|
||||
transform = CGAffineTransformTranslate(upsideDown, point.x, point.y);
|
||||
}
|
||||
|
||||
|
||||
CGPathAddPath(path, &transform, letter);
|
||||
}
|
||||
|
||||
CGPathRelease(letter);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
// return (CGPathRef)CFAutorelease(path);
|
||||
//}
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user