flattern text into several spans

flattern text into several spans (step 1, not finish yet)
This commit is contained in:
Horcrux
2016-09-02 10:24:33 +08:00
parent 13ddd15d09
commit 74b9917bd3
11 changed files with 214 additions and 209 deletions
+4 -4
View File
@@ -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
View File
@@ -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
+1 -2
View File
@@ -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
View File
@@ -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);
}