Skip to content
Snippets Groups Projects
Commit eee4f861 authored by George Nachman's avatar George Nachman
Browse files

Fix bug 2694, which crashes when a dimmed color happens to be the same as a...

Fix bug 2694, which crashes when a dimmed color happens to be the same as a previously used color, and didn't get retained by CRunStorage because it used value equality instead of pointer equality.
parent f5bd2cb8
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -11,6 +11,8 @@
#import <ApplicationServices/ApplicationServices.h>
#import "ScreenChar.h"
 
@class CRunSet;
// Backing storage for CRuns.
@interface CRunStorage : NSObject {
// There are |capacity_| elements in each of these, of which |used_|
Loading
Loading
@@ -24,7 +26,7 @@
int used_; // Number of elements in use.
 
// Like an autorelease pool, but avoids multiple retain/release's per object.
NSMutableSet *colors_;
CRunSet *colors_;
}
 
// Create a new CRunStorage with space preallocated for |capacity| characters.
Loading
Loading
Loading
Loading
@@ -9,6 +9,52 @@
#import "CharacterRun.h"
#import "ScreenChar.h"
 
// A mutable set that only uses pointer equality.
@interface CRunSet : NSObject {
NSMutableDictionary *dict_;
}
- (void)addObject:(NSObject *)object;
- (BOOL)containsObject:(NSObject *)object;
- (NSArray *)values;
@end
@implementation CRunSet
- (id)init {
self = [super init];
if (self) {
dict_ = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)dealloc {
[dict_ release];
[super dealloc];
}
- (NSNumber *)keyForObject:(NSObject *)object {
return [NSNumber numberWithLongLong:(long long)object];
}
- (void)addObject:(NSObject *)object {
NSNumber *key = [self keyForObject:object];
if (![dict_ objectForKey:key]) {
[dict_ setObject:object forKey:key];
}
}
- (BOOL)containsObject:(NSObject *)object {
return [dict_ objectForKey:[self keyForObject:object]] != nil;
}
- (NSArray *)values {
return [dict_ allValues];
}
@end
@implementation CRunStorage : NSObject
 
+ (CRunStorage *)cRunStorageWithCapacity:(int)capacity {
Loading
Loading
@@ -23,7 +69,7 @@
glyphs_ = malloc(sizeof(CGGlyph) * capacity);
advances_ = malloc(sizeof(NSSize) * capacity);
capacity_ = capacity;
colors_ = [[NSMutableSet alloc] init];
colors_ = [[CRunSet alloc] init];
used_ = 0;
}
return self;
Loading
Loading
Loading
Loading
@@ -4,25 +4,25 @@
 
// Initialize the state of a new run, whether it is on the stack or malloc'ed.
CRUN_INLINE void CRunInitialize(CRun *run,
CAttrs *attrs,
CRunStorage *storage,
CGFloat x);
CAttrs *attrs,
CRunStorage *storage,
CGFloat x);
 
// Append a single unicode character (no combining marks allowed) to a run.
// Returns the new tail of the run list.
CRUN_INLINE CRun *CRunAppend(CRun *run,
CAttrs *attrs,
unichar code,
CGFloat advance,
CGFloat x);
CAttrs *attrs,
unichar code,
CGFloat advance,
CGFloat x);
 
// Append a string, possibly with combining marks, to a run.
// Returns the new tail of the run list.
CRUN_INLINE CRun *CRunAppendString(CRun *run,
CAttrs *attrs,
NSString *string,
CGFloat advance,
CGFloat x);
CAttrs *attrs,
NSString *string,
CGFloat advance,
CGFloat x);
 
// Release the storage from a run and its successors in the run list.
CRUN_INLINE void CRunDestroy(CRun *run);
Loading
Loading
@@ -53,182 +53,182 @@ CRUN_INLINE void CRunTerminate(CRun *run);
#pragma mark - Implementations
 
CRUN_INLINE void CRunInitialize(CRun *run,
CAttrs *attrs,
CRunStorage *storage,
CGFloat x) {
run->attrs = *attrs;
run->x = x;
run->length = 0;
run->index = -1;
run->next = NULL;
run->string = nil;
run->terminated = NO;
CAttrs *attrs,
CRunStorage *storage,
CGFloat x) {
run->attrs = *attrs;
run->x = x;
run->length = 0;
run->index = -1;
run->next = NULL;
run->string = nil;
run->terminated = NO;
run->storage = [storage retain];
}
 
