Mercurial > mplayer.hg
comparison libass/ass_font.c @ 34295:6e7f60f6f9d4
Update libass to 0.10 release.
Patch by [subjunk gmail com], see bug #2008.
author | reimar |
---|---|
date | Sat, 03 Dec 2011 21:35:56 +0000 |
parents | 88eebbbbd6a0 |
children | c3aaaf17c721 |
comparison
equal
deleted
inserted
replaced
34294:d30ea496ed2a | 34295:6e7f60f6f9d4 |
---|---|
28 #include <strings.h> | 28 #include <strings.h> |
29 | 29 |
30 #include "ass.h" | 30 #include "ass.h" |
31 #include "ass_library.h" | 31 #include "ass_library.h" |
32 #include "ass_font.h" | 32 #include "ass_font.h" |
33 #include "ass_bitmap.h" | |
34 #include "ass_cache.h" | |
35 #include "ass_fontconfig.h" | 33 #include "ass_fontconfig.h" |
36 #include "ass_utils.h" | 34 #include "ass_utils.h" |
37 | 35 #include "ass_shaper.h" |
38 #define VERTICAL_LOWER_BOUND 0x02f1 | |
39 | 36 |
40 /** | 37 /** |
41 * Select a good charmap, prefer Microsoft Unicode charmaps. | 38 * Select a good charmap, prefer Microsoft Unicode charmaps. |
42 * Otherwise, let FreeType decide. | 39 * Otherwise, let FreeType decide. |
43 */ | 40 */ |
88 for (i = 0; i < library->num_fontdata; ++i) | 85 for (i = 0; i < library->num_fontdata; ++i) |
89 if (strcasecmp(name, library->fontdata[i].name) == 0) | 86 if (strcasecmp(name, library->fontdata[i].name) == 0) |
90 return i; | 87 return i; |
91 return -1; | 88 return -1; |
92 } | 89 } |
93 | |
94 static void face_set_size(FT_Face face, double size); | |
95 | 90 |
96 static void buggy_font_workaround(FT_Face face) | 91 static void buggy_font_workaround(FT_Face face) |
97 { | 92 { |
98 // Some fonts have zero Ascender/Descender fields in 'hhea' table. | 93 // Some fonts have zero Ascender/Descender fields in 'hhea' table. |
99 // In this case, get the information from 'os2' table or, as | 94 // In this case, get the information from 'os2' table or, as |
159 } | 154 } |
160 charmap_magic(font->library, face); | 155 charmap_magic(font->library, face); |
161 buggy_font_workaround(face); | 156 buggy_font_workaround(face); |
162 | 157 |
163 font->faces[font->n_faces++] = face; | 158 font->faces[font->n_faces++] = face; |
164 face_set_size(face, font->size); | 159 ass_face_set_size(face, font->size); |
165 free(path); | 160 free(path); |
166 return font->n_faces - 1; | 161 return font->n_faces - 1; |
167 } | 162 } |
168 | 163 |
169 /** | 164 /** |
170 * \brief Create a new ASS_Font according to "desc" argument | 165 * \brief Create a new ASS_Font according to "desc" argument |
171 */ | 166 */ |
172 ASS_Font *ass_font_new(void *font_cache, ASS_Library *library, | 167 ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library, |
173 FT_Library ftlibrary, void *fc_priv, | 168 FT_Library ftlibrary, void *fc_priv, |
174 ASS_FontDesc *desc) | 169 ASS_FontDesc *desc) |
175 { | 170 { |
176 int error; | 171 int error; |
177 ASS_Font *fontp; | 172 ASS_Font *fontp; |
178 ASS_Font font; | 173 ASS_Font font; |
179 | 174 |
180 fontp = ass_font_cache_find((Hashmap *) font_cache, desc); | 175 fontp = ass_cache_get(font_cache, desc); |
181 if (fontp) | 176 if (fontp) |
182 return fontp; | 177 return fontp; |
183 | 178 |
184 font.library = library; | 179 font.library = library; |
185 font.ftlibrary = ftlibrary; | 180 font.ftlibrary = ftlibrary; |
181 font.shaper_priv = NULL; | |
186 font.n_faces = 0; | 182 font.n_faces = 0; |
187 font.desc.family = strdup(desc->family); | 183 font.desc.family = strdup(desc->family); |
188 font.desc.treat_family_as_pattern = desc->treat_family_as_pattern; | 184 font.desc.treat_family_as_pattern = desc->treat_family_as_pattern; |
189 font.desc.bold = desc->bold; | 185 font.desc.bold = desc->bold; |
190 font.desc.italic = desc->italic; | 186 font.desc.italic = desc->italic; |
197 error = add_face(fc_priv, &font, 0); | 193 error = add_face(fc_priv, &font, 0); |
198 if (error == -1) { | 194 if (error == -1) { |
199 free(font.desc.family); | 195 free(font.desc.family); |
200 return 0; | 196 return 0; |
201 } else | 197 } else |
202 return ass_font_cache_add((Hashmap *) font_cache, &font); | 198 return ass_cache_put(font_cache, &font.desc, &font); |
203 } | 199 } |
204 | 200 |
205 /** | 201 /** |
206 * \brief Set font transformation matrix and shift vector | 202 * \brief Set font transformation matrix and shift vector |
207 **/ | 203 **/ |
214 font->v.x = v->x; | 210 font->v.x = v->x; |
215 font->v.y = v->y; | 211 font->v.y = v->y; |
216 } | 212 } |
217 } | 213 } |
218 | 214 |
219 static void face_set_size(FT_Face face, double size) | 215 void ass_face_set_size(FT_Face face, double size) |
220 { | 216 { |
221 TT_HoriHeader *hori = FT_Get_Sfnt_Table(face, ft_sfnt_hhea); | 217 TT_HoriHeader *hori = FT_Get_Sfnt_Table(face, ft_sfnt_hhea); |
222 TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); | 218 TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); |
223 double mscale = 1.; | 219 double mscale = 1.; |
224 FT_Size_RequestRec rq; | 220 FT_Size_RequestRec rq; |
249 { | 245 { |
250 int i; | 246 int i; |
251 if (font->size != size) { | 247 if (font->size != size) { |
252 font->size = size; | 248 font->size = size; |
253 for (i = 0; i < font->n_faces; ++i) | 249 for (i = 0; i < font->n_faces; ++i) |
254 face_set_size(font->faces[i], size); | 250 ass_face_set_size(font->faces[i], size); |
255 } | 251 } |
256 } | 252 } |
257 | 253 |
258 /** | 254 /** |
259 * \brief Get maximal font ascender and descender. | 255 * \brief Get maximal font ascender and descender. |
274 *desc = FT_MulFix(os2->usWinDescent, y_scale); | 270 *desc = FT_MulFix(os2->usWinDescent, y_scale); |
275 } else { | 271 } else { |
276 *asc = FT_MulFix(face->ascender, y_scale); | 272 *asc = FT_MulFix(face->ascender, y_scale); |
277 *desc = FT_MulFix(-face->descender, y_scale); | 273 *desc = FT_MulFix(-face->descender, y_scale); |
278 } | 274 } |
279 if (font->desc.vertical && ch >= VERTICAL_LOWER_BOUND) { | |
280 *asc = FT_MulFix(face->max_advance_width, y_scale); | |
281 } | |
282 return; | 275 return; |
283 } | 276 } |
284 } | 277 } |
285 | 278 |
286 *asc = *desc = 0; | 279 *asc = *desc = 0; |
386 } | 379 } |
387 | 380 |
388 return 0; | 381 return 0; |
389 } | 382 } |
390 | 383 |
384 void outline_copy(FT_Library lib, FT_Outline *source, FT_Outline **dest) | |
385 { | |
386 if (source == NULL) { | |
387 *dest = NULL; | |
388 return; | |
389 } | |
390 *dest = calloc(1, sizeof(**dest)); | |
391 | |
392 FT_Outline_New(lib, source->n_points, source->n_contours, *dest); | |
393 FT_Outline_Copy(source, *dest); | |
394 } | |
395 | |
396 void outline_free(FT_Library lib, FT_Outline *outline) | |
397 { | |
398 if (outline) | |
399 FT_Outline_Done(lib, outline); | |
400 free(outline); | |
401 } | |
402 | |
391 /** | 403 /** |
392 * Slightly embold a glyph without touching its metrics | 404 * Slightly embold a glyph without touching its metrics |
393 */ | 405 */ |
394 static void ass_glyph_embolden(FT_GlyphSlot slot) | 406 static void ass_glyph_embolden(FT_GlyphSlot slot) |
395 { | 407 { |
403 | 415 |
404 FT_Outline_Embolden(&slot->outline, str); | 416 FT_Outline_Embolden(&slot->outline, str); |
405 } | 417 } |
406 | 418 |
407 /** | 419 /** |
408 * \brief Get a glyph | 420 * \brief Get glyph and face index |
409 * \param ch character code | 421 * Finds a face that has the requested codepoint and returns both face |
410 **/ | 422 * and glyph index. |
411 FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font, | 423 */ |
412 uint32_t ch, ASS_Hinting hinting, int deco) | 424 int ass_font_get_index(void *fcpriv, ASS_Font *font, uint32_t symbol, |
413 { | 425 int *face_index, int *glyph_index) |
414 int error; | 426 { |
415 int index = 0; | 427 int index = 0; |
416 int i; | 428 int i; |
417 FT_Glyph glyph; | |
418 FT_Face face = 0; | 429 FT_Face face = 0; |
419 int flags = 0; | 430 |
420 int vertical = font->desc.vertical; | 431 *glyph_index = 0; |
421 | 432 |
422 if (ch < 0x20) | 433 if (symbol < 0x20) { |
434 *face_index = 0; | |
423 return 0; | 435 return 0; |
436 } | |
424 // Handle NBSP like a regular space when rendering the glyph | 437 // Handle NBSP like a regular space when rendering the glyph |
425 if (ch == 0xa0) | 438 if (symbol == 0xa0) |
426 ch = ' '; | 439 symbol = ' '; |
427 if (font->n_faces == 0) | 440 if (font->n_faces == 0) { |
441 *face_index = 0; | |
428 return 0; | 442 return 0; |
429 | 443 } |
430 for (i = 0; i < font->n_faces; ++i) { | 444 |
445 // try with the requested face | |
446 if (*face_index < font->n_faces) { | |
447 face = font->faces[*face_index]; | |
448 index = FT_Get_Char_Index(face, symbol); | |
449 } | |
450 | |
451 // not found in requested face, try all others | |
452 for (i = 0; i < font->n_faces && index == 0; ++i) { | |
431 face = font->faces[i]; | 453 face = font->faces[i]; |
432 index = FT_Get_Char_Index(face, ch); | 454 index = FT_Get_Char_Index(face, symbol); |
433 if (index) | 455 if (index) |
434 break; | 456 *face_index = i; |
435 } | 457 } |
436 | 458 |
437 #ifdef CONFIG_FONTCONFIG | 459 #ifdef CONFIG_FONTCONFIG |
438 if (index == 0) { | 460 if (index == 0) { |
439 int face_idx; | 461 int face_idx; |
440 ass_msg(font->library, MSGL_INFO, | 462 ass_msg(font->library, MSGL_INFO, |
441 "Glyph 0x%X not found, selecting one more " | 463 "Glyph 0x%X not found, selecting one more " |
442 "font for (%s, %d, %d)", ch, font->desc.family, | 464 "font for (%s, %d, %d)", symbol, font->desc.family, |
443 font->desc.bold, font->desc.italic); | 465 font->desc.bold, font->desc.italic); |
444 face_idx = add_face(fontconfig_priv, font, ch); | 466 face_idx = *face_index = add_face(fcpriv, font, symbol); |
445 if (face_idx >= 0) { | 467 if (face_idx >= 0) { |
446 face = font->faces[face_idx]; | 468 face = font->faces[face_idx]; |
447 index = FT_Get_Char_Index(face, ch); | 469 index = FT_Get_Char_Index(face, symbol); |
448 if (index == 0 && face->num_charmaps > 0) { | 470 if (index == 0 && face->num_charmaps > 0) { |
449 int i; | 471 int i; |
450 ass_msg(font->library, MSGL_WARN, | 472 ass_msg(font->library, MSGL_WARN, |
451 "Glyph 0x%X not found, broken font? Trying all charmaps", ch); | 473 "Glyph 0x%X not found, broken font? Trying all charmaps", symbol); |
452 for (i = 0; i < face->num_charmaps; i++) { | 474 for (i = 0; i < face->num_charmaps; i++) { |
453 FT_Set_Charmap(face, face->charmaps[i]); | 475 FT_Set_Charmap(face, face->charmaps[i]); |
454 if ((index = FT_Get_Char_Index(face, ch)) != 0) break; | 476 if ((index = FT_Get_Char_Index(face, symbol)) != 0) break; |
455 } | 477 } |
456 } | 478 } |
457 if (index == 0) { | 479 if (index == 0) { |
458 ass_msg(font->library, MSGL_ERR, | 480 ass_msg(font->library, MSGL_ERR, |
459 "Glyph 0x%X not found in font for (%s, %d, %d)", | 481 "Glyph 0x%X not found in font for (%s, %d, %d)", |
460 ch, font->desc.family, font->desc.bold, | 482 symbol, font->desc.family, font->desc.bold, |
461 font->desc.italic); | 483 font->desc.italic); |
462 } | 484 } |
463 } | 485 } |
464 } | 486 } |
465 #endif | 487 #endif |
488 // FIXME: make sure we have a valid face_index. this is a HACK. | |
489 *face_index = FFMAX(*face_index, 0); | |
490 *glyph_index = index; | |
491 | |
492 return 1; | |
493 } | |
494 | |
495 /** | |
496 * \brief Get a glyph | |
497 * \param ch character code | |
498 **/ | |
499 FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font, | |
500 uint32_t ch, int face_index, int index, | |
501 ASS_Hinting hinting, int deco) | |
502 { | |
503 int error; | |
504 FT_Glyph glyph; | |
505 FT_Face face = font->faces[face_index]; | |
506 int flags = 0; | |
507 int vertical = font->desc.vertical; | |
466 | 508 |
467 flags = FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | 509 flags = FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH |
468 | FT_LOAD_IGNORE_TRANSFORM; | 510 | FT_LOAD_IGNORE_TRANSFORM; |
469 switch (hinting) { | 511 switch (hinting) { |
470 case ASS_HINTING_NONE: | 512 case ASS_HINTING_NONE: |
503 } | 545 } |
504 | 546 |
505 // Rotate glyph, if needed | 547 // Rotate glyph, if needed |
506 if (vertical && ch >= VERTICAL_LOWER_BOUND) { | 548 if (vertical && ch >= VERTICAL_LOWER_BOUND) { |
507 FT_Matrix m = { 0, double_to_d16(-1.0), double_to_d16(1.0), 0 }; | 549 FT_Matrix m = { 0, double_to_d16(-1.0), double_to_d16(1.0), 0 }; |
550 TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); | |
551 int desc = 0; | |
552 | |
553 if (os2) | |
554 desc = FT_MulFix(os2->sTypoDescender, face->size->metrics.y_scale); | |
555 | |
556 FT_Outline_Translate(&((FT_OutlineGlyph) glyph)->outline, 0, -desc); | |
508 FT_Outline_Transform(&((FT_OutlineGlyph) glyph)->outline, &m); | 557 FT_Outline_Transform(&((FT_OutlineGlyph) glyph)->outline, &m); |
509 FT_Outline_Translate(&((FT_OutlineGlyph) glyph)->outline, | 558 FT_Outline_Translate(&((FT_OutlineGlyph) glyph)->outline, |
510 face->glyph->metrics.vertAdvance, | 559 face->glyph->metrics.vertAdvance, desc); |
511 0); | |
512 glyph->advance.x = face->glyph->linearVertAdvance; | 560 glyph->advance.x = face->glyph->linearVertAdvance; |
513 } | 561 } |
514 | 562 |
515 // Apply scaling and shift | 563 // Apply scaling and shift |
516 FT_Matrix scale = { double_to_d16(font->scale_x), 0, 0, | 564 FT_Matrix scale = { double_to_d16(font->scale_x), 0, 0, |
559 { | 607 { |
560 int i; | 608 int i; |
561 for (i = 0; i < font->n_faces; ++i) | 609 for (i = 0; i < font->n_faces; ++i) |
562 if (font->faces[i]) | 610 if (font->faces[i]) |
563 FT_Done_Face(font->faces[i]); | 611 FT_Done_Face(font->faces[i]); |
612 if (font->shaper_priv) | |
613 ass_shaper_font_data_free(font->shaper_priv); | |
564 free(font->desc.family); | 614 free(font->desc.family); |
565 free(font); | 615 free(font); |
566 } | 616 } |
567 | 617 |
568 /** | 618 /** |
616 * | 666 * |
617 * \param outline FreeType outline, modified in-place | 667 * \param outline FreeType outline, modified in-place |
618 * \param border_x border size, x direction, d6 format | 668 * \param border_x border size, x direction, d6 format |
619 * \param border_x border size, y direction, d6 format | 669 * \param border_x border size, y direction, d6 format |
620 */ | 670 */ |
621 void fix_freetype_stroker(FT_OutlineGlyph glyph, int border_x, int border_y) | 671 void fix_freetype_stroker(FT_Outline *outline, int border_x, int border_y) |
622 { | 672 { |
623 int nc = glyph->outline.n_contours; | 673 int nc = outline->n_contours; |
624 int begin, stop; | 674 int begin, stop; |
625 char modified = 0; | 675 char modified = 0; |
626 char *valid_cont = malloc(nc); | 676 char *valid_cont = malloc(nc); |
627 int start = 0; | 677 int start = 0; |
628 int end = -1; | 678 int end = -1; |
629 FT_BBox *boxes = malloc(nc * sizeof(FT_BBox)); | 679 FT_BBox *boxes = malloc(nc * sizeof(FT_BBox)); |
630 int i, j; | 680 int i, j; |
631 int inside_direction; | 681 int inside_direction; |
632 | 682 |
633 inside_direction = FT_Outline_Get_Orientation(&glyph->outline) == | 683 inside_direction = FT_Outline_Get_Orientation(outline) == |
634 FT_ORIENTATION_TRUETYPE; | 684 FT_ORIENTATION_TRUETYPE; |
635 | 685 |
636 // create a list of cboxes of the contours | 686 // create a list of cboxes of the contours |
637 for (i = 0; i < nc; i++) { | 687 for (i = 0; i < nc; i++) { |
638 start = end + 1; | 688 start = end + 1; |
639 end = glyph->outline.contours[i]; | 689 end = outline->contours[i]; |
640 get_contour_cbox(&boxes[i], glyph->outline.points, start, end); | 690 get_contour_cbox(&boxes[i], outline->points, start, end); |
641 } | 691 } |
642 | 692 |
643 // for each contour, check direction and whether it's "outside" | 693 // for each contour, check direction and whether it's "outside" |
644 // or contained in another contour | 694 // or contained in another contour |
645 end = -1; | 695 end = -1; |
646 for (i = 0; i < nc; i++) { | 696 for (i = 0; i < nc; i++) { |
647 start = end + 1; | 697 start = end + 1; |
648 end = glyph->outline.contours[i]; | 698 end = outline->contours[i]; |
649 int dir = get_contour_direction(glyph->outline.points, start, end); | 699 int dir = get_contour_direction(outline->points, start, end); |
650 valid_cont[i] = 1; | 700 valid_cont[i] = 1; |
651 if (dir == inside_direction) { | 701 if (dir == inside_direction) { |
652 for (j = 0; j < nc; j++) { | 702 for (j = 0; j < nc; j++) { |
653 if (i == j) | 703 if (i == j) |
654 continue; | 704 continue; |
660 } | 710 } |
661 /* "inside" contour but we can't find anything it could be | 711 /* "inside" contour but we can't find anything it could be |
662 * inside of - assume the font is buggy and it should be | 712 * inside of - assume the font is buggy and it should be |
663 * an "outside" contour, and reverse it */ | 713 * an "outside" contour, and reverse it */ |
664 for (j = 0; j < (end + 1 - start) / 2; j++) { | 714 for (j = 0; j < (end + 1 - start) / 2; j++) { |
665 FT_Vector temp = glyph->outline.points[start + j]; | 715 FT_Vector temp = outline->points[start + j]; |
666 char temp2 = glyph->outline.tags[start + j]; | 716 char temp2 = outline->tags[start + j]; |
667 glyph->outline.points[start + j] = glyph->outline.points[end - j]; | 717 outline->points[start + j] = outline->points[end - j]; |
668 glyph->outline.points[end - j] = temp; | 718 outline->points[end - j] = temp; |
669 glyph->outline.tags[start + j] = glyph->outline.tags[end - j]; | 719 outline->tags[start + j] = outline->tags[end - j]; |
670 glyph->outline.tags[end - j] = temp2; | 720 outline->tags[end - j] = temp2; |
671 } | 721 } |
672 dir ^= 1; | 722 dir ^= 1; |
673 } | 723 } |
674 check_inside: | 724 check_inside: |
675 if (dir == inside_direction) { | 725 if (dir == inside_direction) { |
676 FT_BBox box; | 726 FT_BBox box; |
677 get_contour_cbox(&box, glyph->outline.points, start, end); | 727 get_contour_cbox(&box, outline->points, start, end); |
678 int width = box.xMax - box.xMin; | 728 int width = box.xMax - box.xMin; |
679 int height = box.yMax - box.yMin; | 729 int height = box.yMax - box.yMin; |
680 if (width < border_x * 2 || height < border_y * 2) { | 730 if (width < border_x * 2 || height < border_y * 2) { |
681 valid_cont[i] = 0; | 731 valid_cont[i] = 0; |
682 modified = 1; | 732 modified = 1; |
685 } | 735 } |
686 | 736 |
687 // if we need to modify the outline, rewrite it and skip | 737 // if we need to modify the outline, rewrite it and skip |
688 // the contours that we determined should be removed. | 738 // the contours that we determined should be removed. |
689 if (modified) { | 739 if (modified) { |
690 FT_Outline *outline = &glyph->outline; | |
691 int p = 0, c = 0; | 740 int p = 0, c = 0; |
692 for (i = 0; i < nc; i++) { | 741 for (i = 0; i < nc; i++) { |
693 if (!valid_cont[i]) | 742 if (!valid_cont[i]) |
694 continue; | 743 continue; |
695 begin = (i == 0) ? 0 : glyph->outline.contours[i - 1] + 1; | 744 begin = (i == 0) ? 0 : outline->contours[i - 1] + 1; |
696 stop = glyph->outline.contours[i]; | 745 stop = outline->contours[i]; |
697 for (j = begin; j <= stop; j++) { | 746 for (j = begin; j <= stop; j++) { |
698 outline->points[p].x = outline->points[j].x; | 747 outline->points[p].x = outline->points[j].x; |
699 outline->points[p].y = outline->points[j].y; | 748 outline->points[p].y = outline->points[j].y; |
700 outline->tags[p] = outline->tags[j]; | 749 outline->tags[p] = outline->tags[j]; |
701 p++; | 750 p++; |