aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2020-06-02 16:23:59 -0700
committerNicholas Noll <nbnoll@eml.cc>2020-06-02 16:23:59 -0700
commit69adb19d98114d7a35bf73389b9098de33adf42c (patch)
tree9dd88389f02c454d9010288dc22ebbcb56351968 /sys
parent269b52b8c87e692517ea2dc1da14fd19c3c236c2 (diff)
migrated glyph index to a switch statement
Diffstat (limited to 'sys')
-rw-r--r--sys/libfont/font.c201
1 files changed, 117 insertions, 84 deletions
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