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