1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "bvedit.h"
31 
32 #include "cvundoes.h"
33 #include "fontforgevw.h"
34 #include "splinefill.h"
35 #include "ustring.h"
36 
37 #include <math.h>
38 
skewselect(BVTFunc * bvtf,real t)39 void skewselect(BVTFunc *bvtf,real t) {
40     real off, bestoff;
41     int i, best;
42 
43     bestoff = 10; best = 0;
44     for ( i=1; i<=10; ++i ) {
45 	if (  (off = t*i-rint(t*i))<0 ) off = -off;
46 	if ( off<bestoff ) {
47 	    bestoff = off;
48 	    best = i;
49 	}
50     }
51 
52     bvtf->func = bvt_skew;
53     bvtf->x = rint(t*best);
54     bvtf->y = best;
55 }
56 
BCTransFunc(BDFChar * bc,enum bvtools type,int xoff,int yoff)57 void BCTransFunc(BDFChar *bc,enum bvtools type,int xoff,int yoff) {
58     int i, j;
59     uint8 *pt, *end, *pt2, *bitmap;
60     int bpl, temp;
61     int xmin, xmax;
62 
63     BCFlattenFloat(bc);
64     if ( type==bvt_transmove ) {
65 	bc->xmin += xoff; bc->xmax += xoff;
66 	bc->ymin += yoff; bc->ymax += yoff;
67 	bitmap = NULL;
68     } else if ( type==bvt_flipv ) {
69 	for ( i=0, j=bc->ymax-bc->ymin; i<j; ++i, --j ) {
70 	    pt = bc->bitmap + i*bc->bytes_per_line;
71 	    pt2 = bc->bitmap + j*bc->bytes_per_line;
72 	    end = pt+bc->bytes_per_line;
73 	    while ( pt<end ) {
74 		*pt ^= *pt2;
75 		*pt2 ^= *pt;
76 		*pt++ ^= *pt2++;
77 	    }
78 	}
79 	bitmap = NULL;
80     } else if ( !bc->byte_data ) {
81 	if ( type==bvt_fliph ) {
82 	    bitmap = calloc((bc->ymax-bc->ymin+1)*bc->bytes_per_line,sizeof(uint8));
83 	    for ( i=0; i<=bc->ymax-bc->ymin; ++i ) {
84 		pt = bc->bitmap + i*bc->bytes_per_line;
85 		pt2 =    bitmap + i*bc->bytes_per_line;
86 		for ( j=0; j<=bc->xmax-bc->xmin; ++j ) {
87 		    if ( pt[j>>3]&(1<<(7-(j&7))) ) {
88 			int nj = bc->xmax-bc->xmin-j;
89 			pt2[nj>>3] |= (1<<(7-(nj&7)));
90 		    }
91 		}
92 	    }
93 	} else if ( type==bvt_rotate180 ) {
94 	    bitmap = calloc((bc->ymax-bc->ymin+1)*bc->bytes_per_line,sizeof(uint8));
95 	    for ( i=0; i<=bc->ymax-bc->ymin; ++i ) {
96 		pt = bc->bitmap + i*bc->bytes_per_line;
97 		pt2 = bitmap + (bc->ymax-bc->ymin-i)*bc->bytes_per_line;
98 		for ( j=0; j<=bc->xmax-bc->xmin; ++j ) {
99 		    if ( pt[j>>3]&(1<<(7-(j&7))) ) {
100 			int nj = bc->xmax-bc->xmin-j;
101 			pt2[nj>>3] |= (1<<(7-(nj&7)));
102 		    }
103 		}
104 	    }
105 	} else if ( type==bvt_rotate90cw ) {
106 	    bpl = ((bc->ymax-bc->ymin)>>3) + 1;
107 	    bitmap = calloc((bc->xmax-bc->xmin+1)*bpl,sizeof(uint8));
108 	    for ( i=0; i<=bc->ymax-bc->ymin; ++i ) {
109 		pt = bc->bitmap + i*bc->bytes_per_line;
110 		for ( j=0; j<=bc->xmax-bc->xmin; ++j ) {
111 		    if ( pt[j>>3]&(1<<(7-(j&7))) ) {
112 			int nx = bc->ymax-bc->ymin-i;
113 			bitmap[j*bpl+(nx>>3)] |= (1<<(7-(nx&7)));
114 		    }
115 		}
116 	    }
117 	    bc->bytes_per_line = bpl;
118 	    temp = bc->xmax; bc->xmax = bc->ymax; bc->ymax = temp;
119 	    temp = bc->xmin; bc->xmin = bc->ymin; bc->ymin = temp;
120 	} else if ( type==bvt_rotate90ccw ) {
121 	    bpl = ((bc->ymax-bc->ymin)>>3) + 1;
122 	    bitmap = calloc((bc->xmax-bc->xmin+1)*bpl,sizeof(uint8));
123 	    for ( i=0; i<=bc->ymax-bc->ymin; ++i ) {
124 		pt = bc->bitmap + i*bc->bytes_per_line;
125 		for ( j=0; j<=bc->xmax-bc->xmin; ++j ) {
126 		    if ( pt[j>>3]&(1<<(7-(j&7))) ) {
127 			int ny = bc->xmax-bc->xmin-j;
128 			bitmap[ny*bpl+(i>>3)] |= (1<<(7-(i&7)));
129 		    }
130 		}
131 	    }
132 	    bc->bytes_per_line = bpl;
133 	    temp = bc->xmax; bc->xmax = bc->ymax; bc->ymax = temp;
134 	    temp = bc->xmin; bc->xmin = bc->ymin; bc->ymin = temp;
135 	} else /* if ( type==bvt_skew ) */ {
136 	    if ( xoff>0 ) {
137 		xmin = bc->xmin+(xoff*bc->ymin)/yoff;
138 		xmax = bc->xmax+(xoff*bc->ymax)/yoff;
139 	    } else {
140 		xmin = bc->xmin+(xoff*bc->ymax)/yoff;
141 		xmax = bc->xmax+(xoff*bc->ymin)/yoff;
142 	    }
143 	    bpl = ((xmax-xmin)>>3) + 1;
144 	    bitmap = calloc((bc->ymax-bc->ymin+1)*bpl,sizeof(uint8));
145 	    for ( i=0; i<=bc->ymax-bc->ymin; ++i ) {
146 		pt = bc->bitmap + i*bc->bytes_per_line;
147 		pt2 = bitmap + i*bpl;
148 		for ( j=0; j<=bc->xmax-bc->xmin; ++j ) {
149 		    if ( pt[j>>3]&(1<<(7-(j&7))) ) {
150 			int nj = j+bc->xmin-xmin + (xoff*(bc->ymax-i))/yoff;
151 			pt2[nj>>3] |= (1<<(7-(nj&7)));
152 		    }
153 		}
154 	    }
155 	    bc->xmax = xmax; bc->xmin = xmin; bc->bytes_per_line = bpl;
156 	}
157     } else {		/* Byte data */
158 	if ( type==bvt_fliph ) {
159 	    for ( i=0; i<=bc->ymax-bc->ymin; ++i ) {
160 		pt = bc->bitmap + i*bc->bytes_per_line;
161 		for ( j=0; j<=(bc->xmax-bc->xmin)/2; ++j ) {
162 		    int nj = bc->xmax-bc->xmin-j;
163 		    int temp = pt[nj];
164 		    pt[nj] = pt[j];
165 		    pt[j] = temp;
166 		}
167 	    }
168 	    bitmap = NULL;
169 	} else if ( type==bvt_rotate180 ) {
170 	    bitmap = calloc((bc->ymax-bc->ymin+1)*bc->bytes_per_line,sizeof(uint8));
171 	    for ( i=0; i<=bc->ymax-bc->ymin; ++i ) {
172 		pt = bc->bitmap + i*bc->bytes_per_line;
173 		pt2 = bitmap + (bc->ymax-bc->ymin-i)*bc->bytes_per_line;
174 		for ( j=0; j<=bc->xmax-bc->xmin; ++j ) {
175 		    int nj = bc->xmax-bc->xmin-j;
176 		    pt2[nj] = pt[j];
177 		}
178 	    }
179 	} else if ( type==bvt_rotate90cw ) {
180 	    bpl = bc->ymax-bc->ymin + 1;
181 	    bitmap = calloc((bc->xmax-bc->xmin+1)*bpl,sizeof(uint8));
182 	    for ( i=0; i<=bc->ymax-bc->ymin; ++i ) {
183 		pt = bc->bitmap + i*bc->bytes_per_line;
184 		for ( j=0; j<=bc->xmax-bc->xmin; ++j ) {
185 		    int nx = bc->ymax-bc->ymin-i;
186 		    bitmap[j*bpl+nx] = pt[j];
187 		}
188 	    }
189 	    bc->bytes_per_line = bpl;
190 	    temp = bc->xmax; bc->xmax = bc->ymax; bc->ymax = temp;
191 	    temp = bc->xmin; bc->xmin = bc->ymin; bc->ymin = temp;
192 	} else if ( type==bvt_rotate90ccw ) {
193 	    bpl = bc->ymax-bc->ymin + 1;
194 	    bitmap = calloc((bc->xmax-bc->xmin+1)*bpl,sizeof(uint8));
195 	    for ( i=0; i<=bc->ymax-bc->ymin; ++i ) {
196 		pt = bc->bitmap + i*bc->bytes_per_line;
197 		for ( j=0; j<=bc->xmax-bc->xmin; ++j ) {
198 		    int ny = bc->xmax-bc->xmin-j;
199 		    bitmap[ny*bpl+i] = pt[j];
200 		}
201 	    }
202 	    bc->bytes_per_line = bpl;
203 	    temp = bc->xmax; bc->xmax = bc->ymax; bc->ymax = temp;
204 	    temp = bc->xmin; bc->xmin = bc->ymin; bc->ymin = temp;
205 	} else /* if ( type==bvt_skew ) */ {
206 	    if ( xoff>0 ) {
207 		xmin = bc->xmin+(xoff*bc->ymin)/yoff;
208 		xmax = bc->xmax+(xoff*bc->ymax)/yoff;
209 	    } else {
210 		xmin = bc->xmin+(xoff*bc->ymax)/yoff;
211 		xmax = bc->xmax+(xoff*bc->ymin)/yoff;
212 	    }
213 	    bpl = xmax-xmin + 1;
214 	    bitmap = calloc((bc->ymax-bc->ymin+1)*bpl,sizeof(uint8));
215 	    for ( i=0; i<=bc->ymax-bc->ymin; ++i ) {
216 		pt = bc->bitmap + i*bc->bytes_per_line;
217 		pt2 = bitmap + i*bpl;
218 		for ( j=0; j<=bc->xmax-bc->xmin; ++j ) {
219 		    int nj = j+bc->xmin-xmin + (xoff*(bc->ymax-i))/yoff;
220 		    pt2[nj] = pt[j];
221 		}
222 	    }
223 	    bc->xmax = xmax; bc->xmin = xmin; bc->bytes_per_line = bpl;
224 	}
225     }
226     if ( bitmap!=NULL ) {
227 	free(bc->bitmap);
228 	bc->bitmap = bitmap;
229     }
230     BCCompressBitmap(bc);
231 }
232 
BCTrans(BDFFont * bdf,BDFChar * bc,BVTFunc * bvts,FontViewBase * fv)233 void BCTrans(BDFFont *bdf,BDFChar *bc,BVTFunc *bvts,FontViewBase *fv ) {
234     int xoff=0, yoff=0, i;
235 
236     if ( bvts[0].func==bvt_none )
237 return;
238     BCPreserveState(bc);
239     for ( i=0; bvts[i].func!=bvt_none; ++i ) {
240 	if ( bvts[i].func==bvt_transmove ) {
241 	    xoff = rint(bvts[i].x*bdf->pixelsize/(double) (fv->sf->ascent+fv->sf->descent));
242 	    yoff = rint(bvts[i].y*bdf->pixelsize/(double) (fv->sf->ascent+fv->sf->descent));
243 	} else if ( bvts[i].func==bvt_skew ) {
244 	    xoff = bvts[i].x;
245 	    yoff = bvts[i].y;
246 	}
247 	BCTransFunc(bc,bvts[i].func,xoff,yoff);
248     }
249     BCCharChangedUpdate(bc);
250 }
251 
BCRotateCharForVert(BDFChar * bc,BDFChar * from,BDFFont * frombdf)252 void BCRotateCharForVert(BDFChar *bc,BDFChar *from, BDFFont *frombdf) {
253     /* Take the image in from, make a copy of it, put it in bc, rotate it */
254     /*  shift it around slightly so it is aligned properly to work as a CJK */
255     /*  vertically displayed latin letter */
256     int xmin, ymax;
257 
258     BCPreserveState(bc);
259     BCFlattenFloat(from);
260     free(bc->bitmap);
261     bc->xmin = from->xmin; bc->xmax = from->xmax; bc->ymin = from->ymin; bc->ymax = from->ymax;
262     bc->width = from->width; bc->bytes_per_line = from->bytes_per_line;
263     bc->bitmap = malloc(bc->bytes_per_line*(bc->ymax-bc->ymin+1));
264     memcpy(bc->bitmap,from->bitmap,bc->bytes_per_line*(bc->ymax-bc->ymin+1));
265     BCTransFunc(bc,bvt_rotate90cw,0,0);
266     xmin = frombdf->descent + from->ymin;
267     ymax = frombdf->ascent - from->xmin;
268     bc->xmax += xmin-bc->xmin; bc->xmin = xmin;
269     bc->ymin += ymax-bc->ymax-1; bc->ymax = ymax-1;
270     bc->width = frombdf->pixelsize;
271 }
272 
BCExpandBitmap(BDFChar * bc,int x,int y)273 static void BCExpandBitmap(BDFChar *bc, int x, int y) {
274     int xmin, xmax, bpl, ymin, ymax;
275     uint8 *bitmap;
276     int i,j,nj;
277     uint8 *pt, *npt;
278     SplineChar *sc;
279 
280     if ( x<bc->xmin || x>bc->xmax || y<bc->ymin || y>bc->ymax ) {
281 	xmin = x<bc->xmin?x:bc->xmin;
282 	xmax = x>bc->xmax?x:bc->xmax;
283 	ymin = y<bc->ymin?y:bc->ymin;
284 	ymax = y>bc->ymax?y:bc->ymax;
285 	if ( !bc->byte_data ) {
286 	    bpl = ((xmax-xmin)>>3) + 1;
287 	    bitmap = calloc((ymax-ymin+1)*bpl,sizeof(uint8));
288 	    for ( i=0; i<=bc->ymax-bc->ymin; ++i ) {
289 		pt = bc->bitmap + i*bc->bytes_per_line;
290 		npt = bitmap + (i+ymax-bc->ymax)*bpl;
291 		for ( j=0; j<=bc->xmax-bc->xmin; ++j ) {
292 		    if ( pt[j>>3] & (1<<(7-(j&7))) ) {
293 			nj = j+bc->xmin-xmin;
294 			npt[nj>>3] |= (1<<(7-(nj&7)));
295 		    }
296 		}
297 	    }
298 	} else {
299 	    bpl = xmax-xmin + 1;
300 	    bitmap = calloc((ymax-ymin+1)*bpl,sizeof(uint8));
301 	    for ( i=0; i<=bc->ymax-bc->ymin; ++i ) {
302 		pt = bc->bitmap + i*bc->bytes_per_line;
303 		npt = bitmap + (i+ymax-bc->ymax)*bpl;
304 		memcpy(npt+bc->xmin-xmin,pt,bc->bytes_per_line);
305 	    }
306 	}
307 	free(bc->bitmap);
308 	bc->bitmap = bitmap;
309 	bc->xmin = xmin; bc->xmax = xmax; bc->bytes_per_line = bpl;
310 	bc->ymin = ymin; bc->ymax = ymax;
311 
312 	sc = bc->sc;			/* sc can be NULL when loading bitmap references from an sfnt */
313 	if ( sc!=NULL && sc->parent!=NULL && sc->parent->onlybitmaps )
314 	    sc->widthset = true;	/* Mark it as used */
315     }
316 }
317 
BCHasOutputtableBitmap(BDFChar * bc)318 static int BCHasOutputtableBitmap( BDFChar *bc ) {
319     int i;
320 
321     for ( i=0; i<bc->bytes_per_line * ( bc->ymax - bc->ymin + 1 ); i++ ) {
322 	if ( bc->bitmap[i] != 0 )
323 return( true );
324     }
325 return( false );
326 }
327 
BCExpandBitmapToEmBox(BDFChar * bc,int xmin,int ymin,int xmax,int ymax)328 void BCExpandBitmapToEmBox(BDFChar *bc, int xmin, int ymin, int xmax, int ymax) {
329     /* Expand a bitmap so it will always contain 0..width, ascent..descent */
330 
331     if ( !BCHasOutputtableBitmap( bc )) {
332 	free( bc->bitmap );
333 	bc->bytes_per_line = xmax - xmin + 1;
334 	bc->xmin = xmin; bc->xmax = xmax;
335 	bc->ymin = ymin; bc->ymax = ymax;
336 	bc->bitmap = calloc(( ymax - ymin + 1) * bc->bytes_per_line, sizeof( uint8 ));
337     } else {
338 	BCExpandBitmap(bc,xmin,ymin);
339 	BCExpandBitmap(bc,xmax,ymax);
340     }
341 }
342 
BCSetPoint(BDFChar * bc,int x,int y,int color)343 void BCSetPoint(BDFChar *bc, int x, int y, int color ) {
344 
345     if ( x<bc->xmin || x>bc->xmax || y<bc->ymin || y>bc->ymax ) {
346 	if ( color==0 )
347 return;		/* Already clear */
348 	BCExpandBitmap(bc,x,y);
349     }
350     y = bc->ymax-y;
351     x -= bc->xmin;
352     if ( bc->byte_data )
353 	bc->bitmap[y*bc->bytes_per_line+x] = color;
354     else if ( color==0 )
355 	bc->bitmap[y*bc->bytes_per_line+(x>>3)] &= ~(1<<(7-(x&7)));
356     else
357 	bc->bitmap[y*bc->bytes_per_line+(x>>3)] |= (1<<(7-(x&7)));
358 }
359 
BDFFloatFree(BDFFloat * sel)360 void BDFFloatFree(BDFFloat *sel) {
361     if ( sel==NULL )
362 return;
363     free(sel->bitmap);
364     free(sel);
365 }
366 
BDFFloatCopy(BDFFloat * sel)367 BDFFloat *BDFFloatCopy(BDFFloat *sel) {
368     BDFFloat *new;
369     if ( sel==NULL )
370 return(NULL);
371     new = malloc(sizeof(BDFFloat));
372     *new = *sel;
373     new->bitmap = malloc(sel->bytes_per_line*(sel->ymax-sel->ymin+1));
374     memcpy(new->bitmap,sel->bitmap,sel->bytes_per_line*(sel->ymax-sel->ymin+1));
375 return( new );
376 }
377 
BDFFloatConvert(BDFFloat * sel,int todepth,int fromdepth)378 BDFFloat *BDFFloatConvert(BDFFloat *sel,int todepth,int fromdepth) {
379     BDFFloat *new;
380     int i,j,fdiv,tdiv;
381     if ( sel==NULL )
382 return(NULL);
383 
384     if ( todepth==fromdepth )
385 return( BDFFloatCopy(sel));
386 
387     new = malloc(sizeof(BDFFloat));
388     *new = *sel;
389     new->byte_data = todepth!=1;
390     new->depth = todepth;
391     new->bytes_per_line = new->byte_data ? new->xmax-new->xmin+1 : ((new->xmax-new->xmin)>>3)+1;
392     new->bitmap = calloc(new->bytes_per_line*(sel->ymax-sel->ymin+1),1);
393     if ( fromdepth==1 ) {
394 	tdiv = ((1<<todepth)-1);
395 	for ( i=0; i<=sel->ymax-sel->ymin; ++i ) {
396 	    for ( j=0; j<=sel->xmax-sel->xmin; ++j ) {
397 		if ( sel->bitmap[i*sel->bytes_per_line+(j>>3)]&(0x80>>(j&7)) )
398 		    new->bitmap[i*new->bytes_per_line+j] = tdiv;
399 	    }
400 	}
401     } else if ( todepth==1 ) {
402 	fdiv = (1<<fromdepth)/2;
403 	for ( i=0; i<=sel->ymax-sel->ymin; ++i ) {
404 	    for ( j=0; j<=sel->xmax-sel->xmin; ++j ) {
405 		if ( sel->bitmap[i*sel->bytes_per_line+j]>=fdiv )
406 		    new->bitmap[i*new->bytes_per_line+(j>>3)] |= (0x80>>(j&7));
407 	    }
408 	}
409     } else {
410 	fdiv = 255/((1<<fromdepth)-1); tdiv = 255/((1<<todepth)-1);
411 	memcpy(new->bitmap,sel->bitmap,sel->bytes_per_line*(sel->ymax-sel->ymin+1));
412 	for ( i=0 ; i<sel->bytes_per_line*(sel->ymax-sel->ymin+1); ++i )
413 	    new->bitmap[i] = (sel->bitmap[i]*fdiv + tdiv/2)/tdiv;
414     }
415 return( new );
416 }
417 
418 /* Creates a floating selection, and clears out the underlying bitmap */
BDFFloatCreate(BDFChar * bc,int xmin,int xmax,int ymin,int ymax,int clear)419 BDFFloat *BDFFloatCreate(BDFChar *bc,int xmin,int xmax,int ymin,int ymax, int clear) {
420     BDFFloat *new;
421     int x,y;
422     uint8 *bpt, *npt;
423 
424     if ( bc->selection!=NULL ) {
425 	BCFlattenFloat(bc);
426 	bc->selection = NULL;
427     }
428     BCCompressBitmap(bc);
429 
430     if ( xmin>xmax ) {
431 	xmin ^= xmax; xmax ^= xmin; xmin ^= xmax;
432     }
433     if ( ymin>ymax ) {
434 	ymin ^= ymax; ymax ^= ymin; ymin ^= ymax;
435     }
436     if ( xmin<bc->xmin ) xmin = bc->xmin;
437     if ( xmax>bc->xmax ) xmax = bc->xmax;
438     if ( ymin<bc->ymin ) ymin = bc->ymin;
439     if ( ymax>bc->ymax ) ymax = bc->ymax;
440     if ( xmin>xmax || ymin>ymax )
441 return( NULL );
442     new = malloc(sizeof(BDFFloat));
443     new->xmin = xmin;
444     new->xmax = xmax;
445     new->ymin = ymin;
446     new->ymax = ymax;
447     new->byte_data = bc->byte_data;
448     new->depth = bc->depth;
449     if ( bc->byte_data ) {
450 	new->bytes_per_line = xmax-xmin+1;
451 	new->bitmap = calloc(new->bytes_per_line*(ymax-ymin+1),sizeof(uint8));
452 	for ( y=ymin; /* y<=ymax; this test might overflow, so test == at end of loop */; ++y ) {
453 	    bpt = bc->bitmap + (bc->ymax-y)*bc->bytes_per_line;
454 	    npt = new->bitmap + (ymax-y)*new->bytes_per_line;
455 	    memcpy(npt,bpt+xmin-bc->xmin,xmax-xmin+1);
456 	    if ( clear )
457 		memset(bpt+xmin-bc->xmin,0,xmax-xmin+1);
458             if (y == ymax) break;
459 	}
460     } else {
461 	new->bytes_per_line = ((xmax-xmin)>>3)+1;
462 	new->bitmap = calloc(new->bytes_per_line*(ymax-ymin+1),sizeof(uint8));
463 	for ( y=ymin; y<=ymax; ++y ) {
464 	    bpt = bc->bitmap + (bc->ymax-y)*bc->bytes_per_line;
465 	    npt = new->bitmap + (ymax-y)*new->bytes_per_line;
466 	    for ( x=xmin; x<=xmax; ++x ) {
467 		int bx = x-bc->xmin, nx = x-xmin;
468 		if ( bpt[bx>>3]&(1<<(7-(bx&7))) ) {
469 		    npt[nx>>3] |= (1<<(7-(nx&7)));
470 		    if ( clear )
471 			bpt[bx>>3] &= ~(1<<(7-(bx&7)));
472 		}
473 	    }
474 	}
475     }
476     if ( clear )
477 	bc->selection = new;
478 return( new );
479 }
480 
BCFlattenFloat(BDFChar * bc)481 void BCFlattenFloat(BDFChar *bc ) {
482     /* flatten any floating selection */
483     BDFFloat *sel = bc->selection;
484     int x,y;
485     uint8 *bpt, *spt;
486 
487     if ( sel!=NULL ) {
488 	BCExpandBitmapToEmBox( bc,sel->xmin,sel->ymin,sel->xmax,sel->ymax );
489 	if ( bc->byte_data ) {
490 	    for ( y=sel->ymin; y<=sel->ymax; ++y ) {
491 		bpt = bc->bitmap + (bc->ymax-y)*bc->bytes_per_line;
492 		spt = sel->bitmap + (sel->ymax-y)*sel->bytes_per_line;
493 		memcpy(bpt+sel->xmin-bc->xmin,spt,sel->xmax-sel->xmin+1);
494 	    }
495 	} else {
496 	    for ( y=sel->ymin; y<=sel->ymax; ++y ) {
497 		bpt = bc->bitmap + (bc->ymax-y)*bc->bytes_per_line;
498 		spt = sel->bitmap + (sel->ymax-y)*sel->bytes_per_line;
499 		for ( x=sel->xmin; x<=sel->xmax; ++x ) {
500 		    int bx = x-bc->xmin, sx = x-sel->xmin;
501 		    if ( spt[sx>>3]&(1<<(7-(sx&7))) )
502 			bpt[bx>>3] |= (1<<(7-(bx&7)));
503 		    else
504 			bpt[bx>>3] &= ~(1<<(7-(bx&7)));
505 		}
506 	    }
507 	}
508 	BDFFloatFree(sel);
509 	bc->selection = NULL;
510     }
511 }
512 
BCPasteInto(BDFChar * bc,BDFChar * rbc,int ixoff,int iyoff,int invert,int cleartoo)513 void BCPasteInto(BDFChar *bc,BDFChar *rbc,int ixoff,int iyoff, int invert, int cleartoo) {
514     int x, y, bx, rx;
515     uint8 *bpt, *rpt;
516 
517     x = 0;
518     BCExpandBitmapToEmBox( bc,rbc->xmin+ixoff,rbc->ymin+iyoff,rbc->xmax+ixoff,rbc->ymax+iyoff );
519     for ( y=rbc->ymin; y<=rbc->ymax; ++y ) {
520 	bpt = bc->bitmap + (bc->ymax-(y+iyoff))*bc->bytes_per_line;
521 	if ( invert )
522 	    rpt = rbc->bitmap + y*rbc->bytes_per_line;
523 	else
524 	    rpt = rbc->bitmap + (rbc->ymax-y)*rbc->bytes_per_line;
525 	if ( bc->byte_data ) {
526 	    for ( x=rbc->xmin; x<=rbc->xmax; ++x ) {
527 		bx = x+ixoff-bc->xmin; rx = x-rbc->xmin;
528 		if ( rpt[rx] != 0 )
529 		    bpt[bx] |= rpt[rx];
530 		else if ( cleartoo )
531 		    bpt[bx] &= rpt[rx];
532 	    }
533 	} else {
534 	    for ( x=rbc->xmin; x<=rbc->xmax; ++x ) {
535 		bx = x+ixoff-bc->xmin; rx = x-rbc->xmin;
536 		if ( rpt[rx>>3]&(1<<(7-(rx&7))) )
537 		    bpt[bx>>3] |= (1<<(7-(bx&7)));
538 		else if ( cleartoo )
539 		    bpt[bx>>3] &= ~(1<<(7-(bx&7)));
540 	    }
541 	}
542     }
543     BCCompressBitmap(bc);
544 }
545 
BCMergeReferences(BDFChar * base,BDFChar * cur,int8 xoff,int8 yoff)546 void BCMergeReferences(BDFChar *base,BDFChar *cur,int8 xoff,int8 yoff) {
547     BDFRefChar *head;
548 
549     for ( head=cur->refs; head!=NULL; head=head->next ) {
550 	BCPasteInto( base,head->bdfc,xoff+head->xoff,yoff+head->yoff,false,false );
551 	BCMergeReferences( base,head->bdfc,xoff+head->xoff,yoff+head->yoff );
552     }
553 }
554 
BDFGetMergedChar(BDFChar * bc)555 BDFChar *BDFGetMergedChar( BDFChar *bc ) {
556     BDFChar *ret;
557 
558     if ( bc == NULL )
559 return( NULL );
560     ret = chunkalloc( sizeof( BDFChar ));
561     memcpy( ret,bc,sizeof( BDFChar ));
562     ret->bitmap = calloc(ret->bytes_per_line*(ret->ymax-ret->ymin+1),sizeof(uint8));
563     memcpy( ret->bitmap,bc->bitmap,ret->bytes_per_line*(ret->ymax-ret->ymin+1));
564 
565     BCMergeReferences( ret,bc,0,0 );
566     ret->refs = NULL;
567     if ( bc->selection != NULL ) {
568 	ret->selection = BDFFloatConvert(bc->selection,bc->depth,bc->depth);
569 	BCFlattenFloat( ret );
570 	BCCompressBitmap( ret );
571     }
572 return( ret );
573 }
574 
BDFCharQuickBounds(BDFChar * bc,IBounds * bb,int8 xoff,int8 yoff,int use_backup,int first)575 int BDFCharQuickBounds( BDFChar *bc,IBounds *bb,int8 xoff,int8 yoff,int use_backup,int first ) {
576     int has_bitmap = false;
577     int xmin, xmax, ymin, ymax;
578     BDFRefChar *head;
579 
580     if ( use_backup && bc->backup != NULL ) {
581 	xmin = bc->backup->xmin; xmax = bc->backup->xmax;
582 	ymin = bc->backup->ymin; ymax = bc->backup->ymax;
583     } else {
584 	xmin = bc->xmin; xmax = bc->xmax;
585 	ymin = bc->ymin; ymax = bc->ymax;
586     }
587     has_bitmap = BCHasOutputtableBitmap( bc );
588 
589     if ( has_bitmap && first ) {
590 	bb->minx = xmin + xoff; bb->maxx = xmax + xoff;
591 	bb->miny = ymin + yoff; bb->maxy = ymax + yoff;
592     } else if ( has_bitmap ) {
593 	if ( xmin + xoff < bb->minx ) bb->minx = xmin + xoff;
594 	if ( xmax + xoff > bb->maxx ) bb->maxx = xmax + xoff;
595 	if ( ymin + yoff < bb->miny ) bb->miny = ymin + yoff;
596 	if ( ymax + yoff > bb->maxy ) bb->maxy = ymax + yoff;
597     } else if ( first )
598 	memset(bb,0,sizeof(*bb));
599 
600     for ( head=bc->refs; head!=NULL; head=head->next ) {
601 	first = BDFCharQuickBounds( head->bdfc,bb,head->xoff+xoff,head->yoff+yoff,
602 	    has_bitmap || use_backup,first && !has_bitmap );
603     }
604 return( first && !has_bitmap );
605 }
606 
BDFCharFindBounds(BDFChar * bc,IBounds * bb)607 void BDFCharFindBounds(BDFChar *bc,IBounds *bb) {
608     int r,c,first=true;
609 
610     if ( bc->byte_data ) {
611 	for ( r=0; r<=bc->ymax-bc->ymin; ++r ) {
612 	    for ( c=0; c<=bc->xmax-bc->xmin; ++c ) {
613 		if ( bc->bitmap[r*bc->bytes_per_line+c] ) {
614 		    if ( first ) {
615 			bb->minx = bb->maxx = bc->xmin+c;
616 			bb->miny = bb->maxy = bc->ymax-r;
617 			first = false;
618 		    } else {
619 			if ( bc->xmin+c<bb->minx ) bb->minx = bc->xmin+c;
620 			if ( bc->xmin+c>bb->maxx ) bb->maxx = bc->xmin+c;
621 			bb->miny = bc->ymax-r;
622 		    }
623 		}
624 	    }
625 	}
626     } else {
627 	for ( r=0; r<=bc->ymax-bc->ymin; ++r ) {
628 	    for ( c=0; c<=bc->xmax-bc->xmin; ++c ) {
629 		if ( bc->bitmap[r*bc->bytes_per_line+(c>>3)]&(0x80>>(c&7)) ) {
630 		    if ( first ) {
631 			bb->minx = bb->maxx = bc->xmin+c;
632 			bb->miny = bb->maxy = bc->ymax-r;
633 			first = false;
634 		    } else {
635 			if ( bc->xmin+c<bb->minx ) bb->minx = bc->xmin+c;
636 			if ( bc->xmin+c>bb->maxx ) bb->maxx = bc->xmin+c;
637 			bb->miny = bc->ymax-r;
638 		    }
639 		}
640 	    }
641 	}
642     }
643     first = BDFCharQuickBounds( bc,bb,0,0,false,first );
644     if ( first )
645 	memset(bb,0,sizeof(*bb));
646 }
647 
648 /* Prepare a bitmap glyph for dumping to a font file. This function deals   */
649 /* mainly with composite glyphs, and either converts them to normal bitmaps */
650 /* or regularizes for output. The current glyph state is preserved and can  */
651 /* be restored later */
BCPrepareForOutput(BDFChar * bc,int mergeall)652 void BCPrepareForOutput( BDFChar *bc,int mergeall ) {
653     int bmp_has_image = false, bmp_width;
654     int i;
655     IBounds ib;
656 
657     bmp_width = ( bc->ymax - bc->ymin + 1 );
658     bc->ticked = false;
659     if ( bc->refs != NULL ) {
660 	/* Preserve the current glyph bitmap with all related values, unless we */
661 	/* have already done this when detecting width groups for TTF output    */
662 	if ( bc->backup == NULL ) {
663 	    bc->backup = malloc( sizeof( BDFFloat ));
664 	    bc->backup->bytes_per_line = bc->bytes_per_line;
665 	    bc->backup->xmin = bc->xmin; bc->backup->xmax = bc->xmax;
666 	    bc->backup->ymin = bc->ymin; bc->backup->ymax = bc->ymax;
667 	    bc->backup->bitmap = calloc( bc->bytes_per_line * bmp_width,sizeof( uint8 ));
668 	    memcpy( bc->backup->bitmap,bc->bitmap,bc->bytes_per_line * bmp_width );
669 	}
670 
671 	for ( i=0; i<bc->bytes_per_line * bmp_width && !bmp_has_image; i++ ) {
672 	    if ( bc->bitmap[i] != 0 ) bmp_has_image = true;
673 	}
674 
675 	if ( mergeall || bmp_has_image ) {
676 	    /* Can't output glyphs which contain both bitmaps and references. So     */
677 	    /* we merge references into a single bitmap either if the glyph's        */
678 	    /* bitmap already has something worth outputting, or if the font format  */
679 	    /* doesn't support references at all (in which case 'mergeall' should    */
680 	    /* be true) */
681 	    /* If the glyph is going to be output in a width group (EBDT format 5),  */
682 	    /* then unlinking references will compress the bitmap to the actual image*/
683 	    /* size. So preserve the original values and restore them after merging  */
684 	    if ( bc->widthgroup ) {
685 		ib.minx = bc->xmin; ib.maxx = bc->xmax;
686 		ib.miny = bc->ymin; ib.maxy = bc->ymax;
687 	    }
688 	    BCMergeReferences( bc,bc,0,0 );
689 	    if ( bc->widthgroup )
690 		BCExpandBitmapToEmBox( bc,ib.minx,ib.miny,ib.maxx,ib.maxy );
691 	} else {
692 	    /* Otherwise we are going to output a composite glyph. Note that bounding box  */
693 	    /* values have different meaning in our program context (there they denote     */
694 	    /* the bitmap size and position and thus are mostly irrelevant for a glyph were*/
695 	    /* only references are present) and in the EBDT table. In the later case they  */
696 	    /* are used to specify the overall glyph metrics. So we calculate those values */
697 	    /* just for TTF output and then immediately reset them back to zeros. */
698 	    BDFCharQuickBounds( bc,&ib,0,0,false,true );
699 	    bc->xmin = ib.minx; bc->xmax = ib.maxx;
700 	    bc->ymin = ib.miny; bc->ymax = ib.maxy;
701 	    bc->ticked = true;
702 	}
703     } else if ( !bc->widthgroup )
704 	BCCompressBitmap( bc );
705 }
706 
BCRestoreAfterOutput(BDFChar * bc)707 void BCRestoreAfterOutput( BDFChar *bc ) {
708     bc->ticked = false;
709     if ( bc->backup != NULL ) {
710 	bc->bytes_per_line = bc->backup->bytes_per_line;
711 	bc->xmin = bc->backup->xmin; bc->xmax = bc->backup->xmax;
712 	bc->ymin = bc->backup->ymin; bc->ymax = bc->backup->ymax;
713 
714 	free( bc->bitmap );
715 	bc->bitmap = bc->backup->bitmap;
716 	free( bc->backup );
717 	bc->backup = NULL;
718     }
719 }
720 
BCMakeDependent(BDFChar * dependent,BDFChar * base)721 void BCMakeDependent( BDFChar *dependent,BDFChar *base ) {
722     struct bdfcharlist *dlist;
723 
724     for ( dlist=base->dependents; dlist!=NULL && dlist->bc!=dependent; dlist = dlist->next );
725     if ( dlist==NULL ) {
726 	dlist = chunkalloc( sizeof( struct bdfcharlist ));
727 	dlist->bc = dependent;
728 	dlist->next = base->dependents;
729 	base->dependents = dlist;
730     }
731 }
732 
BCRemoveDependent(BDFChar * dependent,BDFRefChar * ref)733 void BCRemoveDependent( BDFChar *dependent,BDFRefChar *ref ) {
734     struct bdfcharlist *dlist, *pd;
735     BDFRefChar *prev;
736 
737     if ( dependent->refs==ref )
738 	dependent->refs = ref->next;
739     else {
740 	for ( prev = dependent->refs; prev->next!=ref; prev=prev->next );
741 	prev->next = ref->next;
742     }
743     /* Check for multiple dependencies (colon has two refs to period) */
744     /*  if there are none, then remove dependent from ref->sc's dependents list */
745     for ( prev = dependent->refs; prev!=NULL && (prev==ref || prev->bdfc!=ref->bdfc); prev = prev->next );
746     if ( prev==NULL ) {
747 	dlist = ref->bdfc->dependents;
748 	if ( dlist==NULL )
749 	    /* Do nothing */;
750 	else if ( dlist->bc == dependent ) {
751 	    ref->bdfc->dependents = dlist->next;
752 	} else {
753 	    for ( pd=dlist, dlist = pd->next; dlist!=NULL && dlist->bc!=dependent; pd=dlist, dlist = pd->next );
754 	    if ( dlist!=NULL )
755 		pd->next = dlist->next;
756 	}
757 	chunkfree( dlist,sizeof( struct bdfcharlist ));
758     }
759     free( ref );
760 }
761 
BCUnlinkThisReference(struct fontviewbase * fv,BDFChar * bc)762 void BCUnlinkThisReference( struct fontviewbase *fv,BDFChar *bc ) {
763     struct bdfcharlist *dep, *dnext;
764     BDFChar *bsc;
765     BDFRefChar *ref, *rnext, *rprev = NULL;
766 
767     if ( bc==NULL )
768 return;
769 
770     for ( dep=bc->dependents; dep!=NULL; dep=dnext ) {
771 	dnext = dep->next;
772 	if ( fv==NULL || !fv->selected[fv->map->backmap[dep->bc->orig_pos]]) {
773 	    bsc = dep->bc;
774 	    /* May be more than one reference to us, colon has two refs to period */
775 	    /*  but only one dlist entry */
776 	    for ( ref = bsc->refs; ref!=NULL; ref=rnext ) {
777 		rnext = ref->next;
778 		if ( ref->bdfc == bc ) {
779 		    BCPasteInto( bsc,bc,ref->xoff,ref->yoff,0,0 );
780 		    if ( rprev == NULL )
781 			bsc->refs = rnext;
782 		    else
783 			rprev->next = rnext;
784 		    free( ref );
785 		    BCCharChangedUpdate( bsc );
786 		} else
787 		    rprev = ref;
788 	    }
789 	}
790     }
791 }
792 
BCScale(BDFChar * old,int from,int to)793 static BDFChar *BCScale(BDFChar *old,int from, int to) {
794     BDFChar *new;
795     int x,y, ox,oy, oxs,oys, oxend, oyend;
796     real tot, scale;
797     real yscale, xscale;
798     real dto = to;
799 
800     if ( old==NULL || old->byte_data )
801 return( NULL );
802     new = chunkalloc(sizeof(BDFChar));
803     new->sc = old->sc;
804     new->xmin = rint(old->xmin*dto/from);
805     new->ymin = rint(old->ymin*dto/from);
806     new->xmax = new->xmin + ceil((old->xmax-old->xmin+1)*dto/from-1);
807     new->ymax = new->ymin + ceil((old->ymax-old->ymin+1)*dto/from-1);
808     if ( new->sc!=NULL && new->sc->width != new->sc->parent->ascent+new->sc->parent->descent )
809 	new->width = rint(new->sc->width*dto/(new->sc->parent->ascent+new->sc->parent->descent)+.5);
810     else
811 	new->width = rint(old->width*dto/from+.5);
812     if ( new->sc!=NULL && new->sc->vwidth != new->sc->parent->ascent+new->sc->parent->descent )
813 	new->vwidth = rint(new->sc->vwidth*dto/(new->sc->parent->ascent+new->sc->parent->descent)+.5);
814     else
815 	new->vwidth = rint(old->vwidth*dto/from+.5);
816     new->bytes_per_line = (new->xmax-new->xmin)/8+1;
817     new->bitmap = calloc((new->ymax-new->ymin+1)*new->bytes_per_line,sizeof(uint8));
818     new->orig_pos = old->orig_pos;
819     new->refs = old->refs;
820     new->dependents = old->dependents;
821 
822     scale = from/dto;
823     scale *= scale;
824     scale /= 2;
825 
826     for ( y=0; y<=new->ymax-new->ymin; ++y ) for ( x=0; x<=new->xmax-new->xmin; ++x ) {
827 	tot = 0;
828 	oys = floor(y*from/dto); oyend = ceil((y+1)*from/dto);
829 	oxs = floor(x*from/dto); oxend = ceil((x+1)*from/dto);
830 	for ( oy = oys; oy<oyend && oy<=old->ymax-old->ymin; ++oy ) {
831 	    yscale = 1;
832 	    if ( oy==oys && oy==oyend-1 )
833 		yscale = 1-(oyend - (y+1)*from/dto) - (y*from/dto - oys);
834 	    else if ( oy==oys )
835 		yscale = 1-(y*from/dto-oys);
836 	    else if ( oy==oyend-1 )
837 		yscale = 1-(oyend - (y+1)*from/dto);
838 	    for ( ox = oxs; ox<oxend && ox<=old->xmax-old->xmin; ++ox ) {
839 		if ( old->bitmap[oy*old->bytes_per_line + (ox>>3)] & (1<<(7-(ox&7))) ) {
840 		    xscale = 1;
841 		    if ( ox==oxs && ox==oxend-1 )
842 			xscale = 1-(oxend - (x+1)*from/dto) - (x*from/dto - oxs);
843 		    else if ( ox==oxs )
844 			xscale = 1-(x*from/dto-oxs);
845 		    else if ( ox==oxend-1 )
846 			xscale = 1-(oxend - (x+1)*from/dto);
847 		    tot += yscale*xscale;
848 		}
849 	    }
850 	}
851 	if ( tot>=scale )
852 	    new->bitmap[y*new->bytes_per_line + (x>>3)] |= (1<<(7-(x&7)));
853     }
854 
855 return( new );
856 }
857 
858 /* Scale a greymap character to either another greymap or a bitmap */
BCScaleGrey(BDFChar * old,int from,int from_depth,int to,int to_depth)859 static BDFChar *BCScaleGrey(BDFChar *old,int from, int from_depth, int to, int to_depth) {
860     BDFChar *new;
861     int x,y, ox,oy, oxs,oys, oxend, oyend;
862     real tot, scale, bscale;
863     real yscale, xscale;
864     real dto = to;
865     real max = (1<<to_depth);
866 
867     if ( old==NULL || !old->byte_data )
868 return( NULL );
869     new = chunkalloc(sizeof(BDFChar));
870     new->sc = old->sc;
871     new->xmin = rint(old->xmin*dto/from);
872     new->ymin = rint(old->ymin*dto/from);
873     new->xmax = new->xmin + ceil((old->xmax-old->xmin+1)*dto/from-1);
874     new->ymax = new->ymin + ceil((old->ymax-old->ymin+1)*dto/from-1);
875     if ( new->sc!=NULL && new->sc->width != new->sc->parent->ascent+new->sc->parent->descent )
876 	new->width = rint(new->sc->width*dto/(new->sc->parent->ascent+new->sc->parent->descent)+.5);
877     else
878 	new->width = rint(old->width*dto/from+.5);
879     if ( new->sc!=NULL && new->sc->vwidth != new->sc->parent->ascent+new->sc->parent->descent )
880 	new->vwidth = rint(new->sc->vwidth*dto/(new->sc->parent->ascent+new->sc->parent->descent)+.5);
881     else
882 	new->vwidth = rint(old->vwidth*dto/from+.5);
883     if ( to_depth==1 ) {
884 	new->bytes_per_line = (new->xmax-new->xmin)/8+1;
885 	new->bitmap = calloc((new->ymax-new->ymin+1)*new->bytes_per_line,sizeof(uint8));
886     } else {
887 	new->bytes_per_line = (new->xmax-new->xmin)+1;
888 	new->bitmap = calloc((new->ymax-new->ymin+1)*new->bytes_per_line,sizeof(uint8));
889 	new->byte_data = true;
890     }
891     new->orig_pos = old->orig_pos;
892     new->refs = old->refs;
893     new->dependents = old->dependents;
894 
895     scale = from/dto;
896     scale *= scale;
897     scale *= (1<<from_depth);
898     bscale = scale/2;
899 
900     for ( y=0; y<=new->ymax-new->ymin; ++y ) for ( x=0; x<=new->xmax-new->xmin; ++x ) {
901 	tot = 0;
902 	oys = floor(y*from/dto); oyend = ceil((y+1)*from/dto);
903 	oxs = floor(x*from/dto); oxend = ceil((x+1)*from/dto);
904 	for ( oy = oys; oy<oyend && oy<=old->ymax-old->ymin; ++oy ) {
905 	    yscale = 1;
906 	    if ( oy==oys && oy==oyend-1 )
907 		yscale = 1-(oyend - (y+1)*from/dto) - (y*from/dto - oys);
908 	    else if ( oy==oys )
909 		yscale = 1-(y*from/dto-oys);
910 	    else if ( oy==oyend-1 )
911 		yscale = 1-(oyend - (y+1)*from/dto);
912 	    for ( ox = oxs; ox<oxend && ox<=old->xmax-old->xmin; ++ox ) {
913 		xscale = 1;
914 		if ( ox==oxs && ox==oxend-1 )
915 		    xscale = 1-(oxend - (x+1)*from/dto) - (x*from/dto - oxs);
916 		else if ( ox==oxs )
917 		    xscale = 1-(x*from/dto-oxs);
918 		else if ( ox==oxend-1 )
919 		    xscale = 1-(oxend - (x+1)*from/dto);
920 		tot += yscale*xscale* old->bitmap[oy*old->bytes_per_line + ox];
921 	    }
922 	}
923 	if ( to_depth!=1 ) {
924 	    real temp = tot*max/scale;
925 	    if ( temp>=max )
926 		temp = max-1;
927 	    new->bitmap[y*new->bytes_per_line + x] = (int) rint(temp);
928 	} else if ( tot>=bscale ) {
929 	    new->bitmap[y*new->bytes_per_line + (x>>3)] |= (1<<(7-(x&7)));
930 	}
931     }
932 
933 return( new );
934 }
935 
BitmapFontScaleTo(BDFFont * old,int to)936 BDFFont *BitmapFontScaleTo(BDFFont *old, int to) {
937     BDFFont *new = chunkalloc(sizeof(BDFFont));
938     int i;
939     int to_depth = (to>>16), old_depth = 1;
940     int linear_scale = 1<<(to_depth/2);
941 
942     to &= 0xffff;
943 
944     if ( old->clut!=NULL )
945 	old_depth = BDFDepth(old);
946 
947     new->sf = old->sf;
948     new->glyphcnt = new->glyphmax = old->glyphcnt;
949     new->glyphs = malloc(new->glyphcnt*sizeof(BDFChar *));
950     new->pixelsize = to;
951     new->ascent = (old->ascent*to+.5)/old->pixelsize;
952     new->descent = to-new->ascent;
953     new->foundry = copy(old->foundry);
954     new->res = -1;
955     for ( i=0; i<old->glyphcnt; ++i ) {
956 	if ( old->clut==NULL ) {
957 	    new->glyphs[i] = BCScale(old->glyphs[i],old->pixelsize,to*linear_scale);
958 	    if ( linear_scale!=1 )
959 		BDFCAntiAlias(new->glyphs[i],linear_scale);
960 	} else {
961 	    new->glyphs[i] = BCScaleGrey(old->glyphs[i],old->pixelsize,old_depth,to,to_depth);
962 	}
963     }
964     if ( linear_scale!=1 )
965 	BDFClut(new,linear_scale);
966 return( new );
967 }
968