1 /**
2 ** buildfnt.c ---- allocate and fill a font descriptor
3 **
4 ** Copyright (c) 1995 Csaba Biegl, 820 Stirrup Dr, Nashville, TN 37221
5 ** [e-mail: csaba@vuse.vanderbilt.edu]
6 **
7 ** This file is part of the GRX graphics library.
8 **
9 ** The GRX graphics library is free software; you can redistribute it
10 ** and/or modify it under some conditions; see the "copying.grx" file
11 ** for details.
12 **
13 ** This library is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 **
17 **/
18
19 #include <string.h>
20 #include <stdio.h>
21
22 #include "libgrx.h"
23 #include "grfontdv.h"
24 #include "allocate.h"
25 #include "arith.h"
26 #include "memfill.h"
27
28 /*
29 * amounts for various font conversions
30 */
31 #define BOLDWDT(width) (((width) + 3) / 10)
32 #define ITALWDT(height) (((height) + 1) / 7)
33 #define PROPGAP(width) (((width) / 6) ? ((width) / 6) : 1)
34
35 /*
36 * Font conversion option structure
37 */
38 typedef struct {
39 int oldhgt; /* height of the source font */
40 int newhgt; /* height of the created font */
41 int boldwdt; /* shift and OR in X dir by this much */
42 int italwdt; /* tilt font by this much */
43 int dofix; /* convert to fixed width */
44 int fixwdt; /* width of the fixed cvt font */
45 int doprop; /* convert to proportional width */
46 int propgap; /* zero edge pixels for prop cvt */
47 } conv;
48
49 #ifdef DEBUG
bdump(char * hd,unsigned char * bmp,int w,int h,int pitch)50 static void bdump(char *hd,unsigned char *bmp,int w,int h,int pitch)
51 {
52 char *s;
53 DBGPRINTF(DBG_FONT, ("%s (%dx%d):\n",hd,w,h));
54 setup_ALLOC();
55 s = ALLOC((size_t) (w + 1));
56 if(s == NULL) DBGPRINTF(DBG_FONT, ("no memory to show the char\n"));
57 else {
58 while(--h >= 0) {
59 int x;
60 for(x = 0; x < w; x++) s[x] = bmp[x] ? '#' : '.';
61 s[x] = '\0';
62 DBGPRINTF(DBG_FONT, ("%s\n", s));
63 bmp += pitch;
64 }
65 FREE(s);
66 }
67 reset_ALLOC();
68 }
69 #define BDUMP(hd,bmp,w,h,pitch) bdump(hd,bmp,w,h,pitch)
70 #else
71 #define BDUMP(hd,bmp,w,h,pitch)
72 #endif
73
cvtbitmap(int oldw,int neww,conv * c,char * bmp)74 static int cvtbitmap(int oldw,int neww,conv *c,char *bmp)
75 {
76 int wofs,i,j,x,y,w,h;
77 unsigned char *work_base;
78 setup_ALLOC();
79 wofs = umax(oldw,neww) + c->boldwdt + c->italwdt + c->propgap;
80 wofs = umax(wofs,c->fixwdt);
81 wofs = (wofs + 15) & ~3;
82 i = wofs * (umax(c->newhgt,c->oldhgt) + 2);
83 work_base = ALLOC((size_t)i);
84 if(work_base) {
85 unsigned char *work = work_base;
86 memzero(work,i);
87 work += wofs;
88 w = neww - c->boldwdt - c->italwdt;
89 h = c->newhgt;
90 if((w == oldw) && (h == c->oldhgt)) {
91 /* No resizing is needed */
92 for(y = 0; y < h; y++) {
93 i = ((w + 7) & ~7) * y;
94 j = wofs * y;
95 for(x = 0; x < w; x++,i++,j++) {
96 work[j] = bmp[i >> 3] & (0x80 >> (i & 7));
97 }
98 }
99 BDUMP("after unpacking",work,w,h,wofs);
100 }
101 else {
102 /* Resize the bitmap */
103 /* The algorithm first looks for rectangles of '1' pixels */
104 /* and then maps these onto the coordinate space of the */
105 /* resized bitmap. This seems to work better than simple */
106 /* pixel sampling. (No feature loss) */
107 for(y = 0; y < c->oldhgt; y++) {
108 unsigned int pos = 0,ones = 0;
109 i = ((oldw + 7) & ~7) * y;
110 for(x = 0; x < oldw; x++,i++) {
111 if(bmp[i >> 3] & (0x80 >> (i & 7))) {
112 if(!ones) pos = x;
113 ones++;
114 if(x != (oldw - 1)) continue;
115 }
116 if(ones > 0) {
117 unsigned int x1 = urscale(pos,w,oldw);
118 unsigned int x2 = urscale((pos + ones),w,oldw);
119 unsigned int y1 = urscale(y,h,c->oldhgt);
120 unsigned int y2 = urscale((y + 1),h,c->oldhgt);
121 do {
122 unsigned int xx = x1;
123 j = (y1 * wofs) + xx;
124 do {
125 work[j++] = 1;
126 } while(++xx < x2);
127 } while(++y1 < y2);
128 ones = 0;
129 }
130 }
131 }
132 BDUMP("after resize",work,w,h,wofs);
133 }
134 /* bold conversion */
135 if(c->boldwdt > 0) {
136 for(y = 0; y < h; y++) {
137 unsigned char *row = &work[wofs * y];
138 unsigned char *p1 = &row[w];
139 unsigned char *p2 = &row[w + c->boldwdt];
140 while(p1 > row) *--p2 |= *--p1;
141 }
142 w += c->boldwdt;
143 BDUMP("after boldify",work,w,h,wofs);
144 }
145 /* italic conversion */
146 if(c->italwdt > 0) {
147 int ymax = h - 1;
148 int yrnd = ymax >> 1;
149 for(y = 0; y < h; y++) {
150 int tilt = ((c->italwdt * (ymax - y)) + yrnd) / ymax;
151 unsigned char *row = &work[wofs * y];
152 unsigned char *p1 = &row[w];
153 unsigned char *p2 = &row[w + tilt];
154 while(p1 > row) *--p2 = *--p1;
155 while(p2 > row) *--p2 = 0;
156 }
157 w += c->italwdt;
158 BDUMP("after italicize",work,w,h,wofs);
159 }
160 x = 0;
161 /* proportional or fixed width adjustment */
162 if(c->dofix || c->doprop) {
163 int minx = w;
164 int maxx = 0;
165 for(y = 0; y < h; y++) {
166 i = y * wofs;
167 for(j = 0; j < w; j++,i++) {
168 if(work[i] && (j < minx)) minx = j;
169 if(work[i] && (j > maxx)) maxx = j;
170 }
171 }
172 if(minx > maxx) {
173 minx = 0;
174 maxx = w - 1;
175 }
176 if(c->dofix) {
177 neww = c->fixwdt;
178 w = maxx - minx + 1;
179 x = (neww - w) >> 1;
180 }
181 if(c->doprop) {
182 w = maxx - minx + 1;
183 x = minx - (c->propgap >> 1);
184 neww = w + c->propgap;
185 }
186 }
187 for(y = 0,i = (neww + 7) >> 3; y < h; y++) {
188 char *bp = &bmp[y * i];
189 unsigned char *wp = &work[y * wofs];
190 int xpos = x;
191 memfill_b(bp,0,i);
192 for(j = 0; j < neww; j++,xpos++) {
193 if(wp[xpos]) bp[j >> 3] |= (0x80 >> (j & 7));
194 }
195 }
196 FREE(work_base);
197 }
198 reset_ALLOC();
199 return(neww);
200 }
201
_GrBuildFont(const GrFontHeader * h,int cvt,int wdt,int hgt,int cmin,int cmax,int (* charwdt)(int chr),int (* bitmap)(int chr,int w,int h,char * buffer),int scaled)202 GrFont *_GrBuildFont(
203 const GrFontHeader *h,
204 int cvt,
205 int wdt,
206 int hgt,
207 int cmin,
208 int cmax,
209 int (*charwdt)(int chr),
210 int (*bitmap)(int chr,int w,int h,char *buffer),
211 int scaled
212 ){
213 GrFont *f = NULL;
214 unsigned int fprop = h->proportional;
215 unsigned int chrcv = GR_FONTCVT_NONE;
216 unsigned int bmpcv = GR_FONTCVT_NONE;
217 unsigned long totwdt = 0L;
218 unsigned long bmplen = 0L;
219 unsigned int bmpofs = 0;
220 unsigned int numch,i,chr;
221 char *bmp = NULL;
222 conv cv;
223 setup_ALLOC();
224 sttzero(&cv);
225 if(cvt & GR_FONTCVT_SKIPCHARS) {
226 unsigned int lastfntchr = h->minchar + h->numchars - 1;
227 cmin = umin(umax(cmin,h->minchar),lastfntchr);
228 cmax = umin(umax(cmax,h->minchar),lastfntchr);
229 if(cmin > cmax) goto error;
230 if((unsigned int)cmin > h->minchar) chrcv = GR_FONTCVT_SKIPCHARS;
231 if((unsigned int)cmax < lastfntchr) chrcv = GR_FONTCVT_SKIPCHARS;
232 }
233 else {
234 cmin = h->minchar;
235 cmax = h->minchar + h->numchars - 1;
236 }
237 if(cvt & GR_FONTCVT_RESIZE) {
238 if((unsigned int)(wdt = imax(2,wdt)) != h->width) bmpcv=GR_FONTCVT_RESIZE;
239 if((unsigned int)(hgt = imax(2,hgt)) != h->height) bmpcv=GR_FONTCVT_RESIZE;
240 }
241 else {
242 wdt = h->width;
243 hgt = h->height;
244 }
245 numch = cmax - cmin + 1;
246 i = sizeof(GrFont) + ((numch - 1) * sizeof(GrFontChrInfo));
247 f = malloc(i);
248 if(!f) goto error;
249 memzero(f,i);
250 f->h.name = malloc(strlen(h->name) + 1);
251 f->h.family = malloc(strlen(h->family) + 1);
252 if(!f->h.name || !f->h.family) goto error;
253 strcpy(f->h.name ,h->name);
254 strcpy(f->h.family,h->family);
255 f->minwidth = 0x7fff;
256 f->maxwidth = 0;
257 for(chr = cmin,i = 0; i < numch; chr++,i++) {
258 int oldw = (*charwdt)(chr);
259 unsigned int neww = urscale(oldw,wdt,h->width);
260 if(oldw < 0) goto error;
261 if(f->minwidth > neww) f->minwidth = neww;
262 if(f->maxwidth < neww) f->maxwidth = neww;
263 f->chrinfo[i].width = oldw;
264 bmplen += ((neww + 7) >> 3) * hgt;
265 }
266 cv.oldhgt = scaled ? hgt : h->height;
267 cv.newhgt = hgt;
268 if(cvt & GR_FONTCVT_BOLDIFY) {
269 cv.boldwdt = BOLDWDT(wdt);
270 cv.boldwdt = imin(cv.boldwdt,(f->minwidth - 1));
271 cv.boldwdt = imax(cv.boldwdt,0);
272 if(cv.boldwdt > 0) bmpcv |= GR_FONTCVT_BOLDIFY;
273 }
274 if(cvt & GR_FONTCVT_ITALICIZE) {
275 cv.italwdt = ITALWDT(hgt);
276 cv.italwdt = imin(cv.italwdt,(f->minwidth - cv.boldwdt - 1));
277 cv.italwdt = imax(cv.italwdt,0);
278 if(cv.italwdt > 0) bmpcv |= GR_FONTCVT_ITALICIZE;
279 }
280 if((cvt & GR_FONTCVT_FIXIFY) && fprop) {
281 bmpcv |= GR_FONTCVT_FIXIFY;
282 cv.fixwdt = f->maxwidth;
283 bmplen = umul32((hgt * ((cv.fixwdt + 7) >> 3)),numch);
284 cv.dofix = TRUE;
285 fprop = FALSE;
286 }
287 if((cvt & GR_FONTCVT_PROPORTION) && !fprop) {
288 bmpcv |= GR_FONTCVT_PROPORTION;
289 cv.propgap = imax(0,(PROPGAP(wdt) - cv.italwdt));
290 bmplen = umul32((hgt * ((wdt + cv.propgap + 7) >> 3)),numch);
291 cv.doprop = TRUE;
292 fprop = TRUE;
293 }
294 if((unsigned long)(unsigned int)bmplen != bmplen) goto error;
295 f->bitmap = farmalloc(bmplen);
296 if(!f->bitmap) goto error;
297 memzero(f->bitmap,(unsigned int)bmplen);
298 i = f->maxwidth;
299 if(h->width > (unsigned int)wdt) i = urscale(i,h->width,wdt);
300 i = ((i + 31) >> 3) * umax(hgt,h->height);
301 bmp = ALLOC((size_t)i);
302 if(!bmp) goto error;
303 f->minwidth = 0x7fff;
304 f->maxwidth = 0;
305 for(chr = cmin,i = 0; i < numch; chr++,i++) {
306 unsigned int oldw = f->chrinfo[i].width;
307 unsigned int neww = imax(urscale(oldw,wdt,h->width),1);
308 unsigned int size;
309 if(scaled) {
310 unsigned int raww = neww - cv.boldwdt - cv.italwdt;
311 if(!(*bitmap)(chr,raww,hgt,bmp)) goto error;
312 if(bmpcv & ~GR_FONTCVT_RESIZE) neww = cvtbitmap(oldw,raww,&cv,bmp);
313 }
314 else {
315 if(!(*bitmap)(chr,oldw,h->height,bmp)) goto error;
316 if(bmpcv) neww = cvtbitmap(oldw,neww,&cv,bmp);
317 }
318 if(f->minwidth > neww) f->minwidth = neww;
319 if(f->maxwidth < neww) f->maxwidth = neww;
320 size = ((neww + 7) >> 3) * hgt;
321 memcpy(&f->bitmap[bmpofs],bmp,size);
322 f->chrinfo[i].width = neww;
323 f->chrinfo[i].offset = bmpofs;
324 bmpofs += size;
325 totwdt += neww;
326 }
327 f->h.proportional = fprop;
328 f->h.scalable = h->scalable;
329 f->h.preloaded = FALSE;
330 f->h.modified = h->modified | chrcv | bmpcv;
331 f->h.minchar = cmin;
332 f->h.numchars = numch;
333 f->h.width = (cv.dofix || cv.doprop) ? (unsigned int)(totwdt / numch) : wdt;
334 f->h.height = hgt;
335 f->h.baseline = urscale(h->baseline,hgt,h->height);
336 f->h.ulpos = urscale(h->ulpos, hgt,h->height);
337 f->h.ulheight = urscale(h->ulheight,hgt,h->height);
338 goto done;
339 error:
340 if(f) {
341 if(f->h.name) free(f->h.name);
342 if(f->h.family) free(f->h.family);
343 if(f->bitmap) farfree(f->bitmap);
344 free(f);
345 f = NULL;
346 }
347 done:
348 if (bmp) FREE(bmp);
349 reset_ALLOC();
350 return(f);
351 }
352
353