]> git.sesse.net Git - vlc/blob - src/video_output/video_text.c
. prototypes de fonctions pour le 8bpp
[vlc] / src / video_output / video_text.c
1 /*******************************************************************************
2  * video_text.c : text manipulation functions
3  * (c)1999 VideoLAN
4  *******************************************************************************/
5
6 /*******************************************************************************
7  * Preamble
8  *******************************************************************************/
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <unistd.h>
15
16 #include "common.h"
17 #include "config.h"
18 #include "video_text.h"
19 #include "intf_msg.h"
20
21 /*******************************************************************************
22  * vout_font_t: bitmap font
23  *******************************************************************************
24  * This structure is used when the system doesn't provide a convenient function 
25  * to print simple characters in a buffer.
26  * VOUT_FIXED_FONTs are stored in raw mode, character after character, with a
27  * first array of characters followed by a second array of borders masks. 
28  * Therefore the border masks can't be complete if the font has pixels on the
29  * border.
30  *******************************************************************************/
31 typedef struct vout_font_s
32 {
33     int                 i_type;                                 /* font type */
34     int                 i_width;                /* character width in pixels */
35     int                 i_height;              /* character height in pixels */
36     int                 i_interspacing; /* characters interspacing in pixels */
37     int                 i_bytes_per_line;        /* bytes per character line */
38     int                 i_bytes_per_char;             /* bytes per character */
39     u16                 i_first;                          /* first character */
40     u16                 i_last;                            /* last character */
41     byte_t *            p_data;                       /* font character data */
42 } vout_font_t;
43
44 /* Font types */
45 #define VOUT_FIXED_FONT       0                         /* simple fixed font */
46
47 /*******************************************************************************
48  * vout_put_byte_t: PutByte function
49  *******************************************************************************
50  * These functions will transform masks in a set of pixels. For each pixel, 
51  * character, then border and background masks are tested, and the first
52  * encountered color is set.
53  *******************************************************************************/
54 typedef void (vout_put_byte_t)( void *p_pic, int i_byte, int i_char, int i_border, 
55                                 int i_bg, u32 i_char_color, u32 i_border_color, u32 i_bg_color );
56
57
58 /*******************************************************************************
59  * Macros
60  *******************************************************************************/
61
62 /* PUT_BYTE_MASK: put pixels from a byte-wide mask. It uses a branching tree
63  * to optimize the number of tests. It is used in the PutByte functions. */
64 #define TREE( i_mask, i_mask_color )                                          \
65 if( i_mask & 0xf0 )                                       /* one from 1111 */ \
66 {                                                                             \
67     if( i_mask & 0xc0 )                                   /* one from 1100 */ \
68     {                                                                         \
69         if( i_mask & 0x80 )                                        /* 1000 */ \
70         {                                                                     \
71             p_pic[0] = i_mask_color;                                          \
72             if( i_mask & 0x40 )                                    /* 0100 */ \
73             {                                                                 \
74                 p_pic[1] = i_mask_color;                                      \
75             }                                                                 \
76         }                                                                     \
77         else                                        /* not 1000 means 0100 */ \
78         {                                                                     \
79             p_pic[1] = i_mask_color;                                          \
80         }                                                                     \
81         if( i_mask & 0x30 )                               /* one from 0011 */ \
82         {                                                                     \
83             if( i_mask & 0x20 )                                    /* 0010 */ \
84             {                                                                 \
85                 p_pic[2] = i_mask_color;                                      \
86                 if( i_mask & 0x10 )                                /* 0001 */ \
87                 {                                                             \
88                     p_pic[3] = i_mask_color;                                  \
89                 }                                                             \
90             }                                                                 \
91             else                                    /* not 0010 means 0001 */ \
92             {                                                                 \
93                  p_pic[3] = i_mask_color;                                     \
94             }                                                                 \
95         }                                                                     \
96     }                                                                         \
97     else                                            /* not 1100 means 0011 */ \
98     {                                                                         \
99         if( i_mask & 0x20 )                                        /* 0010 */ \
100         {                                                                     \
101             p_pic[2] = i_mask_color;                                          \
102             if( i_mask & 0x10 )                                    /* 0001 */ \
103             {                                                                 \
104                 p_pic[3] = i_mask_color;                                      \
105             }                                                                 \
106         }                                                                     \
107         else                                        /* not 0010 means 0001 */ \
108         {                                                                     \
109             p_pic[3] = i_mask_color;                                          \
110         }                                                                     \
111     }                                                                         \
112 }                                                                             \
113 if( i_mask & 0x0f )                                                           \
114 {                                                                             \
115     if( i_mask & 0x0c )                       /* one from 1100 */             \
116     {                                                                         \
117         if( i_mask & 0x08 )                                        /* 1000 */ \
118         {                                                                     \
119             p_pic[4] = i_mask_color;                                          \
120             if( i_mask & 0x04 )                                    /* 0100 */ \
121             {                                                                 \
122                 p_pic[5] = i_mask_color;                                      \
123             }                                                                 \
124         }                                                                     \
125         else                                        /* not 1000 means 0100 */ \
126         {                                                                     \
127             p_pic[5] = i_mask_color;                                          \
128         }                                                                     \
129         if( i_mask & 0x03 )                               /* one from 0011 */ \
130         {                                                                     \
131             if( i_mask & 0x02 )                                    /* 0010 */ \
132             {                                                                 \
133                 p_pic[6] = i_mask_color;                                      \
134                 if( i_mask & 0x01 )                                /* 0001 */ \
135                 {                                                             \
136                     p_pic[7] = i_mask_color;                                  \
137                 }                                                             \
138             }                                                                 \
139             else                                    /* not 0010 means 0001 */ \
140             {                                                                 \
141                  p_pic[7] = i_mask_color;                                     \
142             }                                                                 \
143         }                                                                     \
144     }                                                                         \
145     else                                            /* not 1100 means 0011 */ \
146     {                                                                         \
147         if( i_mask & 0x02 )                                        /* 0010 */ \
148         {                                                                     \
149             p_pic[6] = i_mask_color;                                          \
150             if( i_mask & 0x01 )                                    /* 0001 */ \
151             {                                                                 \
152                 p_pic[7] = i_mask_color;                                      \
153             }                                                                 \
154         }                                                                     \
155         else                                        /* not 0010 means 0001 */ \
156         {                                                                     \
157             p_pic[7] = i_mask_color;                                          \
158         }                                                                     \
159     }                                                                         \
160 }
161
162 /*****************************************************************************
163  * Local prototypes 
164  *****************************************************************************/
165 static void PutByte8 ( u8 *p_pic, int i_byte, int i_char, int i_border,
166                        int i_bg, u32 i_char_color, u32 i_border_color,
167                        u32 i_bg_color );
168 static void PutByte16( u16 *p_pic, int i_byte, int i_char, int i_border,
169                        int i_bg, u32 i_char_color, u32 i_border_color,
170                        u32 i_bg_color );
171 static void PutByte24( void *p_pic, int i_byte, byte_t i_char, byte_t i_border,
172                        byte_t i_bg, u32 i_char_color, u32 i_border_color,
173                        u32 i_bg_color );
174 static void PutByte32( u32 *p_pic, int i_byte, byte_t i_char, byte_t i_border,
175                        byte_t i_bg, u32 i_char_color, u32 i_border_color,
176                        u32 i_bg_color );
177
178 /*****************************************************************************
179  * vout_LoadFont: load a bitmap font from a file
180  *****************************************************************************
181  * This function will try to open a .psf font and load it. It will return
182  * NULL on error.
183  *****************************************************************************/
184 vout_font_t *vout_LoadFont( const char *psz_name )
185 {
186     int                 i_char, i_line;        /* character and line indexes */
187     int                 i_file;                               /* source file */
188     byte_t              pi_buffer[2];                         /* file buffer */
189     vout_font_t *       p_font;                           /* the font itself */
190     
191     /* Open file */
192     i_file = open( psz_name, O_RDONLY );
193     if( i_file == -1 )
194     {
195         intf_ErrMsg("error: can't open file '%s' (%s)\n", psz_name, strerror(errno));        
196         return( NULL );        
197     }
198
199     /* Read magick number */
200     if( read( i_file, pi_buffer, 2 ) != 2 )
201     {
202         intf_ErrMsg("error: unexpected end of file '%s'\n", psz_name );
203         close( i_file );        
204         return( NULL );                
205     }
206
207     /* Allocate font descriptor */
208     p_font = malloc( sizeof( vout_font_t ) );
209     if( p_font == NULL )
210     {
211         intf_ErrMsg("error: %s\n", strerror(ENOMEM));
212         close( i_file );
213         return( NULL );        
214     }
215     
216     /* Read file */
217     switch( ((u16)pi_buffer[0] << 8) | pi_buffer[1] )
218     {
219     case 0x3604:                                              /* .psf file */
220         /* 
221          * PSF font: simple fixed font. Only the first 256 characters are read.
222          * Those fonts are always 1 byte width, and 256 or 512 characters long.
223          */
224
225         /* Read font header - two bytes indicate the font properties */
226         if( read( i_file, pi_buffer, 2 ) != 2)
227         {
228             intf_ErrMsg("error: unexpected end of file '%s'\n", psz_name );
229             free( p_font );            
230             close( i_file );        
231             return( NULL );                
232         }
233
234         /* Copy font properties */
235         p_font->i_type =                VOUT_FIXED_FONT;
236         p_font->i_width =               8;
237         p_font->i_height =              pi_buffer[1];        
238         p_font->i_interspacing =        8;
239         p_font->i_bytes_per_line =      1;
240         p_font->i_bytes_per_char =      pi_buffer[1];
241         p_font->i_first =               0;
242         p_font->i_last =                255;
243         
244         /* Allocate font space */
245         p_font->p_data = malloc( 2 * 256 * pi_buffer[1] );
246         if( p_font->p_data == NULL )
247         {
248             intf_ErrMsg("error: %s\n", strerror(ENOMEM));
249             free( p_font );            
250             close( i_file );
251             return( NULL );        
252         }
253  
254         /* Copy raw data */
255         if( read( i_file, p_font->p_data, 256 * pi_buffer[1] ) != 256 * pi_buffer[1] )
256         {
257             intf_ErrMsg("error: unexpected end of file '%s'\n", psz_name );
258             free( p_font->p_data );            
259             free( p_font );            
260             close( i_file );        
261             return( NULL );                
262         } 
263
264         /* Computes border masks - remember that masks have the same matrix as 
265          * characters, so an empty character border is required to have a complete
266          * border mask. */
267         for( i_char = 0; i_char <= 255; i_char++ )
268         {
269             for( i_line = 0; i_line < pi_buffer[1]; i_line++ )
270             {
271                 
272                 p_font->p_data[ (i_char + 256) * pi_buffer[1] + i_line ] =
273                     ((p_font->p_data[ i_char * pi_buffer[1] + i_line ] << 1) |
274                      (p_font->p_data[ i_char * pi_buffer[1] + i_line ] >> 1) |
275                      (i_line > 0 ? p_font->p_data[ i_char * pi_buffer[1] + i_line - 1]: 0) |
276                      (i_line < pi_buffer[1] - 1 ? p_font->p_data[ i_char * pi_buffer[1] + i_line + 1]: 0)) 
277                     & ~p_font->p_data[ i_char * pi_buffer[1] + i_line ];          
278             }            
279         }
280         
281         break;
282     default:
283         intf_ErrMsg("error: file '%s' has an unknown format\n", psz_name );
284         free( p_font );        
285         close( i_file );
286         return( NULL );        
287         break;                
288     }        
289     
290     
291     intf_DbgMsg( "loaded %s: type %d, %d-%dx%d\n", psz_name, p_font->i_type, 
292                  p_font->i_width, p_font->i_interspacing, p_font->i_height );
293     return( p_font );
294 }
295
296 /*******************************************************************************
297  * vout_UnloadFont: unload a font
298  *******************************************************************************
299  * This function free the resources allocated by vout_LoadFont
300  *******************************************************************************/
301 void vout_UnloadFont( vout_font_t *p_font )
302 {
303     intf_DbgMsg( "font %p\n", p_font );    
304     free( p_font->p_data );    
305     free( p_font );    
306 }
307
308 /*******************************************************************************
309  * vout_TextSize: return the dimensions of a text
310  *******************************************************************************
311  * This function is used to align text. It returns the width and height of a
312  * given text. 
313  *******************************************************************************/
314 void vout_TextSize( vout_font_t *p_font, int i_style, const char *psz_text, int *pi_width, int *pi_height )
315 {
316     switch( p_font->i_type )
317     {
318     case VOUT_FIXED_FONT:        
319         *pi_width  = ((i_style & WIDE_TEXT) ? p_font->i_interspacing * 2 : p_font->i_interspacing) * 
320             (strlen( psz_text ) - 1) + p_font->i_width;
321         *pi_height = p_font->i_height;
322         if( i_style & ITALIC_TEXT )
323         {
324             *pi_width = *pi_height / 3;            
325         }        
326         break;
327 #ifdef DEBUG
328     default:
329         intf_DbgMsg("error: unknown font type %d\n", p_font->i_type );        
330         break;        
331 #endif
332     }
333 }
334
335 /*******************************************************************************
336  * vout_Print: low level printing function
337   *******************************************************************************
338  * This function prints a text, without clipping, in a buffer using a previously
339  * loaded bitmap font.
340  *******************************************************************************/
341 void vout_Print( vout_font_t *p_font, byte_t *p_pic, int i_bytes_per_pixel, int i_bytes_per_line, 
342                  u32 i_char_color, u32 i_border_color, u32 i_bg_color, int i_style, const char *psz_text )
343 {
344     byte_t      *p_char, *p_border;        /* character and border mask data */
345     int         i_char_mask, i_border_mask, i_bg_mask;              /* masks */
346     int         i_line;                         /* current line in character */
347     int         i_byte;                         /* current byte in character */
348     int         i_interspacing;                  /* offset between two chars */
349     int         i_font_bytes_per_line, i_font_height;     /* font properties */
350     vout_put_byte_t *p_PutByte;                          /* PutByte function */
351
352     //?? background: can be something else that whole byte 
353
354     /* Select output function */
355     switch( i_bytes_per_pixel )
356     {
357     case 1:
358         p_PutByte = (vout_put_byte_t *) PutByte8;
359         break;        
360     case 2:
361         p_PutByte = (vout_put_byte_t *) PutByte16;
362         break;
363     case 3:
364         p_PutByte = (vout_put_byte_t *) PutByte24;
365         break;
366     case 4:
367 #ifndef DEBUG
368     default:
369 #endif
370         p_PutByte = (vout_put_byte_t *) PutByte32;
371         break;
372 #ifdef DEBUG
373     default:
374         intf_DbgMsg("error: invalid bytes per pixel %d\n", i_bytes_per_pixel );
375         p_PutByte = NULL;
376         break;
377 #endif
378     }
379
380     /* Choose masks and copy font data to local variables */
381     i_char_mask =               (i_style & VOID_TEXT) ?         0 : 0xff;
382     i_border_mask =             (i_style & OUTLINED_TEXT) ?     0xff : 0;
383     i_bg_mask =                 (i_style & OPAQUE_TEXT) ?       0xff : 0;
384
385     i_font_bytes_per_line =     p_font->i_bytes_per_line;
386     i_font_height =             p_font->i_height;
387     i_interspacing =            i_bytes_per_pixel * ((i_style & WIDE_TEXT) ? 
388                                                      p_font->i_interspacing * 2 : 
389                                                      p_font->i_interspacing);
390
391     /* Print text */
392     for( ; *psz_text != '\0'; psz_text++ )
393     {
394         /* Check that the character is valid */
395         if( (*psz_text >= p_font->i_first) && (*psz_text <= p_font->i_last) )
396         {       
397             /* Select character - bytes per char is always valid, event for
398              * non fixed fonts */
399             p_char =    p_font->p_data + (*psz_text - p_font->i_first) * p_font->i_bytes_per_char;
400             p_border =  p_char + (p_font->i_last - p_font->i_first + 1) * p_font->i_bytes_per_char;            
401
402             /* Select base address for output */            
403             switch( p_font->i_type )
404             {
405             case VOUT_FIXED_FONT:
406                 /* 
407                  * Simple fixed width font 
408                  */
409
410                 /* Italic text: shift picture start right */
411                 if( i_style & ITALIC_TEXT )
412                 {
413                     p_pic += i_bytes_per_pixel * (p_font->i_height / 3);                    
414                 }
415
416                 /* Print character */
417                 for( i_line = 0; i_line < i_font_height; i_line ++ )
418                 {                                        
419                     for( i_byte = 0; i_byte < i_font_bytes_per_line; i_byte++, p_char++, p_border++)
420                     {
421                         /* Put pixels */
422                         p_PutByte( p_pic + i_bytes_per_line * i_line, i_byte, 
423                                    *p_char & i_char_mask, *p_border & i_border_mask, i_bg_mask, 
424                                    i_char_color, i_border_color, i_bg_color );
425                     }
426                         
427                     /* Italic text: shift picture start left */
428                     if( (i_style & ITALIC_TEXT) && !(i_line % 3) )
429                     {                            
430                         p_pic -= i_bytes_per_pixel;
431                     }
432                 }
433
434                 /* Jump to next character */
435                 p_pic += i_interspacing;
436                 break;                
437 #ifdef DEBUG
438             default:
439                 intf_DbgMsg("error: unknown font type %d\n", p_font->i_type );        
440                 break;        
441 #endif
442             }
443         }       
444     }    
445 }
446
447 /* following functions are local */
448
449 /*****************************************************************************
450  * PutByte8: print a fixed width font character byte in 15 or 16 bpp
451  *****************************************************************************/
452 static void PutByte8( u8 *p_pic, int i_byte, int i_char, int i_border,
453                        int i_bg, u32 i_char_color, u32 i_border_color,
454                        u32 i_bg_color )
455 {
456     /* Computes position offset and background mask */
457     p_pic += 8 * i_byte;
458     i_bg &= ~(i_char | i_border);
459
460     /* Put character bits */
461     TREE(i_char, i_char_color);
462     TREE(i_border, i_border_color);
463     TREE(i_bg, i_bg_color);
464 }
465
466 /*****************************************************************************
467  * PutByte16: print a fixed width font character byte in 15 or 16 bpp
468  *****************************************************************************/
469 static void PutByte16( u16 *p_pic, int i_byte, int i_char, int i_border,
470                        int i_bg, u32 i_char_color, u32 i_border_color,
471                        u32 i_bg_color )
472 {
473     /* Computes position offset and background mask */
474     p_pic += 8 * i_byte;
475     i_bg &= ~(i_char | i_border);
476
477     /* Put character bits */
478     TREE(i_char, i_char_color);
479     TREE(i_border, i_border_color);
480     TREE(i_bg, i_bg_color);
481 }
482
483 /*****************************************************************************
484  * PutByte24: print a fixed width font character byte in 24 bpp
485  *****************************************************************************/
486 static void PutByte24( void *p_pic, int i_byte, byte_t i_char, byte_t i_border, byte_t i_bg, 
487                        u32 i_char_color, u32 i_border_color, u32 i_bg_color )
488 {
489     //??
490 }
491
492 /*****************************************************************************
493  * PutByte32: print a fixed width font character byte in 32 bpp
494  *****************************************************************************/
495 static void PutByte32( u32 *p_pic, int i_byte, byte_t i_char, byte_t i_border, byte_t i_bg, 
496                        u32 i_char_color, u32 i_border_color, u32 i_bg_color )
497 {
498     /* Computes position offset and background mask */
499     p_pic += 8 * i_byte;
500     i_bg &= ~(i_char | i_border);
501
502     /* Put character bits */
503     TREE(i_char, i_char_color);
504     TREE(i_border, i_border_color);
505     TREE(i_bg, i_bg_color);
506 }
507