Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_tlsv12/sys/src/libdraw/font.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <draw.h>
4
 
5
static int	fontresize(Font*, int, int, int);
6
static int	freeup(Font*);
7
 
8
#define	PJW	0	/* use NUL==pjw for invisible characters */
9
 
10
int
11
cachechars(Font *f, char **ss, Rune **rr, ushort *cp, int max, int *wp, char **subfontname)
12
{
13
	int i, th, sh, h, ld, w, rw, wid, nc;
14
	char *sp;
15
	Rune r, *rp, vr;
16
	ulong a;
17
	Cacheinfo *c, *tc, *ec;
18
 
19
	if(ss){
20
		sp = *ss;
21
		rp = L"";
22
	}else{
23
		sp = "";
24
		rp = *rr;
25
	}
26
	wid = 0;
27
	*subfontname = 0;
28
	for(i=0; i<max && (*sp || *rp); sp+=w, rp+=rw){
29
		if(ss){
30
			r = *(uchar*)sp;
31
			if(r < Runeself)
32
				w = 1;
33
			else{
34
				w = chartorune(&vr, sp);
35
				r = vr;
36
			}
37
			rw = 0;
38
		}else{
39
			r = *rp;
40
			w = 0;
41
			rw = 1;
42
		}
43
 
44
		sh = (17 * (uint)r) & (f->ncache-NFLOOK-1);
45
		c = &f->cache[sh];
46
		ec = c+NFLOOK;
47
		h = sh;
48
		while(c < ec){
49
			if(c->value==r && c->age)
50
				goto Found;
51
			c++;
52
			h++;
53
		}
54
 
55
		/*
56
		 * Not found; toss out oldest entry
57
		 */
58
		a = ~0;
59
		th = sh;
60
		tc = &f->cache[th];
61
		while(tc < ec){
62
			if(tc->age < a){
63
				a = tc->age;
64
				h = th;
65
				c = tc;
66
			}
67
			tc++;
68
			th++;
69
		}
70
 
71
		if(a && (f->age-a)<500){	/* kicking out too recent; resize */
72
			nc = 2*(f->ncache-NFLOOK) + NFLOOK;
73
			if(nc <= MAXFCACHE){
74
				if(i == 0)
75
					fontresize(f, f->width, nc, f->maxdepth);
76
				/* else flush first; retry will resize */
77
				break;
78
			}
79
		}
80
 
81
		if(c->age == f->age)	/* flush pending string output */
82
			break;
83
 
84
		ld = loadchar(f, r, c, h, i, subfontname);
85
		if(ld <= 0){
86
			if(ld == 0)
87
				continue;
88
			break;
89
		}
90
		c = &f->cache[h];	/* may have reallocated f->cache */
91
 
92
	    Found:
93
		wid += c->width;
94
		c->age = f->age;
95
		cp[i] = h;
96
		i++;
97
	}
98
	if(ss)
99
		*ss = sp;
100
	else
101
		*rr = rp;
102
	*wp = wid;
103
	return i;
104
}
105
 
106
void
107
agefont(Font *f)
108
{
109
	Cacheinfo *c, *ec;
110
	Cachesubf *s, *es;
111
 
112
	f->age++;
113
	if(f->age == 65536){
114
		/*
115
		 * Renormalize ages
116
		 */
117
		c = f->cache;
118
		ec = c+f->ncache;
119
		while(c < ec){
120
			if(c->age){
121
				c->age >>= 2;
122
				c->age++;
123
			}
124
			c++;
125
		}
126
		s = f->subf;
127
		es = s+f->nsubf;
128
		while(s < es){
129
			if(s->age){
130
				if(s->age<SUBFAGE && s->cf->name != nil){
131
					/* clean up */
132
					if(display &&
133
					    s->f != display->defaultsubfont)
134
						freesubfont(s->f);
135
					s->cf = nil;
136
					s->f = nil;
137
					s->age = 0;
138
				}else{
139
					s->age >>= 2;
140
					s->age++;
141
				}
142
			}
143
			s++;
144
		}
145
		f->age = (65536>>2) + 1;
146
	}
147
}
148
 
