git.y1.nz

SameBoy

Accurate GB/GBC emulator
download: https://git.y1.nz/archives/sameboy.tar.gz
README | Files | Log | Refs | LICENSE

HexFiend/HFRepresenterStringEncodingTextView.m

      1 //
      2 //  HFRepresenterStringEncodingTextView.m
      3 //  HexFiend_2
      4 //
      5 //  Copyright 2007 ridiculous_fish. All rights reserved.
      6 //
      7 
      8 #import <HexFiend/HFRepresenterStringEncodingTextView.h>
      9 #import <HexFiend/HFRepresenterTextView_Internal.h>
     10 #include <malloc/malloc.h>
     11 
     12 @implementation HFRepresenterStringEncodingTextView
     13 
     14 static NSString *copy1CharStringForByteValue(unsigned long long byteValue, NSUInteger bytesPerChar, NSStringEncoding encoding) {
     15     NSString *result = nil;
     16     unsigned char bytes[sizeof byteValue];
     17     /* If we are little endian, then the bytesPerChar doesn't matter, because it will all come out the same.  If we are big endian, then it does matter. */
     18 #if ! __BIG_ENDIAN__
     19     *(unsigned long long *)bytes = byteValue;
     20 #else
     21     if (bytesPerChar == sizeof(uint8_t)) {
     22         *(uint8_t *)bytes = (uint8_t)byteValue;
     23     } else if (bytesPerChar == sizeof(uint16_t)) {
     24         *(uint16_t *)bytes = (uint16_t)byteValue;
     25     } else if (bytesPerChar == sizeof(uint32_t)) {
     26         *(uint32_t *)bytes = (uint32_t)byteValue;
     27     } else if (bytesPerChar == sizeof(uint64_t)) {
     28         *(uint64_t *)bytes = (uint64_t)byteValue;
     29     } else {
     30         [NSException raise:NSInvalidArgumentException format:@"Unsupported bytesPerChar of %u", bytesPerChar];
     31     }
     32 #endif
     33 
     34     /* ASCII is mishandled :( */
     35     BOOL encodingOK = YES;
     36     if (encoding == NSASCIIStringEncoding && bytesPerChar == 1 && bytes[0] > 0x7F) {
     37         encodingOK = NO;
     38     }
     39 
     40     
     41     
     42     /* Now create a string from these bytes */
     43     if (encodingOK) {
     44         result = [[NSString alloc] initWithBytes:bytes length:bytesPerChar encoding:encoding];
     45         
     46         if ([result length] > 1) {
     47             /* Try precomposing it */
     48             NSString *temp = [[result precomposedStringWithCompatibilityMapping] copy];
     49             [result release];
     50             result = temp;
     51         }
     52         
     53         /* Ensure it has exactly one character */
     54         if ([result length] != 1) {
     55             [result release];
     56             result = nil;
     57         }
     58     }
     59     
     60     /* All done */
     61     return result;
     62 }
     63 
     64 static BOOL getGlyphs(CGGlyph *glyphs, NSString *string, NSFont *inputFont) {
     65     NSUInteger length = [string length];
     66     HFASSERT(inputFont != nil);
     67     NEW_ARRAY(UniChar, chars, length);
     68     [string getCharacters:chars range:NSMakeRange(0, length)];
     69     bool result = CTFontGetGlyphsForCharacters((CTFontRef)inputFont, chars, glyphs, length);
     70     /* A NO return means some or all characters were not mapped.  This is OK.  We'll use the replacement glyph.  Unless we're calculating the replacement glyph!  Hmm...maybe we should have a series of replacement glyphs that we try? */
     71     
     72     ////////////////////////
     73     // Workaround for a Mavericks bug. Still present as of 10.9.5
     74     // TODO: Hmm, still? Should look into this again, either it's not a bug or Apple needs a poke.
     75     if(!result) for(NSUInteger i = 0; i < length; i+=15) {
     76         CFIndex x = length-i;
     77         if(x > 15) x = 15;
     78         result = CTFontGetGlyphsForCharacters((CTFontRef)inputFont, chars+i, glyphs+i, x);
     79         if(!result) break;
     80     }
     81     ////////////////////////
     82     
     83     FREE_ARRAY(chars);
     84     return result;
     85 }
     86 
     87 static void generateGlyphs(NSFont *baseFont, NSMutableArray *fonts, struct HFGlyph_t *outGlyphs, NSInteger bytesPerChar, NSStringEncoding encoding, const NSUInteger *charactersToLoad, NSUInteger charactersToLoadCount, CGFloat *outMaxAdvance) {
     88     /* If the caller wants the advance, initialize it to 0 */
     89     if (outMaxAdvance) *outMaxAdvance = 0;
     90     
     91     /* Invalid glyph marker */
     92     const struct HFGlyph_t invalidGlyph = {.fontIndex = kHFGlyphFontIndexInvalid, .glyph = -1};
     93     
     94     NSCharacterSet *coveredSet = [baseFont coveredCharacterSet];
     95     NSMutableString *coveredGlyphFetchingString = [[NSMutableString alloc] init];
     96     NSMutableIndexSet *coveredGlyphIndexes = [[NSMutableIndexSet alloc] init];
     97     NSMutableString *substitutionFontsGlyphFetchingString = [[NSMutableString alloc] init];
     98     NSMutableIndexSet *substitutionGlyphIndexes = [[NSMutableIndexSet alloc] init];
     99     
    100     /* Loop over all the characters, appending them to our glyph fetching string */
    101     NSUInteger idx;
    102     for (idx = 0; idx < charactersToLoadCount; idx++) {
    103         NSString *string = copy1CharStringForByteValue(charactersToLoad[idx], bytesPerChar, encoding);
    104         if (string == nil) {
    105             /* This byte value is not represented in this char set (e.g. upper 128 in ASCII) */
    106             outGlyphs[idx] = invalidGlyph;
    107         } else {
    108             if ([coveredSet characterIsMember:[string characterAtIndex:0]]) {
    109                 /* It's covered by our base font */
    110                 [coveredGlyphFetchingString appendString:string];
    111                 [coveredGlyphIndexes addIndex:idx];
    112             } else {
    113                 /* Maybe there's a substitution font */
    114                 [substitutionFontsGlyphFetchingString appendString:string];
    115                 [substitutionGlyphIndexes addIndex:idx];
    116             }
    117         }
    118         [string release];
    119     }
    120     
    121     
    122     /* Fetch the non-substitute glyphs */
    123     {
    124         NEW_ARRAY(CGGlyph, cgglyphs, [coveredGlyphFetchingString length]);
    125         BOOL success = getGlyphs(cgglyphs, coveredGlyphFetchingString, baseFont);
    126         HFASSERT(success == YES);
    127         NSUInteger numGlyphs = [coveredGlyphFetchingString length];
    128         
    129         /* Fill in our glyphs array */
    130         NSUInteger coveredGlyphIdx = [coveredGlyphIndexes firstIndex];
    131         for (NSUInteger i=0; i < numGlyphs; i++) {
    132             outGlyphs[coveredGlyphIdx] = (struct HFGlyph_t){.fontIndex = 0, .glyph = cgglyphs[i]};
    133             coveredGlyphIdx = [coveredGlyphIndexes indexGreaterThanIndex:coveredGlyphIdx];
    134             
    135             /* Record the advancement.  Note that this may be more efficient to do in bulk. */
    136             if (outMaxAdvance) *outMaxAdvance = HFMax(*outMaxAdvance, [baseFont advancementForGlyph:cgglyphs[i]].width);
    137             
    138         }
    139         HFASSERT(coveredGlyphIdx == NSNotFound); //we must have exhausted the table
    140         FREE_ARRAY(cgglyphs);
    141     }
    142     
    143     /* Now do substitution glyphs. */
    144     {
    145         NSUInteger substitutionGlyphIndex = [substitutionGlyphIndexes firstIndex], numSubstitutionChars = [substitutionFontsGlyphFetchingString length];
    146         for (NSUInteger i=0; i < numSubstitutionChars; i++) {
    147             CTFontRef substitutionFont = CTFontCreateForString((CTFontRef)baseFont, (CFStringRef)substitutionFontsGlyphFetchingString, CFRangeMake(i, 1));
    148             if (substitutionFont) {
    149                 /* We have a font for this string */
    150                 CGGlyph glyph;
    151                 unichar c = [substitutionFontsGlyphFetchingString characterAtIndex:i];
    152                 NSString *substring = [[NSString alloc] initWithCharacters:&c length:1];
    153                 BOOL success = getGlyphs(&glyph, substring, (NSFont *)substitutionFont);
    154                 [substring release];
    155                 
    156                 if (! success) {
    157                     /* Turns out there wasn't a glyph like we thought there would be, so set an invalid glyph marker */
    158                     outGlyphs[substitutionGlyphIndex] = invalidGlyph;
    159                 } else {
    160                     /* Find the index in fonts.  If none, add to it. */
    161                     HFASSERT(fonts != nil);
    162                     NSUInteger fontIndex = [fonts indexOfObject:(id)substitutionFont];
    163                     if (fontIndex == NSNotFound) {
    164                         [fonts addObject:(id)substitutionFont];
    165                         fontIndex = [fonts count] - 1;
    166                     }
    167                     
    168                     /* Now make the glyph */
    169                     HFASSERT(fontIndex < UINT16_MAX);
    170                     outGlyphs[substitutionGlyphIndex] = (struct HFGlyph_t){.fontIndex = (uint16_t)fontIndex, .glyph = glyph};
    171                 }
    172                 
    173                 /* We're done with this */
    174                 CFRelease(substitutionFont);
    175                 
    176             }
    177             substitutionGlyphIndex = [substitutionGlyphIndexes indexGreaterThanIndex:substitutionGlyphIndex];
    178         }
    179     }
    180     
    181     [coveredGlyphFetchingString release];
    182     [coveredGlyphIndexes release];
    183     [substitutionFontsGlyphFetchingString release];
    184     [substitutionGlyphIndexes release];
    185 }
    186 
    187 static int compareGlyphFontIndexes(const void *p1, const void *p2) {
    188     const struct HFGlyph_t *g1 = p1, *g2 = p2;
    189     if (g1->fontIndex != g2->fontIndex) {
    190         /* Prefer to sort by font index */
    191         return (g1->fontIndex > g2->fontIndex) - (g2->fontIndex > g1->fontIndex);
    192     } else {	
    193         /* If they have equal font indexes, sort by glyph value */
    194         return (g1->glyph > g2->glyph) - (g2->glyph > g1->glyph);
    195     }
    196 }
    197 
    198 - (void)threadedPrecacheGlyphs:(const struct HFGlyph_t *)glyphs withFonts:(NSArray *)localFonts count:(NSUInteger)count {
    199     /* This method draws glyphs anywhere, so that they get cached by CG and drawing them a second time can be fast. */
    200     NSUInteger i, validGlyphCount;
    201     
    202     /* We can use 0 advances */
    203     NEW_ARRAY(CGSize, advances, count);
    204     bzero(advances, count * sizeof *advances);
    205     
    206     /* Make a local copy of the glyphs, and sort them according to their font index so that we can draw them with the fewest runs. */
    207     NEW_ARRAY(struct HFGlyph_t, validGlyphs, count);
    208     
    209     validGlyphCount = 0;
    210     for (i=0; i < count; i++) {
    211         if (glyphs[i].glyph <= kCGGlyphMax && glyphs[i].fontIndex != kHFGlyphFontIndexInvalid) {
    212             validGlyphs[validGlyphCount++] = glyphs[i];
    213         }
    214     }
    215     qsort(validGlyphs, validGlyphCount, sizeof *validGlyphs, compareGlyphFontIndexes);
    216     
    217     /* Remove duplicate glyphs */
    218     NSUInteger trailing = 0;
    219     struct HFGlyph_t lastGlyph = {.glyph = kCGFontIndexInvalid, .fontIndex = kHFGlyphFontIndexInvalid};
    220     for (i=0; i < validGlyphCount; i++) {
    221         if (! HFGlyphEqualsGlyph(lastGlyph, validGlyphs[i])) {
    222             lastGlyph = validGlyphs[i];
    223             validGlyphs[trailing++] = lastGlyph;
    224         }
    225     }
    226     validGlyphCount = trailing;
    227     
    228     /* Draw the glyphs in runs */
    229     NEW_ARRAY(CGGlyph, cgglyphs, count);
    230     NSImage *glyphDrawingImage = [[NSImage alloc] initWithSize:NSMakeSize(100, 100)];
    231     [glyphDrawingImage lockFocus];
    232     CGContextRef ctx = [[NSGraphicsContext currentContext] graphicsPort];
    233     HFGlyphFontIndex runFontIndex = -1;
    234     NSUInteger runLength = 0;
    235     for (i=0; i <= validGlyphCount; i++) {
    236         if (i == validGlyphCount || validGlyphs[i].fontIndex != runFontIndex) {
    237             /* End the current run */
    238             if (runLength > 0) {
    239                 NSLog(@"Drawing with %@", [localFonts[runFontIndex] screenFont]);
    240                 [[localFonts[runFontIndex] screenFont] set];
    241                 CGContextSetTextPosition(ctx, 0, 50);
    242                 CGContextShowGlyphsWithAdvances(ctx, cgglyphs, advances, runLength);
    243             }
    244             NSLog(@"Drew a run of length %lu", (unsigned long)runLength);
    245             runLength = 0;
    246             if (i < validGlyphCount) runFontIndex = validGlyphs[i].fontIndex;
    247         }
    248         if (i < validGlyphCount) {
    249             /* Append to the current run */
    250             cgglyphs[runLength++] = validGlyphs[i].glyph;
    251         }
    252     }
    253     
    254     /* All done */
    255     [glyphDrawingImage unlockFocus];
    256     [glyphDrawingImage release];
    257     FREE_ARRAY(advances);
    258     FREE_ARRAY(validGlyphs);
    259     FREE_ARRAY(cgglyphs);
    260 }
    261 
    262 - (void)threadedLoadGlyphs:(id)unused {
    263     /* Note that this is running on a background thread */
    264     USE(unused);
    265     
    266     /* Do some things under the lock. Someone else may wish to read fonts, and we're going to write to it, so make a local copy.  Also figure out what characters to load. */
    267     NSMutableArray *localFonts;
    268     NSIndexSet *charactersToLoad;
    269     OSSpinLockLock(&glyphLoadLock);
    270     localFonts = [fonts mutableCopy];
    271     charactersToLoad = requestedCharacters;
    272     /* Set requestedCharacters to nil so that the caller knows we aren't going to check again, and will have to re-invoke us. */
    273     requestedCharacters = nil;
    274     OSSpinLockUnlock(&glyphLoadLock);
    275     
    276     /* The base font is the first font */
    277     NSFont *font = localFonts[0];
    278     
    279     NSUInteger charVal, glyphIdx, charCount = [charactersToLoad count];
    280     NEW_ARRAY(struct HFGlyph_t, glyphs, charCount);
    281     
    282     /* Now generate our glyphs */
    283     NEW_ARRAY(NSUInteger, characters, charCount);
    284     [charactersToLoad getIndexes:characters maxCount:charCount inIndexRange:NULL];
    285     generateGlyphs(font, localFonts, glyphs, bytesPerChar, encoding, characters, charCount, NULL);
    286     FREE_ARRAY(characters);
    287     
    288     /* The first time we draw glyphs, it's slow, so pre-cache them by drawing them now. */
    289     // This was disabled because it blows up the CG glyph cache
    290     //    [self threadedPrecacheGlyphs:glyphs withFonts:localFonts count:charCount];    
    291     
    292     /* Replace fonts.  Do this before we insert into the glyph trie, because the glyph trie references fonts that we're just now putting in the fonts array. */
    293     id oldFonts;
    294     OSSpinLockLock(&glyphLoadLock);
    295     oldFonts = fonts;
    296     fonts = localFonts;
    297     OSSpinLockUnlock(&glyphLoadLock);
    298     [oldFonts release];
    299     
    300     /* Now insert all of the glyphs into the glyph trie */
    301     glyphIdx = 0;
    302     for (charVal = [charactersToLoad firstIndex]; charVal != NSNotFound; charVal = [charactersToLoad indexGreaterThanIndex:charVal]) {
    303         HFGlyphTrieInsert(&glyphTable, charVal, glyphs[glyphIdx++]);
    304     }
    305     FREE_ARRAY(glyphs);
    306     
    307     /* Trigger a redisplay */
    308     [self performSelectorOnMainThread:@selector(triggerRedisplay:) withObject:nil waitUntilDone:NO];
    309     
    310     /* All done. We inherited the retain on requestedCharacters, so release it. */
    311     [charactersToLoad release];
    312 }
    313 
    314 - (void)triggerRedisplay:unused {
    315     USE(unused);
    316     [self setNeedsDisplay:YES];
    317 }
    318 
    319 - (void)beginLoadGlyphsForCharacters:(NSIndexSet *)charactersToLoad {
    320     /* Create the operation (and maybe the operation queue itself) */
    321     if (! glyphLoader) {
    322         glyphLoader = [[NSOperationQueue alloc] init];
    323         [glyphLoader setMaxConcurrentOperationCount:1];
    324     }
    325     if (! fonts) {
    326         NSFont *font = [self font];
    327         fonts = [[NSMutableArray alloc] initWithObjects:&font count:1];
    328     }
    329     
    330     BOOL needToStartOperation;    
    331     OSSpinLockLock(&glyphLoadLock);
    332     if (requestedCharacters) {
    333         /* There's a pending request, so just add to it */
    334         [requestedCharacters addIndexes:charactersToLoad];
    335         needToStartOperation = NO;
    336     } else {
    337         /* There's no pending request, so we will create one */
    338         requestedCharacters = [charactersToLoad mutableCopy];
    339         needToStartOperation = YES;
    340     }
    341     OSSpinLockUnlock(&glyphLoadLock);
    342     
    343     if (needToStartOperation) {
    344         NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(threadedLoadGlyphs:) object:charactersToLoad];
    345         [glyphLoader addOperation:op];
    346         [op release];
    347     }
    348 }
    349 
    350 - (void)dealloc {
    351     HFGlyphTreeFree(&glyphTable);
    352     [fonts release];
    353     [super dealloc];
    354 }
    355 
    356 - (void)staleTieredProperties {
    357     tier1DataIsStale = YES;
    358     /* We have to free the glyph table */
    359     requestedCancel = YES;
    360     [glyphLoader waitUntilAllOperationsAreFinished];
    361     requestedCancel = NO;
    362     HFGlyphTreeFree(&glyphTable);
    363     HFGlyphTrieInitialize(&glyphTable, bytesPerChar);
    364     [fonts release];
    365     fonts = nil;
    366     [fontCache release];
    367     fontCache = nil;
    368 }
    369 
    370 - (void)setFont:(NSFont *)font {
    371     [self staleTieredProperties];
    372     /* fonts is preloaded with our one font */
    373     if (! fonts) fonts = [[NSMutableArray alloc] init];
    374     [fonts addObject:font];
    375     [super setFont:font];
    376 }
    377 
    378 - (instancetype)initWithCoder:(NSCoder *)coder {
    379     HFASSERT([coder allowsKeyedCoding]);
    380     self = [super initWithCoder:coder];
    381     encoding = (NSStringEncoding)[coder decodeInt64ForKey:@"HFStringEncoding"];
    382     bytesPerChar = HFStringEncodingCharacterLength(encoding);
    383     [self staleTieredProperties];
    384     return self;
    385 }
    386 
    387 - (instancetype)initWithFrame:(NSRect)frameRect {
    388     self = [super initWithFrame:frameRect];
    389     encoding = NSMacOSRomanStringEncoding;
    390     bytesPerChar = HFStringEncodingCharacterLength(encoding);
    391     [self staleTieredProperties];
    392     return self;
    393 }
    394 
    395 - (void)encodeWithCoder:(NSCoder *)coder {
    396     HFASSERT([coder allowsKeyedCoding]);
    397     [super encodeWithCoder:coder];
    398     [coder encodeInt64:encoding forKey:@"HFStringEncoding"];
    399 }
    400 
    401 - (NSStringEncoding)encoding {
    402     return encoding;
    403 }
    404 
    405 - (void)setEncoding:(NSStringEncoding)val {
    406     if (encoding != val) {
    407         /* Our glyph table is now stale. Call this first to ensure our background operation is complete. */
    408         [self staleTieredProperties];
    409         
    410         /* Store the new encoding. */
    411         encoding = val;	
    412         
    413         /* Compute bytes per character */
    414         bytesPerChar = HFStringEncodingCharacterLength(encoding);
    415         HFASSERT(bytesPerChar > 0);
    416         
    417         /* Ensure the tree knows about the new bytes per character */
    418         HFGlyphTrieInitialize(&glyphTable, bytesPerChar);
    419 		
    420         /* Redraw ourselves with our new glyphs */
    421         [self setNeedsDisplay:YES];
    422     }
    423 }
    424 
    425 - (void)loadTier1Data {
    426     NSFont *font = [self font];
    427     
    428     /* Use the max advance as the glyph advance */
    429     glyphAdvancement = HFCeil([font maximumAdvancement].width);
    430     
    431     /* Generate replacementGlyph */
    432     CGGlyph glyph[1];
    433     BOOL foundReplacement = NO;
    434     if (! foundReplacement) foundReplacement = getGlyphs(glyph, @".", font);
    435     if (! foundReplacement) foundReplacement = getGlyphs(glyph, @"*", font);
    436     if (! foundReplacement) foundReplacement = getGlyphs(glyph, @"!", font);
    437     if (! foundReplacement) {
    438         /* Really we should just fall back to another font in this case */
    439         [NSException raise:NSInternalInconsistencyException format:@"Unable to find replacement glyph for font %@", font];
    440     }
    441     replacementGlyph.fontIndex = 0;
    442     replacementGlyph.glyph = glyph[0];
    443     
    444     /* We're no longer stale */
    445     tier1DataIsStale = NO;
    446 }
    447 
    448 /* Override of base class method for font substitution */
    449 - (NSFont *)fontAtSubstitutionIndex:(uint16_t)idx {
    450     HFASSERT(idx != kHFGlyphFontIndexInvalid);
    451     if (idx >= [fontCache count]) {
    452         /* Our font cache is out of date.  Take the lock and update the cache. */
    453         NSArray *newFonts = nil;
    454         OSSpinLockLock(&glyphLoadLock);
    455         HFASSERT(idx < [fonts count]);
    456         newFonts = [fonts copy];
    457         OSSpinLockUnlock(&glyphLoadLock);
    458         
    459         /* Store the new cache */
    460         [fontCache release];
    461         fontCache = newFonts;
    462         
    463         /* Now our cache should be up to date */
    464         HFASSERT(idx < [fontCache count]);
    465     }
    466     return fontCache[idx];
    467 }
    468 
    469 /* Override of base class method in case we are 16 bit */
    470 - (NSUInteger)bytesPerCharacter {
    471     return bytesPerChar;
    472 }
    473 
    474 - (void)extractGlyphsForBytes:(const unsigned char *)bytes count:(NSUInteger)numBytes offsetIntoLine:(NSUInteger)offsetIntoLine intoArray:(struct HFGlyph_t *)glyphs advances:(CGSize *)advances resultingGlyphCount:(NSUInteger *)resultGlyphCount {
    475     HFASSERT(bytes != NULL);
    476     HFASSERT(glyphs != NULL);
    477     HFASSERT(resultGlyphCount != NULL);
    478     HFASSERT(advances != NULL);
    479     USE(offsetIntoLine);
    480     
    481     /* Ensure we have advance, etc. before trying to use it */
    482     if (tier1DataIsStale) [self loadTier1Data];
    483     
    484     CGSize advance = CGSizeMake(glyphAdvancement, 0);
    485     NSMutableIndexSet *charactersToLoad = nil; //note: in UTF-32 this may have to move to an NSSet
    486     
    487     const uint8_t localBytesPerChar = bytesPerChar;
    488     NSUInteger charIndex, numChars = numBytes / localBytesPerChar, byteIndex = 0;
    489     for (charIndex = 0; charIndex < numChars; charIndex++) {
    490         NSUInteger character = -1;
    491         if (localBytesPerChar == 1) {
    492             character = *(const uint8_t *)(bytes + byteIndex);
    493         } else if (localBytesPerChar == 2) {
    494             character = *(const uint16_t *)(bytes + byteIndex);
    495         } else if (localBytesPerChar == 4) {
    496             character = *(const uint32_t *)(bytes + byteIndex);	    
    497         }
    498         
    499         struct HFGlyph_t glyph = HFGlyphTrieGet(&glyphTable, character);
    500         if (glyph.glyph == 0 && glyph.fontIndex == 0) {
    501             /* Unloaded glyph, so load it */
    502             if (! charactersToLoad) charactersToLoad = [[NSMutableIndexSet alloc] init];
    503             [charactersToLoad addIndex:character];
    504             glyph = replacementGlyph;	    
    505         } else if (glyph.glyph == (uint16_t)-1 && glyph.fontIndex == kHFGlyphFontIndexInvalid) {
    506             /* Missing glyph, so ignore it */
    507             glyph = replacementGlyph;
    508         } else {
    509             /* Valid glyph */
    510         }
    511         
    512         HFASSERT(glyph.fontIndex != kHFGlyphFontIndexInvalid);
    513         
    514         advances[charIndex] = advance;
    515         glyphs[charIndex] = glyph;
    516         byteIndex += localBytesPerChar;
    517     }
    518     *resultGlyphCount = numChars;
    519     
    520     if (charactersToLoad) {
    521         [self beginLoadGlyphsForCharacters:charactersToLoad];
    522         [charactersToLoad release];
    523     }
    524 }
    525 
    526 - (CGFloat)advancePerCharacter {
    527     /* The glyph advancement is determined by our glyph table */
    528     if (tier1DataIsStale) [self loadTier1Data];
    529     return glyphAdvancement;
    530 }
    531 
    532 - (CGFloat)advanceBetweenColumns {
    533     return 0; //don't have any space between columns
    534 }
    535 
    536 - (NSUInteger)maximumGlyphCountForByteCount:(NSUInteger)byteCount {
    537     return byteCount / [self bytesPerCharacter];
    538 }
    539 
    540 @end

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.