// Append codes to an existing run. It must not have a complex string already set.
CRUN_INLINE void CRunAppendSelf(CRun *run,
unichar code,
CGFloat advance) {
assert(!run->string);
int theIndex = [run->storage appendCode:code andAdvance:NSMakeSize(advance, 0)];
unichar code,
CGFloat advance) {
assert(!run->string);
int theIndex = [run->storage appendCode:code andAdvance:NSMakeSize(advance, 0)];
if (run->index < 0) {
run->index = theIndex;
}
run->length++;
run->length++;
}
 
// Append a complex string to a run which has neither characters nor a string
// already set.
CRUN_INLINE void CRunAppendSelfString(CRun *run,
NSString *string,
CGFloat advance) {
assert(run->length == 0);
int theIndex = [run->storage appendCode:0 andAdvance:NSMakeSize(advance, 0)];
NSString *string,
CGFloat advance) {
assert(run->length == 0);
int theIndex = [run->storage appendCode:0 andAdvance:NSMakeSize(advance, 0)];
if (run->index < 0) {
run->index = theIndex;
}
run->string = [string retain];
run->string = [string retain];
}
 
// Allocate a new run and append a character to it. Link the new run as the
// successor of |run|.
CRUN_INLINE CRun *CRunAppendNew(CRun *run,
CAttrs *attrs,
CGFloat x,
unichar code,
CGFloat advance) {
assert(!run->next);
CRun *newRun = malloc(sizeof(CRun));
CRunInitialize(newRun, attrs, run->storage, x);
CRunAppendSelf(newRun, code, advance);
run->next = newRun;
return newRun;
CAttrs *attrs,
CGFloat x,
unichar code,
CGFloat advance) {
assert(!run->next);
CRun *newRun = malloc(sizeof(CRun));
CRunInitialize(newRun, attrs, run->storage, x);
CRunAppendSelf(newRun, code, advance);
run->next = newRun;
return newRun;
}
 
// Allocate a new run and append a complex string to it. Link the new run as
// the successor of |run|.
CRUN_INLINE CRun *CRunAppendNewString(CRun *run,
CAttrs *attrs,
CGFloat x,
NSString *string,
CGFloat advance) {
CAttrs *attrs,
CGFloat x,
NSString *string,
CGFloat advance) {
assert(!run->next);
CRun *newRun = malloc(sizeof(CRun));
CRunInitialize(newRun, attrs, run->storage, x);
CRunAppendSelfString(newRun, string, advance);
CRun *newRun = malloc(sizeof(CRun));
CRunInitialize(newRun, attrs, run->storage, x);
CRunAppendSelfString(newRun, string, advance);
run->next = newRun;
return newRun;
return newRun;
}
 
CRUN_INLINE CRun *CRunAppend(CRun *run,
CAttrs *attrs,
unichar code,
CGFloat advance,
CGFloat x) {
if (run->attrs.antiAlias == attrs->antiAlias &&
run->attrs.color == attrs->color &&
run->attrs.fakeBold == attrs->fakeBold &&
CAttrs *attrs,
unichar code,
CGFloat advance,
CGFloat x) {
if (run->attrs.antiAlias == attrs->antiAlias &&
run->attrs.color == attrs->color &&
run->attrs.fakeBold == attrs->fakeBold &&
run->attrs.underline == attrs->underline &&
run->attrs.fontInfo == attrs->fontInfo &&
!run->terminated &&
!run->string) {
CRunAppendSelf(run, code, advance);
return run;
} else {
return CRunAppendNew(run, attrs, x, code, advance);
}
run->attrs.fontInfo == attrs->fontInfo &&
!run->terminated &&
!run->string) {
CRunAppendSelf(run, code, advance);
return run;
} else {
return CRunAppendNew(run, attrs, x, code, advance);
}
}
 
