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"
54 #if (FREETYPE_MAJOR > 2) || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR >= 1)
55 #define HAVE_FREETYPE21
58 char *subtitle_font_encoding
= NULL
;
59 float text_font_scale_factor
= 3.5;
60 float osd_font_scale_factor
= 4.0;
61 float subtitle_font_radius
= 2.0;
62 float subtitle_font_thickness
= 2.0;
67 int subtitle_autoscale
= 3;
69 int vo_image_width
= 0;
70 int vo_image_height
= 0;
73 int using_freetype
= 0;
74 int font_fontconfig
= 0;
77 static unsigned int const colors
= 256;
78 static unsigned int const maxcolor
= 255;
79 static unsigned const base
= 256;
80 static unsigned const first_char
= 33;
81 #define MAX_CHARSET_SIZE 60000
83 static FT_Library library
;
85 #define OSD_CHARSET_SIZE 15
87 static FT_ULong osd_charset
[OSD_CHARSET_SIZE
] =
89 0xe001, 0xe002, 0xe003, 0xe004, 0xe005, 0xe006, 0xe007, 0xe008,
90 0xe009, 0xe00a, 0xe00b, 0xe010, 0xe011, 0xe012, 0xe013
93 static FT_ULong osd_charcodes
[OSD_CHARSET_SIZE
] =
95 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
96 0x09,0x0a,0x0b,0x10,0x11,0x12,0x13
99 #define f266ToInt(x) (((x)+32)>>6) // round fractional fixed point number to integer
100 // coordinates are in 26.6 pixels (i.e. 1/64th of pixels)
101 #define f266CeilToInt(x) (((x)+63)>>6) // ceiling
102 #define f266FloorToInt(x) ((x)>>6) // floor
103 #define f1616ToInt(x) (((x)+0x8000)>>16) // 16.16
104 #define floatTof266(x) ((int)((x)*(1<<6)+0.5))
106 #define ALIGN(x) (((x)+7)&~7) // 8 byte align
108 #define WARNING(msg, args...) mp_msg(MSGT_OSD, MSGL_WARN, msg "\n", ## args)
112 //static double ttime;
115 static void paste_bitmap(unsigned char *bbuffer
, FT_Bitmap
*bitmap
, int x
, int y
, int width
, int height
, int bwidth
) {
116 int drow
= x
+y
*width
;
119 if (bitmap
->pixel_mode
==ft_pixel_mode_mono
)
120 for (h
= bitmap
->rows
; h
>0 && height
> 0; --h
, height
--, drow
+=width
, srow
+=bitmap
->pitch
)
121 for (w
= bwidth
, sp
=dp
=0; w
>0; --w
, ++dp
, ++sp
)
122 bbuffer
[drow
+dp
] = (bitmap
->buffer
[srow
+sp
/8] & (0x80>>(sp
%8))) ? 255:0;
124 for (h
= bitmap
->rows
; h
>0 && height
> 0; --h
, height
--, drow
+=width
, srow
+=bitmap
->pitch
)
125 for (w
= bwidth
, sp
=dp
=0; w
>0; --w
, ++dp
, ++sp
)
126 bbuffer
[drow
+dp
] = bitmap
->buffer
[srow
+sp
];
130 static int check_font(font_desc_t
*desc
, float ppem
, int padding
, int pic_idx
,
131 int charset_size
, FT_ULong
*charset
, FT_ULong
*charcodes
,
134 FT_Face face
= desc
->faces
[pic_idx
];
135 int const load_flags
= FT_LOAD_DEFAULT
;
136 int ymin
= INT_MAX
, ymax
= INT_MIN
;
137 int space_advance
= 20;
139 unsigned char *bbuffer
;
140 int i
, uni_charmap
= 1;
142 error
= FT_Select_Charmap(face
, ft_encoding_unicode
);
143 // fprintf(stderr, "select unicode charmap: %d\n", error);
145 if (face
->charmap
==NULL
|| face
->charmap
->encoding
!=ft_encoding_unicode
) {
146 WARNING("Unicode charmap not available for this font. Very bad!");
148 error
= FT_Set_Charmap(face
, face
->charmaps
[0]);
149 if (error
) WARNING("No charmaps! Strange.");
153 if (FT_IS_SCALABLE(face
)) {
154 error
= FT_Set_Char_Size(face
, 0, floatTof266(ppem
), 0, 0);
155 if (error
) WARNING("FT_Set_Char_Size failed.");
158 int jppem
= face
->available_sizes
[0].height
;
159 /* find closest size */
160 for (i
= 0; i
<face
->num_fixed_sizes
; ++i
) {
161 if (fabs(face
->available_sizes
[i
].height
- ppem
) < abs(face
->available_sizes
[i
].height
- jppem
)) {
163 jppem
= face
->available_sizes
[i
].height
;
166 WARNING("Selected font is not scalable. Using ppem=%i.", face
->available_sizes
[j
].height
);
167 error
= FT_Set_Pixel_Sizes(face
, face
->available_sizes
[j
].width
, face
->available_sizes
[j
].height
);
168 if (error
) WARNING("FT_Set_Pixel_Sizes failed.");
171 if (FT_IS_FIXED_WIDTH(face
))
172 WARNING("Selected font is fixed-width.");
174 /* compute space advance */
175 error
= FT_Load_Char(face
, ' ', load_flags
);
176 if (error
) WARNING("spacewidth set to default.");
177 else space_advance
= f266ToInt(face
->glyph
->advance
.x
);
179 if (!desc
->spacewidth
) desc
->spacewidth
= 2*padding
+ space_advance
;
180 if (!desc
->charspace
) desc
->charspace
= -2*padding
;
181 if (!desc
->height
) desc
->height
= f266ToInt(face
->size
->metrics
.height
);
184 for (i
= 0; i
<charset_size
; ++i
) {
185 FT_ULong character
, code
;
188 character
= charset
[i
];
190 desc
->font
[unicode
?character
:code
] = pic_idx
;
195 glyph_index
= FT_Get_Char_Index(face
, uni_charmap
? character
:code
);
196 if (glyph_index
==0) {
197 WARNING("Glyph for char 0x%02lx|U+%04lX|%c not found.", code
, character
,
198 code
<' '||code
>255 ? '.':(char)code
);
199 desc
->font
[unicode
?character
:code
] = -1;
203 desc
->glyph_index
[unicode
?character
:code
] = glyph_index
;
205 // fprintf(stderr, "font height: %lf\n", (double)(face->bbox.yMax-face->bbox.yMin)/(double)face->units_per_EM*ppem);
206 // fprintf(stderr, "font width: %lf\n", (double)(face->bbox.xMax-face->bbox.xMin)/(double)face->units_per_EM*ppem);
208 ymax
= (double)(face
->bbox
.yMax
)/(double)face
->units_per_EM
*ppem
+1;
209 ymin
= (double)(face
->bbox
.yMin
)/(double)face
->units_per_EM
*ppem
-1;
211 width
= ppem
*(face
->bbox
.xMax
-face
->bbox
.xMin
)/face
->units_per_EM
+3+2*padding
;
212 if (desc
->max_width
< width
) desc
->max_width
= width
;
213 width
= ALIGN(width
);
214 desc
->pic_b
[pic_idx
]->charwidth
= width
;
217 mp_msg(MSGT_OSD
, MSGL_ERR
, "Wrong bounding box, width <= 0 !\n");
222 mp_msg(MSGT_OSD
, MSGL_ERR
, "Something went wrong. Use the source!\n");
226 height
= ymax
- ymin
+ 2*padding
;
228 mp_msg(MSGT_OSD
, MSGL_ERR
, "Wrong bounding box, height <= 0 !\n");
232 if (desc
->max_height
< height
) desc
->max_height
= height
;
233 desc
->pic_b
[pic_idx
]->charheight
= height
;
235 // fprintf(stderr, "font height2: %d\n", height);
236 desc
->pic_b
[pic_idx
]->baseline
= ymax
+ padding
;
237 desc
->pic_b
[pic_idx
]->padding
= padding
;
238 desc
->pic_b
[pic_idx
]->current_alloc
= 0;
239 desc
->pic_b
[pic_idx
]->current_count
= 0;
243 desc
->pic_b
[pic_idx
]->w
= width
;
244 desc
->pic_b
[pic_idx
]->h
= height
;
245 desc
->pic_b
[pic_idx
]->c
= colors
;
246 desc
->pic_b
[pic_idx
]->bmp
= bbuffer
;
247 desc
->pic_b
[pic_idx
]->pen
= 0;
265 for (y
= 0; y
<height
; y
++) {
266 for (x
= 0; x
<width
; x
++) {
270 const int x1
=(x
<r
) ? r
-x
: 0;
271 const int y1
=(y
<r
) ? r
-y
: 0;
272 const int x2
=(x
+r
>=width
) ? r
+width
-x
: 2*r
+1;
273 const int y2
=(y
+r
>=height
) ? r
+height
-y
: 2*r
+1;
274 register unsigned char *dstp
= t
+ (y1
+y
-r
)* stride
+ x
-r
;
275 //register int *mp = m + y1 *mwidth;
276 register unsigned char *mp
= m
+ msize
*src
+ y1
*mwidth
;
279 for(my
= y1
; my
<y2
; my
++){
281 for(mx
= x1
; mx
<x2
; mx
++){
282 if(dstp
[mx
] < mp
[mx
]) dstp
[mx
]= mp
[mx
];
295 static void outline1(
303 int skip
= stride
-width
;
305 for (x
= 0; x
<width
; ++x
, ++s
, ++t
) *t
= *s
;
308 for (y
= 1; y
<height
-1; ++y
) {
310 for (x
= 1; x
<width
-1; ++x
, ++s
, ++t
) {
323 *t
= v
>maxcolor
? maxcolor
: v
;
329 for (x
= 0; x
<width
; ++x
, ++s
, ++t
) *t
= *s
;
333 static void outline0(
340 for (y
= 0; y
<height
; ++y
) {
349 unsigned char *buffer
,
350 unsigned short *tmp2
,
360 unsigned char *s
= buffer
;
361 unsigned short *t
= tmp2
+1;
362 for(y
=0; y
<height
; y
++){
363 memset(t
-1, 0, (width
+1)*sizeof(short));
368 register unsigned short *dstp
= t
+ x
-r
;
370 unsigned *m3
= m2
+ src
*mwidth
;
371 for(mx
=r
-x
; mx
<mwidth
; mx
++){
377 for(; x
<width
-r
; x
++){
380 register unsigned short *dstp
= t
+ x
-r
;
382 unsigned *m3
= m2
+ src
*mwidth
;
383 for(mx
=0; mx
<mwidth
; mx
++){
392 register unsigned short *dstp
= t
+ x
-r
;
394 const int x2
= r
+width
-x
;
395 unsigned *m3
= m2
+ src
*mwidth
;
396 for(mx
=0; mx
<x2
; mx
++){
407 for(x
=0; x
<width
; x
++){
409 unsigned short *srcp
= t
+ y
*(width
+1) + 1;
412 register unsigned short *dstp
= srcp
- 1 + width
+1;
413 const int src2
= (src
+ 128)>>8;
414 unsigned *m3
= m2
+ src2
*mwidth
;
418 for(mx
=r
-1; mx
<mwidth
; mx
++){
424 for(; y
<height
-r
; y
++){
425 unsigned short *srcp
= t
+ y
*(width
+1) + 1;
428 register unsigned short *dstp
= srcp
- 1 - r
*(width
+1);
429 const int src2
= (src
+ 128)>>8;
430 unsigned *m3
= m2
+ src2
*mwidth
;
434 for(mx
=0; mx
<mwidth
; mx
++){
440 for(; y
<height
; y
++){
441 unsigned short *srcp
= t
+ y
*(width
+1) + 1;
444 const int y2
=r
+height
-y
;
445 register unsigned short *dstp
= srcp
- 1 - r
*(width
+1);
446 const int src2
= (src
+ 128)>>8;
447 unsigned *m3
= m2
+ src2
*mwidth
;
451 for(mx
=0; mx
<y2
; mx
++){
462 for(y
=0; y
<height
; y
++){
463 for(x
=0; x
<width
; x
++){
471 static void resample_alpha(unsigned char *abuf
, unsigned char *bbuf
, int width
, int height
, int stride
, float factor
)
475 for (i
= 0; i
< height
; i
++) {
476 unsigned char *a
= abuf
+i
*stride
;
477 unsigned char *b
= bbuf
+i
*stride
;
478 for(j
=0;j
<width
;j
++,a
++,b
++){
481 x
=255-((x
*f
)>>8); // scale
482 if (x
+y
>255) x
=255-y
; // to avoid overflows
483 if (x
<1) x
=1; else if (x
>=252) x
=0;
489 #define ALLOC_INCR 32
490 void render_one_glyph(font_desc_t
*desc
, int c
)
494 FT_BitmapGlyph glyph
;
495 int width
, height
, stride
, maxw
, off
;
496 unsigned char *abuffer
, *bbuffer
;
498 int const load_flags
= FT_LOAD_DEFAULT
;
500 int font
= desc
->font
[c
];
503 // fprintf(stderr, "render_one_glyph %d\n", c);
505 if (!desc
->dynamic
) return;
506 if (desc
->width
[c
] != -1) return;
507 if (desc
->font
[c
] == -1) return;
509 glyph_index
= desc
->glyph_index
[c
];
512 error
= FT_Load_Glyph(desc
->faces
[font
], glyph_index
, load_flags
);
514 WARNING("FT_Load_Glyph 0x%02x (char 0x%04x) failed.", glyph_index
, c
);
518 slot
= desc
->faces
[font
]->glyph
;
521 if (slot
->format
!= ft_glyph_format_bitmap
) {
522 error
= FT_Render_Glyph(slot
, ft_render_mode_normal
);
524 WARNING("FT_Render_Glyph 0x%04x (char 0x%04x) failed.", glyph_index
, c
);
530 // extract glyph image
531 error
= FT_Get_Glyph(slot
, (FT_Glyph
*)&glyph
);
533 WARNING("FT_Get_Glyph 0x%04x (char 0x%04x) failed.", glyph_index
, c
);
538 // fprintf(stderr, "glyph generated\n");
540 maxw
= desc
->pic_b
[font
]->charwidth
;
542 if (glyph
->bitmap
.width
> maxw
) {
543 fprintf(stderr
, "glyph too wide!\n");
546 // allocate new memory, if needed
547 // fprintf(stderr, "\n%d %d %d\n", desc->pic_b[font]->charwidth, desc->pic_b[font]->charheight, desc->pic_b[font]->current_alloc);
548 if (desc
->pic_b
[font
]->current_count
>= desc
->pic_b
[font
]->current_alloc
) {
549 int newsize
= desc
->pic_b
[font
]->charwidth
*desc
->pic_b
[font
]->charheight
*(desc
->pic_b
[font
]->current_alloc
+ALLOC_INCR
);
550 int increment
= desc
->pic_b
[font
]->charwidth
*desc
->pic_b
[font
]->charheight
*ALLOC_INCR
;
551 desc
->pic_b
[font
]->current_alloc
+= ALLOC_INCR
;
553 // fprintf(stderr, "\nns = %d inc = %d\n", newsize, increment);
555 desc
->pic_b
[font
]->bmp
= realloc(desc
->pic_b
[font
]->bmp
, newsize
);
556 desc
->pic_a
[font
]->bmp
= realloc(desc
->pic_a
[font
]->bmp
, newsize
);
558 off
= desc
->pic_b
[font
]->current_count
*desc
->pic_b
[font
]->charwidth
*desc
->pic_b
[font
]->charheight
;
559 memset(desc
->pic_b
[font
]->bmp
+off
, 0, increment
);
560 memset(desc
->pic_a
[font
]->bmp
+off
, 0, increment
);
563 abuffer
= desc
->pic_a
[font
]->bmp
;
564 bbuffer
= desc
->pic_b
[font
]->bmp
;
566 off
= desc
->pic_b
[font
]->current_count
*desc
->pic_b
[font
]->charwidth
*desc
->pic_b
[font
]->charheight
;
568 paste_bitmap(bbuffer
+off
,
570 desc
->pic_b
[font
]->padding
+ glyph
->left
,
571 desc
->pic_b
[font
]->baseline
- glyph
->top
,
572 desc
->pic_b
[font
]->charwidth
, desc
->pic_b
[font
]->charheight
,
573 glyph
->bitmap
.width
<= maxw
? glyph
->bitmap
.width
: maxw
);
575 // fprintf(stderr, "glyph pasted\n");
576 FT_Done_Glyph((FT_Glyph
)glyph
);
579 pen_xa
= f266ToInt(slot
->advance
.x
) + 2*desc
->pic_b
[font
]->padding
;
580 if (pen_xa
> maxw
) pen_xa
= maxw
;
582 desc
->start
[c
] = off
;
583 width
= desc
->width
[c
] = pen_xa
;
584 height
= desc
->pic_b
[font
]->charheight
;
585 stride
= desc
->pic_b
[font
]->w
;
587 if (desc
->tables
.o_r
== 0) {
588 outline0(bbuffer
+off
, abuffer
+off
, width
, height
, stride
);
589 } else if (desc
->tables
.o_r
== 1) {
590 outline1(bbuffer
+off
, abuffer
+off
, width
, height
, stride
);
592 outline(bbuffer
+off
, abuffer
+off
, width
, height
, stride
,
593 desc
->tables
.omt
, desc
->tables
.o_r
, desc
->tables
.o_w
,
594 desc
->tables
.o_size
);
596 // fprintf(stderr, "fg: outline t = %lf\n", GetTimer()-t);
598 if (desc
->tables
.g_r
) {
599 blur(abuffer
+off
, desc
->tables
.tmp
, width
, height
, stride
,
600 desc
->tables
.gt2
, desc
->tables
.g_r
,
602 // fprintf(stderr, "fg: blur t = %lf\n", GetTimer()-t);
605 resample_alpha(abuffer
+off
, bbuffer
+off
, width
, height
, stride
, font_factor
);
607 desc
->pic_b
[font
]->current_count
++;
611 static int prepare_font(font_desc_t
*desc
, FT_Face face
, float ppem
, int pic_idx
,
612 int charset_size
, FT_ULong
*charset
, FT_ULong
*charcodes
, int unicode
,
613 double thickness
, double radius
)
616 int padding
= ceil(radius
) + ceil(thickness
);
618 desc
->faces
[pic_idx
] = face
;
620 desc
->pic_a
[pic_idx
] = malloc(sizeof(raw_file
));
621 if (!desc
->pic_a
[pic_idx
]) return -1;
622 desc
->pic_b
[pic_idx
] = malloc(sizeof(raw_file
));
623 if (!desc
->pic_b
[pic_idx
]) return -1;
625 desc
->pic_a
[pic_idx
]->bmp
= NULL
;
626 desc
->pic_a
[pic_idx
]->pal
= NULL
;
627 desc
->pic_b
[pic_idx
]->bmp
= NULL
;
628 desc
->pic_b
[pic_idx
]->pal
= NULL
;
630 desc
->pic_a
[pic_idx
]->pal
= malloc(sizeof(unsigned char)*256*3);
631 if (!desc
->pic_a
[pic_idx
]->pal
) return -1;
632 for (i
= 0; i
<768; ++i
) desc
->pic_a
[pic_idx
]->pal
[i
] = i
/3;
634 desc
->pic_b
[pic_idx
]->pal
= malloc(sizeof(unsigned char)*256*3);
635 if (!desc
->pic_b
[pic_idx
]->pal
) return -1;
636 for (i
= 0; i
<768; ++i
) desc
->pic_b
[pic_idx
]->pal
[i
] = i
/3;
638 // ttime = GetTimer();
639 err
= check_font(desc
, ppem
, padding
, pic_idx
, charset_size
, charset
, charcodes
, unicode
);
640 // ttime=GetTimer()-ttime;
641 // printf("render: %7lf us\n",ttime);
643 // fprintf(stderr, "fg: render t = %lf\n", GetTimer()-t);
645 desc
->pic_a
[pic_idx
]->w
= desc
->pic_b
[pic_idx
]->w
;
646 desc
->pic_a
[pic_idx
]->h
= desc
->pic_b
[pic_idx
]->h
;
647 desc
->pic_a
[pic_idx
]->c
= colors
;
649 desc
->pic_a
[pic_idx
]->bmp
= NULL
;
651 // fprintf(stderr, "fg: w = %d, h = %d\n", desc->pic_a[pic_idx]->w, desc->pic_a[pic_idx]->h);
656 static int generate_tables(font_desc_t
*desc
, double thickness
, double radius
)
658 int width
= desc
->max_height
;
659 int height
= desc
->max_width
;
661 double A
= log(1.0/base
)/(radius
*radius
*2);
663 double volume_diff
, volume_factor
= 0;
666 desc
->tables
.g_r
= ceil(radius
);
667 desc
->tables
.o_r
= ceil(thickness
);
668 desc
->tables
.g_w
= 2*desc
->tables
.g_r
+1;
669 desc
->tables
.o_w
= 2*desc
->tables
.o_r
+1;
670 desc
->tables
.o_size
= desc
->tables
.o_w
* desc
->tables
.o_w
;
672 // fprintf(stderr, "o_r = %d\n", desc->tables.o_r);
674 if (desc
->tables
.g_r
) {
675 desc
->tables
.g
= malloc(desc
->tables
.g_w
* sizeof(unsigned));
676 desc
->tables
.gt2
= malloc(256 * desc
->tables
.g_w
* sizeof(unsigned));
677 if (desc
->tables
.g
==NULL
|| desc
->tables
.gt2
==NULL
) {
681 desc
->tables
.om
= malloc(desc
->tables
.o_w
*desc
->tables
.o_w
* sizeof(unsigned));
682 desc
->tables
.omt
= malloc(desc
->tables
.o_size
*256);
684 omtp
= desc
->tables
.omt
;
685 desc
->tables
.tmp
= malloc((width
+1)*height
*sizeof(short));
687 if (desc
->tables
.om
==NULL
|| desc
->tables
.omt
==NULL
|| desc
->tables
.tmp
==NULL
) {
691 if (desc
->tables
.g_r
) {
692 // gaussian curve with volume = 256
693 for (volume_diff
=10000000; volume_diff
>0.0000001; volume_diff
*=0.5){
694 volume_factor
+= volume_diff
;
695 desc
->tables
.volume
=0;
696 for (i
= 0; i
<desc
->tables
.g_w
; ++i
) {
697 desc
->tables
.g
[i
] = (unsigned)(exp(A
* (i
-desc
->tables
.g_r
)*(i
-desc
->tables
.g_r
)) * volume_factor
+ .5);
698 desc
->tables
.volume
+= desc
->tables
.g
[i
];
700 if(desc
->tables
.volume
>256) volume_factor
-= volume_diff
;
702 desc
->tables
.volume
=0;
703 for (i
= 0; i
<desc
->tables
.g_w
; ++i
) {
704 desc
->tables
.g
[i
] = (unsigned)(exp(A
* (i
-desc
->tables
.g_r
)*(i
-desc
->tables
.g_r
)) * volume_factor
+ .5);
705 desc
->tables
.volume
+= desc
->tables
.g
[i
];
709 for(mx
=0;mx
<desc
->tables
.g_w
;mx
++){
711 desc
->tables
.gt2
[mx
+i
*desc
->tables
.g_w
] = i
*desc
->tables
.g
[mx
];
717 for (my
= 0; my
<desc
->tables
.o_w
; ++my
) {
718 for (mx
= 0; mx
<desc
->tables
.o_w
; ++mx
) {
719 // antialiased circle would be perfect here, but this one is good enough
720 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
));
721 desc
->tables
.om
[mx
+my
*desc
->tables
.o_w
] = d
>=1 ? base
: d
<=0 ? 0 : (d
*base
+ .5);
727 for(mx
=0;mx
<desc
->tables
.o_size
;mx
++) *(omtp
++) = (i
*desc
->tables
.om
[mx
] + (base
/2))/base
;
734 /* decode from 'encoding' to unicode */
735 static FT_ULong
decode_char(iconv_t
*cd
, char c
) {
738 char *outbuf
= (char*)&o
;
739 size_t inbytesleft
= 1;
740 size_t outbytesleft
= sizeof(FT_ULong
);
742 iconv(*cd
, &inbuf
, &inbytesleft
, &outbuf
, &outbytesleft
);
744 /* convert unicode BigEndian -> MachineEndian */
747 // if (count==-1) o = 0; // not OK, at least my iconv() returns E2BIG for all
748 if (outbytesleft
!=0) o
= 0;
750 /* we don't want control characters */
751 if (o
>=0x7f && o
<0xa0) o
= 0;
755 static int prepare_charset(char *charmap
, char *encoding
, FT_ULong
*charset
, FT_ULong
*charcodes
) {
761 // check if ucs-4 is available
762 cd
= iconv_open(charmap
, charmap
);
763 if (cd
==(iconv_t
)-1) {
764 mp_msg(MSGT_OSD
, MSGL_ERR
, "iconv doesn't know %s encoding. Use the source!\n", charmap
);
770 cd
= iconv_open(charmap
, encoding
);
771 if (cd
==(iconv_t
)-1) {
772 mp_msg(MSGT_OSD
, MSGL_ERR
, "Unsupported encoding `%s', use iconv --list to list character sets known on your system.\n", encoding
);
776 charset_size
= 256 - first_char
;
777 for (i
= 0; i
<charset_size
; ++i
) {
778 charcodes
[count
] = i
+first_char
;
779 charset
[count
] = decode_char(&cd
, i
+first_char
);
780 if (charset
[count
]!=0) ++count
;
782 charcodes
[count
] = charset
[count
] = 0; ++count
;
783 charset_size
= count
;
786 if (charset_size
==0) {
787 mp_msg(MSGT_OSD
, MSGL_ERR
, "No characters to render!\n");
794 static int prepare_charset_unicode(FT_Face face
, FT_ULong
*charset
, FT_ULong
*charcodes
) {
795 #ifdef HAVE_FREETYPE21
803 if (face
->charmap
==NULL
|| face
->charmap
->encoding
!=ft_encoding_unicode
) {
804 WARNING("Unicode charmap not available for this font. Very bad!");
807 #ifdef HAVE_FREETYPE21
809 charcode
= FT_Get_First_Char( face
, &gindex
);
810 while (gindex
!= 0) {
811 if (charcode
< 65536 && charcode
>= 33) { // sanity check
812 charset
[i
] = charcode
;
816 charcode
= FT_Get_Next_Char( face
, charcode
, &gindex
);
819 // for FT < 2.1 we have to use brute force enumeration
821 for (j
= 33; j
< 65536; j
++) {
822 gindex
= FT_Get_Char_Index(face
, j
);
830 mp_msg(MSGT_OSD
, MSGL_V
, "Unicode font: %d glyphs.\n", i
);
836 static font_desc_t
* init_font_desc(void)
841 desc
= malloc(sizeof(font_desc_t
));
842 if(!desc
) return NULL
;
843 memset(desc
,0,sizeof(font_desc_t
));
847 /* setup sane defaults */
853 desc
->spacewidth
= 0;
856 desc
->max_height
= 0;
859 desc
->tables
.g
= NULL
;
860 desc
->tables
.gt2
= NULL
;
861 desc
->tables
.om
= NULL
;
862 desc
->tables
.omt
= NULL
;
863 desc
->tables
.tmp
= NULL
;
865 for(i
= 0; i
< 65536; i
++)
866 desc
->start
[i
] = desc
->width
[i
] = desc
->font
[i
] = -1;
867 for(i
= 0; i
< 16; i
++)
868 desc
->pic_a
[i
] = desc
->pic_b
[i
] = NULL
;
873 void free_font_desc(font_desc_t
*desc
)
879 // if (!desc->dynamic) return; // some vo_aa crap, better leaking than crashing
881 if (desc
->name
) free(desc
->name
);
882 if (desc
->fpath
) free(desc
->fpath
);
884 for(i
= 0; i
< 16; i
++) {
885 if (desc
->pic_a
[i
]) {
886 if (desc
->pic_a
[i
]->bmp
) free(desc
->pic_a
[i
]->bmp
);
887 if (desc
->pic_a
[i
]->pal
) free(desc
->pic_a
[i
]->pal
);
888 free (desc
->pic_a
[i
]);
890 if (desc
->pic_b
[i
]) {
891 if (desc
->pic_b
[i
]->bmp
) free(desc
->pic_b
[i
]->bmp
);
892 if (desc
->pic_b
[i
]->pal
) free(desc
->pic_b
[i
]->pal
);
893 free (desc
->pic_b
[i
]);
897 if (desc
->tables
.g
) free(desc
->tables
.g
);
898 if (desc
->tables
.gt2
) free(desc
->tables
.gt2
);
899 if (desc
->tables
.om
) free(desc
->tables
.om
);
900 if (desc
->tables
.omt
) free(desc
->tables
.omt
);
901 if (desc
->tables
.tmp
) free(desc
->tables
.tmp
);
903 for(i
= 0; i
< desc
->face_cnt
; i
++) {
904 FT_Done_Face(desc
->faces
[i
]);
910 static int load_sub_face(const char *name
, int face_index
, FT_Face
*face
)
914 if (name
) err
= FT_New_Face(library
, name
, face_index
, face
);
917 char *font_file
= get_path("subfont.ttf");
918 err
= FT_New_Face(library
, font_file
, 0, face
);
921 err
= FT_New_Face(library
, MPLAYER_DATADIR
"/subfont.ttf", 0, face
);
923 mp_msg(MSGT_OSD
, MSGL_ERR
, MSGTR_LIBVO_FONT_LOAD_FT_NewFaceFailed
);
931 static int load_osd_face(FT_Face
*face
)
933 if ( FT_New_Memory_Face(library
, osd_font_pfb
, sizeof(osd_font_pfb
), 0, face
) ) {
934 mp_msg(MSGT_OSD
, MSGL_ERR
, MSGTR_LIBVO_FONT_LOAD_FT_NewMemoryFaceFailed
);
940 int kerning(font_desc_t
*desc
, int prevc
, int c
)
944 if (!desc
->dynamic
) return 0;
945 if (prevc
< 0 || c
< 0) return 0;
946 if (desc
->font
[prevc
] != desc
->font
[c
]) return 0;
947 if (desc
->font
[prevc
] == -1 || desc
->font
[c
] == -1) return 0;
948 FT_Get_Kerning(desc
->faces
[desc
->font
[c
]],
949 desc
->glyph_index
[prevc
], desc
->glyph_index
[c
],
950 ft_kerning_default
, &kern
);
952 // fprintf(stderr, "kern: %c %c %d\n", prevc, c, f266ToInt(kern.x));
954 return f266ToInt(kern
.x
);
957 font_desc_t
* read_font_desc_ft(const char *fname
, int face_index
, int movie_width
, int movie_height
, float font_scale_factor
)
959 font_desc_t
*desc
= NULL
;
963 FT_ULong
*my_charset
= malloc(MAX_CHARSET_SIZE
* sizeof(FT_ULong
)); /* characters we want to render; Unicode */
964 FT_ULong
*my_charcodes
= malloc(MAX_CHARSET_SIZE
* sizeof(FT_ULong
)); /* character codes in 'encoding' */
966 char *charmap
= "ucs-4";
974 float subtitle_font_ppem
;
977 if (my_charset
== NULL
|| my_charcodes
== NULL
) {
978 mp_msg(MSGT_OSD
, MSGL_ERR
, "subtitle font: malloc failed.\n");
982 switch (subtitle_autoscale
) {
984 movie_size
= movie_height
;
987 movie_size
= movie_width
;
990 movie_size
= sqrt(movie_height
*movie_height
+movie_width
*movie_width
);
997 subtitle_font_ppem
= movie_size
*font_scale_factor
/100.0;
998 osd_font_ppem
= movie_size
*(font_scale_factor
+1)/100.0;
1000 if (subtitle_font_ppem
< 5) subtitle_font_ppem
= 5;
1001 if (osd_font_ppem
< 5) osd_font_ppem
= 5;
1003 if (subtitle_font_ppem
> 128) subtitle_font_ppem
= 128;
1004 if (osd_font_ppem
> 128) osd_font_ppem
= 128;
1006 if ((subtitle_font_encoding
== NULL
)
1007 || (strcasecmp(subtitle_font_encoding
, "unicode") == 0)) {
1013 desc
= init_font_desc();
1014 if(!desc
) goto err_out
;
1018 /* generate the subtitle font */
1019 err
= load_sub_face(fname
, face_index
, &face
);
1021 mp_msg(MSGT_OSD
, MSGL_WARN
, MSGTR_LIBVO_FONT_LOAD_FT_SubFaceFailed
);
1028 charset_size
= prepare_charset_unicode(face
, my_charset
, my_charcodes
);
1030 if (subtitle_font_encoding
) {
1031 charset_size
= prepare_charset(charmap
, subtitle_font_encoding
, my_charset
, my_charcodes
);
1033 charset_size
= prepare_charset(charmap
, "iso-8859-1", my_charset
, my_charcodes
);
1037 if (charset_size
< 0) {
1038 mp_msg(MSGT_OSD
, MSGL_ERR
, MSGTR_LIBVO_FONT_LOAD_FT_SubFontCharsetFailed
);
1045 // fprintf(stderr, "fg: prepare t = %lf\n", GetTimer()-t);
1047 err
= prepare_font(desc
, face
, subtitle_font_ppem
, desc
->face_cnt
-1,
1048 charset_size
, my_charset
, my_charcodes
, unicode
,
1049 subtitle_font_thickness
, subtitle_font_radius
);
1052 mp_msg(MSGT_OSD
, MSGL_ERR
, MSGTR_LIBVO_FONT_LOAD_FT_CannotPrepareSubtitleFont
);
1058 /* generate the OSD font */
1059 err
= load_osd_face(&face
);
1065 err
= prepare_font(desc
, face
, osd_font_ppem
, desc
->face_cnt
-1,
1066 OSD_CHARSET_SIZE
, osd_charset
, osd_charcodes
, 0,
1067 subtitle_font_thickness
, subtitle_font_radius
);
1070 mp_msg(MSGT_OSD
, MSGL_ERR
, MSGTR_LIBVO_FONT_LOAD_FT_CannotPrepareOSDFont
);
1074 err
= generate_tables(desc
, subtitle_font_thickness
, subtitle_font_radius
);
1077 mp_msg(MSGT_OSD
, MSGL_ERR
, MSGTR_LIBVO_FONT_LOAD_FT_CannotGenerateTables
);
1083 desc
->width
[' ']=desc
->spacewidth
;
1086 if (desc
->font
[j
] < 0) j
= '?';
1087 if (desc
->font
[j
] < 0) j
= ' ';
1088 render_one_glyph(desc
, j
);
1089 for(i
= 0; i
< 65536; i
++) {
1090 if (desc
->font
[i
] < 0 && i
!= ' ') {
1091 desc
->start
[i
] = desc
->start
[j
];
1092 desc
->width
[i
] = desc
->width
[j
];
1093 desc
->font
[i
] = desc
->font
[j
];
1102 free_font_desc(desc
);
1108 int init_freetype(void)
1112 /* initialize freetype */
1113 err
= FT_Init_FreeType(&library
);
1115 mp_msg(MSGT_OSD
, MSGL_ERR
, "Init_FreeType failed.\n");
1118 mp_msg(MSGT_OSD
, MSGL_V
, "init_freetype\n");
1123 int done_freetype(void)
1127 if (!using_freetype
)
1130 err
= FT_Done_FreeType(library
);
1132 mp_msg(MSGT_OSD
, MSGL_ERR
, MSGTR_LIBVO_FONT_LOAD_FT_DoneFreeTypeFailed
);
1139 void load_font_ft(int width
, int height
, font_desc_t
** fontp
, const char *font_name
, float font_scale_factor
)
1141 #ifdef CONFIG_FONTCONFIG
1142 FcPattern
*fc_pattern
;
1143 FcPattern
*fc_pattern2
;
1148 font_desc_t
*vo_font
= *fontp
;
1149 vo_image_width
= width
;
1150 vo_image_height
= height
;
1152 // protection against vo_aa font hacks
1153 if (vo_font
&& !vo_font
->dynamic
) return;
1155 if (vo_font
) free_font_desc(vo_font
);
1157 #ifdef CONFIG_FONTCONFIG
1158 if (font_fontconfig
> 0)
1161 font_name
= strdup("sans-serif");
1163 fc_pattern
= FcNameParse(font_name
);
1164 FcConfigSubstitute(0, fc_pattern
, FcMatchPattern
);
1165 FcDefaultSubstitute(fc_pattern
);
1166 fc_pattern2
= fc_pattern
;
1167 fc_pattern
= FcFontMatch(0, fc_pattern
, 0);
1168 FcPatternDestroy(fc_pattern2
);
1169 FcPatternGetBool(fc_pattern
, FC_SCALABLE
, 0, &scalable
);
1170 if (scalable
!= FcTrue
) {
1171 FcPatternDestroy(fc_pattern
);
1172 fc_pattern
= FcNameParse("sans-serif");
1173 FcConfigSubstitute(0, fc_pattern
, FcMatchPattern
);
1174 FcDefaultSubstitute(fc_pattern
);
1175 fc_pattern2
= fc_pattern
;
1176 fc_pattern
= FcFontMatch(0, fc_pattern
, 0);
1177 FcPatternDestroy(fc_pattern2
);
1179 // s doesn't need to be freed according to fontconfig docs
1180 FcPatternGetString(fc_pattern
, FC_FILE
, 0, &s
);
1181 FcPatternGetInteger(fc_pattern
, FC_INDEX
, 0, &face_index
);
1182 *fontp
=read_font_desc_ft(s
, face_index
, width
, height
, font_scale_factor
);
1183 FcPatternDestroy(fc_pattern
);
1187 *fontp
=read_font_desc_ft(font_name
, 0, width
, height
, font_scale_factor
);