149
static Subfont*
150
cf2subfont(Cachefont *cf, Font *f)
151
{
152
	int depth;
153
	char *name;
154
	Subfont *sf;
155
 
156
	name = cf->subfontname;
157
	if(name == nil){
158
		if(f->display && f->display->screenimage)
159
			depth = f->display->screenimage->depth;
160
		else
161
			depth = 8;
162
		name = subfontname(cf->name, f->name, depth);
163
		if(name == nil)
164
			return nil;
165
		cf->subfontname = name;
166
	}
167
	sf = lookupsubfont(f->display, name);
168
	return sf;
169
}
170
 
171
/* return 1 if load succeeded, 0 if failed, -1 if must retry */
172
int
173
loadchar(Font *f, Rune r, Cacheinfo *c, int h, int noflush, char **subfontname)
174
{
175
	int i, oi, wid, top, bottom;
176
	Rune pic;
177
	Fontchar *fi;
178
	Cachefont *cf;
179
	Cachesubf *subf, *of;
180
	uchar *b;
181
 
182
	pic = r;
183
    Again:
184
	for(i=0; i<f->nsub; i++){
185
		cf = f->sub[i];
186
		if(cf->min<=pic && pic<=cf->max)
187
			goto Found;
188
	}
189
    TryPJW:
190
	if(pic != PJW){
191
		pic = PJW;
192
		goto Again;
193
	}
194
	return 0;
195
 
196
    Found:
197
	/*
198
	 * Choose exact or oldest
199
	 */
200
	oi = 0;
201
	subf = &f->subf[0];
202
	for(i=0; i<f->nsubf; i++){
203
		if(cf == subf->cf)
204
			goto Found2;
205
		if(subf->age < f->subf[oi].age)
206
			oi = i;
207
		subf++;
208
	}
209
	subf = &f->subf[oi];
210
 
211
	if(subf->f){
212
		if(f->age-subf->age>SUBFAGE || f->nsubf>MAXSUBF){
213
    Toss:
214
			/* ancient data; toss */
215
			freesubfont(subf->f);
216
			subf->cf = nil;
217
			subf->f = nil;
218
			subf->age = 0;
219
		}else{				/* too recent; grow instead */
220
			of = f->subf;
221
			f->subf = malloc((f->nsubf+DSUBF)*sizeof *subf);
222
			if(f->subf == nil){
223
				f->subf = of;
224
				goto Toss;
225
			}
226
			memmove(f->subf, of, (f->nsubf+DSUBF)*sizeof *subf);
227
			memset(f->subf+f->nsubf, 0, DSUBF*sizeof *subf);
228
			subf = &f->subf[f->nsubf];
229
			f->nsubf += DSUBF;
230
			free(of);
231
		}
232
	}
233
	subf->age = 0;
234
	subf->cf = nil;
235
	subf->f = cf2subfont(cf, f);
236
	if(subf->f == nil){
237
		if(cf->subfontname == nil)
238
			goto TryPJW;
239
		*subfontname = cf->subfontname;
240
		return -1;
241
	}
242
 
243
	subf->cf = cf;
244
	if(subf->f->ascent > f->ascent && f->display){
245
		/* should print something? this is a mistake in the font file */
246
		/* must prevent c->top from going negative when loading cache */
247
		Image *b;
248
		int d, t;
249
		d = subf->f->ascent - f->ascent;
250
		b = subf->f->bits;
251
		draw(b, b->r, b, nil, addpt(b->r.min, Pt(0, d)));
252
		draw(b, Rect(b->r.min.x, b->r.max.y-d, b->r.max.x, b->r.max.y), f->display->black, nil, b->r.min);
253
		for(i=0; i<subf->f->n; i++){
254
			t = subf->f->info[i].top-d;
255
			if(t < 0)
256
				t = 0;
257
			subf->f->info[i].top = t;
258
			t = subf->f->info[i].bottom-d;
259
			if(t < 0)
260
				t = 0;
261
			subf->f->info[i].bottom = t;
262
		}
263
		subf->f->ascent = f->ascent;
264
	}
265
 
266
    Found2:
267
	subf->age = f->age;
268
 
269
	/* possible overflow here, but works out okay */
270
	pic += cf->offset;
271
	pic -= cf->min;
272
	if(pic >= subf->f->n)
273
		goto TryPJW;
274
	fi = &subf->f->info[pic];
275
	if(fi->width == 0)
276
		goto TryPJW;
277
	wid = (fi+1)->x - fi->x;
278
	if(f->width < wid || f->width == 0 || f->maxdepth < subf->f->bits->depth){
279
		/*
280
		 * Flush, free, reload (easier than reformatting f->b)
281
		 */
282
		if(noflush)
283
			return -1;
284
		if(f->width < wid)
285
			f->width = wid;
286
		if(f->maxdepth < subf->f->bits->depth)
287
			f->maxdepth = subf->f->bits->depth;
288
		i = fontresize(f, f->width, f->ncache, f->maxdepth);
289
		if(i <= 0)
290
			return i;
291
		/* c is still valid as didn't reallocate f->cache */
292
	}
293
	c->value = r;
294
	top = fi->top + (f->ascent-subf->f->ascent);
295
	bottom = fi->bottom + (f->ascent-subf->f->ascent);
296
	c->width = fi->width;
297
	c->x = h*f->width;
298
	c->left = fi->left;
299
	if(f->display == nil)
300
		return 1;
301
	flushimage(f->display, 0);	/* flush any pending errors */
302
	b = bufimage(f->display, 37);
303
	if(b == 0)
304
		return 0;
305
	b[0] = 'l';
306
	BPLONG(b+1, f->cacheimage->id);
307
	BPLONG(b+5, subf->f->bits->id);
308
	BPSHORT(b+9, c-f->cache);
309
	BPLONG(b+11, c->x);
310
	BPLONG(b+15, top);
311
	BPLONG(b+19, c->x+((fi+1)->x-fi->x));
312
	BPLONG(b+23, bottom);
313
	BPLONG(b+27, fi->x);
314
	BPLONG(b+31, fi->top);
315
	b[35] = fi->left;
316
	b[36] = fi->width;
317
	return 1;
318
}
319
 
