summaryrefslogtreecommitdiff
path: root/sys/src/libttf/cmap.c
diff options
context:
space:
mode:
authoraiju <devnull@localhost>2018-06-09 14:33:19 +0000
committeraiju <devnull@localhost>2018-06-09 14:33:19 +0000
commitdb71e19005574388bdc368081848327a5c104e5a (patch)
treedb33f3a6c6aac49dd9d5bd5a04145b3acf1f0cb7 /sys/src/libttf/cmap.c
parent198f10bb25382882c4abd9081dac4dd74dbdbb9f (diff)
add libttf
Diffstat (limited to 'sys/src/libttf/cmap.c')
-rw-r--r--sys/src/libttf/cmap.c322
1 files changed, 322 insertions, 0 deletions
diff --git a/sys/src/libttf/cmap.c b/sys/src/libttf/cmap.c
new file mode 100644
index 000000000..94092f03e
--- /dev/null
+++ b/sys/src/libttf/cmap.c
@@ -0,0 +1,322 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ttf.h>
+#include "impl.h"
+
+int
+ttffindchar(TTFont *fx, Rune r)
+{
+ int i, j, k, rv;
+ TTChMap *p;
+ TTFontU *f;
+
+ f = fx->u;
+ i = 0;
+ j = f->ncmap - 1;
+ if(r < f->cmap[0].start || r > f->cmap[j].end) return 0;
+ while(i < j){
+ k = (i + j) / 2;
+ if(f->cmap[k].end < r)
+ i = k+1;
+ else if(f->cmap[k].start > r)
+ j = k-1;
+ else
+ i = j = k;
+ }
+ if(i > j) return 0;
+ p = &f->cmap[i];
+ if(r < p->start || r > p->end) return 0;
+ if((p->flags & TTCINVALID) != 0) return 0;
+ if(p->tab != nil)
+ return p->tab[r - p->start];
+ rv = r + p->delta;
+ if((p->flags & TTCDELTA16) != 0)
+ rv = (u16int)rv;
+ return rv;
+}
+
+int
+ttfenumchar(TTFont *fx, Rune r, Rune *rp)
+{
+ int i, j, k, rv;
+ TTChMap *p;
+ TTFontU *f;
+
+ f = fx->u;
+ i = 0;
+ j = f->ncmap - 1;
+ if(r > f->cmap[j].end) return 0;
+ while(i < j){
+ k = (i + j) / 2;
+ if(f->cmap[k].end < r)
+ i = k+1;
+ else if(f->cmap[k].start > r)
+ j = k-1;
+ else
+ i = j = k;
+ }
+ if(j < 0) j = 0;
+ for(p = &f->cmap[j]; p < &f->cmap[f->ncmap]; p++){
+ if((p->flags & TTCINVALID) != 0)
+ continue;
+ if(r < p->start)
+ r = p->start;
+ if(p->tab != nil){
+ SET(rv);
+ while(r <= p->end && (rv = p->tab[r - p->start], rv == 0))
+ r++;
+ if(r > p->end)
+ continue;
+ if(rp != nil)
+ *rp = r;
+ return rv;
+ }
+ while(r < p->end){
+ rv = r + p->delta;
+ if((p->flags & TTCDELTA16) != 0)
+ rv = (u16int) rv;
+ if(rv != 0){
+ if(rp != nil)
+ *rp = r;
+ return rv;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+ttfgotosub(TTFontU *f)
+{
+ int i;
+ u16int nsub, id, sid, off;
+ int rank, maxrank;
+ u32int maxoff;
+ #define SUBID(a,b) ((a)<<16|(b))
+
+ if(ttfgototable(f, "cmap") < 0)
+ return -1;
+ ttfunpack(f, ".. w", &nsub);
+ maxrank = 0;
+ maxoff = 0;
+ for(i = 0; i < nsub; i++){
+ ttfunpack(f, "wwl", &id, &sid, &off);
+ switch(id << 16 | sid){
+ case SUBID(0, 4): /* Unicode 2.0 or later (BMP and non-BMP) */
+ rank = 100;
+ break;
+ case SUBID(0, 0): /* Unicode default */
+ case SUBID(0, 1): /* Unicode 1.1 */
+ case SUBID(0, 2): /* ISO 10646 */
+ case SUBID(0, 3): /* Unicode 2.0 (BMP) */
+ rank = 80;
+ break;
+ case SUBID(3, 10): /* Windows, UCS-4 */
+ rank = 60;
+ break;
+ case SUBID(3, 1): /* Windows, UCS-2 */
+ rank = 40;
+ break;
+ case SUBID(3, 0): /* Windows, Symbol */
+ rank = 20;
+ break;
+ default:
+ rank = 0;
+ break;
+ }
+ if(rank > maxrank){
+ maxrank = rank;
+ maxoff = off;
+ }
+ }
+ if(maxrank == 0){
+ werrstr("no suitable character table");
+ return -1;
+ }
+ if(ttfgototable(f, "cmap") < 0)
+ return -1;
+ Bseek(f->bin, maxoff, 1);
+ return 0;
+
+}
+
+static int
+cmap0(TTFontU *f)
+{
+ u16int len;
+ int i;
+ u8int *p;
+ int *q;
+
+ ttfunpack(f, "w2", &len);
+ if(len < 262){
+ werrstr("character table too short");
+ return -1;
+ }
+ f->cmap = mallocz(sizeof(TTChMap), 1);
+ if(f->cmap == nil)
+ return -1;
+ f->ncmap = 1;
+ f->cmap->start = 0;
+ f->cmap->end = 0xff;
+ f->cmap->tab = mallocz(256 * sizeof(int), 1);
+ if(f->cmap->tab == nil)
+ return -1;
+ Bread(f->bin, f->cmap->tab, 256 * sizeof(int));
+ p = (u8int*)f->cmap->tab + 256;
+ q = f->cmap->tab + 256;
+ for(i = 255; i >= 0; i--)
+ *--q = *--p;
+ return 0;
+}
+
+static int
+cmap4(TTFontU *f)
+{
+ u16int len, ncmap;
+ int i, j, n, n0, off;
+ u16int v;
+ u8int *buf;
+
+ ttfunpack(f, "w2", &len);
+ if(len < 16){
+ werrstr("character table too short");
+ return -1;
+ }
+ ttfunpack(f, "w6", &ncmap);
+ ncmap /= 2;
+ if(len < 16 + 8 * ncmap){
+ werrstr("character table too short");
+ return -1;
+ }
+ f->cmap = mallocz(sizeof(TTChMap) * ncmap, 1);
+ if(f->cmap == nil) return -1;
+ f->ncmap = ncmap;
+ for(i = 0; i < ncmap; i++)
+ f->cmap[i].flags = TTCDELTA16;
+ for(i = 0; i < ncmap; i++)
+ ttfunpack(f, "W", &f->cmap[i].end);
+ ttfunpack(f, "..");
+ for(i = 0; i < ncmap; i++)
+ ttfunpack(f, "W", &f->cmap[i].start);
+ for(i = 0; i < ncmap; i++)
+ ttfunpack(f, "W", &f->cmap[i].delta);
+ for(i = 0; i < ncmap; i++)
+ ttfunpack(f, "W", &f->cmap[i].temp);
+ len -= 10 + 8 * ncmap;
+ buf = malloc(len);
+ if(buf == nil)
+ return -1;
+ Bread(f->bin, buf, len);
+ for(i = 0; i < ncmap; i++){
+ if(f->cmap[i].temp == 0) continue;
+ n0 = f->cmap[i].end - f->cmap[i].start + 1;
+ n = n0;
+ off = f->cmap[i].temp - (ncmap - i) * 2;
+ if(off + 2 * n > len) n = (len - off) / 2;
+ if(off < 0 || n <= 0){
+ f->cmap[i].flags |= TTCINVALID;
+ continue;
+ }
+ f->cmap[i].tab = mallocz(n0 * sizeof(int), 1);
+ if(f->cmap[i].tab == nil)
+ return -1;
+ for(j = 0; j < n; j++){
+ v = buf[off + 2*j] << 8 | buf[off + 2*j + 1];
+ if(v != 0) v += f->cmap[i].delta;
+ f->cmap[i].tab[j] = v;
+ }
+ }
+ free(buf);
+ return 0;
+}
+
+static int
+cmap6(TTFontU *f)
+{
+ u16int len, first, cnt, v;
+ int *p;
+ u8int *q;
+
+ ttfunpack(f, "w2", &len);
+ if(len < 12){
+ werrstr("character table too short");
+ return -1;
+ }
+ ttfunpack(f, "ww", &first, &cnt);
+ f->cmap = mallocz(sizeof(TTChMap), 1);
+ if(f->cmap == nil)
+ return -1;
+ f->ncmap = 1;
+ f->cmap->start = first;
+ f->cmap->end = first + len - 1;
+ f->cmap->tab = mallocz(cnt * sizeof(int), 1);
+ if(f->cmap->tab == nil)
+ return -1;
+ if(len < 10 + 2 * cnt){
+ werrstr("character table too short");
+ return -1;
+ }
+ Bread(f->bin, f->cmap->tab, 2 * cnt);
+ p = f->cmap->tab + cnt;
+ q = (u8int*) f->cmap->tab + 2 * cnt;
+ while(p > f->cmap->tab){
+ v = *--q;
+ v |= *--q << 8;
+ *--p = v;
+ }
+ return 0;
+}
+
+static int
+cmap12(TTFontU *f)
+{
+ u32int len;
+ u32int ncmap;
+ int i;
+
+ ttfunpack(f, "2l4", &len);
+ if(len < 16){
+ werrstr("character table too short");
+ return -1;
+ }
+ ttfunpack(f, "l", &ncmap);
+ if(len < 16 + 12 * ncmap){
+ werrstr("character table too short");
+ return -1;
+ }
+ f->cmap = mallocz(sizeof(TTChMap) * ncmap, 1);
+ if(f->cmap == nil)
+ return -1;
+ f->ncmap = ncmap;
+ for(i = 0; i < ncmap; i++){
+ ttfunpack(f, "lll", &f->cmap[i].start, &f->cmap[i].end, &f->cmap[i].delta);
+ f->cmap[i].delta -= f->cmap[i].start;
+ }
+ return 0;
+}
+
+int (*cmaphand[])(TTFontU *) = {
+ [0] cmap0,
+ [4] cmap4,
+ [6] cmap6,
+ [12] cmap12,
+};
+
+int
+ttfparsecmap(TTFontU *f)
+{
+ u16int format;
+
+ if(ttfgotosub(f) < 0)
+ return -1;
+ ttfunpack(f, "w", &format);
+ if(format >= nelem(cmaphand) || cmaphand[format] == nil){
+ werrstr("character table in unknown format %d", format);
+ return -1;
+ }
+ if(cmaphand[format](f) < 0)
+ return -1;
+ return 0;
+}