]> www.fi.muni.cz Git - evince.git/blob - dvi/dvilib/dl-pkfont.cc
409d531a69ff1b7cbe0fb1688ce875be7ee88453
[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     uint *bitmap 
193         = new uint [width * height];
194     fill (bitmap, bitmap + width * height, 0x00000000);
195     
196     weight = 128;
197     
198     for (i=0; i < height * width; i++)
199     {
200         if ((*data.packed & weight) != 0)
201         {
202             bitmap[i] = 0xff000000;
203         }
204
205         if (weight == 1)
206         {
207             weight = 128;
208             data.packed++;
209         }
210         else
211         {
212             weight >>= 1;
213         }
214     }
215     
216     data.bitmap = (uchar *)bitmap;
217 }
218
219 void
220 PkChar::unpack (void)
221 {
222     if (unpacked)
223         return;
224     
225     if (dyn_f == 14)
226     {
227         unpack_bitmap();
228     }
229     else
230     {
231         Bitmap bitmap (width, height);
232         
233         RleContext nr (data.packed, 
234                        first_is_black? BLACK : WHITE,
235                        bitmap);
236         unpack_rle (nr);
237         data.bitmap = bitmap.steal_pixels ();
238
239 #if 0
240         if (character_code == '6')
241             cout << "HERER" << endl;
242         else
243             cout << '[' << character_code << " not " << (int)'6' << ']' << endl;
244 #endif
245     }
246     
247     unpacked = true;
248 }
249
250 PkChar::PkChar (AbstractLoader &loader)
251 {
252     uint flag_byte = loader.get_uint8 ();
253     
254     dyn_f = flag_byte >> 4;
255     if (dyn_f == 15)
256         throw string ("Corrupt .pk file");
257     
258     first_is_black = (flag_byte & 8)? true : false;
259     
260     uint length = 0; // to quiet gcc
261
262     switch (flag_byte & 7)
263     {
264     case 0: case 1: case 2: case 3:
265         /* short preamble */
266         length = loader.get_uint8 () + ((flag_byte & 3) << 8) - 8;
267         character_code = loader.get_uint8 ();
268         tfm_width = loader.get_uint24 ();
269         dx = loader.get_uint8 () << 16;
270         dy = 0;
271         width = loader.get_uint8 ();
272         height = loader.get_uint8 ();
273         hoffset = loader.get_int8 ();
274         voffset = loader.get_int8 ();
275         break;
276
277     case 4: case 5: case 6:
278         /* extended short preamble */
279         length = loader.get_uint16 () + ((flag_byte & 3) << 16) - 13;
280 #if 0
281         cout << length;
282 #endif
283         character_code = loader.get_uint8 ();
284 #if 0
285         cout << ',' << character_code;
286 #endif
287         tfm_width = loader.get_uint24 ();
288         dx = loader.get_uint16 () << 16;
289         dy = 0;
290         width = loader.get_uint16 ();
291         height = loader.get_uint16 ();
292         hoffset = loader.get_int16 ();
293         voffset = loader.get_int16 ();
294         break;
295
296     case 7:
297         /* long preamble */
298         length = loader.get_int32 () - 28;
299         character_code = loader.get_int32 ();
300         tfm_width = loader.get_int32 ();
301         dx = loader.get_int32 ();
302         dy = loader.get_int32 ();
303         width = loader.get_int32 ();
304         height = loader.get_int32 ();
305         hoffset = loader.get_int32 ();
306         voffset = loader.get_int32 ();
307         break;
308
309     default:
310         /* should not be reached */
311         break;
312     }
313     unpacked = false;
314     data.packed = new uchar[length];
315     loader.get_n (length, data.packed);
316 }
317
318 void
319 PkChar::paint (DviRuntime &runtime) 
320 {
321     const unsigned char *bitmap;
322     bitmap = get_bitmap ();
323     runtime.paint_bitmap (bitmap, 
324                           get_width(), get_height(),
325                           get_hoffset(), get_voffset());
326     
327 }
328 void
329 PkFont::load (void)
330 {
331     PkOpcode c;
332     
333     c = (PkOpcode) loader.get_uint8 ();
334     if (c != DL_PK_PRE)
335         throw string ("Not a .pk file (no pre)");
336     
337     id = loader.get_uint8 ();
338     if (id != 89)
339         throw string ("Not a .pk file (incorrect id)");
340     
341     comment = loader.get_string8 ();
342     design_size = loader.get_uint32 (); 
343     checksum = loader.get_uint32 ();
344     hppp = loader.get_uint32 ();
345     vppp = loader.get_uint32 ();
346     
347     do
348     {
349         c = (PkOpcode)loader.get_uint8 ();
350         switch (c)
351         {
352         case DL_PK_XXX1:
353             loader.skip_string8 ();
354             break;
355         case DL_PK_XXX2:
356             loader.skip_string16 ();
357             break;
358         case DL_PK_XXX3:
359             loader.skip_string24 ();
360             break;
361         case DL_PK_XXX4:
362             loader.skip_string32 ();
363             break;
364         case DL_PK_YYY:
365             loader.get_uint32 ();
366             break;
367         case DL_PK_POST:
368             break;
369         case DL_PK_NOP:
370             break;
371         case DL_PK_PRE:
372             throw string ("Unexpected PRE");
373             break;
374         default:
375             loader.goto_from_current (-1);
376             if (c <= DL_PK_FIRST_COMMAND)
377             {
378                 PkChar *pkc = new PkChar (loader);
379                 chars[pkc->get_character_code()] = pkc;
380 #if 0
381                 cout << '[' << pkc->get_character_code() << ']';
382 #endif
383             }
384             else
385                 throw string ("Undefined PK command");
386             break;
387         }
388     } while (c != DL_PK_POST);
389 }
390
391 PkFont::PkFont (AbstractLoader& l, int at_size_arg) :
392     loader (l),
393     at_size (at_size_arg)
394 {
395     load ();
396 }
397
398 PkFont::PkFont (AbstractLoader& l) :
399     loader (l)
400 {
401     load ();
402     at_size = design_size;
403 }