Skip to content

Commit

Permalink
Fix crashing bug when printing binary files. Not sure of the exact ca…
Browse files Browse the repository at this point in the history
…use, but the code is much cleaner and full of asserts now.
  • Loading branch information
gnachman committed Dec 31, 2012
1 parent 837f1da commit 616f7e5
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 100 deletions.
31 changes: 4 additions & 27 deletions CharacterRun.h
Expand Up @@ -8,31 +8,7 @@

#import <Cocoa/Cocoa.h>
#import "PTYFontInfo.h"

@interface SharedCharacterRunData : NSObject {
int capacity_; // Allocated entries in codes, advances, glyphs arrays.
__weak unichar *codes_;
__weak CGSize *advances_;
__weak CGGlyph *glyphs_;
NSRange freeRange_;
}

@property (nonatomic, assign) __weak unichar* codes; // Shared pointer to code point(s) for this char.
@property (nonatomic, assign) __weak CGSize* advances; // Shared pointer to advances for each code.
@property (nonatomic, assign) __weak CGGlyph* glyphs; // Shared pointer to glyphs for these chars (single code point only)
@property (nonatomic, assign) NSRange freeRange; // Unused space at the end of the arrays.

+ (SharedCharacterRunData *)sharedCharacterRunDataWithCapacity:(int)capacity;

// Mark a number of cells beginning at freeRange.location as used.
- (void)advance:(int)positions;

// Makes sure there is room for at least 'space' more codes/advances/glyphs beyond what is used.
// Allocates more space if necessary. Call this before writing to shared pointers and before
// calling -advance:.
- (void)reserve:(int)space;

@end
#import "SharedCharacterRunData.h"

