2 * Renders antialiased fonts for mplayer using freetype library.
3 * Should work with TrueType, Type1 and any other font supported by libfreetype.
5 * Artur Zaprzala <zybi@fanthom.irc.pl>
7 * ported inside MPlayer by Jindrich Makovicka <makovick@gmail.com>
9 * This file is part of MPlayer.
11 * MPlayer is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * MPlayer is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
38 #include FT_FREETYPE_H
41 #ifdef CONFIG_FONTCONFIG
42 #include <fontconfig/fontconfig.h>
45 #include "libavutil/common.h"
47 #include "font_load.h"
53 #if (FREETYPE_MAJOR > 2) || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR >= 1)
54 #define HAVE_FREETYPE21
57 char *subtitle_font_encoding
= NULL
;
58 float text_font_scale_factor
= 3.5;
59 float osd_font_scale_factor
= 4.0;
60 float subtitle_font_radius
= 2.0;
61 float subtitle_font_thickness
= 2.0;
66 int subtitle_autoscale
= 3;
68 int vo_image_width
= 0;
69 int vo_image_height
= 0;
72 int using_freetype
= 0;
73 int font_fontconfig
= 1;
76 static unsigned int const colors
= 256;
77 static unsigned int const maxcolor
= 255;
78 static unsigned const base
= 256;
79 static unsigned const first_char
= 33;
80 #define MAX_CHARSET_SIZE 60000
82 static FT_Library library
;
84 #define OSD_CHARSET_SIZE 15
86 static const FT_ULong osd_charset
[OSD_CHARSET_SIZE
] =
88 0xe001, 0xe002, 0xe003, 0xe004, 0xe005, 0xe006, 0xe007, 0xe008,
89 0xe009, 0xe00a, 0xe00b, 0xe010, 0xe011, 0xe012, 0xe013
92 static const FT_ULong osd_charcodes
[OSD_CHARSET_SIZE
] =
94 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
95 0x09,0x0a,0x0b,0x10,0x11,0x12,0x13
98 #define f266ToInt(x) (((x)+32)>>6) // round fractional fixed point number to integer
99 // coordinates are in 26.6 pixels (i.e. 1/64th of pixels)
100 #define f266CeilToInt(x) (((x)+63)>>6) // ceiling
101 #define f266FloorToInt(x) ((x)>>6) // floor
102 #define f1616ToInt(x) (((x)+0x8000)>>16) // 16.16
103 #define floatTof266(x) ((int)((x)*(1<<6)+0.5))
105 #define ALIGN(x) (((x)+7)&~7) // 8 byte align
107 #define WARNING(msg, args...) mp_msg(MSGT_OSD, MSGL_WARN, msg "\n", ## args)
111 //static double ttime;
114 static void paste_bitmap(unsigned char *bbuffer
, FT_Bitmap
*bitmap
, int x
, int y
, int width
, int height
, int bwidth
) {
115 int drow
= x
+y
*width
;
118 if (bitmap
->pixel_mode
==ft_pixel_mode_mono
)
119 for (h
= bitmap
->rows
; h
>0 && height
> 0; --h
, height
--, drow
+=width
, srow
+=bitmap
->pitch
)
120 for (w
= bwidth
, sp
=dp
=0; w
>0; --w
, ++dp
, ++sp
)
121 bbuffer
[drow
+dp
] = (bitmap
->buffer
[srow
+sp
/8] & (0x80>>(sp
%8))) ? 255:0;
123 for (h
= bitmap
->rows
; h
>0 && height
> 0; --h
, height
--, drow
+=width
, srow
+=bitmap
->pitch
)
124 for (w
= bwidth
, sp
=dp
=0; w
>0; --w
, ++dp
, ++sp
)
125 bbuffer
[drow
+dp
] = bitmap
->buffer
[srow
+sp
];
129 static int check_font(font_desc_t
*desc
, float ppem
, int padding
, int pic_idx
,
130 int charset_size
, FT_ULong
*charset
, FT_ULong
*charcodes
,
133 FT_Face face
= desc
->faces
[pic_idx
];
134 int const load_flags
= FT_LOAD_DEFAULT
;
135 int ymin
= INT_MAX
, ymax
= INT_MIN
;
136 int space_advance
= 20;
138 unsigned char *bbuffer
;
139 int i
, uni_charmap
= 1;
141 error
= FT_Select_Charmap(face
, ft_encoding_unicode
);
142 // fprintf(stderr, "select unicode charmap: %d\n", error);
144 if (face
->charmap
==NULL
|| face
->charmap
->encoding
!=ft_encoding_unicode
) {
145 WARNING("Unicode charmap not available for this font. Very bad!");
147 error
= FT_Set_Charmap(face
, face
->charmaps
[0]);
148 if (error
) WARNING("No charmaps! Strange.");
152 if (FT_IS_SCALABLE(face
)) {
153 error
= FT_Set_Char_Size(face
, 0, floatTof266(ppem
), 0, 0);
154 if (error
) WARNING("FT_Set_Char_Size failed.");
157 int jppem
= face
->available_sizes
[0].height
;
158 /* find closest size */
159 for (i
= 0; i
<face
->num_fixed_sizes
; ++i
) {
160 if (fabs(face
->available_sizes
[i
].height
- ppem
) < abs(face
->available_sizes
[i
].height
- jppem
)) {
162 jppem
= face
->available_sizes
[i
].height
;
165 WARNING("Selected font is not scalable. Using ppem=%i.", face
->available_sizes
[j
].height
);
166 error
= FT_Set_Pixel_Sizes(face
, face
->available_sizes
[j
].width
, face
->available_sizes
[j
].height
);
167 if (error
) WARNING("FT_Set_Pixel_Sizes failed.");
170 if (FT_IS_FIXED_WIDTH(face
))
171 WARNING("Selected font is fixed-width.");
173 /* compute space advance */
174 error
= FT_Load_Char(face
, ' ', load_flags
);
175 if (error
) WARNING("spacewidth set to default.");
176 else space_advance
= f266ToInt(face
->glyph
->advance
.x
);
178 if (!desc
->spacewidth
) desc
->spacewidth
= 2*padding
+ space_advance
;
179 if (!desc
->charspace
) desc
->charspace
= -2*padding
;
180 if (!desc
->height
) desc
->height
= f266ToInt(face
->size
->metrics
.height
);
183 for (i
= 0; i
<charset_size
; ++i
) {
184 FT_ULong character
, code
;
187 character
= charset
[i
];
189 desc
->font
[unicode
?character
:code
] = pic_idx
;
194 glyph_index
= FT_Get_Char_Index(face
, uni_charmap
? character
:code
);
195 if (glyph_index
==0) {
196 WARNING("Glyph for char 0x%02lx|U+%04lX|%c not found.", code
, character
,
197 code
<' '||code
>255 ? '.':(char)code
);
198 desc
->font
[unicode
?character
:code
] = -1;
202 desc
->glyph_index
[unicode
?character
:code
] = glyph_index
;
204 // fprintf(stderr, "font height: %lf\n", (double)(face->bbox.yMax-face->bbox.yMin)/(double)face->units_per_EM*ppem);
205 // fprintf(stderr, "font width: %lf\n", (double)(face->bbox.xMax-face->bbox.xMin)/(double)face->units_per_EM*ppem);
207 ymax
= (double)(face
->bbox
.yMax
)/(double)face
->units_per_EM
*ppem
+1;
208 ymin
= (double)(face
->bbox
.yMin
)/(double)face
->units_per_EM
*ppem
-1;
210 width
= ppem
*(face
->bbox
.xMax
-face
->bbox
.xMin
)/face
->units_per_EM
+3+2*padding
;
211 if (desc
->max_width
< width
) desc
->max_width
= width
;
212 width
= ALIGN(width
);
213 desc
->pic_b
[pic_idx
]->charwidth
= width
;
216 mp_msg(MSGT_OSD
, MSGL_ERR
, "Wrong bounding box, width <= 0 !\n");
221 mp_msg(MSGT_OSD
, MSGL_ERR
, "Something went wrong. Use the source!\n");
225 height
= ymax
- ymin
+ 2*padding
;
227 mp_msg(MSGT_OSD
, MSGL_ERR
, "Wrong bounding box, height <= 0 !\n");
231 if (desc
->max_height
< height
) desc
->max_height
= height
;
232 desc
->pic_b
[pic_idx
]->charheight
= height
;
234 // fprintf(stderr, "font height2: %d\n", height);
235 desc
->pic_b
[pic_idx
]->baseline
= ymax
+ padding
;
236 desc
->pic_b
[pic_idx
]->padding
= padding
;
237 desc
->pic_b
[pic_idx
]->current_alloc
= 0;
238 desc
->pic_b
[pic_idx
]->current_count
= 0;
242 desc
->pic_b
[pic_idx
]->w
= width
;
243 desc
->pic_b
[pic_idx
]->h
= height
;
244 desc
->pic_b
[pic_idx
]->c
= colors
;
245 desc
->pic_b
[pic_idx
]->bmp
= bbuffer
;
246 desc
->pic_b
[pic_idx
]->pen
= 0;
264 for (y
= 0; y
<height
; y
++) {
265 for (x
= 0; x
<width
; x
++) {
269 const int x1
=(x
<r
) ? r
-x
: 0;
270 const int y1
=(y
<r
) ? r
-y
: 0;
271 const int x2
=(x
+r
>=width
) ? r
+width
-x
: 2*r
+1;
272 const int y2
=(y
+r
>=height
) ? r
+height
-y
: 2*r
+1;
273 register unsigned char *dstp
= t
+ (y1
+y
-r
)* stride
+ x
-r
;
274 //register int *mp = m + y1 *mwidth;
275 register unsigned char *mp
= m
+ msize
*src
+ y1
*mwidth
;
278 for(my
= y1
; my
<y2
; my
++){
280 for(mx
= x1
; mx
<x2
; mx
++){
281 if(dstp
[mx
] < mp
[mx
]) dstp
[mx
]= mp
[mx
];
294 static void outline1(
302 int skip
= stride
-width
;
304 for (x
= 0; x
<width
; ++x
, ++s
, ++t
) *t
= *s
;
307 for (y
= 1; y
<height
-1; ++y
) {
309 for (x
= 1; x
<width
-1; ++x
, ++s
, ++t
) {
322 *t
= v
>maxcolor
? maxcolor
: v
;
328 for (x
= 0; x
<width
; ++x
, ++s
, ++t
) *t
= *s
;
332 static void outline0(
339 for (y
= 0; y
<height
; ++y
) {
348 unsigned char *buffer
,
349 unsigned short *tmp2
,
359 unsigned char *s
= buffer
;
360 unsigned short *t
= tmp2
+1;
361 for(y
=0; y
<height
; y
++){
362 memset(t
-1, 0, (width
+1)*sizeof(short));
367 register unsigned short *dstp
= t
+ x
-r
;
369 unsigned *m3
= m2
+ src
*mwidth
;
370 for(mx
=r
-x
; mx
<mwidth
; mx
++){
376 for(; x
<width
-r
; x
++){
379 register unsigned short *dstp
= t
+ x
-r
;
381 unsigned *m3
= m2
+ src
*mwidth
;
382 for(mx
=0; mx
<mwidth
; mx
++){
391 register unsigned short *dstp
= t
+ x
-r
;
393 const int x2
= r
+width
-x
;
394 unsigned *m3
= m2
+ src
*mwidth
;
395 for(mx
=0; mx
<x2
; mx
++){
406 for(x
=0; x
<width
; x
++){
408 unsigned short *srcp
= t
+ y
*(width
+1) + 1;
411 register unsigned short *dstp
= srcp
- 1 + width
+1;
412 const int src2
= (src
+ 128)>>8;
413 unsigned *m3
= m2
+ src2
*mwidth
;
417 for(mx
=r
-1; mx
<mwidth
; mx
++){
423 for(; y
<height
-r
; y
++){
424 unsigned short *srcp
= t
+ y
*(width
+1) + 1;
427 register unsigned short *dstp
= srcp
- 1 - r
*(width
+1);
428 const int src2
= (src
+ 128)>>8;
429 unsigned *m3
= m2
+ src2
*mwidth
;
433 for(mx
=0; mx
<mwidth
; mx
++){
439 for(; y
<height
; y
++){
440 unsigned short *srcp
= t
+ y
*(width
+1) + 1;
443 const int y2
=r
+height
-y
;
444 register unsigned short *dstp
= srcp
- 1 - r
*(width
+1);
445 const int src2
= (src
+ 128)>>8;
446 unsigned *m3
= m2
+ src2
*mwidth
;
450 for(mx
=0; mx
<y2
; mx
++){
461 for(y
=0; y
<height
; y
++){
462 for(x
=0; x
<width
; x
++){
470 static void resample_alpha(unsigned char *abuf
, unsigned char *bbuf
, int width
, int height
, int stride
, float factor
)
474 for (i
= 0; i
< height
; i
++) {
475 unsigned char *a
= abuf
+i
*stride
;
476 unsigned char *b
= bbuf
+i
*stride
;
477 for(j
=0;j
<width
;j
++,a
++,b
++){
480 x
=255-((x
*f
)>>8); // scale
481 if (x
+y
>255) x
=255-y
; // to avoid overflows
482 if (x
<1) x
=1; else if (x
>=252) x
=0;
488 #define ALLOC_INCR 32
489 void render_one_glyph(font_desc_t
*desc
, int c
)
493 FT_BitmapGlyph glyph
;
494 int width
, height
, stride
, maxw
, off
;
495 unsigned char *abuffer
, *bbuffer
;
497 int const load_flags
= FT_LOAD_DEFAULT
;
499 int font
= desc
->font
[c
];
502 // fprintf(stderr, "render_one_glyph %d\n", c);
504 if (!desc
->dynamic
) return;
505 if (desc
->width
[c
] != -1) return;
506 if (desc
->font
[c
] == -1) return;
508 glyph_index
= desc
->glyph_index
[c
];
511 error
= FT_Load_Glyph(desc
->faces
[font
], glyph_index
, load_flags
);
513 WARNING("FT_Load_Glyph 0x%02x (char 0x%04x) failed.", glyph_index
, c
);
517 slot
= desc
->faces
[font
]->glyph
;
520 if (slot
->format
!= ft_glyph_format_bitmap
) {
521 error
= FT_Render_Glyph(slot
, ft_render_mode_normal
);
523 WARNING("FT_Render_Glyph 0x%04x (char 0x%04x) failed.", glyph_index
, c
);
529 // extract glyph image
530 error
= FT_Get_Glyph(slot
, (FT_Glyph
*)&glyph
);
532 WARNING("FT_Get_Glyph 0x%04x (char 0x%04x) failed.", glyph_index
, c
);
537 // fprintf(stderr, "glyph generated\n");
539 maxw
= desc
->pic_b
[font
]->charwidth
;
541 if (glyph
->bitmap
.width
> maxw
) {
542 fprintf(stderr
, "glyph too wide!\n");
545 // allocate new memory, if needed
546 // fprintf(stderr, "\n%d %d %d\n", desc->pic_b[font]->charwidth, desc->pic_b[font]->charheight, desc->pic_b[font]->current_alloc);
547 if (desc
->pic_b
[font
]->current_count
>= desc
->pic_b
[font
]->current_alloc
) {
548 int newsize
= desc
->pic_b
[font
]->charwidth
*desc
->pic_b
[font
]->charheight
*(desc
->pic_b
[font
]->current_alloc
+ALLOC_INCR
);
549 int increment
= desc
->pic_b
[font
]->charwidth
*desc
->pic_b
[font
]->charheight
*ALLOC_INCR
;
550 desc
->pic_b
[font
]->current_alloc
+= ALLOC_INCR
;
552 // fprintf(stderr, "\nns = %d inc = %d\n", newsize, increment);
554 desc
->pic_b
[font
]->bmp
= realloc(desc
->pic_b
[font
]->bmp
, newsize
);
555 desc
->pic_a
[font
]->bmp
= realloc(desc
->pic_a
[font
]->bmp
, newsize
);
557 off
= desc
->pic_b
[font
]->current_count
*desc
->pic_b
[font
]->charwidth
*desc
->pic_b
[font
]->charheight
;
558 memset(desc
->pic_b
[font
]->bmp
+off
, 0, increment
);
559 memset(desc
->pic_a
[font
]->bmp
+off
, 0, increment
);
562 abuffer
= desc
->pic_a
[font
]->bmp
;
563 bbuffer
= desc
->pic_b
[font
]->bmp
;
565 off
= desc
->pic_b
[font
]->current_count
*desc
->pic_b
[font
]->charwidth
*desc
->pic_b
[font
]->charheight
;
567 paste_bitmap(bbuffer
+off
,
569 desc
->pic_b
[font
]->padding
+ glyph
->left
,
570 desc
->pic_b
[font
]->baseline
- glyph
->top
,
571 desc
->pic_b
[font
]->charwidth
, desc
->pic_b
[font
]->charheight
,
572 glyph
->bitmap
.width
<= maxw
? glyph
->bitmap
.width
: maxw
);
574 // fprintf(stderr, "glyph pasted\n");
575 FT_Done_Glyph((FT_Glyph
)glyph
);
578 pen_xa
= f266ToInt(slot
->advance
.x
) + 2*desc
->pic_b
[font
]->padding
;
579 if (pen_xa
> maxw
) pen_xa
= maxw
;
581 desc
->start
[c
] = off
;
582 width
= desc
->width
[c
] = pen_xa
;
583 height
= desc
->pic_b
[font
]->charheight
;
584 stride
= desc
->pic_b
[font
]->w
;
586 if (desc
->tables
.o_r
== 0) {
587 outline0(bbuffer
+off
, abuffer
+off
, width
, height
, stride
);
588 } else if (desc
->tables
.o_r
== 1) {
589 outline1(bbuffer
+off
, abuffer
+off
, width
, height
, stride
);
591 outline(bbuffer
+off
, abuffer
+off
, width
, height
, stride
,
592 desc
->tables
.omt
, desc
->tables
.o_r
, desc
->tables
.o_w
,
593 desc
->tables
.o_size
);
595 // fprintf(stderr, "fg: outline t = %lf\n", GetTimer()-t);
597 if (desc
->tables
.g_r
) {
598 blur(abuffer
+off
, desc
->tables
.tmp
, width
, height
, stride
,
599 desc
->tables
.gt2
, desc
->tables
.g_r
,
601 // fprintf(stderr, "fg: blur t = %lf\n", GetTimer()-t);
604 resample_alpha(abuffer
+off
, bbuffer
+off
, width
, height
, stride
, font_factor
);
606 desc
->pic_b
[font
]->current_count
++;
610 static int prepare_font(font_desc_t
*desc
, FT_Face face
, float ppem
, int pic_idx
,
611 int charset_size
, FT_ULong
*charset
, FT_ULong
*charcodes
, int unicode
,
612 double thickness
, double radius
)
615 int padding
= ceil(radius
) + ceil(thickness
);
617 desc
->faces
[pic_idx
] = face
;
619 desc
->pic_a
[pic_idx
] = malloc(sizeof(raw_file
));
620 if (!desc
->pic_a
[pic_idx
]) return -1;
621 desc
->pic_b
[pic_idx
] = malloc(sizeof(raw_file
));
622 if (!desc
->pic_b
[pic_idx
]) return -1;
624 desc
->pic_a
[pic_idx
]->bmp
= NULL
;
625 desc
->pic_a
[pic_idx
]->pal
= NULL
;
626 desc
->pic_b
[pic_idx
]->bmp
= NULL
;
627 desc
->pic_b
[pic_idx
]->pal
= NULL
;
629 desc
->pic_a
[pic_idx
]->pal
= malloc(sizeof(unsigned char)*256*3);
630 if (!desc
->pic_a
[pic_idx
]->pal
) return -1;
631 for (i
= 0; i
<768; ++i
) desc
->pic_a
[pic_idx
]->pal
[i
] = i
/3;
633 desc
->pic_b
[pic_idx
]->pal
= malloc(sizeof(unsigned char)*256*3);
634 if (!desc
->pic_b
[pic_idx
]->pal
) return -1;
635 for (i
= 0; i
<768; ++i
) desc
->pic_b
[pic_idx
]->pal
[i
] = i
/3;
637 // ttime = GetTimer();
638 err
= check_font(desc
, ppem
, padding
, pic_idx
, charset_size
, charset
, charcodes
, unicode
);
639 // ttime=GetTimer()-ttime;
640 // printf("render: %7lf us\n",ttime);
642 // fprintf(stderr, "fg: render t = %lf\n", GetTimer()-t);
644 desc
->pic_a
[pic_idx
]->w
= desc
->pic_b
[pic_idx
]->w
;
645 desc
->pic_a
[pic_idx
]->h
= desc
->pic_b
[pic_idx
]->h
;
646 desc
->pic_a
[pic_idx
]->c
= colors
;
648 desc
->pic_a
[pic_idx
]->bmp
= NULL
;
650 // fprintf(stderr, "fg: w = %d, h = %d\n", desc->pic_a[pic_idx]->w, desc->pic_a[pic_idx]->h);
655 static int generate_tables(font_desc_t
*desc
, double thickness
, double radius
)
657 int width
= desc
->max_height
;
658 int height
= desc
->max_width
;
660 double A
= log(1.0/base
)/(radius
*radius
*2);
662 double volume_diff
, volume_factor
= 0;
665 desc
->tables
.g_r
= ceil(radius
);
666 desc
->tables
.o_r
= ceil(thickness
);
667 desc
->tables
.g_w
= 2*desc
->tables
.g_r
+1;
668 desc
->tables
.o_w
= 2*desc
->tables
.o_r
+1;
669 desc
->tables
.o_size
= desc
->tables
.o_w
* desc
->tables
.o_w
;
671 // fprintf(stderr, "o_r = %d\n", desc->tables.o_r);
673 if (desc
->tables
.g_r
) {
674 desc
->tables
.g
= malloc(desc
->tables
.g_w
* sizeof(unsigned));
675 desc
->tables
.gt2
= malloc(256 * desc
->tables
.g_w
* sizeof(unsigned));
676 if (desc
->tables
.g
==NULL
|| desc
->tables
.gt2
==NULL
) {
680 desc
->tables
.om
= malloc(desc
->tables
.o_w
*desc
->tables
.o_w
* sizeof(unsigned));
681 desc
->tables
.omt
= malloc(desc
->tables
.o_size
*256);
683 omtp
= desc
->tables
.omt
;
684 desc
->tables
.tmp
= malloc((width
+1)*height
*sizeof(short));
686 if (desc
->tables
.om
==NULL
|| desc
->tables
.omt
==NULL
|| desc
->tables
.tmp
==NULL
) {
690 if (desc
->tables
.g_r
) {
691 // gaussian curve with volume = 256
692 for (volume_diff
=10000000; volume_diff
>0.0000001; volume_diff
*=0.5){
693 volume_factor
+= volume_diff
;
694 desc
->tables
.volume
=0;
695 for (i
= 0; i
<desc
->tables
.g_w
; ++i
) {
696 desc
->tables
.g
[i
] = (unsigned)(exp(A
* (i
-desc
->tables
.g_r
)*(i
-desc
->tables
.g_r
)) * volume_factor
+ .5);
697 desc
->tables
.volume
+= desc
->tables
.g
[i
];
699 if(desc
->tables
.volume
>256) volume_factor
-= volume_diff
;
701 desc
->tables
.volume
=0;
702 for (i
= 0; i
<desc
->tables
.g_w
; ++i
) {
703 desc
->tables
.g
[i
] = (unsigned)(exp(A
* (i
-desc
->tables
.g_r
)*(i
-desc
->tables
.g_r
)) * volume_factor
+ .5);
704 desc
->tables
.volume
+= desc
->tables
.g
[i
];
708 for(mx
=0;mx
<desc
->tables
.g_w
;mx
++){
710 desc
->tables
.gt2
[mx
+i
*desc
->tables
.g_w
] = i
*desc
->tables
.g
[mx
];
716 for (my
= 0; my
<desc
->tables
.o_w
; ++my
) {
717 for (mx
= 0; mx
<desc
->tables
.o_w
; ++mx
) {
718 // antialiased circle would be perfect here, but this one is good enough
719 double d
= thickness
+ 1 - sqrt((mx
-desc
->tables
.o_r
)*(mx
-desc
->tables
.o_r
)+(my
-desc
->tables
.o_r
)*(my
-desc
->tables
.o_r
));
720 desc
->tables
.om
[mx
+my
*desc
->tables
.o_w
] = d
>=1 ? base
: d
<=0 ? 0 : (d
*base
+ .5);
726 for(mx
=0;mx
<desc
->tables
.o_size
;mx
++) *(omtp
++) = (i
*desc
->tables
.om
[mx
] + (base
/2))/base
;
733 /* decode from 'encoding' to unicode */
734 static FT_ULong
decode_char(iconv_t
*cd
, char c
) {
737 char *outbuf
= (char*)&o
;
738 size_t inbytesleft
= 1;
739 size_t outbytesleft
= sizeof(FT_ULong
);
741 iconv(*cd
, &inbuf
, &inbytesleft
, &outbuf
, &outbytesleft
);
743 /* convert unicode BigEndian -> MachineEndian */
746 // if (count==-1) o = 0; // not OK, at least my iconv() returns E2BIG for all
747 if (outbytesleft
!=0) o
= 0;
749 /* we don't want control characters */
750 if (o
>=0x7f && o
<0xa0) o
= 0;
754 static int prepare_charset(char *charmap
, char *encoding
, FT_ULong
*charset
, FT_ULong
*charcodes
) {
760 // check if ucs-4 is available
761 cd
= iconv_open(charmap
, charmap
);
762 if (cd
==(iconv_t
)-1) {
763 mp_msg(MSGT_OSD
, MSGL_ERR
, "iconv doesn't know %s encoding. Use the source!\n", charmap
);
769 cd
= iconv_open(charmap
, encoding
);
770 if (cd
==(iconv_t
)-1) {
771 mp_msg(MSGT_OSD
, MSGL_ERR
, "Unsupported encoding `%s', use iconv --list to list character sets known on your system.\n", encoding
);
775 charset_size
= 256 - first_char
;
776 for (i
= 0; i
<charset_size
; ++i
) {
777 charcodes
[count
] = i
+first_char
;
778 charset
[count
] = decode_char(&cd
, i
+first_char
);
779 if (charset
[count
]!=0) ++count
;
781 charcodes
[count
] = charset
[count
] = 0; ++count
;
782 charset_size
= count
;
785 if (charset_size
==0) {
786 mp_msg(MSGT_OSD
, MSGL_ERR
, "No characters to render!\n");
793 static int prepare_charset_unicode(FT_Face face
, FT_ULong
*charset
, FT_ULong
*charcodes
) {
794 #ifdef HAVE_FREETYPE21
802 if (face
->charmap
==NULL
|| face
->charmap
->encoding
!=ft_encoding_unicode
) {
803 WARNING("Unicode charmap not available for this font. Very bad!");
806 #ifdef HAVE_FREETYPE21
808 charcode
= FT_Get_First_Char( face
, &gindex
);
809 while (gindex
!= 0) {
810 if (charcode
< 65536 && charcode
>= 33) { // sanity check
811 charset
[i
] = charcode
;
815 charcode
= FT_Get_Next_Char( face
, charcode
, &gindex
);
818 // for FT < 2.1 we have to use brute force enumeration
820 for (j
= 33; j
< 65536; j
++) {
821 gindex
= FT_Get_Char_Index(face
, j
);
829 mp_msg(MSGT_OSD
, MSGL_V
, "Unicode font: %d glyphs.\n", i
);
835 static font_desc_t
* init_font_desc(void)
839 desc
= calloc(1, sizeof(*desc
));
840 if(!desc
) return NULL
;
844 /* setup sane defaults */
847 memset(desc
->start
, 0xff, sizeof(desc
->start
));
848 memset(desc
->width
, 0xff, sizeof(desc
->width
));
849 memset(desc
->font
, 0xff, sizeof(desc
->font
));
854 void free_font_desc(font_desc_t
*desc
)
860 // if (!desc->dynamic) return; // some vo_aa crap, better leaking than crashing
862 if (desc
->name
) free(desc
->name
);
863 if (desc
->fpath
) free(desc
->fpath
);
865 for(i
= 0; i
< 16; i
++) {
866 if (desc
->pic_a
[i
]) {
867 if (desc
->pic_a
[i
]->bmp
) free(desc
->pic_a
[i
]->bmp
);
868 if (desc
->pic_a
[i
]->pal
) free(desc
->pic_a
[i
]->pal
);
869 free (desc
->pic_a
[i
]);
871 if (desc
->pic_b
[i
]) {
872 if (desc
->pic_b
[i
]->bmp
) free(desc
->pic_b
[i
]->bmp
);
873 if (desc
->pic_b
[i
]->pal
) free(desc
->pic_b
[i
]->pal
);
874 free (desc
->pic_b
[i
]);
878 if (desc
->tables
.g
) free(desc
->tables
.g
);
879 if (desc
->tables
.gt2
) free(desc
->tables
.gt2
);
880 if (desc
->tables
.om
) free(desc
->tables
.om
);
881 if (desc
->tables
.omt
) free(desc
->tables
.omt
);
882 if (desc
->tables
.tmp
) free(desc
->tables
.tmp
);
884 for(i
= 0; i
< desc
->face_cnt
; i
++) {
885 FT_Done_Face(desc
->faces
[i
]);
891 static int load_sub_face(const char *name
, int face_index
, FT_Face
*face
)
895 if (name
) err
= FT_New_Face(library
, name
, face_index
, face
);
898 char *font_file
= get_path("subfont.ttf");
899 err
= FT_New_Face(library
, font_file
, 0, face
);
902 err
= FT_New_Face(library
, MPLAYER_DATADIR
"/subfont.ttf", 0, face
);
904 mp_tmsg(MSGT_OSD
, MSGL_ERR
, "New_Face failed. Maybe the font path is wrong.\nPlease supply the text font file (~/.mplayer/subfont.ttf).\n");
912 static int load_osd_face(FT_Face
*face
)
914 if ( FT_New_Memory_Face(library
, osd_font_pfb
, sizeof(osd_font_pfb
), 0, face
) ) {
915 mp_tmsg(MSGT_OSD
, MSGL_ERR
, "New_Memory_Face failed..\n");
921 int kerning(font_desc_t
*desc
, int prevc
, int c
)
925 if (!desc
->dynamic
) return 0;
926 if (prevc
< 0 || c
< 0) return 0;
927 if (desc
->font
[prevc
] != desc
->font
[c
]) return 0;
928 if (desc
->font
[prevc
] == -1 || desc
->font
[c
] == -1) return 0;
929 FT_Get_Kerning(desc
->faces
[desc
->font
[c
]],
930 desc
->glyph_index
[prevc
], desc
->glyph_index
[c
],
931 ft_kerning_default
, &kern
);
933 // fprintf(stderr, "kern: %c %c %d\n", prevc, c, f266ToInt(kern.x));
935 return f266ToInt(kern
.x
);
938 font_desc_t
* read_font_desc_ft(const char *fname
, int face_index
, int movie_width
, int movie_height
, float font_scale_factor
)
940 font_desc_t
*desc
= NULL
;
944 FT_ULong
*my_charset
= malloc(MAX_CHARSET_SIZE
* sizeof(FT_ULong
)); /* characters we want to render; Unicode */
945 FT_ULong
*my_charcodes
= malloc(MAX_CHARSET_SIZE
* sizeof(FT_ULong
)); /* character codes in 'encoding' */
947 char *charmap
= "ucs-4";
955 float subtitle_font_ppem
;
958 if (my_charset
== NULL
|| my_charcodes
== NULL
) {
959 mp_msg(MSGT_OSD
, MSGL_ERR
, "subtitle font: malloc failed.\n");
963 switch (subtitle_autoscale
) {
965 movie_size
= movie_height
;
968 movie_size
= movie_width
;
971 movie_size
= sqrt(movie_height
*movie_height
+movie_width
*movie_width
);
978 subtitle_font_ppem
= movie_size
*font_scale_factor
/100.0;
979 osd_font_ppem
= movie_size
*(font_scale_factor
+1)/100.0;
981 if (subtitle_font_ppem
< 5) subtitle_font_ppem
= 5;
982 if (osd_font_ppem
< 5) osd_font_ppem
= 5;
984 if (subtitle_font_ppem
> 128) subtitle_font_ppem
= 128;
985 if (osd_font_ppem
> 128) osd_font_ppem
= 128;
987 if ((subtitle_font_encoding
== NULL
)
988 || (strcasecmp(subtitle_font_encoding
, "unicode") == 0)) {
994 desc
= init_font_desc();
995 if(!desc
) goto err_out
;
999 /* generate the subtitle font */
1000 err
= load_sub_face(fname
, face_index
, &face
);
1002 mp_tmsg(MSGT_OSD
, MSGL_WARN
, "subtitle font: load_sub_face failed.\n");
1009 charset_size
= prepare_charset_unicode(face
, my_charset
, my_charcodes
);
1011 if (subtitle_font_encoding
) {
1012 charset_size
= prepare_charset(charmap
, subtitle_font_encoding
, my_charset
, my_charcodes
);
1014 charset_size
= prepare_charset(charmap
, "iso-8859-1", my_charset
, my_charcodes
);
1018 if (charset_size
< 0) {
1019 mp_tmsg(MSGT_OSD
, MSGL_ERR
, "subtitle font: prepare_charset failed.\n");
1026 // fprintf(stderr, "fg: prepare t = %lf\n", GetTimer()-t);
1028 err
= prepare_font(desc
, face
, subtitle_font_ppem
, desc
->face_cnt
-1,
1029 charset_size
, my_charset
, my_charcodes
, unicode
,
1030 subtitle_font_thickness
, subtitle_font_radius
);
1033 mp_tmsg(MSGT_OSD
, MSGL_ERR
, "Cannot prepare subtitle font.\n");
1039 /* generate the OSD font */
1040 err
= load_osd_face(&face
);
1046 err
= prepare_font(desc
, face
, osd_font_ppem
, desc
->face_cnt
-1,
1047 OSD_CHARSET_SIZE
, osd_charset
, osd_charcodes
, 0,
1048 subtitle_font_thickness
, subtitle_font_radius
);
1051 mp_tmsg(MSGT_OSD
, MSGL_ERR
, "Cannot prepare OSD font.\n");
1055 err
= generate_tables(desc
, subtitle_font_thickness
, subtitle_font_radius
);
1058 mp_tmsg(MSGT_OSD
, MSGL_ERR
, "Cannot generate tables.\n");
1064 desc
->width
[' ']=desc
->spacewidth
;
1067 if (desc
->font
[j
] < 0) j
= '?';
1068 if (desc
->font
[j
] < 0) j
= ' ';
1069 render_one_glyph(desc
, j
);
1070 for(i
= 0; i
< 65536; i
++) {
1071 if (desc
->font
[i
] < 0 && i
!= ' ') {
1072 desc
->start
[i
] = desc
->start
[j
];
1073 desc
->width
[i
] = desc
->width
[j
];
1074 desc
->font
[i
] = desc
->font
[j
];
1083 free_font_desc(desc
);
1089 int init_freetype(void)
1093 /* initialize freetype */
1094 err
= FT_Init_FreeType(&library
);
1096 mp_msg(MSGT_OSD
, MSGL_ERR
, "Init_FreeType failed.\n");
1099 mp_msg(MSGT_OSD
, MSGL_V
, "init_freetype\n");
1104 int done_freetype(void)
1108 if (!using_freetype
)
1111 err
= FT_Done_FreeType(library
);
1113 mp_tmsg(MSGT_OSD
, MSGL_ERR
, "FT_Done_FreeType failed.\n");
1120 void load_font_ft(int width
, int height
, font_desc_t
** fontp
, const char *font_name
, float font_scale_factor
)
1122 #ifdef CONFIG_FONTCONFIG
1123 FcPattern
*fc_pattern
;
1124 FcPattern
*fc_pattern2
;
1130 font_desc_t
*vo_font
= *fontp
;
1131 vo_image_width
= width
;
1132 vo_image_height
= height
;
1134 // protection against vo_aa font hacks
1135 if (vo_font
&& !vo_font
->dynamic
) return;
1137 if (vo_font
) free_font_desc(vo_font
);
1139 #ifdef CONFIG_FONTCONFIG
1140 if (font_fontconfig
> 0)
1143 fc_pattern
= FcNameParse(font_name
? font_name
: "sans-serif");
1144 FcConfigSubstitute(0, fc_pattern
, FcMatchPattern
);
1145 FcDefaultSubstitute(fc_pattern
);
1146 fc_pattern2
= fc_pattern
;
1147 fc_pattern
= FcFontMatch(0, fc_pattern
, &result
);
1149 FcPatternDestroy(fc_pattern2
);
1150 FcPatternGetBool(fc_pattern
, FC_SCALABLE
, 0, &scalable
);
1151 if (scalable
!= FcTrue
) {
1152 FcPatternDestroy(fc_pattern
);
1153 fc_pattern
= FcNameParse("sans-serif");
1154 FcConfigSubstitute(0, fc_pattern
, FcMatchPattern
);
1155 FcDefaultSubstitute(fc_pattern
);
1156 fc_pattern2
= fc_pattern
;
1157 fc_pattern
= FcFontMatch(0, fc_pattern
, 0);
1158 FcPatternDestroy(fc_pattern2
);
1160 // s doesn't need to be freed according to fontconfig docs
1161 FcPatternGetString(fc_pattern
, FC_FILE
, 0, &s
);
1162 FcPatternGetInteger(fc_pattern
, FC_INDEX
, 0, &face_index
);
1163 *fontp
=read_font_desc_ft(s
, face_index
, width
, height
, font_scale_factor
);
1164 FcPatternDestroy(fc_pattern
);
1167 mp_tmsg(MSGT_OSD
, MSGL_ERR
, "Fontconfig failed to select a font. "
1168 "Trying without fontconfig...\n");
1171 *fontp
=read_font_desc_ft(font_name
, 0, width
, height
, font_scale_factor
);