]> www.fi.muni.cz Git - evince.git/blob - backend/dvi/mdvi-lib/pk.c
Reorganize source tree.
[evince.git] / backend / dvi / mdvi-lib / pk.c
1
2 /* Copyright (C) 2000, Matias Atria
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 /*
20  * History:
21  *
22  * 11/3/2000:
23  *    - First working version
24  * 11/4/2000:
25  *    - FIXED: entirely white/black rows were missed.
26  * 11/8/2000:
27  *    - TESTED: Glyphs are rendered correctly in different byte orders.
28  *    - Made bitmap code much more efficient and compact.
29  */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <math.h>
36
37 #include "mdvi.h"
38 #include "private.h"
39
40 #define PK_ID      89
41 #define PK_CMD_START 240
42 #define PK_X1     240
43 #define PK_X2     241
44 #define PK_X3     242
45 #define PK_X4     243
46 #define PK_Y      244
47 #define PK_POST   245
48 #define PK_NOOP   246
49 #define PK_PRE    247
50
51 #define PK_DYN_F(x)     (((x) >> 4) & 0xf)
52 #define PK_PACKED(x)    (PK_DYN_F(x) != 14)
53
54 static int pk_load_font __PROTO((DviParams *, DviFont *));
55 static int pk_font_get_glyph __PROTO((DviParams *, DviFont *, int));
56
57 static int pk_auto_generate = 1; /* this is ON by default */
58
59 typedef struct {
60         char    currbyte;
61         char    nybpos;
62         int     dyn_f;
63 } pkread;
64
65 static char *pk_lookup __PROTO((const char *, Ushort *, Ushort *));
66 static char *pk_lookupn __PROTO((const char *, Ushort *, Ushort *));
67
68 /* only symbols exported by this file */
69 DviFontInfo pk_font_info = {
70         "PK",
71         0, /* scaling not supported natively */
72         pk_load_font,
73         pk_font_get_glyph,
74         mdvi_shrink_glyph,
75         mdvi_shrink_glyph_grey,
76         NULL,   /* free */
77         NULL,   /* reset */
78         pk_lookup,      /* lookup */
79         kpse_pk_format,
80         NULL
81 };
82
83 DviFontInfo pkn_font_info = {
84         "PKN",
85         0, /* scaling not supported natively */
86         pk_load_font,
87         pk_font_get_glyph,
88         mdvi_shrink_glyph,
89         mdvi_shrink_glyph_grey,
90         NULL,   /* free */
91         NULL,   /* reset */
92         pk_lookupn,     /* lookup */
93         kpse_pk_format,
94         NULL
95 };
96
97 static char *pk_lookup(const char *name, Ushort *hdpi, Ushort *vdpi)
98 {
99         kpse_glyph_file_type type;
100         char *filename;
101
102         if(pk_auto_generate == 0) {
103                 kpse_set_program_enabled(kpse_pk_format, 1, kpse_src_cmdline);
104                 pk_auto_generate = 1;
105         }
106         filename = kpse_find_glyph(name, Max(*hdpi, *vdpi),
107                 kpse_pk_format, &type);
108         if(filename && type.source == kpse_glyph_source_fallback) {
109                 mdvi_free(filename);
110                 filename = NULL;
111         } else if(filename) {
112                 *hdpi = *vdpi = type.dpi;
113         }
114         return filename;        
115 }
116
117 static char *pk_lookupn(const char *name, Ushort *hdpi, Ushort *vdpi)
118 {
119         kpse_glyph_file_type type;
120         char *filename;
121
122         if(pk_auto_generate) {
123                 kpse_set_program_enabled(kpse_pk_format, 0, kpse_src_cmdline);
124                 pk_auto_generate = 0;
125         }
126         filename = kpse_find_glyph(name, Max(*hdpi, *vdpi),
127                 kpse_pk_format, &type);
128         if(filename && type.source == kpse_glyph_source_fallback) {
129                 mdvi_free(filename);
130                 filename = NULL;
131         } else if(filename) {
132                 *hdpi = *vdpi = type.dpi;
133         }
134         return filename;        
135 }
136
137 static inline int pk_get_nyb(FILE *p, pkread *pk)
138 {
139         unsigned t;
140         int     nb;
141         char    c;
142         
143         t = c = pk->currbyte;
144         nb = pk->nybpos;
145         
146         switch(nb) {
147         case 0:
148                 c = pk->currbyte = fuget1(p);
149                 t = (c >> 4);
150                 break;
151         case 1:
152                 t = c;
153                 break;
154         }
155         pk->nybpos = !nb;
156         return (t & 0xf);
157 }
158
159 /* 
160  * this is a bit cumbersome because we have to pass around
161  * the `pkread' data...
162  */
163 static int pk_packed_num(FILE *p, pkread *pkr, int *repeat)
164 {
165         int     i, j;
166         int     dyn_f = pkr->dyn_f;
167         
168         i = pk_get_nyb(p, pkr);
169         if(i == 0) {
170                 do {
171                         j = pk_get_nyb(p, pkr);
172                         i++;
173                 } while(j == 0);
174                 while(i-- > 0)
175                         j = (j << 4) + pk_get_nyb(p, pkr);
176                 return (j - 15 + ((13 - dyn_f) << 4) + 
177                         dyn_f);
178         } else if(i <= dyn_f)
179                 return i;
180         else if(i < 14)
181                 return ((i - dyn_f - 1) << 4) + 
182                         pk_get_nyb(p, pkr) + dyn_f + 1;
183         else {
184                 *repeat = 1;
185                 if(i == 14)
186                         *repeat = pk_packed_num(p, pkr, repeat);
187                 return pk_packed_num(p, pkr, repeat);
188         }
189 }
190
191 #define ROUND(x,y)      (((x) + (y) - 1) / (y))
192
193 static BITMAP *get_bitmap(FILE *p, int w, int h, int flags)
194 {
195         int     i, j;
196         BmUnit  *ptr;
197         BITMAP  *bm;
198         int     bitpos;
199         int     currch;
200                 
201         flags = 0; /* shut up that compiler */
202         bitpos = -1;
203         if((bm = bitmap_alloc(w, h)) == NULL)
204                 return NULL;
205         DEBUG((DBG_BITMAPS, "get_bitmap(%d,%d,%d): reading raw bitmap\n",
206                 w, h, flags));
207         ptr = bm->data;
208         currch = 0;
209         for(i = 0; i < h; i++) {
210                 BmUnit  mask;
211                 
212                 mask = FIRSTMASK;
213                 for(j = 0; j < w; j++) {
214                         if(bitpos < 0) {
215                                 currch = fuget1(p);
216                                 bitpos = 7;
217                         }
218                         if(currch & (1 << bitpos))
219                                 *ptr |= mask;
220                         bitpos--;
221                         if(mask == LASTMASK) {
222                                 ptr++;
223                                 mask = FIRSTMASK;
224                         } else
225                                 NEXTMASK(mask);
226                 }
227                 ptr = bm_offset(ptr, bm->stride);
228         }
229         return bm;
230 }
231
232 static BITMAP *get_packed(FILE *p, int w, int h, int flags)
233 {
234         int     inrow, count;
235         int     row;
236         BITMAP  *bm;
237         int     repeat_count;
238         int     paint;
239         pkread  pkr;
240                 
241         pkr.nybpos = 0;
242         pkr.currbyte = 0;
243         pkr.dyn_f = PK_DYN_F(flags);
244         paint = !!(flags & 0x8);
245
246         repeat_count = 0;
247         row = 0;
248         inrow = w;
249         if((bm = bitmap_alloc(w, h)) == NULL)
250                 return NULL;
251         DEBUG((DBG_BITMAPS, "get_packed(%d,%d,%d): reading packed glyph\n",
252                 w, h, flags));
253         while(row < h) {
254                 int     i = 0;
255                 
256                 count = pk_packed_num(p, &pkr, &i);
257                 if(i > 0) {
258                         if(repeat_count)
259                                 fprintf(stderr, "second repeat count for this row (had %d and got %d)\n",
260                                         repeat_count, i);
261                         repeat_count = i;
262                 }
263                 
264                 if(count >= inrow) {
265                         Uchar   *r, *t;
266                         BmUnit  *a, mask;
267                         
268                         /* first finish current row */
269                         if(paint)
270                                 bitmap_set_row(bm, row, w - inrow, inrow, paint);
271                         /* now copy it as many times as required */
272                         r = (Uchar *)bm->data + row * bm->stride;
273                         while(repeat_count-- > 0) {
274                                 t = r + bm->stride;
275                                 /* copy entire lines */
276                                 memcpy(t, r, bm->stride);
277                                 r = t;
278                                 row++;
279                         }
280                         repeat_count = 0;
281                         /* count first row we drew */
282                         row++;
283                         /* update run count */
284                         count -= inrow;
285                         /* now r points to the beginning of the last row we finished */
286                         if(paint)
287                                 mask = ~((BmUnit)0);
288                         else
289                                 mask = 0;
290                         /* goto next row */
291                         a = (BmUnit *)(r + bm->stride);
292                         /* deal with entirely with/black rows */
293                         while(count >= w) {
294                                 /* count number of atoms in a row */
295                                 i = ROUND(w, BITMAP_BITS);
296                                 while(i-- > 0)
297                                         *a++ = mask;
298                                 count -= w;
299                                 row++;
300                         }
301                         inrow = w;
302                 }
303                 if(count > 0)
304                         bitmap_set_row(bm, row, w - inrow, count, paint);
305                 inrow -= count;
306                 paint = !paint;
307         }
308         if(row != h || inrow != w) {
309                 error(_("Bad PK file: More bits than required\n"));
310                 bitmap_destroy(bm);
311                 return NULL;
312         }
313         return bm;
314 }
315
316 static BITMAP *get_char(FILE *p, int w, int h, int flags)
317 {
318         /* check if dyn_f == 14 */
319         if(((flags >> 4) & 0xf) == 14)
320                 return get_bitmap(p, w, h, flags);
321         else
322                 return get_packed(p, w, h, flags);
323 }
324
325 /* supports any number of characters in a font */
326 static int pk_load_font(DviParams *unused, DviFont *font)
327 {
328         int     i;
329         int     flag_byte;
330         int     loc, hic, maxch;
331         Int32   checksum;
332         FILE    *p;
333 #ifndef NODEBUG
334         char    s[256];
335 #endif
336         long    alpha, beta, z;
337
338         font->chars = xnalloc(DviFontChar, 256);
339         p = font->in;
340         memzero(font->chars, 256 * sizeof(DviFontChar));
341         for(i = 0; i < 256; i++)
342                 font->chars[i].offset = 0;
343
344         /* check the preamble */
345         loc = fuget1(p); hic = fuget1(p);
346         if(loc != PK_PRE || hic != PK_ID)
347                 goto badpk;
348         i = fuget1(p);
349 #ifndef NODEBUG
350         for(loc = 0; loc < i; loc++)
351                 s[loc] = fuget1(p);
352         s[loc] = 0;
353         DEBUG((DBG_FONTS, "(pk) %s: %s\n", font->fontname, s));
354 #else
355         fseek(in, (long)i, SEEK_CUR);
356 #endif
357         /* get the design size */
358         font->design = fuget4(p);
359         /* get the checksum */
360         checksum = fuget4(p);
361         if(checksum && font->checksum && font->checksum != checksum) {
362                 warning(_("%s: checksum mismatch (expected %u, got %u)\n"),
363                         font->fontname, font->checksum, checksum);
364         } else if(!font->checksum)
365                 font->checksum = checksum;
366         /* skip pixel per point ratios */
367         fuget4(p);
368         fuget4(p);
369         if(feof(p))
370                 goto badpk;     
371
372         /* now start reading the font */
373         loc = 256; hic = -1; maxch = 256;
374         
375         /* initialize alpha and beta for TFM width computation */
376         TFMPREPARE(font->scale, z, alpha, beta);
377
378         while((flag_byte = fuget1(p)) != PK_POST) {
379                 if(feof(p))
380                         break;
381                 if(flag_byte >= PK_CMD_START) {
382                         switch(flag_byte) {
383                         case PK_X1:
384                         case PK_X2:
385                         case PK_X3:
386                         case PK_X4: {
387 #ifndef NODEBUG
388                                 char    *t;
389                                 int     n;
390                                 
391                                 i = fugetn(p, flag_byte - PK_X1 + 1);
392                                 if(i < 256)
393                                         t = &s[0];
394                                 else
395                                         t = mdvi_malloc(i + 1);
396                                 for(n = 0; n < i; n++)
397                                         t[n] = fuget1(p);
398                                 t[n] = 0;
399                                 DEBUG((DBG_SPECIAL, "(pk) %s: Special \"%s\"\n",
400                                         font->fontname, t));
401                                 if(t != &s[0])
402                                         mdvi_free(t);
403 #else
404                                 i = fugetn(p, flag_byte - PK_X1 + 1);
405                                 while(i-- > 0)
406                                         fuget1(p);
407 #endif
408                                 break;
409                         }
410                         case PK_Y:
411                                 i = fuget4(p);
412                                 DEBUG((DBG_SPECIAL, "(pk) %s: MF special %u\n",
413                                         font->fontname, (unsigned)i));
414                                 break;
415                         case PK_POST:
416                         case PK_NOOP:
417                                 break;
418                         case PK_PRE:
419                                 error(_("%s: unexpected preamble\n"), font->fontname);
420                                 goto error;
421                         }
422                 } else {
423                         int     pl;
424                         int     cc;
425                         int     w, h;
426                         int     x, y;
427                         int     offset;
428                         long    tfm;
429                         
430                         switch(flag_byte & 0x7) {
431                         case 7:
432                                 pl = fuget4(p);
433                                 cc = fuget4(p);
434                                 offset = ftell(p) + pl;
435                                 tfm = fuget4(p);
436                                 fsget4(p); /* skip dx */
437                                 fsget4(p); /* skip dy */
438                                 w  = fuget4(p);
439                                 h  = fuget4(p); 
440                                 x  = fsget4(p);
441                                 y  = fsget4(p);
442                                 break;
443                         case 4:
444                         case 5:
445                         case 6:                         
446                                 pl = (flag_byte % 4) * 65536 + fuget2(p);
447                                 cc = fuget1(p);
448                                 offset = ftell(p) + pl;
449                                 tfm = fuget3(p);
450                                 fsget2(p); /* skip dx */
451                                            /* dy assumed 0 */
452                                 w = fuget2(p);
453                                 h = fuget2(p);
454                                 x = fsget2(p);
455                                 y = fsget2(p);
456                                 break;
457                         default:
458                                 pl = (flag_byte % 4) * 256 + fuget1(p);
459                                 cc = fuget1(p);
460                                 offset = ftell(p) + pl;
461                                 tfm = fuget3(p);
462                                 fsget1(p); /* skip dx */
463                                            /* dy assumed 0 */
464                                 w = fuget1(p);
465                                 h = fuget1(p);
466                                 x = fsget1(p);
467                                 y = fsget1(p);
468                         }
469                         if(feof(p))
470                                 break;
471                         if(cc < loc)
472                                 loc = cc;
473                         if(cc > hic)
474                                 hic = cc;
475                         if(cc > maxch) {
476                                 font->chars = xresize(font->chars, 
477                                         DviFontChar, cc + 16);
478                                 for(i = maxch; i < cc + 16; i++)
479                                         font->chars[i].offset = 0;
480                                 maxch = cc + 16;
481                         }
482                         font->chars[cc].code = cc;
483                         font->chars[cc].flags = flag_byte;
484                         font->chars[cc].offset = ftell(p);
485                         font->chars[cc].width = w;
486                         font->chars[cc].height = h;
487                         font->chars[cc].glyph.data = NULL;
488                         font->chars[cc].x = x;
489                         font->chars[cc].y = y;
490                         font->chars[cc].glyph.x = x;
491                         font->chars[cc].glyph.y = y;
492                         font->chars[cc].glyph.w = w;
493                         font->chars[cc].glyph.h = h;
494                         font->chars[cc].grey.data = NULL;
495                         font->chars[cc].shrunk.data = NULL;
496                         font->chars[cc].tfmwidth = TFMSCALE(z, tfm, alpha, beta);
497                         font->chars[cc].loaded = 0;
498                         fseek(p, (long)offset, SEEK_SET);
499                 }
500         }
501         if(flag_byte != PK_POST) {
502                 error(_("%s: unexpected end of file (no postamble)\n"),
503                         font->fontname);
504                 goto error;
505         }
506         while((flag_byte = fuget1(p)) != EOF) {
507                 if(flag_byte != PK_NOOP) {
508                         error(_("invalid PK file! (junk in postamble)\n"));
509                         goto error;
510                 }
511         }
512
513         /* resize font char data */
514         if(loc > 0 || hic < maxch-1) {
515                 memmove(font->chars, font->chars + loc, 
516                         (hic - loc + 1) * sizeof(DviFontChar));
517                 font->chars = xresize(font->chars,
518                         DviFontChar, hic - loc + 1);
519         }
520         font->loc = loc;
521         font->hic = hic;                
522         return 0;
523
524 badpk:
525         error(_("%s: File corrupted, or not a PK file\n"), font->fontname);
526 error:
527         mdvi_free(font->chars);
528         font->chars = NULL;
529         font->loc = font->hic = 0;
530         return -1;
531 }
532
533 static int pk_font_get_glyph(DviParams *params, DviFont *font, int code)
534 {
535         DviFontChar     *ch;
536
537         if((ch = FONTCHAR(font, code)) == NULL)
538                 return -1;
539         
540         if(ch->offset == 0)
541                 return -1;
542         DEBUG((DBG_GLYPHS, "(pk) loading glyph for character %d (%dx%d) in font `%s'\n",
543                 code, ch->width, ch->height, font->fontname));
544         if(font->in == NULL && font_reopen(font) < 0)
545                 return -1;
546         if(!ch->width || !ch->height) {
547                 /* this happens for ` ' (ASCII 32) in some fonts */
548                 ch->glyph.x = ch->x;
549                 ch->glyph.y = ch->y;
550                 ch->glyph.w = ch->width;
551                 ch->glyph.h = ch->height;
552                 ch->glyph.data = NULL;
553                 return 0; 
554         }
555         if(fseek(font->in, ch->offset, SEEK_SET) == -1)
556                 return -1;
557         ch->glyph.data = get_char(font->in, 
558                 ch->width, ch->height, ch->flags);
559         if(ch->glyph.data) {
560                 /* restore original settings */
561                 ch->glyph.x = ch->x;
562                 ch->glyph.y = ch->y;
563                 ch->glyph.w = ch->width;
564                 ch->glyph.h = ch->height;
565         } else
566                 return -1;
567         ch->loaded = 1;
568         return 0;
569 }