]> www.fi.muni.cz Git - evince.git/blob - dvi/dvilib/dl-pkfont.cc
2544e35da3b9534bf8470952c9858ac8592059d4
[evince.git] / dvi / dvilib / dl-pkfont.cc
1 #include "dl-pkfont.hh"
2 #include <algorithm>
3 #include <iostream>
4
5 using namespace DviLib;
6
7 enum PkOpcode {
8     DL_PK_FIRST_COMMAND = 240,
9     DL_PK_XXX1 = 240,
10     DL_PK_XXX2,
11     DL_PK_XXX3,
12     DL_PK_XXX4,
13     DL_PK_YYY,
14     DL_PK_POST,
15     DL_PK_NOP,
16     DL_PK_PRE
17 };
18
19 enum Color {
20     BLACK,
21     WHITE
22 };
23
24 class Bitmap {
25     uint *data;
26     uint width;
27 public:
28     Bitmap (uint width_arg, uint height)
29     {
30         width = width_arg;
31         data = new uint [width * height];
32         std::fill (data, data + width * height, 0x00000000);
33     }
34     uchar *steal_pixels (void)
35     {
36         uchar *r = (uchar *)data;
37         data = 0;
38         return r;
39     }
40     ~Bitmap () 
41     { 
42     }
43     void fill_black (uint index, uint len)
44     {
45 #if 0
46         cout << "filling: " << len << endl;
47 #endif
48         std::fill (data + index,
49                    data + index + len,
50                    0xff000000);
51     }
52     void copy (uint src_index, uint len, uint dest_index)
53     {
54         std::copy (data + src_index, 
55                    data + (src_index + len),
56                    data + dest_index);
57     }
58     uint x (uint index)
59     {
60         return index % width;
61     }
62 #if 0
63     uint y (uint index)
64     {
65         return (index * 4) / (width * 4);
66     }
67 #endif
68     bool pixel (uint index) { 
69         return *(data + index) == 0xff000000;
70     }
71 };
72
73 class DviLib::RleContext {
74     uchar *data;
75     bool first;
76     uchar nyb0 (uchar x) { return x >> 4; };
77     uchar nyb1 (uchar x) { return x & 15; };
78     Bitmap& bitmap;
79 public:
80     uint index;
81     Color color;
82     RleContext (uchar *data_arg,
83                 Color color_arg,
84                 Bitmap &bitmap_arg) :
85         data (data_arg),
86         first (true),
87         bitmap (bitmap_arg),
88         
89         index (0),
90         color (color_arg)
91     { }
92     uchar get_nybble (void)
93     {
94         if (first)
95         {
96             first = false;
97             return nyb0 (*data);
98         }
99         else
100         {
101             first = true;
102             return nyb1 (*data++);
103         }
104     }
105     Bitmap& get_bitmap () { return bitmap; }
106 };
107
108 inline CountType
109 PkChar::get_count (RleContext& nr, uint *count)
110 {
111     CountType result = RUN_COUNT;
112     uint i;
113     
114     i = nr.get_nybble();
115     if (i == 15)
116     {
117         *count = 1;
118         return REPEAT_COUNT;
119     }
120     else if (i == 14)
121     {
122         result = REPEAT_COUNT;
123         i = nr.get_nybble();
124     }
125     switch (i) {
126     case 15: case 14:
127         throw string ("Duplicated repeat count");
128         break;
129     case 0:
130         for (i = 1; (*count = nr.get_nybble()) == 0; ++i)
131             ;
132         while (i-- > 0)
133             *count = (*count << 4) + nr.get_nybble();
134         *count = *count - 15 + (13 - dyn_f)*16 + dyn_f;
135         break;
136     default:
137         if (i <= dyn_f)
138             *count = i;
139         else
140             *count = (i - dyn_f - 1)*16 + nr.get_nybble() + dyn_f + 1;
141         break;
142     }
143     return result;
144 }
145
146 void
147 PkChar::unpack_rle (RleContext& nr)
148 {
149     uint count;
150     
151     while (nr.index < height * width)
152     {
153         CountType count_type = get_count (nr, &count);
154         Bitmap& bm = nr.get_bitmap ();
155         
156         switch (count_type) {
157         case RUN_COUNT:
158             if (nr.color == BLACK)                  
159             {
160                 bm.fill_black (nr.index, count);
161                 nr.color = WHITE;
162             }
163             else
164                 nr.color = BLACK;
165             nr.index += count;
166             break;
167         case REPEAT_COUNT:
168             uint temp = nr.index;
169             
170             nr.index += count * width;
171             unpack_rle (nr);
172             
173             uint x = bm.x(temp);
174             
175             if (bm.pixel (temp - x))
176                 bm.fill_black (temp + count * width - x, x);
177             
178             for (uint i = 0; i < count; ++i)
179                 bm.copy (temp + count * width - x, width, 
180                          temp - x + i * width);
181             return;
182             break;
183         }
184     }
185 }
186
187 void
188 PkChar::unpack_bitmap (void)
189 {
190     uint i, weight;
191     
192     uchar *bitmap 
193         = new uchar [4 * width * height];
194     fill (bitmap, bitmap + 4 * width * height, 0xFF);
195     
196     weight = 128;
197     
198     for (i=0; i < height * width; i+=4)
199     {
200         if ((*data.packed & weight) != 0)
201             bitmap[i] = bitmap[i+1] = 
202                 bitmap[i+2] = bitmap[i+3] = 0x00;
203         weight = (weight == 1)?
204             (data.packed++, 128) : weight >> 1;
205     }
206     data.bitmap = bitmap;
207 }
208
209 void
210 PkChar::unpack (void)
211 {
212     if (unpacked)
213         return;
214     
215     if (dyn_f == 14)
216         unpack_bitmap();
217     else
218     {
219         Bitmap bitmap (width, height);
220         
221         RleContext nr (data.packed, 
222                        first_is_black? BLACK : WHITE,
223                        bitmap);
224         unpack_rle (nr);
225         unpacked = true;
226         data.bitmap = bitmap.steal_pixels ();
227     }
228 }
229
230 PkChar::PkChar (AbstractLoader &loader)
231 {
232     uint flag_byte = loader.get_uint8 ();
233     
234     dyn_f = flag_byte >> 4;
235     if (dyn_f == 15)
236         throw string ("Corrupt .pk file");
237     
238     first_is_black = (flag_byte & 8)? true : false;
239     
240     uint length = 0; // to quiet gcc
241
242     switch (flag_byte & 7)
243     {
244     case 0: case 1: case 2: case 3:
245         /* short preamble */
246         length = loader.get_uint8 () + ((flag_byte & 3) << 8) - 8;
247         character_code = loader.get_uint8 ();
248         tfm_width = loader.get_uint24 ();
249         dx = loader.get_uint8 () << 16;
250         dy = 0;
251         width = loader.get_uint8 ();
252         height = loader.get_uint8 ();
253         hoffset = loader.get_int8 ();
254         voffset = loader.get_int8 ();
255         break;
256
257     case 4: case 5: case 6:
258         /* extended short preamble */
259         length = loader.get_uint16 () + ((flag_byte & 3) << 16) - 13;
260         cout << length;
261         character_code = loader.get_uint8 ();
262         cout << ',' << character_code;
263         tfm_width = loader.get_uint24 ();
264         dx = loader.get_uint16 () << 16;
265         dy = 0;
266         width = loader.get_uint16 ();
267         height = loader.get_uint16 ();
268         hoffset = loader.get_int16 ();
269         voffset = loader.get_int16 ();
270         break;
271
272     case 7:
273         /* long preamble */
274         length = loader.get_int32 () - 28;
275         character_code = loader.get_int32 ();
276         tfm_width = loader.get_int32 ();
277         dx = loader.get_int32 ();
278         dy = loader.get_int32 ();
279         width = loader.get_int32 ();
280         height = loader.get_int32 ();
281         hoffset = loader.get_int32 ();
282         voffset = loader.get_int32 ();
283         break;
284
285     default:
286         /* should not be reached */
287         break;
288     }
289     unpacked = false;
290     data.packed = new uchar[length];
291     loader.get_n (length, data.packed);
292 }
293
294 void
295 PkChar::paint (DviRuntime &runtime) 
296 {
297     const unsigned char *bitmap;
298     bitmap = get_bitmap ();
299     runtime.paint_bitmap (bitmap, 
300                           get_width(), get_height(),
301                           get_hoffset(), get_voffset());
302     
303 }
304 void
305 PkFont::load (void)
306 {
307     PkOpcode c;
308     
309     c = (PkOpcode) loader.get_uint8 ();
310     if (c != DL_PK_PRE)
311         throw string ("Not a .pk file (no pre)");
312     
313     id = loader.get_uint8 ();
314     if (id != 89)
315         throw string ("Not a .pk file (incorrect id)");
316     
317     comment = loader.get_string8 ();
318     design_size = loader.get_uint32 (); 
319     checksum = loader.get_uint32 ();
320     hppp = loader.get_uint32 ();
321     vppp = loader.get_uint32 ();
322     
323     do
324     {
325         c = (PkOpcode)loader.get_uint8 ();
326         switch (c)
327         {
328         case DL_PK_XXX1:
329             loader.skip_string8 ();
330             break;
331         case DL_PK_XXX2:
332             loader.skip_string16 ();
333             break;
334         case DL_PK_XXX3:
335             loader.skip_string24 ();
336             break;
337         case DL_PK_XXX4:
338             loader.skip_string32 ();
339             break;
340         case DL_PK_YYY:
341             loader.get_uint32 ();
342             break;
343         case DL_PK_POST:
344             break;
345         case DL_PK_NOP:
346             break;
347         case DL_PK_PRE:
348             throw string ("Unexpected PRE");
349             break;
350         default:
351             loader.goto_from_current (-1);
352             if (c <= DL_PK_FIRST_COMMAND)
353             {
354                 PkChar *pkc = new PkChar (loader);
355                 chars[pkc->get_character_code()] = pkc;
356 #if 0
357                 cout << '[' << pkc->get_character_code() << ']';
358 #endif
359             }
360             else
361                 throw string ("Undefined PK command");
362             break;
363         }
364     } while (c != DL_PK_POST);
365 }
366
367 PkFont::PkFont (AbstractLoader& l, int at_size_arg) :
368     loader (l),
369     at_size (at_size_arg)
370 {
371     load ();
372 }
373
374 PkFont::PkFont (AbstractLoader& l) :
375     loader (l)
376 {
377     load ();
378     at_size = design_size;
379 }