|  |  | @ -22,6 +22,7 @@ | 
			
		
	
		
		
			
				
					
					|  |  |  | //   Mikko Mononen: compound shape support, more cmap formats
 |  |  |  | //   Mikko Mononen: compound shape support, more cmap formats
 | 
			
		
	
		
		
			
				
					
					|  |  |  | //   Tor Andersson: kerning, subpixel rendering
 |  |  |  | //   Tor Andersson: kerning, subpixel rendering
 | 
			
		
	
		
		
			
				
					
					|  |  |  | //   Dougall Johnson: OpenType / Type 2 font handling
 |  |  |  | //   Dougall Johnson: OpenType / Type 2 font handling
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | //   Daniel Ribeiro Maciel: basic GPOS-based kerning
 | 
			
		
	
		
		
			
				
					
					|  |  |  | //
 |  |  |  | //
 | 
			
		
	
		
		
			
				
					
					|  |  |  | //   Misc other:
 |  |  |  | //   Misc other:
 | 
			
		
	
		
		
			
				
					
					|  |  |  | //       Ryan Gordon
 |  |  |  | //       Ryan Gordon
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -701,7 +702,7 @@ struct stbtt_fontinfo | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |    int numGlyphs;                     // number of glyphs, needed for range checking
 |  |  |  |    int numGlyphs;                     // number of glyphs, needed for range checking
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |    int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf
 |  |  |  |    int loca,head,glyf,hhea,hmtx,kern,gpos; // table locations as offset from start of .ttf
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |    int index_map;                     // a cmap mapping for our chosen character encoding
 |  |  |  |    int index_map;                     // a cmap mapping for our chosen character encoding
 | 
			
		
	
		
		
			
				
					
					|  |  |  |    int indexToLocFormat;              // format needed to map from glyph index to glyph
 |  |  |  |    int indexToLocFormat;              // format needed to map from glyph index to glyph
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -1344,6 +1345,7 @@ static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, in | 
			
		
	
		
		
			
				
					
					|  |  |  |    info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required
 |  |  |  |    info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required
 | 
			
		
	
		
		
			
				
					
					|  |  |  |    info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required
 |  |  |  |    info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required
 | 
			
		
	
		
		
			
				
					
					|  |  |  |    info->kern = stbtt__find_table(data, fontstart, "kern"); // not required
 |  |  |  |    info->kern = stbtt__find_table(data, fontstart, "kern"); // not required
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |    info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |    if (!cmap || !info->head || !info->hhea || !info->hmtx) |  |  |  |    if (!cmap || !info->head || !info->hhea || !info->hmtx) | 
			
		
	
		
		
			
				
					
					|  |  |  |       return 0; |  |  |  |       return 0; | 
			
		
	
	
		
		
			
				
					|  |  | @ -2262,7 +2264,7 @@ STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_inde | 
			
		
	
		
		
			
				
					
					|  |  |  |    } |  |  |  |    } | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | STBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) |  |  |  | static int  stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |    stbtt_uint8 *data = info->data + info->kern; |  |  |  |    stbtt_uint8 *data = info->data + info->kern; | 
			
		
	
		
		
			
				
					
					|  |  |  |    stbtt_uint32 needle, straw; |  |  |  |    stbtt_uint32 needle, straw; | 
			
		
	
	
		
		
			
				
					|  |  | @ -2292,9 +2294,242 @@ STBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, | 
			
		
	
		
		
			
				
					
					|  |  |  |    return 0; |  |  |  |    return 0; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | static stbtt_int32  stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     switch(coverageFormat) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         case 1: { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             // Binary search.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             stbtt_int32 l=0, r=glyphCount-1, m; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             int straw, needle=glyph; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             while (l <= r) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 m = (l + r) >> 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 stbtt_uint8 *glyphArray = coverageTable + 4; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 stbtt_uint16 glyphID = ttUSHORT(glyphArray + 2 * m); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 straw = glyphID; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 if (needle < straw) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     r = m - 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 else if (needle > straw) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     l = m + 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                      return m; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } break; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         case 2: { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             stbtt_uint8 *rangeArray = coverageTable + 4; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             // Binary search.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             stbtt_int32 l=0, r=rangeCount-1, m; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             int strawStart, strawEnd, needle=glyph; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             while (l <= r) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 m = (l + r) >> 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 stbtt_uint8 *rangeRecord = rangeArray + 6 * m; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 strawStart = ttUSHORT(rangeRecord); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 strawEnd = ttUSHORT(rangeRecord + 2); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 if (needle < strawStart) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     r = m - 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 else if (needle > strawEnd) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     l = m + 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     return startCoverageIndex + glyph - strawStart; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } break; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         default: { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             // There are no other cases.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             STBTT_assert(false); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } break; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     return -1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | static stbtt_int32  stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     switch(classDefFormat) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         case 1: { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             stbtt_uint8 *classDef1ValueArray = classDefTable + 6; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             classDefTable = classDef1ValueArray + 2 * glyphCount; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } break; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         case 2: { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             stbtt_uint8 *classRangeRecords = classDefTable + 4; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             // Binary search.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             stbtt_int32 l=0, r=classRangeCount-1, m; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             int strawStart, strawEnd, needle=glyph; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             while (l <= r) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 m = (l + r) >> 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 stbtt_uint8 *classRangeRecord = classRangeRecords + 6 * m; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 strawStart = ttUSHORT(classRangeRecord); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 strawEnd = ttUSHORT(classRangeRecord + 2); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 if (needle < strawStart) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     r = m - 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 else if (needle > strawEnd) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     l = m + 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 else | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     return (stbtt_int32)ttUSHORT(classRangeRecord + 4); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             classDefTable = classRangeRecords + 6 * classRangeCount; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } break; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         default: { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             // There are no other cases.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             STBTT_assert(false); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } break; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     return -1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // Define to STBTT_assert(x) if you want to break on unimplemented formats.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | #define STBTT_GPOS_TODO_assert(x) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | static stbtt_int32  stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if (!info->gpos) return 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     stbtt_uint8 *data = info->data + info->gpos; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if (ttUSHORT(data+0) != 1) return 0; // Major version 1
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if (ttUSHORT(data+2) != 0) return 0; // Minor version 0
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     stbtt_uint16 lookupListOffset = ttUSHORT(data+8); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     stbtt_uint8 *lookupList = data + lookupListOffset; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     stbtt_uint16 lookupCount = ttUSHORT(lookupList); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     for (stbtt_int32 i=0; i<lookupCount; ++i) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         stbtt_uint8 *lookupTable = lookupList + lookupOffset; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         stbtt_uint16 lookupType = ttUSHORT(lookupTable); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         stbtt_uint8 *subTableOffsets = lookupTable + 6; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         switch(lookupType) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             case 2: { // Pair Adjustment Positioning Subtable
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 for (stbtt_int32 sti=0; sti<subTableCount; sti++) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     stbtt_uint8 *table = lookupTable + subtableOffset; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     stbtt_uint16 posFormat = ttUSHORT(table); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     stbtt_uint16 coverageOffset = ttUSHORT(table + 2); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     if (coverageIndex == -1) continue; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     switch (posFormat) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         case 1: { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             // TODO: Support more formats.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             STBTT_GPOS_TODO_assert(valueFormat1 == 4); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             if (valueFormat1 != 4) return 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             STBTT_GPOS_TODO_assert(valueFormat2 == 0); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             if (valueFormat2 != 0) return 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             stbtt_int32 valueRecordPairSizeInBytes = 2; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             stbtt_uint16 pairSetCount = ttUSHORT(table + 8); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             STBTT_assert(coverageIndex < pairSetCount); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             stbtt_uint8 *pairValueTable = table + pairPosOffset; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             stbtt_uint8 *pairValueArray = pairValueTable + 2; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             // Binary search.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             stbtt_int32 l=0, r=pairValueCount-1, m; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             int straw, needle=glyph2; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             while (l <= r) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 m = (l + r) >> 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 stbtt_uint8 *pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 stbtt_uint16 secondGlyph = ttUSHORT(pairValue); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 straw = secondGlyph; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 if (needle < straw) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                     r = m - 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 else if (needle > straw) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                     l = m + 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                     stbtt_int16 xAdvance = ttSHORT(pairValue + 2); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                     return xAdvance; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         } break; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         case 2: { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             // TODO: Support more formats.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             STBTT_GPOS_TODO_assert(valueFormat1 == 4); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             if (valueFormat1 != 4) return 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             STBTT_GPOS_TODO_assert(valueFormat2 == 0); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             if (valueFormat2 != 0) return 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             stbtt_uint16 class1Count = ttUSHORT(table + 12); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             stbtt_uint16 class2Count = ttUSHORT(table + 14); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             STBTT_assert(glyph1class < class1Count); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             STBTT_assert(glyph2class < class2Count); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 stbtt_uint8 *class1Records = table + 16; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 return xAdvance; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         } break; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         default: { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             // There are no other cases.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             STBTT_assert(false); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         } break; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } break; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             default: { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 // TODO: Implement other stuff.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } break; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     return 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | STBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |    int xAdvance = 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |    if (info->gpos) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |    if (info->kern) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |    return xAdvance; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | STBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) |  |  |  | STBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |    if (!info->kern) // if no kerning table, don't waste time looking up both codepoint->glyphs
 |  |  |  |    if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |       return 0; |  |  |  |       return 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |    return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); |  |  |  |    return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
	
		
		
			
				
					|  |  | 
 |