CRUN_INLINE CRun *CRunAppendString(CRun *run,
CAttrs *attrs,
NSString *string,
CGFloat advance,
CGFloat x) {
if (run->length == 0 && !run->string) {
CRunAppendSelfString(run, string, advance);
return run;
} else {
return CRunAppendNewString(run, attrs, x, string, advance);
}
CAttrs *attrs,
NSString *string,
CGFloat advance,
CGFloat x) {
if (run->length == 0 && !run->string) {
CRunAppendSelfString(run, string, advance);
return run;
} else {
return CRunAppendNewString(run, attrs, x, string, advance);
}
}
 
CRUN_INLINE void CRunDestroy(CRun *run) {
[run->string release];
[run->storage release];
if (run->next) {
CRunDestroy(run->next);
free(run->next);
run->next = NULL;
}
[run->string release];
[run->storage release];
if (run->next) {
CRunDestroy(run->next);
free(run->next);
run->next = NULL;
}
}
 
CRUN_INLINE void CRunFree(CRun *run) {
CRunDestroy(run);
free(run);
CRunDestroy(run);
free(run);
}
 
CRUN_INLINE void CRunAdvance(CRun *run, int offset) {
assert(!run->string);
assert(run->length >= offset);
assert(!run->string);
assert(run->length >= offset);
NSSize *advances = [run->storage advancesFromIndex:run->index];
for (int i = 0; i < offset; i++) {
run->x += advances[i].width;
}
for (int i = 0; i < offset; i++) {
run->x += advances[i].width;
}
run->index += offset;
run->length -= offset;
run->length -= offset;
}
 
CRUN_INLINE CRun *CRunSplit(CRun *run, int newStart) {
if (run->length == 0) {
return nil;
}
assert(newStart < run->length);
CRun *newRun = malloc(sizeof(CRun));
// Skip past |newStart| chars
CRunAdvance(run, newStart);
// Create a new string run from the first char
CRunInitialize(newRun, &run->attrs, run->storage, run->x);
CRunAppendString(newRun,
&run->attrs,
[NSString stringWithCharacters:[run->storage codesFromIndex:run->index]
if (run->length == 0) {
return nil;
}
assert(newStart < run->length);
CRun *newRun = malloc(sizeof(CRun));
// Skip past |newStart| chars
CRunAdvance(run, newStart);
// Create a new string run from the first char
CRunInitialize(newRun, &run->attrs, run->storage, run->x);
CRunAppendString(newRun,
&run->attrs,
[NSString stringWithCharacters:[run->storage codesFromIndex:run->index]
length:1],
[run->storage advancesFromIndex:run->index][newStart].width,
run->x);
[run->storage advancesFromIndex:run->index][newStart].width,
run->x);
 
// Skip past that one char.
CRunAdvance(run, 1);
// Skip past that one char.
CRunAdvance(run, 1);
 
return newRun;
return newRun;
}
 
CRUN_INLINE CGGlyph *CRunGetGlyphs(CRun *run, int *firstMissingGlyph) {
assert(!run->string);
assert(run->index >= 0);
*firstMissingGlyph = -1;
if (run->length == 0) {
return nil;
}
assert(run->index >= 0);
*firstMissingGlyph = -1;
if (run->length == 0) {
return nil;
}
CGGlyph *glyphs = [run->storage glyphsFromIndex:run->index];
BOOL foundAllGlyphs = CTFontGetGlyphsForCharacters((CTFontRef)run->attrs.fontInfo.font,
[run->storage codesFromIndex:run->index],
BOOL foundAllGlyphs = CTFontGetGlyphsForCharacters((CTFontRef)run->attrs.fontInfo.font,
[run->storage codesFromIndex:run->index],
glyphs,
run->length);
if (!foundAllGlyphs) {
for (int i = 0; i < run->length; i++) {
if (!glyphs[i]) {
*firstMissingGlyph = i;
break;
}
}
}
return glyphs;
run->length);
if (!foundAllGlyphs) {
for (int i = 0; i < run->length; i++) {
if (!glyphs[i]) {
*firstMissingGlyph = i;
break;
}
}
}
return glyphs;
}
 
CRUN_INLINE void CRunTerminate(CRun *run) {
run->terminated = YES;
run->terminated = YES;
}
 
CRUN_INLINE NSSize *CRunGetAdvances(CRun *run) {
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment