contrib/OWB: add correct SDL dependency, fix compilers used
[AROS-Contrib.git] / freetype1 / contrib / ttf2pk / pklib.c
blob51c4805de285c92f0880d9c98460ea7e47b21dcd
1 /*
2 * pklib.c
4 * This file is part of the ttf2pk package.
6 * Copyright 1997-1999 by
7 * Frederic Loyer <loyer@ensta.fr>
8 * Werner Lemberg <wl@gnu.org>
9 */
12 * This code has been derived from the program gsftopk.
13 * Here the original copyright.
17 * Copyright (c) 1994 Paul Vojta. All rights reserved.
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
21 * are met:
22 * 1. Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <stddef.h> /* for size_t */
45 #include <string.h>
46 #include <errno.h>
47 #include <ctype.h>
49 #include "newobj.h"
50 #include "pklib.h"
51 #include "errormsg.h"
52 #include "filesrch.h"
54 #ifndef MAXPATHLEN
55 #define MAXPATHLEN 256
56 #endif
58 #define PK_PRE (char)247
59 #define PK_ID 89
60 #define PK_POST (char)245
61 #define PK_NOP (char)246
63 int dpi;
65 FILE *pk_file;
69 * Information from the .tfm file.
72 int tfm_lengths[12];
74 #define lh tfm_lengths[1]
75 #define bc tfm_lengths[2]
76 #define ec tfm_lengths[3]
77 #define nw tfm_lengths[4]
79 long checksum;
80 long design;
81 byte width_index[256];
82 long tfm_widths[256];
85 * Information on the bitmap currently being worked on.
88 byte *bitmap;
89 int width;
90 int skip;
91 int height;
92 int hoff;
93 int voff;
94 int bytes_wide;
95 size_t bm_size;
96 byte *bitmap_end;
97 int pk_len;
100 * Here's the path searching stuff. First the typedefs and variables.
103 static char searchpath[MAXPATHLEN + 1];
105 #define HUNKSIZE (MAXPATHLEN + 2)
107 struct spacenode /* used for storage of directory names */
109 struct spacenode *next;
110 char *sp_end; /* end of data for this chunk */
111 char sp[HUNKSIZE];
112 } firstnode;
116 static FILE *
117 search_tfm(char **name)
119 char *p;
120 FILE *f;
123 p = TeX_search_tfm(name);
124 if (p == NULL)
125 return NULL;
126 strcpy(searchpath, p);
127 f = fopen(searchpath, "rb");
128 return f;
132 static long
133 getlong(FILE *f)
135 unsigned long value;
138 value = (unsigned long)getc(f) << 24;
139 value |= (unsigned long)getc(f) << 16;
140 value |= (unsigned long)getc(f) << 8;
141 value |= (unsigned long)getc(f);
142 return value;
146 char line[82];
149 static byte masks[] = {0, 1, 3, 7, 017, 037, 077, 0177, 0377};
151 byte flag;
152 int pk_dyn_f;
153 int pk_dyn_g;
154 int base; /* cost of this character if pk_dyn_f = 0 */
155 int deltas[13]; /* cost of increasing pk_dyn_f from i to i+1 */
159 * Add up statistics for putting out the given shift count.
162 static void
163 tallyup(int n)
165 int m;
168 if (n > 208)
170 ++base;
171 n -= 192;
172 for (m = 0x100; m != 0 && m < n; m <<= 4)
173 base += 2;
174 if (m != 0 && (m = (m - n) / 15) < 13)
175 deltas[m] += 2;
177 else if (n > 13)
178 ++deltas[(208 - n) / 15];
179 else
180 --deltas[n - 1];
185 * Routines for storing the shift counts.
188 static Boolean odd = False;
189 static byte part;
192 static void
193 pk_put_nyb(int n)
195 if (odd)
197 *bitmap_end++ = (part << 4) | n;
198 odd = False;
200 else
202 part = n;
203 odd = True;
208 static void
209 pk_put_long(int n)
211 if (n >= 16)
213 pk_put_nyb(0);
214 pk_put_long(n / 16);
216 pk_put_nyb(n % 16);
220 static void
221 pk_put_count(int n)
223 if (n > pk_dyn_f)
225 if (n > pk_dyn_g)
226 pk_put_long(n - pk_dyn_g + 15);
227 else
229 pk_put_nyb(pk_dyn_f + (n - pk_dyn_f + 15) / 16);
230 pk_put_nyb((n - pk_dyn_f - 1) % 16);
233 else
234 pk_put_nyb(n);
238 static void
239 trim_bitmap(void)
241 byte *p;
242 byte mask;
245 /* clear out garbage bits in bitmap */
247 if (width % 8 != 0)
249 mask = ~masks[8 - width % 8];
250 for (p = bitmap + bytes_wide - 1; p < bitmap_end; p += bytes_wide)
251 *p &= mask;
254 /* Find the bounding box of the bitmap. */
256 /* trim top */
258 skip = 0;
259 mask = 0;
261 for (;;)
263 if (bitmap >= bitmap_end) /* if bitmap is empty */
265 width = height = hoff = voff = 0;
266 return;
269 p = bitmap + bytes_wide;
270 while (p > bitmap)
271 mask |= *--p;
272 if (mask)
273 break;
274 ++skip;
275 bitmap += bytes_wide;
278 height -= skip;
279 voff -= skip;
281 #ifdef DEBUG
282 if (skip < 2 || skip > 3)
283 printf("Character has %d empty rows at top\n", skip);
284 #endif
286 /* trim bottom */
288 skip = 0;
289 mask = 0;
291 for (;;)
293 p = bitmap_end - bytes_wide;
294 while (p < bitmap_end)
295 mask |= *p++;
296 if (mask)
297 break;
298 ++skip;
299 bitmap_end -= bytes_wide;
302 height -= skip;
304 #ifdef DEBUG
305 if (skip < 2 || skip > 3)
306 printf("Character has %d empty rows at bottom\n", skip);
307 #endif
309 /* trim right */
311 skip = 0;
312 --width;
314 for (;;)
316 mask = 0;
317 for (p = bitmap + width / 8; p < bitmap_end; p += bytes_wide)
318 mask |= *p;
319 if (mask & (0x80 >> (width % 8)))
320 break;
322 --width;
323 ++skip;
326 ++width;
328 #ifdef DEBUG
329 if (skip < 2 || skip > 3)
330 printf("Character has %d empty columns at right\n", skip);
331 #endif
333 /* trim left */
335 skip = 0;
337 for (;;)
339 mask = 0;
340 for (p = bitmap + skip / 8; p < bitmap_end; p += bytes_wide)
341 mask |= *p;
342 if (mask & (0x80 >> (skip % 8)))
343 break;
345 ++skip;
348 width -= skip;
349 hoff -= skip;
351 #ifdef DEBUG
352 if (skip < 2 || skip > 3)
353 printf("Character has %d empty columns at left\n", skip);
354 #endif
356 bitmap += skip / 8;
357 skip = skip % 8;
362 * Pack the bitmap using the rll method. (Return false if it's better
363 * to just pack the bits.)
366 static Boolean
367 pk_rll_cvt(void)
369 static int *counts = NULL; /* area for saving bit counts */
370 static int maxcounts = 0; /* size of this area */
371 unsigned int ncounts; /* max to allow this time */
372 int *nextcount; /* next count value */
374 int *counts_end; /* pointer to end */
375 byte *rowptr;
376 byte *p;
377 byte mask;
378 byte *rowdup; /* last row checked for dup */
379 byte paint_switch; /* 0 or 0xff */
380 int bits_left; /* bits left in row */
381 int cost;
382 int i;
385 /* Allocate space for bit counts. */
387 ncounts = (width * height + 3) / 4;
388 if (ncounts > maxcounts)
390 if (counts != NULL)
391 free(counts);
392 counts = (int *)mymalloc((ncounts + 2) * sizeof (int));
393 maxcounts = ncounts;
395 counts_end = counts + ncounts;
397 /* Form bit counts and collect statistics */
399 base = 0;
400 memset(deltas, 0, sizeof (deltas));
401 rowdup = NULL; /* last row checked for duplicates */
402 p = rowptr = bitmap;
403 mask = 0x80 >> skip;
404 flag = 0;
405 paint_switch = 0;
407 if (*p & mask)
409 flag = 8;
410 paint_switch = 0xff;
413 bits_left = width;
414 nextcount = counts;
416 while (rowptr < bitmap_end) /* loop over shift counts */
418 int shift_count = bits_left;
421 for (;;)
423 if (bits_left == 0)
425 if ((p = rowptr += bytes_wide) >= bitmap_end)
426 break;
427 mask = 0x80 >> skip;
428 bits_left = width;
429 shift_count += width;
431 if (((*p ^ paint_switch) & mask) != 0)
432 break;
433 --bits_left;
434 mask >>= 1;
435 if (mask == 0)
437 ++p;
438 while (*p == paint_switch && bits_left >= 8)
440 ++p;
441 bits_left -= 8;
443 mask = 0x80;
447 if (nextcount >= counts_end)
448 return False;
449 shift_count -= bits_left;
450 *nextcount++ = shift_count;
451 tallyup(shift_count);
453 /* check for duplicate rows */
454 if (rowptr != rowdup && bits_left != width)
456 byte *p1 = rowptr;
457 byte *q = rowptr + bytes_wide;
458 int repeat_count;
461 while (q < bitmap_end && *p1 == *q)
463 ++p1;
464 ++q;
466 repeat_count = (p1 - rowptr) / bytes_wide;
467 if (repeat_count > 0)
469 *nextcount++ = -repeat_count;
470 if (repeat_count == 1)
471 --base;
472 else
474 ++base;
475 tallyup(repeat_count);
477 rowptr += repeat_count * bytes_wide;
479 rowdup = rowptr;
481 paint_switch = ~paint_switch;
484 #ifdef DEBUG
486 * Dump the bitmap
489 for (p = bitmap; p < bitmap_end; p += bytes_wide)
491 byte *p1 = p;
492 int j;
495 mask = 0x80 >> skip;
496 for (j = 0; j < width; ++j)
498 putchar(*p1 & mask ? '@' : '.');
499 if ((mask >>= 1) == 0)
501 mask = 0x80;
502 ++p1;
505 putchar('\n');
507 putchar('\n');
508 #endif
510 /* Determine the best pk_dyn_f */
512 pk_dyn_f = 0;
513 cost = base += 2 * (nextcount - counts);
515 for (i = 1; i < 14; ++i)
517 base += deltas[i - 1];
518 if (base < cost)
520 pk_dyn_f = i;
521 cost = base;
525 /* last chance to bail out */
527 if (cost * 4 > width * height)
528 return False;
530 /* Pack the bit counts */
532 pk_dyn_g = 208 - 15 * pk_dyn_f;
533 flag |= pk_dyn_f << 4;
534 bitmap_end = bitmap;
535 *nextcount = 0;
536 nextcount = counts;
538 while (*nextcount != 0)
540 if (*nextcount > 0)
541 pk_put_count(*nextcount);
542 else
543 if (*nextcount == -1)
544 pk_put_nyb(15);
545 else
547 pk_put_nyb(14);
548 pk_put_count(-*nextcount);
550 ++nextcount;
553 if (odd)
555 pk_put_nyb(0);
556 ++cost;
559 if (cost != 2 * (bitmap_end - bitmap))
560 printf("Cost miscalculation: expected %d, got %ld\n",
561 cost, (long)(2 * (bitmap_end - bitmap)));
562 pk_len = bitmap_end - bitmap;
563 return True;
567 static void
568 pk_bm_cvt(void)
570 byte *rowptr;
571 byte *p;
572 int blib1; /* bits left in byte */
573 int bits_left; /* bits left in row */
574 byte *q;
575 int blib2;
576 byte nextbyte;
579 flag = 14 << 4;
580 q = bitmap;
581 blib2 = 8;
582 nextbyte = 0;
584 for (rowptr = bitmap; rowptr < bitmap_end; rowptr += bytes_wide)
586 p = rowptr;
587 blib1 = 8 - skip;
588 bits_left = width;
590 if (blib2 != 8)
592 int n;
595 if (blib1 < blib2)
597 nextbyte |= *p << (blib2 - blib1);
598 n = blib1;
600 else
602 nextbyte |= *p >> (blib1 - blib2);
603 n = blib2;
605 blib2 -= n;
606 if ((bits_left -= n) < 0)
608 blib2 -= bits_left;
609 continue;
611 if ((blib1 -= n) == 0)
613 blib1 = 8;
614 ++p;
615 if (blib2 > 0)
617 nextbyte |= *p >> (8 - blib2);
618 blib1 -= blib2;
619 bits_left -= blib2;
620 if (bits_left < 0)
622 blib2 = -bits_left;
623 continue;
627 *q++ = nextbyte;
630 /* fill up whole (destination) bytes */
632 while (bits_left >= 8)
634 nextbyte = *p++ << (8 - blib1);
635 *q++ = nextbyte | (*p >> blib1);
636 bits_left -= 8;
639 /* now do the remainder */
641 nextbyte = *p << (8 - blib1);
642 if (bits_left > blib1)
643 nextbyte |= p[1] >> blib1;
644 blib2 = 8 - bits_left;
647 if (blib2 != 8)
648 *q++ = nextbyte;
650 pk_len = q - bitmap;
654 static void
655 putshort(short w)
657 putc(w >> 8, pk_file);
658 putc(w, pk_file);
662 static void
663 putmed(long w)
665 putc(w >> 16, pk_file);
666 putc(w >> 8, pk_file);
667 putc(w, pk_file);
671 static void
672 putlong(long w)
674 putc(w >> 24, pk_file);
675 putc(w >> 16, pk_file);
676 putc(w >> 8, pk_file);
677 putc(w, pk_file);
681 char
682 xgetc(FILE *f)
684 int c;
687 c = getc(f);
688 if (c == EOF)
689 oops("Premature end of file.");
690 return (byte)c;
695 * Open and read the tfm file.
698 void
699 TFMopen(char **filename)
701 FILE *tfm_file;
702 int i;
703 int cc;
706 tfm_file = search_tfm(filename);
707 if (tfm_file == NULL)
708 oops("Cannot find tfm file.");
710 for (i = 0; i < 12; i++)
712 int j;
715 j = (int)((byte)getc(tfm_file)) << 8;
716 tfm_lengths[i] = j | (int)((byte)xgetc(tfm_file));
719 checksum = getlong(tfm_file);
720 design = getlong(tfm_file);
721 fseek(tfm_file, 4 * (lh + 6), 0);
723 for (cc = bc; cc <= ec; ++cc)
725 width_index[cc] = (byte)xgetc(tfm_file);
727 (void)xgetc(tfm_file);
728 (void)xgetc(tfm_file);
729 (void)xgetc(tfm_file);
732 for (i = 0; i < nw; ++i)
733 tfm_widths[i] = getlong(tfm_file);
735 fclose(tfm_file);
740 * Create pk file and write preamble.
743 void
744 PKopen(char *filename,
745 char *ident,
746 int resolution)
748 int ppp;
749 int i;
752 dpi = resolution;
754 if ((pk_file = fopen(filename, "wb")) == NULL)
756 perror(filename);
757 exit(1);
760 putc(PK_PRE, pk_file);
761 putc(PK_ID, pk_file);
763 i = strlen(ident);
765 putc(i, pk_file);
766 fwrite(ident, 1, i, pk_file);
767 putlong(design);
768 putlong(checksum);
769 ppp = dpi / 72.27 * 65536.0 + 0.5;
770 putlong(ppp); /* hppp */
771 putlong(ppp); /* vppp */
775 void
776 PKputglyph(int cc,
777 int llx, int lly, int urx, int ury,
778 int w, int h,
779 byte *b)
781 float char_width;
783 long dm;
784 long tfm_wid;
787 bitmap = b;
788 width = w;
789 height = h;
791 hoff = -llx;
792 voff = ury - 2; /* Don't ask me why `-2' */
793 /* Fred */
795 if (width != urx - llx || height != ury - lly)
796 oops("Dimensions do not match: (%d - %d) (%d - %d) <=> %d %d",
797 llx, lly, urx, ury, width, height);
799 bytes_wide = (width + 7) / 8;
800 bm_size = bytes_wide * height;
801 bitmap_end = bitmap + bm_size;
803 trim_bitmap();
805 if (height == 0 || !pk_rll_cvt())
806 pk_bm_cvt();
808 if (!width_index[cc])
809 return;
811 tfm_wid = tfm_widths[width_index[cc]];
812 char_width = tfm_wid / 1048576.0 * design / 1048576.0 * dpi / 72.27;
813 dm = (long)(char_width + 0.5) - (char_width < -0.5);
815 if (pk_len + 8 < 4 * 256 && tfm_wid < (1<<24) &&
816 dm >= 0 && dm < 256 && width < 256 && height < 256 &&
817 hoff >= -128 && hoff < 128 && voff >= -128 && voff < 128)
819 putc(flag | ((pk_len + 8) >> 8), pk_file);
820 putc(pk_len + 8, pk_file);
821 putc(cc, pk_file);
822 putmed(tfm_wid);
823 putc(dm, pk_file);
824 putc(width, pk_file);
825 putc(height, pk_file);
826 putc(hoff, pk_file);
827 putc(voff, pk_file);
829 else if (pk_len + 13 < 3 * 65536L && tfm_wid < (1<<24) &&
830 dm >= 0 && dm < 65536L && width < 65536L && height < 65536L &&
831 hoff >= -65536L && hoff < 65536L &&
832 voff >= -65536L && voff < 65536L)
834 putc(flag | 4 | ((pk_len + 13) >> 16), pk_file);
835 putshort(pk_len + 13);
836 putc(cc, pk_file);
837 putmed(tfm_wid);
838 putshort(dm);
839 putshort(width);
840 putshort(height);
841 putshort(hoff);
842 putshort(voff);
844 else
846 putc(flag | 7, pk_file);
847 putlong(pk_len + 28);
848 putlong(cc);
849 putlong(tfm_wid);
850 putlong((long)(char_width * 65536.0 + 0.5) - (char_width < -0.5));
851 putlong(0);
852 putlong(width);
853 putlong(height);
854 putlong(hoff);
855 putlong(voff);
857 fwrite(bitmap, 1, pk_len, pk_file);
861 void
862 PKclose(void)
864 putc(PK_POST, pk_file);
865 while (ftell(pk_file) % 4 != 0)
866 putc(PK_NOP, pk_file);
868 fclose(pk_file);
872 /* end */