]> git.sesse.net Git - vlc/blob - src/video_output/video_text.c
Mise place du scaling, episode II
[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 PutByte16( u16 *p_pic, int i_byte, int i_char, int i_border, int i_bg, 
166                        u32 i_char_color, u32 i_border_color, u32 i_bg_color );
167 static void PutByte24( void *p_pic, int i_byte, byte_t i_char, byte_t i_border, byte_t i_bg, 
168                        u32 i_char_color, u32 i_border_color, u32 i_bg_color );
169 static void PutByte32( u32 *p_pic, int i_byte, byte_t i_char, byte_t i_border, byte_t i_bg, 
170                        u32 i_char_color, u32 i_border_color, u32 i_bg_color );
171
172 /*******************************************************************************
173  * vout_LoadFont: load a bitmap font from a file
174  *******************************************************************************
175  * This function will try to open a .psf font and load it. It will return
176  * NULL on error.
177  *******************************************************************************/
178 vout_font_t *vout_LoadFont( const char *psz_name )
179 {
180     int                 i_char, i_line;          /* character and line indexes */    
181     int                 i_file;                                 /* source file */
182     byte_t              pi_buffer[2];                           /* file buffer */
183     vout_font_t *       p_font;                             /* the font itself */                
184     
185     /* Open file */
186     i_file = open( psz_name, O_RDONLY );
187     if( i_file == -1 )
188     {
189         intf_ErrMsg("error: can't open file '%s' (%s)\n", psz_name, strerror(errno));        
190         return( NULL );        
191     }
192
193     /* Read magick number */
194     if( read( i_file, pi_buffer, 2 ) != 2 )
195     {
196         intf_ErrMsg("error: unexpected end of file '%s'\n", psz_name );
197         close( i_file );        
198         return( NULL );                
199     }
200
201     /* Allocate font descriptor */
202     p_font = malloc( sizeof( vout_font_t ) );
203     if( p_font == NULL )
204     {
205         intf_ErrMsg("error: %s\n", strerror(ENOMEM));
206         close( i_file );
207         return( NULL );        
208     }
209     
210     /* Read file */
211     switch( ((u16)pi_buffer[0] << 8) | pi_buffer[1] )
212     {
213     case 0x3604:                                              /* .psf file */
214         /* 
215          * PSF font: simple fixed font. Only the first 256 characters are read.
216          * Those fonts are always 1 byte width, and 256 or 512 characters long.
217          */
218
219         /* Read font header - two bytes indicate the font properties */
220         if( read( i_file, pi_buffer, 2 ) != 2)
221         {
222             intf_ErrMsg("error: unexpected end of file '%s'\n", psz_name );
223             free( p_font );            
224             close( i_file );        
225             return( NULL );                
226         }
227
228         /* Copy font properties */
229         p_font->i_type =                VOUT_FIXED_FONT;
230         p_font->i_width =               8;
231         p_font->i_height =              pi_buffer[1];        
232         p_font->i_interspacing =        8;
233         p_font->i_bytes_per_line =      1;
234         p_font->i_bytes_per_char =      pi_buffer[1];
235         p_font->i_first =               0;
236         p_font->i_last =                255;
237         
238         /* Allocate font space */
239         p_font->p_data = malloc( 2 * 256 * pi_buffer[1] );
240         if( p_font->p_data == NULL )
241         {
242             intf_ErrMsg("error: %s\n", strerror(ENOMEM));
243             free( p_font );            
244             close( i_file );
245             return( NULL );        
246         }
247  
248         /* Copy raw data */
249         if( read( i_file, p_font->p_data, 256 * pi_buffer[1] ) != 256 * pi_buffer[1] )
250         {
251             intf_ErrMsg("error: unexpected end of file '%s'\n", psz_name );
252             free( p_font->p_data );            
253             free( p_font );            
254             close( i_file );        
255             return( NULL );                
256         } 
257
258         /* Computes border masks - remember that masks have the same matrix as 
259          * characters, so an empty character border is required to have a complete
260          * border mask. */
261         for( i_char = 0; i_char <= 255; i_char++ )
262         {
263             for( i_line = 0; i_line < pi_buffer[1]; i_line++ )
264             {
265                 
266                 p_font->p_data[ (i_char + 256) * pi_buffer[1] + i_line ] =
267                     ((p_font->p_data[ i_char * pi_buffer[1] + i_line ] << 1) |
268                      (p_font->p_data[ i_char * pi_buffer[1] + i_line ] >> 1) |
269                      (i_line > 0 ? p_font->p_data[ i_char * pi_buffer[1] + i_line - 1]: 0) |
270                      (i_line < pi_buffer[1] ? p_font->p_data[ i_char * pi_buffer[1] + i_line + 1]: 0)) 
271                     & ~p_font->p_data[ i_char * pi_buffer[1] + i_line ];          
272             }            
273         }
274         
275         break;
276     default:
277         intf_ErrMsg("error: file '%s' has an unknown format\n", psz_name );
278         free( p_font );        
279         close( i_file );
280         return( NULL );        
281         break;                
282     }        
283     
284     
285     intf_DbgMsg( "loaded %s: type %d, %d-%dx%d\n", psz_name, p_font->i_type, 
286                  p_font->i_width, p_font->i_interspacing, p_font->i_height );
287     return( p_font );
288 }
289
290 /*******************************************************************************
291  * vout_UnloadFont: unload a font
292  *******************************************************************************
293  * This function free the resources allocated by vout_LoadFont
294  *******************************************************************************/
295 void vout_UnloadFont( vout_font_t *p_font )
296 {
297     intf_DbgMsg( "font %p\n", p_font );    
298     free( p_font->p_data );    
299     free( p_font );    
300 }
301
302 /*******************************************************************************
303  * vout_TextSize: return the dimensions of a text
304  *******************************************************************************
305  * This function is used to align text. It returns the width and height of a
306  * given text. 
307  *******************************************************************************/
308 void vout_TextSize( vout_font_t *p_font, int i_style, const char *psz_text, int *pi_width, int *pi_height )
309 {
310     switch( p_font->i_type )
311     {
312     case VOUT_FIXED_FONT:        
313         *pi_width  = ((i_style & WIDE_TEXT) ? p_font->i_interspacing * 2 : p_font->i_interspacing) * 
314             (strlen( psz_text ) - 1) + p_font->i_width;
315         *pi_height = p_font->i_height;
316         if( i_style & ITALIC_TEXT )
317         {
318             *pi_width = *pi_height / 3;            
319         }        
320         break;
321 #ifdef DEBUG
322     default:
323         intf_DbgMsg("error: unknown font type %d\n", p_font->i_type );        
324         break;        
325 #endif
326     }
327 }
328
329 /*******************************************************************************
330  * vout_Print: low level printing function
331   *******************************************************************************
332  * This function prints a text, without clipping, in a buffer using a previously
333  * loaded bitmap font.
334  *******************************************************************************/
335 void vout_Print( vout_font_t *p_font, byte_t *p_pic, int i_bytes_per_pixel, int i_bytes_per_line, 
336                  u32 i_char_color, u32 i_border_color, u32 i_bg_color, int i_style, const char *psz_text )
337 {
338     byte_t      *p_char, *p_border;          /* character and border mask data */    
339     int         i_char_mask, i_border_mask, i_bg_mask;                /* masks */    
340     int         i_line;                           /* current line in character */    
341     int         i_byte;                           /* current byte in character */
342     int         i_interspacing;                    /* offset between two chars */    
343     int         i_font_bytes_per_line, i_font_height;       /* font properties */    
344     vout_put_byte_t *p_PutByte;                            /* PutByte function */    
345
346     //?? background: can be something else that whole byte 
347
348     /* Select output function */
349     switch( i_bytes_per_pixel )
350     {
351     case 2:
352         p_PutByte = (vout_put_byte_t *) PutByte16;        
353         break;        
354     case 3:
355         p_PutByte = (vout_put_byte_t *) PutByte24;        
356         break;        
357     case 4:
358 #ifndef DEBUG
359     default:        
360 #endif
361         p_PutByte = (vout_put_byte_t *) PutByte32;        
362         break;        
363 #ifdef DEBUG
364     default:
365         intf_DbgMsg("error: invalid bytes per pixel %d\n", i_bytes_per_pixel );        
366         p_PutByte = NULL;        
367         break;
368 #endif
369     }    
370
371     /* Choose masks and copy font data to local variables */
372     i_char_mask =               (i_style & VOID_TEXT) ?         0 : 0xff;
373     i_border_mask =             (i_style & OUTLINED_TEXT) ?     0xff : 0;
374     i_bg_mask =                 (i_style & OPAQUE_TEXT) ?       0xff : 0;
375
376     i_font_bytes_per_line =     p_font->i_bytes_per_line;
377     i_font_height =             p_font->i_height;
378     i_interspacing =            i_bytes_per_pixel * ((i_style & WIDE_TEXT) ? 
379                                                      p_font->i_interspacing * 2 : 
380                                                      p_font->i_interspacing);
381
382     /* Print text */
383     for( ; *psz_text != '\0'; psz_text++ )
384     {
385         /* Check that the character is valid */
386         if( (*psz_text >= p_font->i_first) && (*psz_text <= p_font->i_last) )
387         {       
388             /* Select character - bytes per char is always valid, event for
389              * non fixed fonts */
390             p_char =    p_font->p_data + (*psz_text - p_font->i_first) * p_font->i_bytes_per_char;
391             p_border =  p_char + (p_font->i_last - p_font->i_first + 1) * p_font->i_bytes_per_char;            
392
393             /* Select base address for output */            
394             switch( p_font->i_type )
395             {
396             case VOUT_FIXED_FONT:
397                 /* 
398                  * Simple fixed width font 
399                  */
400
401                 /* Italic text: shift picture start right */
402                 if( i_style & ITALIC_TEXT )
403                 {
404                     p_pic += i_bytes_per_pixel * (p_font->i_height / 3);                    
405                 }
406
407                 /* Print character */
408                 for( i_line = 0; i_line < i_font_height; i_line ++ )
409                 {                                        
410                     for( i_byte = 0; i_byte < i_font_bytes_per_line; i_byte++, p_char++, p_border++)
411                     {
412                         /* Put pixels */
413                         p_PutByte( p_pic + i_bytes_per_line * i_line, i_byte, 
414                                    *p_char & i_char_mask, *p_border & i_border_mask, i_bg_mask, 
415                                    i_char_color, i_border_color, i_bg_color );
416                     }
417                         
418                     /* Italic text: shift picture start left */
419                     if( (i_style & ITALIC_TEXT) && !(i_line % 3) )
420                     {                            
421                         p_pic -= i_bytes_per_pixel;
422                     }
423                 }
424
425                 /* Jump to next character */
426                 p_pic += i_interspacing;
427                 break;                
428 #ifdef DEBUG
429             default:
430                 intf_DbgMsg("error: unknown font type %d\n", p_font->i_type );        
431                 break;        
432 #endif
433             }
434         }       
435     }    
436 }
437
438 /* following functions are local */
439
440 /*******************************************************************************
441  * PutByte16: print a fixed width font character byte in 15 or 16 bpp
442  *******************************************************************************/
443 static void PutByte16( u16 *p_pic, int i_byte, int i_char, int i_border, int i_bg, 
444                        u32 i_char_color, u32 i_border_color, u32 i_bg_color )
445 {
446     /* Computes position offset and background mask */
447     p_pic += 8 * i_byte;
448     i_bg &= ~(i_char | i_border);
449
450     /* Put character bits */
451     TREE(i_char, i_char_color);
452     TREE(i_border, i_border_color);
453     TREE(i_bg, i_bg_color);
454 }
455
456 /*******************************************************************************
457  * PutByte24: print a fixed width font character byte in 24 bpp
458  *******************************************************************************/
459 static void PutByte24( void *p_pic, int i_byte, byte_t i_char, byte_t i_border, byte_t i_bg, 
460                        u32 i_char_color, u32 i_border_color, u32 i_bg_color )
461 {
462     //??
463 }
464
465 /*******************************************************************************
466  * PutByte32: print a fixed width font character byte in 32 bpp
467  *******************************************************************************/
468 static void PutByte32( u32 *p_pic, int i_byte, byte_t i_char, byte_t i_border, byte_t i_bg, 
469                        u32 i_char_color, u32 i_border_color, u32 i_bg_color )
470 {
471     /* Computes position offset and background mask */
472     p_pic += 8 * i_byte;
473     i_bg &= ~(i_char | i_border);
474
475     /* Put character bits */
476     TREE(i_char, i_char_color);
477     TREE(i_border, i_border_color);
478     TREE(i_bg, i_bg_color);
479 }
480