typedef enum {
kCharacterRunMultipleSimpleChars, // A run of cells with one code point each.
Expand Down Expand Up @@ -74,8 +50,9 @@ typedef enum {
- (void)appendCodesFromString:(NSString *)string withAdvance:(CGFloat)advance;
- (void)appendCode:(unichar)code withAdvance:(CGFloat)advance;

// For kCharacterRunMultipleSimpleChars, there is one advance but many parallel codes/glyphs.
// For kCharacterRunSingleCharWithCombiningMarks, codes/glyphs/advances are all parallel.
// Clear the allocated range.
- (void)clearAllocation;

- (unichar *)codes;
- (CGSize *)advances;
- (CGGlyph *)glyphs;
Expand Down
97 changes: 28 additions & 69 deletions CharacterRun.m
Expand Up @@ -9,50 +9,6 @@
#import "CharacterRun.h"
#import "ScreenChar.h"

@implementation SharedCharacterRunData

@synthesize codes = codes_;
@synthesize advances = advances_;
@synthesize glyphs = glyphs_;
@synthesize freeRange = freeRange_;

+ (SharedCharacterRunData *)sharedCharacterRunDataWithCapacity:(int)capacity {
SharedCharacterRunData *data = [[[SharedCharacterRunData alloc] init] autorelease];
data->capacity_ = capacity;
data.codes = malloc(sizeof(unichar) * capacity);
data.advances = malloc(sizeof(CGSize) * capacity);
data.glyphs = malloc(sizeof(CGGlyph) * capacity);
data.freeRange = NSMakeRange(0, capacity);
return data;
}

- (void)dealloc {
free(codes_);
free(advances_);
free(glyphs_);
[super dealloc];
}

- (void)advance:(int)positions {
freeRange_.location += positions;
assert(freeRange_.length >= positions);
freeRange_.length -= positions;
}

- (void)reserve:(int)space {
if (freeRange_.length < space) {
int newSize = (capacity_ + space) * 2;
int growth = newSize - capacity_;
capacity_ = newSize;
freeRange_.length += growth;
codes_ = realloc(codes_, sizeof(unichar) * capacity_);
advances_ = realloc(advances_, sizeof(CGSize) * capacity_);
glyphs_ = realloc(glyphs_, sizeof(CGGlyph) * capacity_);
}
}

@end

@implementation CharacterRun

@synthesize antiAlias = antiAlias_;
Expand Down Expand Up @@ -96,39 +52,37 @@ - (NSString *)description {
NSMutableString *d = [NSMutableString string];
[d appendFormat:@"<CharacterRun: %p codes=\"", self];
unichar *c = [self codes];
c += range_.location;
for (int i = 0; i < range_.length; i++) {
[d appendFormat:@"%x ", (int)c[i + range_.location]];
[d appendFormat:@"%x ", (((int)c[i]) & 0xffff)];
}
[d appendFormat:@"\">"];
return d;
}

- (unichar *)codes {
return sharedData_.codes + range_.location;
return [sharedData_ codesInRange:range_];
}

- (CGSize *)advances {
return sharedData_.advances + range_.location;
return [sharedData_ advancesInRange:range_];
}

- (CGGlyph *)glyphs {
return sharedData_.glyphs + range_.location;
return [sharedData_ glyphsInRange:range_];
}

// Given a run with codes x1,x2,...,xn, change self to have codes x1,x2,...,x(i-1).
// and return a new run (with the same attributes as self) with codes xi,x(i+1),...,xn.
- (CharacterRun *)splitBeforeIndex:(int)truncateBeforeIndex
{
CharacterRun *tailRun = [[self copy] autorelease];
assert(range_.length >= truncateBeforeIndex);
CGSize *advances = [self advances];

for (int i = 0; i < truncateBeforeIndex; ++i) {
tailRun.x += advances[i].width;
}
tailRun.range = NSMakeRange(tailRun.range.location + truncateBeforeIndex,
tailRun.range.length - truncateBeforeIndex);
range_.length = truncateBeforeIndex;
[sharedData_ advanceAllocation:&tailRun->range_ by:truncateBeforeIndex];
[sharedData_ truncateAllocation:&range_ toSize:truncateBeforeIndex];

return tailRun;
}
Expand All @@ -144,9 +98,7 @@ - (int)indexOfFirstMissingGlyph {
return -1;
}

// NOTE: Not idempotent! This calls [sharedData_ advance:].
- (void)appendRunsWithGlyphsToArray:(NSMutableArray *)newRuns {
[sharedData_ advance:range_.length];
[newRuns addObject:self];
if (runType_ == kCharacterRunSingleCharWithCombiningMarks) {
// These don't actually need glyphs. This algorithm is incompatible
Expand Down Expand Up @@ -225,15 +177,20 @@ - (void)appendRunsWithGlyphsToArray:(NSMutableArray *)newRuns {
}
if (i >= 0) {
isOk = CTFontGetGlyphsForCharacters((CTFontRef)currentRun.fontInfo.font,
[currentRun codes],
[currentRun glyphs],
[self codes],
[self glyphs],
currentRun.range.length);
} else {
break;
}
}
}

- (NSArray *)runsWithGlyphs
{
if (!range_.length) {
return nil;
}
NSMutableArray *newRuns = [NSMutableArray array];
[self appendRunsWithGlyphsToArray:newRuns];
return newRuns;
Expand All @@ -248,24 +205,26 @@ - (BOOL)isCompatibleWith:(CharacterRun *)otherRun {
antiAlias_ == otherRun.antiAlias);
}

- (void)appendAdvance:(CGFloat)width {
sharedData_.advances[range_.location + range_.length] = CGSizeMake(width, 0);
}

- (void)appendCode:(unichar)code withAdvance:(CGFloat)advance {
sharedData_.codes[range_.location + range_.length] = code;
[sharedData_ reserve:1];
[self appendAdvance:advance];
++range_.length;
[sharedData_ growAllocation:&range_ by:1];
unichar *codes = [self codes];
CGSize *advances = [self advances];
codes[range_.length - 1] = code;
advances[range_.length - 1] = CGSizeMake(advance, 0);
}

- (void)appendCodesFromString:(NSString *)string withAdvance:(CGFloat)advance {
int offset = range_.length;
int length = [string length];
[sharedData_ reserve:length];
[string getCharacters:[self codes]
[sharedData_ growAllocation:&range_ by:length];
[string getCharacters:[self codes] + offset
range:NSMakeRange(0, length)];
[self appendAdvance:advance];
range_.length += length;
CGSize *advances = [self advances];
advances[offset] = CGSizeMake(advance, 0);
}

- (void)clearAllocation {
range_ = NSMakeRange(0, 0);
}

@end
4 changes: 2 additions & 2 deletions PTYTextView.m
Expand Up @@ -6044,7 +6044,7 @@ - (void)_constructRuns:(NSPoint)initialPoint
}
// Begin a new run.
currentRun = [[thisChar copy] autorelease];
currentRun.range = NSMakeRange(sharedData.freeRange.location, 0);
[currentRun clearAllocation];
currentRun.sharedData = sharedData;
currentRun.x = curX;
}
Expand Down Expand Up @@ -6263,7 +6263,7 @@ - (void)_drawCharactersInLine:(screen_char_t*)theLine
indexRange:indexRange
bgColor:bgColor
matches:matches];

[self _drawRuns:initialPoint runs:runs];
}

Expand Down
33 changes: 33 additions & 0 deletions SharedCharacterRunData.h
@@ -0,0 +1,33 @@
//
// SharedCharacterRunData.h
// iTerm
//
// Created by George Nachman on 12/31/12.
//
//

#import <Foundation/Foundation.h>