320
/* release all subfonts, return number freed */
321
static
322
int
323
freeup(Font *f)
324
{
325
	Cachesubf *s, *es;
326
	int nf;
327
 
328
	if(f->sub[0]->name == nil)	/* font from mkfont; don't free */
329
		return 0;
330
	s = f->subf;
331
	es = s+f->nsubf;
332
	nf = 0;
333
	while(s < es){
334
		if(s->age){
335
			freesubfont(s->f);
336
			s->cf = nil;
337
			s->f = nil;
338
			s->age = 0;
339
			nf++;
340
		}
341
		s++;
342
	}
343
	return nf;
344
}
345
 
346
/* return whether resize succeeded && f->cache is unchanged */
347
static int
348
fontresize(Font *f, int wid, int ncache, int depth)
349
{
350
	Cacheinfo *i;
351
	int ret;
352
	Image *new;
353
	uchar *b;
354
	Display *d;
355
 
356
	ret = 0;
357
	if(depth <= 0)
358
		depth = 1;
359
	if(wid <= 0)
360
		wid = 1;
361
 
362
	d = f->display;
363
	if(d == nil)
364
		goto Nodisplay;
365
 
366
	new = allocimage(d, Rect(0, 0, ncache*wid, f->height), CHAN1(CGrey, depth), 0, 0);
367
	if(new == nil){
368
		fprint(2, "font cache resize failed: %r\n");
369
		abort();
370
		goto Return;
371
	}
372
	flushimage(d, 0);	/* flush any pending errors */
373
	b = bufimage(d, 1+4+4+1);
374
	if(b == 0){
375
		freeimage(new);
376
		goto Return;
377
	}
378
	b[0] = 'i';
379
	BPLONG(b+1, new->id);
380
	BPLONG(b+5, ncache);
381
	b[9] = f->ascent;
382
	if(flushimage(d, 0) < 0){
383
		fprint(2, "resize: init failed: %r\n");
384
		freeimage(new);
385
		goto Return;
386
	}
387
	freeimage(f->cacheimage);
388
	f->cacheimage = new;
389
    Nodisplay:
390
	f->width = wid;
391
	f->maxdepth = depth;
392
	ret = 1;
393
	if(f->ncache != ncache){
394
		i = malloc(ncache*sizeof f->cache[0]);
395
		if(i != nil){
396
			ret = 0;
397
			free(f->cache);
398
			f->ncache = ncache;
399
			f->cache = i;
400
		}
401
		/* else just wipe the cache clean and things will be ok */
402
	}
403
    Return:
404
	memset(f->cache, 0, f->ncache*sizeof f->cache[0]);
405
	return ret;
406
}