自定义CTLine结构

时间:2018-07-18 15:04:53

标签: objective-c macos performance cocoa core-text

我正在为我的项目创建自定义CTLine结构。这是一个非常简单的实现,因为它不使用CFAttributeString创建行。整行只有一种颜色,所有字形都具有相同的大小。但是CFString越长,创建它所需的时间就越多,并且比CTLineCreateWithAttributedString()慢。

#import <Cocoa/Cocoa.h>

#define sc (CFStringRef)

    struct Line {
        CGGlyph*line_glyphs;
        CGPoint*point;
        CTFontRef font;
        int length;
    };


    typedef  struct Line* LineRef;

    LineRef create(CFStringRef str, CTFontRef font);

    @interface View : NSView
    {
        LineRef line;
        CTLineRef l;
        CTFontRef font;
        CGFontRef font2;
        CFMutableStringRef string;

    }
 @end



 #import "View.h"
    #include <time.h>


    LineRef create(CFStringRef str, CTFontRef font){

        LineRef line = malloc(sizeof(struct Line));
        long length = CFStringGetLength(str);

        CGGlyph* gl = malloc(sizeof(CGGlyph)*length);
        CGPoint* points = malloc(sizeof(CGPoint)*length);
        CGRect rects[length];
        UniChar buffer[length];
        CFStringGetCharacters(str, CFRangeMake(0, length), buffer);
        CTFontGetGlyphsForCharacters(font, buffer, gl, length);
        CTFontGetBoundingRectsForGlyphs(font, kCTFontOrientationHorizontal, gl, rects, length);
        int x_offset  = 0;
        int y = 200;
        CGPoint temp;
        for(int i = 0;i<length;i++)
        {
            temp = CGPointMake(x_offset , y);
            x_offset += rects[i].size.width + (rects[i].size.width == 0)*10;

            points[i] = temp;
        }

        line->line_glyphs = gl;
        line->point = points;
        line->font = font;
        line->length = length;
        return line;
    }



    @implementation View


    -(void)awakeFromNib{
        font = CTFontCreateWithName(CFSTR("Comic Sans MS"), 30, 0);
        font2= CGFontCreateWithFontName(CFSTR("Comic Sans MS"));
        line = create(CFSTR(""), font);
        string = CFStringCreateMutable(kCFAllocatorDefault, 0);
        [[self window] makeFirstResponder:self];


    }



    -(void)keyDown:(NSEvent *)event{
        static int index = 0;

        NSString* i = [event characters];

        CFStringAppend(string,sc  i);
        CFMutableAttributedStringRef s = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
        CFAttributedStringReplaceString(s, CFRangeMake(0, 0), string);
        CFAttributedStringSetAttribute(s, CFRangeMake(0, CFStringGetLength(string)), kCTFontAttributeName, font);
        CFAbsoluteTime t1 = CFAbsoluteTimeGetCurrent();
        l = CTLineCreateWithAttributedString(s);
        CFAbsoluteTime t2 = CFAbsoluteTimeGetCurrent();
        double d1 = t2-t1;
        CFAbsoluteTime T1 = CFAbsoluteTimeGetCurrent();
        line = create(string, font);
        CFAbsoluteTime T2 = CFAbsoluteTimeGetCurrent();
        double d2 = T2 - T1;
        printf("test:%i core text: %f       my implem : %f \n",index, d1,d2);



        index++;
    }
@end

并输出:

  test:0 core text: 0.000761       my implem : 0.000016 
    test:1 core text: 0.000047       my implem : 0.000029 
    test:2 core text: 0.000041       my implem : 0.000027 
    test:3 core text: 0.000045       my implem : 0.000032 
    test:4 core text: 0.000045       my implem : 0.000032 
    test:5 core text: 0.000046       my implem : 0.000034
    ...
    test:176 core text: 0.000068     my implem : 0.000151 
    test:177 core text: 0.000084     my implem : 0.000171 
    test:178 core text: 0.000099     my implem : 0.000230 
    test:179 core text: 0.000061     my implem : 0.000145 
    test:180 core text: 0.000071     my implem : 0.000224 
    test:181 core text: 0.000057     my implem : 0.000149

您看到,最初的几个调用比创建CTLine更快,但是比起我的实现开始花费更多的时间来完成工作。 也许是多个CTFontGetGlyphsForCharacters()调用出错?您可以提出一些建议来加快此代码的速度吗?

1 个答案:

答案 0 :(得分:1)

tl; dr必要时使用CTLineCreateWithAttributedString()并继续;管道中的其他地方存在更大的性能问题。 CGContextDrawPath()是你真正的敌人。

我通过凭据的方式编写了一个iOS应用,该应用允许OSM's entire dataset向下渲染并显示在iPhone上-一直到人行道和建筑物。看起来像这样(请注意,人行道的所有小脚都是字体中的字形):

a map tile

我的管道看起来像这样:

  1. 选中每个字符串的边界框,并尽可能丢弃
  2. 在其余字符串上调用CTLineCreateWithAttributedString()
  3. 遍历每个CTRun并使用CTFontCreatePathForGlyph()获取每个字形路径。
  4. 选中每个路径的边界框,并尽可能丢弃。
  5. 呼叫CGContextDrawPath()其余路径

第1步和第4步是优化的地方。绘制摆动的线(字形)需要大量的计算,没有办法解决。唯一的制胜法宝是不玩¹

(要获得更多优化乐趣,请查看MinimumRubber,特别是MRPathMetrics函数,这些函数可用于避免使用昂贵的基于CGPath的函数)