Commit 16756c26 authored by George Nachman's avatar George Nachman

Add a fast path for drawing ASCII text. This disables ligatures for...

Add a fast path for drawing ASCII text. This disables ligatures for alphabetic, numeric, and space characters when using a font with ligatures (or for all ASCII characters when the font does not support ligatures), and uses a much faster drawing algorithm for them. It demonstrates a 33% speedup for vimdiff output on my iMac.
parent 183b29bf
......@@ -8,13 +8,49 @@
#import <Foundation/Foundation.h>
#define ENABLE_TEXT_DRAWING_FAST_PATH 1
@protocol iTermAttributedString<NSObject>
@property (readonly) NSUInteger length;
- (void)addAttribute:(NSString *)name value:(id)value;
- (void)beginEditing;
- (void)endEditing;
- (void)appendAttributedString:(NSAttributedString *)attrString;
@end
// We don't render these characters with CoreText, so they will never get ligatures. This allows
// much better rendering performance because CoreText is very slow compared to Core Graphics.
static inline BOOL iTermCharacterSupportsFastPath(unichar code, BOOL asciiLigaturesAvailable) {
if (asciiLigaturesAvailable) {
return isalpha(code) || isnumber(code) || code == ' ';
} else {
return isascii(code);
}
}
@interface iTermMutableAttributedStringBuilder : NSObject
@property(nonatomic, readonly) NSMutableAttributedString *attributedString;
// Either a NSMutableAttributedString or an iTermCheapAttributedString
@property(nonatomic, readonly) id attributedString;
@property(nonatomic, copy) NSDictionary *attributes;
@property(nonatomic, readonly) NSInteger length;
@property(nonatomic, assign) BOOL asciiLigaturesAvailable;
- (void)appendString:(NSString *)string;
- (void)appendCharacter:(unichar)code;
@end
@interface iTermCheapAttributedString : NSObject<iTermAttributedString>
#warning An unsafe unretained reference to the buffer internal to the builder. This only works by accident and I need to improve it.
@property (nonatomic, readonly) unichar *characters;
@property (nonatomic, readonly) NSDictionary *attributes;
- (void)addAttribute:(NSString *)name value:(id)value;
@end
@interface NSMutableAttributedString(iTermMutableAttributedStringBuilder) <iTermAttributedString>
// Adds the attribute across the whole length of the string. For compat with
// how iTermCheapAttributedString works.
- (void)addAttribute:(NSString *)name value:(id)value;
@end
......@@ -8,22 +8,57 @@
#import "iTermMutableAttributedStringBuilder.h"
#import "NSMutableAttributedString+iTerm.h"
#import "NSDictionary+iTerm.h"
#define MAX_CHARACTERS 100
#warning Use a dynamically sized buffer to avoid wasting memory. Never stop because you hit the max size.
#define MAX_CHARACTERS 300
@interface iTermCheapAttributedString()
@property (nonatomic, assign) unichar *characters;
@property (assign) NSUInteger length;
@property (nonatomic, retain) NSDictionary *attributes;
@end
@implementation iTermCheapAttributedString
- (void)dealloc {
[_attributes release];
[super dealloc];
}
- (void)addAttribute:(NSString *)name value:(id)value {
self.attributes = [self.attributes dictionaryBySettingObject:value forKey:name];
}
- (void)beginEditing {
[self doesNotRecognizeSelector:_cmd];
}
- (void)endEditing {
[self doesNotRecognizeSelector:_cmd];
}
- (void)appendAttributedString:(NSAttributedString *)attrString {
[self doesNotRecognizeSelector:_cmd];
}
@end
@implementation iTermMutableAttributedStringBuilder {
NSMutableAttributedString *_attributedString;
id<iTermAttributedString> _attributedString;
NSMutableString *_string;
unichar _characters[MAX_CHARACTERS];
NSInteger _numCharacters;
BOOL _canUseFastPath;
}
- (instancetype)init {
self = [super init];
if (self) {
_attributedString = [[NSMutableAttributedString alloc] init];
[_attributedString beginEditing];
_string = [[NSMutableString alloc] init];
#if ENABLE_TEXT_DRAWING_FAST_PATH
_canUseFastPath = YES;
#endif
}
return self;
}
......@@ -45,22 +80,38 @@
}
- (void)build {
if (_canUseFastPath && !_attributedString && _numCharacters && !_string.length) {
iTermCheapAttributedString *cheap = [[iTermCheapAttributedString alloc] init];
cheap.characters = _characters;
cheap.length = _numCharacters;
cheap.attributes = _attributes;
_attributedString = cheap;
return;
}
if (_numCharacters) {
[self flushCharacters];
}
if (_string.length) {
_canUseFastPath = NO;
if (!_attributedString) {
_attributedString = [[NSMutableAttributedString alloc] init];
[_attributedString beginEditing];
}
[_attributedString appendAttributedString:[NSAttributedString attributedStringWithString:_string
attributes:_attributes]];
[_string setString:@""];
}
}
- (NSMutableAttributedString *)attributedString {
- (id<iTermAttributedString>)attributedString {
[self build];
[_attributedString endEditing];
if ([_attributedString isKindOfClass:[NSAttributedString class]]) {
[_attributedString endEditing];
}
return _attributedString;
}
- (void)appendString:(NSString *)string {
_canUseFastPath = NO;
if (_numCharacters) {
[self flushCharacters];
}
......@@ -69,10 +120,12 @@
- (void)flushCharacters {
[_string appendString:[NSString stringWithCharacters:_characters length:_numCharacters]];
_canUseFastPath = NO;
_numCharacters = 0;
}
- (void)appendCharacter:(unichar)code {
_canUseFastPath &= iTermCharacterSupportsFastPath(code, _asciiLigaturesAvailable);
if (_numCharacters == MAX_CHARACTERS) {
[self flushCharacters];
}
......@@ -84,3 +137,11 @@
}
@end
@implementation NSMutableAttributedString(iTermMutableAttributedStringBuilder)
- (void)addAttribute:(NSString *)name value:(id)value {
[self addAttribute:name value:value range:NSMakeRange(0, self.length)];
}
@end
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment