]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libttf/cmap.c
zuke: include libtags in CFLAGS
[plan9front.git] / sys / src / libttf / cmap.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <ttf.h>
5 #include "impl.h"
6
7 int
8 ttffindchar(TTFont *fx, Rune r)
9 {
10         int i, j, k, rv;
11         TTChMap *p;
12         TTFontU *f;
13
14         f = fx->u;
15         i = 0;
16         j = f->ncmap - 1;
17         if(r < f->cmap[0].start || r > f->cmap[j].end) return 0;
18         while(i < j){
19                 k = (i + j) / 2;
20                 if(f->cmap[k].end < r)
21                         i = k+1;
22                 else if(f->cmap[k].start > r)
23                         j = k-1;
24                 else
25                         i = j = k;
26         }
27         if(i > j) return 0;
28         p = &f->cmap[i];
29         if(r < p->start || r > p->end) return 0;
30         if((p->flags & TTCINVALID) != 0) return 0;
31         if(p->tab != nil)
32                 return p->tab[r - p->start];
33         rv = r + p->delta;
34         if((p->flags & TTCDELTA16) != 0)
35                 rv = (u16int)rv;
36         return rv;
37 }
38
39 int
40 ttfenumchar(TTFont *fx, Rune r, Rune *rp)
41 {
42         int i, j, k, rv;
43         TTChMap *p;
44         TTFontU *f;
45
46         f = fx->u;
47         i = 0;
48         j = f->ncmap - 1;
49         if(r > f->cmap[j].end) return 0;
50         while(i < j){
51                 k = (i + j) / 2;
52                 if(f->cmap[k].end < r)
53                         i = k+1;
54                 else if(f->cmap[k].start > r)
55                         j = k-1;
56                 else
57                         i = j = k;
58         }
59         if(j < 0) j = 0;
60         for(p = &f->cmap[j]; p < &f->cmap[f->ncmap]; p++){
61                 if((p->flags & TTCINVALID) != 0)
62                         continue;
63                 if(r < p->start)
64                         r = p->start;
65                 if(p->tab != nil){
66                         SET(rv);
67                         while(r <= p->end && (rv = p->tab[r - p->start], rv == 0))
68                                 r++;
69                         if(r > p->end)
70                                 continue;
71                         if(rp != nil)
72                                 *rp = r;
73                         return rv;
74                 }
75                 while(r < p->end){
76                         rv = r + p->delta;
77                         if((p->flags & TTCDELTA16) != 0)
78                                 rv = (u16int) rv;
79                         if(rv != 0){
80                                 if(rp != nil)
81                                         *rp = r;
82                                 return rv;
83                         }
84                 }
85         }
86         return 0;
87 }
88
89 static int
90 ttfgotosub(TTFontU *f)
91 {
92         int i;
93         u16int nsub, id, sid;
94         int rank, maxrank;
95         u32int maxoff, off;
96         #define SUBID(a,b) ((a)<<16|(b))
97
98         if(ttfgototable(f, "cmap") < 0)
99                 return -1;
100         ttfunpack(f, ".. w", &nsub);
101         maxrank = 0;
102         maxoff = 0;
103         for(i = 0; i < nsub; i++){
104                 ttfunpack(f, "wwl", &id, &sid, &off);
105                 switch(id << 16 | sid){
106                 case SUBID(0, 4): /* Unicode 2.0 or later (BMP and non-BMP) */
107                         rank = 100;
108                         break;
109                 case SUBID(3, 10): /* Windows, UCS-4 */
110                         rank = 80;
111                         break;
112                 case SUBID(0, 0): /* Unicode default */
113                 case SUBID(0, 1): /* Unicode 1.1 */
114                 case SUBID(0, 2): /* ISO 10646 */
115                 case SUBID(0, 3): /* Unicode 2.0 (BMP) */
116                         rank = 60;
117                         break;
118                 case SUBID(3, 1): /* Windows, UCS-2 */
119                         rank = 40;
120                         break;
121                 case SUBID(3, 0): /* Windows, Symbol */
122                         rank = 20;
123                         break;
124                 default:
125                         rank = 0;
126                         break;
127                 }
128                 if(rank > maxrank){
129                         maxrank = rank;
130                         maxoff = off;
131                 }
132         }
133         if(maxrank == 0){
134                 werrstr("no suitable character table");
135                 return -1;
136         }
137         if(ttfgototable(f, "cmap") < 0)
138                 return -1;
139         Bseek(f->bin, maxoff, 1);
140         return 0;
141
142 }
143
144 static int
145 cmap0(TTFontU *f)
146 {
147         u16int len;
148         int i;
149         u8int *p;
150         int *q;
151
152         ttfunpack(f, "w2", &len);
153         if(len < 262){
154                 werrstr("character table too short");
155                 return -1;
156         }
157         f->cmap = mallocz(sizeof(TTChMap), 1);
158         if(f->cmap == nil)
159                 return -1;
160         f->ncmap = 1;
161         f->cmap->start = 0;
162         f->cmap->end = 0xff;
163         f->cmap->tab = mallocz(256 * sizeof(int), 1);
164         if(f->cmap->tab == nil)
165                 return -1;
166         Bread(f->bin, f->cmap->tab, 256 * sizeof(int));
167         p = (u8int*)f->cmap->tab + 256;
168         q = f->cmap->tab + 256;
169         for(i = 255; i >= 0; i--)
170                 *--q = *--p;
171         return 0;
172 }
173
174 static int
175 cmap4(TTFontU *f)
176 {
177         u16int len, ncmap;
178         int i, j, n, n0, off;
179         u16int v;
180         u8int *buf;
181
182         ttfunpack(f, "w2", &len);
183         if(len < 16){
184                 werrstr("character table too short");
185                 return -1;
186         }
187         ttfunpack(f, "w6", &ncmap);
188         ncmap /= 2;
189         if(len < 16 + 8 * ncmap){
190                 werrstr("character table too short");
191                 return -1;
192         }
193         f->cmap = mallocz(sizeof(TTChMap) * ncmap, 1);
194         if(f->cmap == nil) return -1;
195         f->ncmap = ncmap;
196         for(i = 0; i < ncmap; i++)
197                 f->cmap[i].flags = TTCDELTA16;
198         for(i = 0; i < ncmap; i++)
199                 ttfunpack(f, "W", &f->cmap[i].end);
200         ttfunpack(f, "..");
201         for(i = 0; i < ncmap; i++)
202                 ttfunpack(f, "W", &f->cmap[i].start);
203         for(i = 0; i < ncmap; i++)
204                 ttfunpack(f, "W", &f->cmap[i].delta);
205         for(i = 0; i < ncmap; i++)
206                 ttfunpack(f, "W", &f->cmap[i].temp);
207         len -= 10 + 8 * ncmap;
208         buf = malloc(len);
209         if(buf == nil)
210                 return -1;
211         Bread(f->bin, buf, len);
212         for(i = 0; i < ncmap; i++){
213                 if(f->cmap[i].temp == 0) continue;
214                 n0 = f->cmap[i].end - f->cmap[i].start + 1;
215                 n = n0;
216                 off = f->cmap[i].temp - (ncmap - i) * 2;
217                 if(off + 2 * n > len) n = (len - off) / 2;
218                 if(off < 0 || n <= 0){
219                         f->cmap[i].flags |= TTCINVALID;
220                         continue;
221                 }
222                 f->cmap[i].tab = mallocz(n0 * sizeof(int), 1);
223                 if(f->cmap[i].tab == nil)
224                         return -1;
225                 for(j = 0; j < n; j++){
226                         v = buf[off + 2*j] << 8 | buf[off + 2*j + 1];
227                         if(v != 0) v += f->cmap[i].delta;
228                         f->cmap[i].tab[j] = v;
229                 }
230         }
231         free(buf);
232         return 0;
233 }
234
235 static int
236 cmap6(TTFontU *f)
237 {
238         u16int len, first, cnt, v;
239         int *p;
240         u8int *q;
241
242         ttfunpack(f, "w2", &len);
243         if(len < 12){
244                 werrstr("character table too short");
245                 return -1;
246         }
247         ttfunpack(f, "ww", &first, &cnt);
248         f->cmap = mallocz(sizeof(TTChMap), 1);
249         if(f->cmap == nil)
250                 return -1;
251         f->ncmap = 1;
252         f->cmap->start = first;
253         f->cmap->end = first + len - 1;
254         f->cmap->tab = mallocz(cnt * sizeof(int), 1);
255         if(f->cmap->tab == nil)
256                 return -1;
257         if(len < 10 + 2 * cnt){
258                 werrstr("character table too short");
259                 return -1;
260         }
261         Bread(f->bin, f->cmap->tab, 2 * cnt);
262         p = f->cmap->tab + cnt;
263         q = (u8int*) f->cmap->tab + 2 * cnt;
264         while(p > f->cmap->tab){
265                 v = *--q;
266                 v |= *--q << 8;
267                 *--p = v;
268         }
269         return 0;
270 }
271
272 static int
273 cmap12(TTFontU *f)
274 {
275         u32int len;
276         u32int ncmap;
277         int i;
278         
279         ttfunpack(f, "2l4", &len);
280         if(len < 16){
281                 werrstr("character table too short");
282                 return -1;
283         }
284         ttfunpack(f, "l", &ncmap);
285         if(len < 16 + 12 * ncmap){
286                 werrstr("character table too short");
287                 return -1;
288         }
289         f->cmap = mallocz(sizeof(TTChMap) * ncmap, 1);
290         if(f->cmap == nil)
291                 return -1;
292         f->ncmap = ncmap;
293         for(i = 0; i < ncmap; i++){
294                 ttfunpack(f, "lll", &f->cmap[i].start, &f->cmap[i].end, &f->cmap[i].delta);
295                 f->cmap[i].delta -= f->cmap[i].start;
296         }
297         return 0;
298 }
299
300 int (*cmaphand[])(TTFontU *) = {
301         [0] cmap0,
302         [4] cmap4,
303         [6] cmap6,
304         [12] cmap12,
305 };
306
307 int
308 ttfparsecmap(TTFontU *f)
309 {
310         u16int format;
311
312         if(ttfgotosub(f) < 0)
313                 return -1;
314         ttfunpack(f, "w", &format);
315         if(format >= nelem(cmaphand) || cmaphand[format] == nil){
316                 werrstr("character table in unknown format %d", format);
317                 return -1;
318         }
319         if(cmaphand[format](f) < 0)
320                 return -1;
321         return 0;
322 }