From 69adb19d98114d7a35bf73389b9098de33adf42c Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Tue, 2 Jun 2020 16:23:59 -0700 Subject: migrated glyph index to a switch statement --- sys/libfont/font.c | 201 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 117 insertions(+), 84 deletions(-) (limited to 'sys') diff --git a/sys/libfont/font.c b/sys/libfont/font.c index c7944d0..734ca25 100644 --- a/sys/libfont/font.c +++ b/sys/libfont/font.c @@ -534,95 +534,128 @@ font·free(font·Info *info) int font·glyph_index(font·Info *info, int unicode_codepoint) { - uchar *data = info->data; - uint32 index_map = info->index_map; - - ushort format = ttushort(data + index_map + 0); - if (format == 0) { // apple byte encoding - int32 bytes = ttushort(data + index_map + 2); - if (unicode_codepoint < bytes-6) - return ttBYTE(data + index_map + 6 + unicode_codepoint); - return 0; - } else if (format == 6) { - uint32 first = ttushort(data + index_map + 6); - uint32 count = ttushort(data + index_map + 8); - if ((uint32) unicode_codepoint >= first && (uint32) unicode_codepoint < first+count) - return ttushort(data + index_map + 10 + (unicode_codepoint - first)*2); - return 0; - } else if (format == 2) { - assert(0); // @TODO: high-byte mapping for japanese/chinese/korean - return 0; - } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges - ushort segcount = ttushort(data+index_map+6) >> 1; - ushort searchRange = ttushort(data+index_map+8) >> 1; - ushort entrySelector = ttushort(data+index_map+10); - ushort rangeShift = ttushort(data+index_map+12) >> 1; - - // do a binary search of the segments - uint32 endCount = index_map + 14; - uint32 search = endCount; - - if (unicode_codepoint > 0xffff) - return 0; + uchar *data; + ushort fmt; + uint32 index_map; + union { + int32 bytes; + struct { + uint32 first; + uint32 count; + }; + struct { + ushort segcount; + ushort srchrange; + ushort entrysel; + ushort rangeshft; + + uint32 end; + uint32 search; + }; - // they lie from endCount .. endCount + segCount - // but searchRange is the nearest power of two, so... - if (unicode_codepoint >= ttushort(data + search + rangeShift*2)) - search += rangeShift*2; - - // now decrement to bias correctly to find smallest - search -= 2; - while (entrySelector) { - ushort end; - searchRange >>= 1; - end = ttushort(data + search + searchRange*2); - if (unicode_codepoint > end) - search += searchRange*2; - --entrySelector; - } - search += 2; + struct { + uint32 begg, begc, endc, ngroups; + int32 low, mid, high; + }; + } v; + + data = info->data; + index_map = info->index_map; + + fmt = ttushort(data + index_map + 0); + switch (fmt) { + case 0: /* apple byte encoding */ + v.bytes = ttushort(data + index_map + 2); + if (unicode_codepoint < v.bytes-6) + return ttBYTE(data + index_map + 6 + unicode_codepoint); + return 0; - { - ushort offset, start; - ushort item = (ushort) ((search - endCount) >> 1); + case 6: + v.first = ttushort(data + index_map + 6); + v.count = ttushort(data + index_map + 8); + if ((uint32)unicode_codepoint >= v.first && (uint32)unicode_codepoint < v.first+v.count) + return ttushort(data + index_map + 10 + (unicode_codepoint - v.first)*2); + return 0; - assert(unicode_codepoint <= ttushort(data + endCount + 2*item)); - start = ttushort(data + index_map + 14 + segcount*2 + 2 + 2*item); - if (unicode_codepoint < start) - return 0; + case 2: + panicf("high-byte mapping for asian characters not implemented"); + return 0; - offset = ttushort(data + index_map + 14 + segcount*6 + 2 + 2*item); - if (offset == 0) - return (ushort) (unicode_codepoint + ttshort(data + index_map + 14 + segcount*4 + 2 + 2*item)); + case 4: /* standard mapping for windows fonts: binary search collection of ranges */ + v.segcount = ttushort(data+index_map+6) >> 1; + v.srchrange = ttushort(data+index_map+8) >> 1; + v.entrysel = ttushort(data+index_map+10); + v.rangeshft = ttushort(data+index_map+12) >> 1; + + // do a binary search of the segments + v.end = index_map + 14; + v.search = v.end; + + if (unicode_codepoint > 0xffff) + return 0; + + // they lie from endCount .. endCount + segCount + // but searchRange is the nearest power of two, so... + if (unicode_codepoint >= ttushort(data + v.search + v.rangeshft*2)) + v.search += v.rangeshft*2; + + // now decrement to bias correctly to find smallest + v.search -= 2; + while (v.entrysel) { + ushort end; + v.srchrange >>= 1; + end = ttushort(data + v.search + v.srchrange*2); + if (unicode_codepoint > end) + v.search += v.srchrange*2; + --v.entrysel; + } + v.search += 2; + + { + ushort offset, start; + ushort item = (ushort) ((v.search - v.end) >> 1); + + assert(unicode_codepoint <= ttushort(data + v.end+ 2*item)); + start = ttushort(data + index_map + 14 + v.segcount*2 + 2 + 2*item); + if (unicode_codepoint < start) + return 0; + + offset = ttushort(data + index_map + 14 + v.segcount*6 + 2 + 2*item); + if (offset == 0) + return (ushort) (unicode_codepoint + ttshort(data + index_map + 14 + v.segcount*4 + 2 + 2*item)); + + return ttushort(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + v.segcount*6 + 2 + 2*item); + } + + case 12: case 13: + v.ngroups = ttulong(data+index_map+12); + v.low = 0; v.high = (int32)v.ngroups; + // Binary search the right group. + while (v.low < v.high) { + v.mid = v.low + ((v.high-v.low) >> 1); // rounds down, so low <= mid < high + v.begc = ttulong(data+index_map+16+v.mid*12); + v.endc = ttulong(data+index_map+16+v.mid*12+4); + if ((uint32)unicode_codepoint < v.begc) + v.high = v.mid; + else if ((uint32) unicode_codepoint > v.endc) + v.low = v.mid+1; + else { + v.begg = ttulong(data+index_map+16+v.mid*12+8); + if (fmt == 12) + return v.begg + unicode_codepoint-v.begc; + else // fmt == 13 + return v.begg; + } + } + return 0; // not found + + default: + ; + } - return ttushort(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); - } - } else if (format == 12 || format == 13) { - uint32 ngroups = ttulong(data+index_map+12); - int32 low,high; - low = 0; high = (int32)ngroups; - // Binary search the right group. - while (low < high) { - int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high - uint32 start_char = ttulong(data+index_map+16+mid*12); - uint32 end_char = ttulong(data+index_map+16+mid*12+4); - if ((uint32) unicode_codepoint < start_char) - high = mid; - else if ((uint32) unicode_codepoint > end_char) - low = mid+1; - else { - uint32 start_glyph = ttulong(data+index_map+16+mid*12+8); - if (format == 12) - return start_glyph + unicode_codepoint-start_char; - else // format == 13 - return start_glyph; - } - } - return 0; // not found - } - // @TODO - assert(0); - return 0; + // @TODO + assert(0); + return 0; } int -- cgit v1.2.1