@interface SharedCharacterRunData : NSObject {
int capacity_; // Allocated entries in codes, advances, glyphs arrays.
__weak unichar *codes_;
__weak CGSize *advances_;
__weak CGGlyph *glyphs_;
NSRange freeRange_;
}

+ (SharedCharacterRunData *)sharedCharacterRunDataWithCapacity:(int)capacity;

#pragma mark Modify allocated range

- (void)growAllocation:(NSRange *)allocation by:(int)growBy;
- (void)advanceAllocation:(NSRange *)allocation by:(int)advanceBy;
- (void)truncateAllocation:(NSRange *)allocation toSize:(int)newSize;

#pragma mark Access values in allocated range

- (unichar *)codesInRange:(NSRange)allocation;
- (CGSize *)advancesInRange:(NSRange)allocation;
- (CGGlyph *)glyphsInRange:(NSRange)allocation;

@end
116 changes: 116 additions & 0 deletions SharedCharacterRunData.m
@@ -0,0 +1,116 @@
//
// SharedCharacterRunData.m
// iTerm
//
// Created by George Nachman on 12/31/12.
//
//

#import "SharedCharacterRunData.h"

@interface SharedCharacterRunData ()

@property (nonatomic, assign) __weak unichar* codes; // Shared pointer to code point(s) for this char.
@property (nonatomic, assign) __weak CGSize* advances; // Shared pointer to advances for each code.
@property (nonatomic, assign) __weak CGGlyph* glyphs; // Shared pointer to glyphs for these chars (single code point only)
@property (nonatomic, assign) NSRange freeRange; // Unused space at the end of the arrays.

+ (SharedCharacterRunData *)sharedCharacterRunDataWithCapacity:(int)capacity;

// Mark a number of cells beginning at freeRange.location as used.
- (void)advance:(int)positions;

// Makes sure there is room for at least 'space' more codes/advances/glyphs beyond what is used.
// Allocates more space if necessary. Call this before writing to shared pointers and before
// calling -advance:.
- (void)reserve:(int)space;

@end

@implementation SharedCharacterRunData

@synthesize codes = codes_;
@synthesize advances = advances_;
@synthesize glyphs = glyphs_;
@synthesize freeRange = freeRange_;

+ (SharedCharacterRunData *)sharedCharacterRunDataWithCapacity:(int)capacity {
SharedCharacterRunData *data = [[[SharedCharacterRunData alloc] init] autorelease];
data->capacity_ = capacity;
data.codes = malloc(sizeof(unichar) * capacity);
data.advances = malloc(sizeof(CGSize) * capacity);
data.glyphs = malloc(sizeof(CGGlyph) * capacity);
data.freeRange = NSMakeRange(0, capacity);
return data;
}

- (void)dealloc {
free(codes_);
free(advances_);
free(glyphs_);
[super dealloc];
}

- (void)advance:(int)positions {
[self reserve:positions];
freeRange_.location += positions;
assert(freeRange_.length >= positions);
freeRange_.length -= positions;
}

- (void)reserve:(int)space {
if (freeRange_.length < space) {
int newSize = (capacity_ + space) * 2;
int growth = newSize - capacity_;
capacity_ = newSize;
freeRange_.length += growth;
codes_ = realloc(codes_, sizeof(unichar) * capacity_);
advances_ = realloc(advances_, sizeof(CGSize) * capacity_);
glyphs_ = realloc(glyphs_, sizeof(CGGlyph) * capacity_);
}
}

- (void)growAllocation:(NSRange *)range by:(int)growBy {
assert(growBy > 0);
if (!range->length) {
assert(!range->location);
int offset = freeRange_.location;
[self advance:growBy];
range->length = growBy;
range->location = offset;
} else {
assert(range->length >= 0);
assert(range->location + range->length == freeRange_.location);
[self advance:growBy];
range->length += growBy;
}
}

- (unichar *)codesInRange:(NSRange)range {
assert(range.location + range.length <= freeRange_.location);
return codes_ + range.location;
}

- (CGSize *)advancesInRange:(NSRange)range {
assert(range.location + range.length <= freeRange_.location);
return advances_ + range.location;
}

- (CGGlyph *)glyphsInRange:(NSRange)range {
assert(range.location + range.length <= freeRange_.location);
return glyphs_ + range.location;
}

- (void)advanceAllocation:(NSRange *)range by:(int)advanceBy {
assert(range->length >= advanceBy);
range->location += advanceBy;
range->length -= advanceBy;
}

- (void)truncateAllocation:(NSRange *)range toSize:(int)newSize {
assert(newSize <= range->length);
assert(newSize >= 0);
range->length = newSize;
}

@end

0 comments on commit 616f7e5

Please sign in to comment.