mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-05-30 05:31:01 +00:00
flattern text into several spans
flattern text into several spans (step 1, not finish yet)
This commit is contained in:
@@ -10,10 +10,10 @@
|
||||
#import "RNSVGPath.h"
|
||||
#import "RNSVGTextFrame.h"
|
||||
|
||||
@interface RNSVGText : RNSVGPath
|
||||
@interface RNSVGTSpan : RNSVGPath
|
||||
|
||||
@property (nonatomic, assign) CTTextAlignment alignment;
|
||||
@property (nonatomic, assign) RNSVGTextFrame textFrame;
|
||||
@property (nonatomic, assign) NSString
|
||||
@property (nonatomic, assign) NSString *line;
|
||||
@property (nonatomic, assign) NSString *dx;
|
||||
@property (nonatomic, assign) NSString *dy;
|
||||
|
||||
@end
|
||||
|
||||
+2
-116
@@ -6,131 +6,17 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "RNSVGText.h"
|
||||
#import "RNSVGTSpan.h"
|
||||
#import "RNSVGBezierPath.h"
|
||||
#import <CoreText/CoreText.h>
|
||||
|
||||
@implementation RNSVGText
|
||||
|
||||
static void RNSVGFreeTextFrame(RNSVGTextFrame frame)
|
||||
{
|
||||
if (frame.count) {
|
||||
// We must release each line before freeing up this struct
|
||||
for (int i = 0; i < frame.count; i++) {
|
||||
CFRelease(frame.lines[i]);
|
||||
}
|
||||
free(frame.lines);
|
||||
free(frame.widths);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setAlignment:(CTTextAlignment)alignment
|
||||
{
|
||||
[self invalidate];
|
||||
_alignment = alignment;
|
||||
}
|
||||
|
||||
- (void)setTextFrame:(RNSVGTextFrame)textFrame
|
||||
{
|
||||
RNSVGFreeTextFrame(_textFrame);
|
||||
[self invalidate];
|
||||
_textFrame = textFrame;
|
||||
}
|
||||
|
||||
- (void)setPath:(NSArray *)path
|
||||
{
|
||||
if (path == _path) {
|
||||
return;
|
||||
}
|
||||
[self invalidate];
|
||||
_path = path;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
RNSVGFreeTextFrame(_textFrame);
|
||||
}
|
||||
@implementation RNSVGTSpan
|
||||
|
||||
- (CGPathRef)getPath:(CGContextRef)context
|
||||
{
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
RNSVGTextFrame frame = self.textFrame;
|
||||
for (int i = 0; i < frame.count; i++) {
|
||||
CGFloat shift;
|
||||
CGFloat width = frame.widths[i];
|
||||
switch (self.alignment) {
|
||||
case kCTTextAlignmentRight:
|
||||
shift = width;
|
||||
break;
|
||||
case kCTTextAlignmentCenter:
|
||||
shift = width / 2;
|
||||
break;
|
||||
default:
|
||||
shift = 0;
|
||||
break;
|
||||
}
|
||||
// We should consider snapping this shift to device pixels to improve rendering quality
|
||||
// when a line has subpixel width.
|
||||
CGAffineTransform offset = CGAffineTransformMakeTranslation(-shift, frame.baseLine + frame.lineHeight * i + (self.path ? -frame.lineHeight : 0));
|
||||
|
||||
CGMutablePathRef line = [self setLinePath:frame.lines[i]];
|
||||
CGPathAddPath(path, &offset, line);
|
||||
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;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,10 +10,9 @@
|
||||
#import "RNSVGPath.h"
|
||||
#import "RNSVGTextFrame.h"
|
||||
|
||||
@interface RNSVGText : RNSVGPath
|
||||
@interface RNSVGText : RNSVGRenderable
|
||||
|
||||
@property (nonatomic, assign) CTTextAlignment alignment;
|
||||
@property (nonatomic, assign) RNSVGTextFrame textFrame;
|
||||
@property (nonatomic, copy) NSArray<NSArray *> *path;
|
||||
|
||||
@end
|
||||
|
||||
+45
-45
@@ -12,30 +12,30 @@
|
||||
|
||||
@implementation RNSVGText
|
||||
|
||||
static void RNSVGFreeTextFrame(RNSVGTextFrame frame)
|
||||
{
|
||||
if (frame.count) {
|
||||
// We must release each line before freeing up this struct
|
||||
for (int i = 0; i < frame.count; i++) {
|
||||
CFRelease(frame.lines[i]);
|
||||
}
|
||||
free(frame.lines);
|
||||
free(frame.widths);
|
||||
}
|
||||
}
|
||||
//static void RNSVGFreeTextFrame(RNSVGTextFrame frame)
|
||||
//{
|
||||
// if (frame.count) {
|
||||
// // We must release each line before freeing up this struct
|
||||
// for (int i = 0; i < frame.count; i++) {
|
||||
// CFRelease(frame.lines[i]);
|
||||
// }
|
||||
// free(frame.lines);
|
||||
// free(frame.widths);
|
||||
// }
|
||||
//}
|
||||
|
||||
- (void)setAlignment:(CTTextAlignment)alignment
|
||||
{
|
||||
[self invalidate];
|
||||
_alignment = alignment;
|
||||
}
|
||||
|
||||
- (void)setTextFrame:(RNSVGTextFrame)textFrame
|
||||
{
|
||||
RNSVGFreeTextFrame(_textFrame);
|
||||
[self invalidate];
|
||||
_textFrame = textFrame;
|
||||
}
|
||||
//
|
||||
//- (void)setTextFrame:(RNSVGTextFrame)textFrame
|
||||
//{
|
||||
// RNSVGFreeTextFrame(_textFrame);
|
||||
// [self invalidate];
|
||||
// _textFrame = textFrame;
|
||||
//}
|
||||
|
||||
- (void)setPath:(NSArray *)path
|
||||
{
|
||||
@@ -46,37 +46,37 @@ static void RNSVGFreeTextFrame(RNSVGTextFrame frame)
|
||||
_path = path;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
RNSVGFreeTextFrame(_textFrame);
|
||||
}
|
||||
//- (void)dealloc
|
||||
//{
|
||||
// RNSVGFreeTextFrame(_textFrame);
|
||||
//}
|
||||
|
||||
- (CGPathRef)getPath:(CGContextRef)context
|
||||
{
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
RNSVGTextFrame frame = self.textFrame;
|
||||
for (int i = 0; i < frame.count; i++) {
|
||||
CGFloat shift;
|
||||
CGFloat width = frame.widths[i];
|
||||
switch (self.alignment) {
|
||||
case kCTTextAlignmentRight:
|
||||
shift = width;
|
||||
break;
|
||||
case kCTTextAlignmentCenter:
|
||||
shift = width / 2;
|
||||
break;
|
||||
default:
|
||||
shift = 0;
|
||||
break;
|
||||
}
|
||||
// We should consider snapping this shift to device pixels to improve rendering quality
|
||||
// when a line has subpixel width.
|
||||
CGAffineTransform offset = CGAffineTransformMakeTranslation(-shift, frame.baseLine + frame.lineHeight * i + (self.path ? -frame.lineHeight : 0));
|
||||
|
||||
CGMutablePathRef line = [self setLinePath:frame.lines[i]];
|
||||
CGPathAddPath(path, &offset, line);
|
||||
CGPathRelease(line);
|
||||
}
|
||||
// RNSVGTextFrame frame = self.textFrame;
|
||||
// for (int i = 0; i < frame.count; i++) {
|
||||
// CGFloat shift;
|
||||
// CGFloat width = frame.widths[i];
|
||||
// switch (self.alignment) {
|
||||
// case kCTTextAlignmentRight:
|
||||
// shift = width;
|
||||
// break;
|
||||
// case kCTTextAlignmentCenter:
|
||||
// shift = width / 2;
|
||||
// break;
|
||||
// default:
|
||||
// shift = 0;
|
||||
// break;
|
||||
// }
|
||||
// // We should consider snapping this shift to device pixels to improve rendering quality
|
||||
// // when a line has subpixel width.
|
||||
// CGAffineTransform offset = CGAffineTransformMakeTranslation(-shift, frame.baseLine + frame.lineHeight * i + (self.path ? -frame.lineHeight : 0));
|
||||
//
|
||||
// CGMutablePathRef line = [self setLinePath:frame.lines[i]];
|
||||
// CGPathAddPath(path, &offset, line);
|
||||
// CGPathRelease(line);
|
||||
// }
|
||||
|
||||
return (CGPathRef)CFAutorelease(path);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user