Don't use deprecated and removed API in Mozilla plugin.
[vlc.git] / modules / misc / win32text.c
blob98a7d878bd125d04206dcec6ef9ed6e56d99276b
1 /*****************************************************************************
2 * win32text.c : Text drawing routines using the TextOut win32 API
3 *****************************************************************************
4 * Copyright (C) 2002 - 2005 the VideoLAN team
5 * $Id$
7 * Authors: Gildas Bazin <gbazin@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_vout.h>
35 #include <vlc_osd.h>
36 #include <vlc_block.h>
37 #include <vlc_filter.h>
39 #include <math.h>
41 /*****************************************************************************
42 * Local prototypes
43 *****************************************************************************/
44 static int Create ( vlc_object_t * );
45 static void Destroy( vlc_object_t * );
47 /* The RenderText call maps to pf_render_string, defined in vlc_filter.h */
48 static int RenderText( filter_t *, subpicture_region_t *,
49 subpicture_region_t * );
51 static int Render( filter_t *, subpicture_region_t *, uint8_t *, int, int);
52 static int SetFont( filter_t *, int );
54 /*****************************************************************************
55 * Module descriptor
56 *****************************************************************************/
57 #define FONT_TEXT N_("Font")
58 #define FONT_LONGTEXT N_("Filename for the font you want to use")
59 #define FONTSIZE_TEXT N_("Font size in pixels")
60 #define FONTSIZE_LONGTEXT N_("This is the default size of the fonts " \
61 "that will be rendered on the video. " \
62 "If set to something different than 0 this option will override the " \
63 "relative font size." )
64 #define OPACITY_TEXT N_("Opacity")
65 #define OPACITY_LONGTEXT N_("The opacity (inverse of transparency) of the " \
66 "text that will be rendered on the video. 0 = transparent, " \
67 "255 = totally opaque. " )
68 #define COLOR_TEXT N_("Text default color")
69 #define COLOR_LONGTEXT N_("The color of the text that will be rendered on "\
70 "the video. This must be an hexadecimal (like HTML colors). The first two "\
71 "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
72 " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
73 #define FONTSIZER_TEXT N_("Relative font size")
74 #define FONTSIZER_LONGTEXT N_("This is the relative default size of the " \
75 "fonts that will be rendered on the video. If absolute font size is set, "\
76 "relative size will be overriden." )
78 static int const pi_sizes[] = { 20, 18, 16, 12, 6 };
79 static char *const ppsz_sizes_text[] = {
80 N_("Smaller"), N_("Small"), N_("Normal"), N_("Large"), N_("Larger") };
81 static const int pi_color_values[] = {
82 0x00000000, 0x00808080, 0x00C0C0C0, 0x00FFFFFF, 0x00800000,
83 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x00808000, 0x00008000, 0x00008080,
84 0x0000FF00, 0x00800080, 0x00000080, 0x000000FF, 0x0000FFFF };
86 static const char *const ppsz_color_descriptions[] = {
87 N_("Black"), N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"),
88 N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"), N_("Teal"),
89 N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"), N_("Aqua") };
91 vlc_module_begin();
92 set_shortname( N_("Text renderer"));
93 set_description( N_("Win32 font renderer") );
94 set_category( CAT_VIDEO );
95 set_subcategory( SUBCAT_VIDEO_SUBPIC );
97 add_integer( "win32text-fontsize", 0, NULL, FONTSIZE_TEXT,
98 FONTSIZE_LONGTEXT, true );
100 /* opacity valid on 0..255, with default 255 = fully opaque */
101 add_integer_with_range( "win32-opacity", 255, 0, 255, NULL,
102 OPACITY_TEXT, OPACITY_LONGTEXT, false );
104 /* hook to the color values list, with default 0x00ffffff = white */
105 add_integer( "win32text-color", 0x00FFFFFF, NULL, COLOR_TEXT,
106 COLOR_LONGTEXT, true );
107 change_integer_list( pi_color_values, ppsz_color_descriptions, 0 );
109 add_integer( "win32text-rel-fontsize", 16, NULL, FONTSIZER_TEXT,
110 FONTSIZER_LONGTEXT, false );
111 change_integer_list( pi_sizes, ppsz_sizes_text, 0 );
113 set_capability( "text renderer", 50 );
114 add_shortcut( "text" );
115 set_callbacks( Create, Destroy );
116 vlc_module_end();
118 /*****************************************************************************
119 * filter_sys_t: win32text local data
120 *****************************************************************************/
121 struct filter_sys_t
123 uint8_t i_font_opacity;
124 int i_font_color;
125 int i_font_size;
127 int i_default_font_size;
128 int i_display_height;
130 HDC hcdc;
131 HFONT hfont;
132 HFONT hfont_bak;
133 int i_logpy;
136 static uint8_t pi_gamma[16] =
137 {0x00, 0x41, 0x52, 0x63, 0x84, 0x85, 0x96, 0xa7, 0xb8, 0xc9,
138 0xca, 0xdb, 0xdc, 0xed, 0xee, 0xff};
140 /*****************************************************************************
141 * Create: creates the module
142 *****************************************************************************/
143 static int Create( vlc_object_t *p_this )
145 filter_t *p_filter = (filter_t *)p_this;
146 filter_sys_t *p_sys;
147 char *psz_fontfile = NULL;
148 vlc_value_t val;
149 HDC hdc;
151 /* Allocate structure */
152 p_filter->p_sys = p_sys = malloc( sizeof( filter_sys_t ) );
153 if( !p_sys )
155 msg_Err( p_filter, "out of memory" );
156 return VLC_ENOMEM;
158 p_sys->i_font_size = 0;
159 p_sys->i_display_height = 0;
161 var_Create( p_filter, "win32text-font",
162 VLC_VAR_STRING | VLC_VAR_DOINHERIT );
163 var_Create( p_filter, "win32text-fontsize",
164 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
165 var_Create( p_filter, "win32text-rel-fontsize",
166 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
167 var_Create( p_filter, "win32text-opacity",
168 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
169 var_Get( p_filter, "win32text-opacity", &val );
170 p_sys->i_font_opacity = __MAX( __MIN( val.i_int, 255 ), 0 );
171 var_Create( p_filter, "win32text-color",
172 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
173 var_Get( p_filter, "win32text-color", &val );
174 p_sys->i_font_color = __MAX( __MIN( val.i_int, 0xFFFFFF ), 0 );
176 p_sys->hfont = p_sys->hfont_bak = 0;
177 hdc = GetDC( NULL );
178 p_sys->hcdc = CreateCompatibleDC( hdc );
179 p_sys->i_logpy = GetDeviceCaps( hdc, LOGPIXELSY );
180 ReleaseDC( NULL, hdc );
181 SetBkMode( p_sys->hcdc, TRANSPARENT );
183 var_Get( p_filter, "win32text-fontsize", &val );
184 p_sys->i_default_font_size = val.i_int;
185 if( SetFont( p_filter, 0 ) != VLC_SUCCESS ) goto error;
187 free( psz_fontfile );
188 p_filter->pf_render_text = RenderText;
189 p_filter->pf_render_html = NULL;
190 return VLC_SUCCESS;
192 error:
193 free( psz_fontfile );
194 free( p_sys );
195 return VLC_EGENERIC;
198 /*****************************************************************************
199 * Destroy: destroy the module
200 *****************************************************************************/
201 static void Destroy( vlc_object_t *p_this )
203 filter_t *p_filter = (filter_t *)p_this;
204 filter_sys_t *p_sys = p_filter->p_sys;
206 if( p_sys->hfont_bak ) SelectObject( p_sys->hcdc, p_sys->hfont_bak );
207 if( p_sys->hfont ) DeleteObject( p_sys->hfont );
208 DeleteDC( p_sys->hcdc );
209 free( p_sys );
212 /*****************************************************************************
213 * Render: place string in picture
214 *****************************************************************************
215 * This function merges the previously rendered win32text glyphs into a picture
216 *****************************************************************************/
217 static int Render( filter_t *p_filter, subpicture_region_t *p_region,
218 uint8_t *p_bitmap, int i_width, int i_height )
220 uint8_t *p_dst;
221 video_format_t fmt;
222 int i, i_pitch;
223 subpicture_region_t *p_region_tmp;
224 bool b_outline = true;
226 /* Create a new subpicture region */
227 memset( &fmt, 0, sizeof(video_format_t) );
228 fmt.i_chroma = VLC_FOURCC('Y','U','V','P');
229 fmt.i_width = fmt.i_visible_width = i_width + (b_outline ? 4 : 0);
230 fmt.i_height = fmt.i_visible_height = i_height + (b_outline ? 4 : 0);
231 fmt.i_x_offset = fmt.i_y_offset = 0;
232 p_region_tmp = spu_CreateRegion( p_filter, &fmt );
233 if( !p_region_tmp )
235 msg_Err( p_filter, "cannot allocate SPU region" );
236 return VLC_EGENERIC;
239 /* Build palette */
240 fmt.p_palette->i_entries = 16;
241 for( i = 0; i < fmt.p_palette->i_entries; i++ )
243 fmt.p_palette->palette[i][0] = pi_gamma[i];
244 fmt.p_palette->palette[i][1] = 128;
245 fmt.p_palette->palette[i][2] = 128;
246 fmt.p_palette->palette[i][3] = pi_gamma[i];
249 p_region->fmt = p_region_tmp->fmt;
250 p_region->picture = p_region_tmp->picture;
251 free( p_region_tmp );
253 p_dst = p_region->picture.Y_PIXELS;
254 i_pitch = p_region->picture.Y_PITCH;
256 if( b_outline )
258 memset( p_dst, 0, i_pitch * fmt.i_height );
259 p_dst += p_region->picture.Y_PITCH * 2 + 2;
262 for( i = 0; i < i_height; i++ )
264 memcpy( p_dst, p_bitmap, i_width );
265 p_bitmap += (i_width+3) & ~3;
266 p_dst += i_pitch;
269 /* Outlining (find something better than nearest neighbour filtering ?) */
270 if( b_outline )
272 uint8_t *p_top = p_dst; /* Use 1st line as a cache */
273 uint8_t left, current;
274 int x, y;
276 p_dst = p_region->picture.Y_PIXELS;
278 for( y = 1; y < (int)fmt.i_height - 1; y++ )
280 memcpy( p_top, p_dst, fmt.i_width );
281 p_dst += i_pitch;
282 left = 0;
284 for( x = 1; x < (int)fmt.i_width - 1; x++ )
286 current = p_dst[x];
287 p_dst[x] = ( 4 * (int)p_dst[x] + left + p_top[x] + p_dst[x+1] +
288 p_dst[x + i_pitch]) / 8;
289 left = current;
292 memset( p_top, 0, fmt.i_width );
295 return VLC_SUCCESS;
298 static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
299 subpicture_region_t *p_region_in )
301 filter_sys_t *p_sys = p_filter->p_sys;
302 int i_font_color, i_font_alpha, i_font_size;
303 uint8_t *p_bitmap;
304 TCHAR *psz_string;
305 int i, i_width, i_height;
306 HBITMAP bitmap, bitmap_bak;
307 BITMAPINFO *p_bmi;
308 RECT rect = {0};
309 SIZE size;
311 /* Sanity check */
312 if( !p_region_in || !p_region_out ) return VLC_EGENERIC;
313 #ifdef UNICODE
314 psz_string = malloc( (strlen( p_region_in->psz_text )+1) * sizeof(TCHAR) );
315 if( mbstowcs( psz_string, p_region_in->psz_text,
316 strlen( p_region_in->psz_text ) * sizeof(TCHAR) ) < 0 )
318 free( psz_string );
319 return VLC_EGENERIC;
321 #else
322 psz_string = strdup( p_region_in->psz_text );
323 #endif
324 if( !psz_string || !*psz_string ) return VLC_EGENERIC;
326 if( p_region_in->p_style )
328 i_font_color = __MAX( __MIN( p_region_in->p_style->i_font_color, 0xFFFFFF ), 0 );
329 i_font_alpha = __MAX( __MIN( p_region_in->p_style->i_font_alpha, 255 ), 0 );
330 i_font_size = __MAX( __MIN( p_region_in->p_style->i_font_size, 255 ), 0 );
332 else
334 i_font_color = p_sys->i_font_color;
335 i_font_alpha = 255 - p_sys->i_font_opacity;
336 i_font_size = p_sys->i_default_font_size;
339 SetFont( p_filter, i_font_size );
341 SetTextColor( p_sys->hcdc, RGB( (i_font_color >> 16) & 0xff,
342 (i_font_color >> 8) & 0xff, i_font_color & 0xff) );
344 GetTextExtentExPoint( p_sys->hcdc, psz_string, _tcslen(psz_string),
345 0, 0, 0, &size );
346 i_width = rect.right = size.cx; i_height = rect.bottom = size.cy;
348 p_bmi = malloc(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*16);
349 memset( p_bmi, 0, sizeof(BITMAPINFOHEADER) );
350 p_bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
351 p_bmi->bmiHeader.biWidth = (i_width+3) & ~3;
352 p_bmi->bmiHeader.biHeight = - i_height;
353 p_bmi->bmiHeader.biPlanes = 1;
354 p_bmi->bmiHeader.biBitCount = 8;
355 p_bmi->bmiHeader.biCompression = BI_RGB;
356 p_bmi->bmiHeader.biClrUsed = 16;
358 for( i = 0; i < 16; i++ )
360 p_bmi->bmiColors[i].rgbBlue =
361 p_bmi->bmiColors[i].rgbGreen =
362 p_bmi->bmiColors[i].rgbRed = pi_gamma[i];
365 bitmap = CreateDIBSection( p_sys->hcdc, p_bmi, DIB_RGB_COLORS,
366 (void **)&p_bitmap, NULL, 0 );
367 if( !bitmap )
369 msg_Err( p_filter, "could not create bitmap" );
370 return VLC_EGENERIC;
373 bitmap_bak = SelectObject( p_sys->hcdc, bitmap );
374 FillRect( p_sys->hcdc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH) );
376 //TextOut( p_sys->hcdc, 0, 0, psz_string, strlen(psz_string) );
377 if( !DrawText( p_sys->hcdc, psz_string, -1, &rect, 0 ) )
379 msg_Err( p_filter, "could not draw text" );
382 p_region_out->i_x = p_region_in->i_x;
383 p_region_out->i_y = p_region_in->i_y;
384 Render( p_filter, p_region_out, p_bitmap, i_width, i_height );
386 SelectObject( p_sys->hcdc, bitmap_bak );
387 DeleteObject( bitmap );
388 return VLC_SUCCESS;
391 static int SetFont( filter_t *p_filter, int i_size )
393 filter_sys_t *p_sys = p_filter->p_sys;
394 LOGFONT logfont;
396 if( i_size && i_size == p_sys->i_font_size ) return VLC_SUCCESS;
398 if( !i_size )
400 vlc_value_t val;
402 if( !p_sys->i_default_font_size &&
403 p_sys->i_display_height == (int)p_filter->fmt_out.video.i_height )
404 return VLC_SUCCESS;
406 if( p_sys->i_default_font_size )
408 i_size = p_sys->i_default_font_size;
410 else
412 var_Get( p_filter, "win32text-rel-fontsize", &val );
413 i_size = (int)p_filter->fmt_out.video.i_height / val.i_int;
414 p_filter->p_sys->i_display_height =
415 p_filter->fmt_out.video.i_height;
417 if( i_size <= 0 )
419 msg_Warn( p_filter, "invalid fontsize, using 12" );
420 i_size = 12;
423 msg_Dbg( p_filter, "using fontsize: %i", i_size );
426 p_sys->i_font_size = i_size;
428 if( p_sys->hfont_bak ) SelectObject( p_sys->hcdc, p_sys->hfont_bak );
429 if( p_sys->hfont ) DeleteObject( p_sys->hfont );
431 i_size = i_size * (int64_t)p_sys->i_logpy / 72;
433 logfont.lfHeight = i_size;
434 logfont.lfWidth = 0;
435 logfont.lfEscapement = 0;
436 logfont.lfOrientation = 0;
437 logfont.lfWeight = 0;
438 logfont.lfItalic = FALSE;
439 logfont.lfUnderline = FALSE;
440 logfont.lfStrikeOut = FALSE;
441 logfont.lfCharSet = ANSI_CHARSET;
442 logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
443 logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
444 logfont.lfQuality = ANTIALIASED_QUALITY;
445 logfont.lfPitchAndFamily = DEFAULT_PITCH;
446 memcpy( logfont.lfFaceName, _T("Arial"), sizeof(_T("Arial")) );
448 p_sys->hfont = CreateFontIndirect( &logfont );
450 p_sys->hfont_bak = SelectObject( p_sys->hcdc, p_sys->hfont );
452 return VLC_SUCCESS;