Ticket #2099: libass.patch
| File libass.patch, 32.6 KB (added by , 14 years ago) |
|---|
-
ass.c
191 191 style->MarginL = style->MarginR = style->MarginV = 20; 192 192 } 193 193 194 /**195 * \brief find style by name196 * \param track track197 * \param name style name198 * \return index in track->styles199 * Returnes 0 if no styles found => expects at least 1 style.200 * Parsing code always adds "Default" style in the end.201 */202 static int lookup_style(ASS_Track *track, char *name)203 {204 int i;205 if (*name == '*')206 ++name; // FIXME: what does '*' really mean ?207 for (i = track->n_styles - 1; i >= 0; --i) {208 if (strcmp(track->styles[i].Name, name) == 0)209 return i;210 }211 i = track->default_style;212 ass_msg(track->library, MSGL_WARN,213 "[%p]: Warning: no style named '%s' found, using '%s'",214 track, name, track->styles[i].Name);215 return i; // use the first style216 }217 218 194 static uint32_t string2color(ASS_Library *library, char *p) 219 195 { 220 196 uint32_t tmp; -
ass.h
23 23 #include <stdarg.h> 24 24 #include "ass_types.h" 25 25 26 #define LIBASS_VERSION 0x010 0000026 #define LIBASS_VERSION 0x01010000 27 27 28 28 /* 29 29 * A linked list of images produced by an ass renderer. … … 214 214 void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing); 215 215 216 216 /** 217 * \brief Set vertical line position. 218 * \param priv renderer handle 219 * \param line_position vertical line position of subtitles in percent 220 * (0-100: 0 = on the bottom (default), 100 = on top) 221 */ 222 void ass_set_line_position(ASS_Renderer *priv, double line_position); 223 224 /** 217 225 * \brief Set font lookup defaults. 218 226 * \param default_font path to default font to use. Must be supplied if 219 227 * fontconfig is disabled or unavailable. -
ass_drawing.c
87 87 static void drawing_finish(ASS_Drawing *drawing, int raw_mode) 88 88 { 89 89 int i, offset; 90 double pbo; 90 91 FT_BBox bbox = drawing->cbox; 91 92 FT_Outline *ol = &drawing->outline; 92 93 … … 103 104 104 105 drawing->advance.x = bbox.xMax - bbox.xMin; 105 106 106 drawing->desc = double_to_d6(-drawing->pbo * drawing->scale_y); 107 pbo = drawing->pbo / (64.0 / (1 << (drawing->scale - 1))); 108 drawing->desc = double_to_d6(-pbo * drawing->scale_y); 107 109 drawing->asc = bbox.yMax - bbox.yMin + drawing->desc; 108 110 109 111 // Place it onto the baseline 110 offset = (bbox.yMax - bbox.yMin) + double_to_d6(- drawing->pbo *112 offset = (bbox.yMax - bbox.yMin) + double_to_d6(-pbo * 111 113 drawing->scale_y); 112 114 for (i = 0; i < ol->n_points; i++) 113 115 ol->points[i].y += offset; -
ass_parse.c
105 105 } 106 106 107 107 /** 108 * \brief Change border width 109 * negative value resets border to style value 108 * \brief Calculate valid border size. Makes sure the border sizes make sense. 109 * 110 * \param priv renderer state object 111 * \param border_x requested x border size 112 * \param border_y requested y border size 110 113 */ 111 void change_border(ASS_Renderer *render_priv, double border_x, 112 double border_y) 114 void calc_border(ASS_Renderer *priv, double border_x, double border_y) 113 115 { 114 int bord;115 if (!render_priv->state.font)116 return;117 118 116 if (border_x < 0 && border_y < 0) { 119 if ( render_priv->state.style->BorderStyle == 1 ||120 render_priv->state.style->BorderStyle == 3)121 border_x = border_y = render_priv->state.style->Outline;117 if (priv->state.border_style == 1 || 118 priv->state.border_style == 3) 119 border_x = border_y = priv->state.style->Outline; 122 120 else 123 121 border_x = border_y = 1.; 124 122 } 125 123 126 render_priv->state.border_x = border_x; 127 render_priv->state.border_y = border_y; 124 priv->state.border_x = border_x; 125 priv->state.border_y = border_y; 126 } 128 127 129 bord = 64 * border_x * render_priv->border_scale; 128 /** 129 * \brief Change border width 130 * 131 * \param render_priv renderer state object 132 * \param info glyph state object 133 */ 134 void change_border(ASS_Renderer *render_priv, double border_x, double border_y) 135 { 136 int bord = 64 * border_x * render_priv->border_scale; 137 130 138 if (bord > 0 && border_x == border_y) { 131 139 if (!render_priv->state.stroker) { 132 140 int error; … … 138 146 "failed to get stroker"); 139 147 render_priv->state.stroker = 0; 140 148 } 149 render_priv->state.stroker_radius = -1.0; 141 150 } 142 if (render_priv->state.stroker )151 if (render_priv->state.stroker && render_priv->state.stroker_radius != bord) { 143 152 FT_Stroker_Set(render_priv->state.stroker, bord, 144 153 FT_STROKER_LINECAP_ROUND, 145 154 FT_STROKER_LINEJOIN_ROUND, 0); 155 render_priv->state.stroker_radius = bord; 156 } 146 157 } else { 147 158 FT_Stroker_Done(render_priv->state.stroker); 148 159 render_priv->state.stroker = 0; … … 242 253 * \param p string to parse 243 254 * \param pwr multiplier for some tag effects (comes from \t tags) 244 255 */ 245 staticchar *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)256 char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr) 246 257 { 247 258 skip_to('\\'); 248 259 skip('\\'); … … 256 267 val = render_priv->state.border_x * (1 - pwr) + val * pwr; 257 268 else 258 269 val = -1.; 259 c hange_border(render_priv, val, render_priv->state.border_y);270 calc_border(render_priv, val, render_priv->state.border_y); 260 271 render_priv->state.bm_run_id++; 261 272 } else if (mystrcmp(&p, "ybord")) { 262 273 double val; … … 264 275 val = render_priv->state.border_y * (1 - pwr) + val * pwr; 265 276 else 266 277 val = -1.; 267 change_border(render_priv, render_priv->state.border_x, val); 278 calc_border(render_priv, render_priv->state.border_x, val); 279 render_priv->state.bm_run_id++; 268 280 } else if (mystrcmp(&p, "xshad")) { 269 281 double val; 270 282 if (mystrtod(&p, &val)) … … 388 400 } else if (mystrcmp(&p, "bord")) { 389 401 double val; 390 402 if (mystrtod(&p, &val)) { 391 if (render_priv->state.border_x == render_priv->state.border_y)392 403 val = render_priv->state.border_x * (1 - pwr) + val * pwr; 393 404 } else 394 405 val = -1.; // reset to default 395 c hange_border(render_priv, val, val);406 calc_border(render_priv, val, val); 396 407 render_priv->state.bm_run_id++; 397 408 } else if (mystrcmp(&p, "move")) { 398 409 double x1, x2, y1, y2; … … 730 741 ass_msg(render_priv->library, MSGL_DBG2, "single c/a at %f: %c%c = %X", 731 742 pwr, n, cmd, render_priv->state.c[cidx]); 732 743 } else if (mystrcmp(&p, "r")) { 733 reset_render_context(render_priv); 744 char *start = p; 745 char *style; 746 skip_to('\\'); 747 if (p > start) { 748 style = malloc(p - start + 1); 749 strncpy(style, start, p - start); 750 style[p - start] = '\0'; 751 reset_render_context(render_priv, 752 render_priv->track->styles + lookup_style(render_priv->track, style)); 753 free(style); 754 } else 755 reset_render_context(render_priv, NULL); 734 756 } else if (mystrcmp(&p, "be")) { 735 757 int val; 736 758 if (mystrtoi(&p, &val)) { … … 977 999 978 1000 979 1001 /** 980 * \brief Get next ucs4 char from string, parsing and executing style overrides1002 * \brief Get next ucs4 char from string, parsing UTF-8 and escapes 981 1003 * \param str string pointer 982 1004 * \return ucs4 code of the next char 983 1005 * On return str points to the unparsed part of the string … … 986 1008 { 987 1009 char *p = *str; 988 1010 unsigned chr; 989 if (*p == '{') { // '\0' goes here990 p++;991 while (1) {992 p = parse_tag(render_priv, p, 1.);993 if (*p == '}') { // end of tag994 p++;995 if (*p == '{') {996 p++;997 continue;998 } else999 break;1000 } else if (*p != '\\')1001 ass_msg(render_priv->library, MSGL_V,1002 "Unable to parse: '%.30s'", p);1003 if (*p == 0)1004 break;1005 }1006 }1007 1011 if (*p == '\t') { 1008 1012 ++p; 1009 1013 *str = p; -
ass_parse.h
28 28 29 29 void update_font(ASS_Renderer *render_priv); 30 30 double ensure_font_size(ASS_Renderer *priv, double size); 31 void calc_border(ASS_Renderer *priv, double border_x, double border_y); 31 32 void change_border(ASS_Renderer *render_priv, double border_x, 32 33 double border_y); 33 34 void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event); 34 35 void process_karaoke_effects(ASS_Renderer *render_priv); 35 36 unsigned get_next_char(ASS_Renderer *render_priv, char **str); 37 char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr); 36 38 extern void change_alpha(uint32_t *var, uint32_t new, double pwr); 37 39 extern uint32_t mult_alpha(uint32_t a, uint32_t b); 38 40 -
ass_render.c
841 841 * \brief partially reset render_context to style values 842 842 * Works like {\r}: resets some style overrides 843 843 */ 844 void reset_render_context(ASS_Renderer *render_priv )844 void reset_render_context(ASS_Renderer *render_priv, ASS_Style *style) 845 845 { 846 render_priv->state.c[0] = render_priv->state.style->PrimaryColour; 847 render_priv->state.c[1] = render_priv->state.style->SecondaryColour; 848 render_priv->state.c[2] = render_priv->state.style->OutlineColour; 849 render_priv->state.c[3] = render_priv->state.style->BackColour; 846 if (!style) 847 style = render_priv->state.style; 848 849 render_priv->state.c[0] = style->PrimaryColour; 850 render_priv->state.c[1] = style->SecondaryColour; 851 render_priv->state.c[2] = style->OutlineColour; 852 render_priv->state.c[3] = style->BackColour; 850 853 render_priv->state.flags = 851 ( render_priv->state.style->Underline ? DECO_UNDERLINE : 0) |852 ( render_priv->state.style->StrikeOut ? DECO_STRIKETHROUGH : 0);853 render_priv->state.font_size = render_priv->state.style->FontSize;854 (style->Underline ? DECO_UNDERLINE : 0) | 855 (style->StrikeOut ? DECO_STRIKETHROUGH : 0); 856 render_priv->state.font_size = style->FontSize; 854 857 855 858 free(render_priv->state.family); 856 859 render_priv->state.family = NULL; 857 render_priv->state.family = strdup( render_priv->state.style->FontName);860 render_priv->state.family = strdup(style->FontName); 858 861 render_priv->state.treat_family_as_pattern = 859 render_priv->state.style->treat_fontname_as_pattern;860 render_priv->state.bold = render_priv->state.style->Bold;861 render_priv->state.italic = render_priv->state.style->Italic;862 style->treat_fontname_as_pattern; 863 render_priv->state.bold = style->Bold; 864 render_priv->state.italic = style->Italic; 862 865 update_font(render_priv); 863 866 864 change_border(render_priv, -1., -1.); 865 render_priv->state.scale_x = render_priv->state.style->ScaleX; 866 render_priv->state.scale_y = render_priv->state.style->ScaleY; 867 render_priv->state.hspacing = render_priv->state.style->Spacing; 867 render_priv->state.border_style = style->BorderStyle; 868 calc_border(render_priv, style->Outline, style->Outline); 869 change_border(render_priv, render_priv->state.border_x, render_priv->state.border_y); 870 render_priv->state.scale_x = style->ScaleX; 871 render_priv->state.scale_y = style->ScaleY; 872 render_priv->state.hspacing = style->Spacing; 868 873 render_priv->state.be = 0; 869 874 render_priv->state.blur = 0.0; 870 render_priv->state.shadow_x = render_priv->state.style->Shadow;871 render_priv->state.shadow_y = render_priv->state.style->Shadow;875 render_priv->state.shadow_x = style->Shadow; 876 render_priv->state.shadow_y = style->Shadow; 872 877 render_priv->state.frx = render_priv->state.fry = 0.; 873 render_priv->state.frz = M_PI * render_priv->state.style->Angle / 180.;878 render_priv->state.frz = M_PI * style->Angle / 180.; 874 879 render_priv->state.fax = render_priv->state.fay = 0.; 875 880 render_priv->state.wrap_style = render_priv->track->WrapStyle; 876 render_priv->state.font_encoding = render_priv->state.style->Encoding;881 render_priv->state.font_encoding = style->Encoding; 877 882 } 878 883 879 884 /** … … 886 891 render_priv->state.style = render_priv->track->styles + event->Style; 887 892 render_priv->state.parsed_tags = 0; 888 893 889 reset_render_context(render_priv );894 reset_render_context(render_priv, render_priv->state.style); 890 895 891 896 render_priv->state.evt_type = EVENT_NORMAL; 892 897 render_priv->state.alignment = render_priv->state.style->Alignment; … … 1036 1041 key->scale_y = double_to_d16(info->scale_y); 1037 1042 key->outline.x = double_to_d16(info->border_x); 1038 1043 key->outline.y = double_to_d16(info->border_y); 1039 key->border_style = priv->state.style->BorderStyle;1044 key->border_style = info->border_style; 1040 1045 key->hash = info->drawing->hash; 1041 1046 key->text = info->drawing->text; 1042 1047 key->pbo = info->drawing->pbo; … … 1055 1060 key->outline.x = double_to_d16(info->border_x); 1056 1061 key->outline.y = double_to_d16(info->border_y); 1057 1062 key->flags = info->flags; 1058 key->border_style = priv->state.style->BorderStyle;1063 key->border_style = info->border_style; 1059 1064 } 1060 1065 } 1061 1066 … … 1095 1100 v.desc = drawing->desc; 1096 1101 key.u.drawing.text = strdup(drawing->text); 1097 1102 } else { 1098 ass_face_set_size(info->font->faces[info->face_index], 1099 info->font_size); 1100 ass_font_set_transform(info->font, info->scale_x, 1101 info->scale_y, NULL); 1103 // arbitrary, not too small to prevent grid fitting rounding effects 1104 // XXX: this is a rather crude hack 1105 const double ft_size = 256.0; 1106 ass_face_set_size(info->font->faces[info->face_index], ft_size); 1107 ass_font_set_transform(info->font, 1108 info->scale_x * info->font_size / ft_size, 1109 info->scale_y * info->font_size / ft_size, 1110 NULL); 1102 1111 FT_Glyph glyph = 1103 1112 ass_font_get_glyph(priv->fontconfig_priv, info->font, 1104 1113 info->symbol, info->face_index, info->glyph_index, … … 1113 1122 FT_Done_Glyph(glyph); 1114 1123 ass_font_get_asc_desc(info->font, info->symbol, 1115 1124 &v.asc, &v.desc); 1116 v.asc *= info->scale_y ;1117 v.desc *= info->scale_y ;1125 v.asc *= info->scale_y * info->font_size / ft_size; 1126 v.desc *= info->scale_y * info->font_size / ft_size; 1118 1127 } 1119 1128 } 1120 1129 … … 1123 1132 1124 1133 FT_Outline_Get_CBox(v.outline, &v.bbox_scaled); 1125 1134 1126 if ( priv->state.style->BorderStyle == 3 &&1135 if (info->border_style == 3 && 1127 1136 (info->border_x > 0 || info->border_y > 0)) { 1128 1137 FT_Vector advance; 1129 1138 … … 1141 1150 } else if ((info->border_x > 0 || info->border_y > 0) 1142 1151 && double_to_d6(info->scale_x) && double_to_d6(info->scale_y)) { 1143 1152 1153 change_border(priv, info->border_x, info->border_y); 1144 1154 outline_copy(priv->ftlibrary, v.outline, &v.border); 1145 1155 stroke_outline(priv, v.border, 1146 1156 double_to_d6(info->border_x * priv->border_scale), … … 1275 1285 // calculating rotation shift vector (from rotation origin to the glyph basepoint) 1276 1286 shift.x = key->shift_x; 1277 1287 shift.y = key->shift_y; 1278 fax_scaled = info->fax * render_priv->state.scale_x;1279 fay_scaled = info->fay * render_priv->state.scale_y;1288 fax_scaled = info->fax / info->scale_y * info->scale_x; 1289 fay_scaled = info->fay / info->scale_x * info->scale_y; 1280 1290 1281 1291 // apply rotation 1282 1292 transform_3d(shift, outline, border, … … 1308 1318 &hash_val.bm_s, info->be, 1309 1319 info->blur * render_priv->border_scale, 1310 1320 key->shadow_offset, 1311 render_priv->state.style->BorderStyle);1321 info->border_style); 1312 1322 if (error) 1313 1323 info->symbol = 0; 1314 1324 … … 1707 1717 num_glyphs = 0; 1708 1718 p = event->Text; 1709 1719 1720 int in_tag = 0; 1721 1710 1722 // Event parsing. 1711 1723 while (1) { 1712 1724 // get next char, executing style override 1713 1725 // this affects render_context 1714 1726 do { 1715 code = get_next_char(render_priv, &p); 1716 if (render_priv->state.drawing_mode && code) 1717 ass_drawing_add_char(drawing, (char) code); 1718 } while (code && render_priv->state.drawing_mode); // skip everything in drawing mode 1727 code = 0; 1728 if (!in_tag && *p == '{') { // '\0' goes here 1729 p++; 1730 in_tag = 1; 1731 } 1732 if (in_tag) { 1733 int prev_drawing_mode = render_priv->state.drawing_mode; 1734 p = parse_tag(render_priv, p, 1.); 1735 if (*p == '}') { // end of tag 1736 p++; 1737 in_tag = 0; 1738 } else if (*p != '\\') { 1739 ass_msg(render_priv->library, MSGL_V, 1740 "Unable to parse: '%.30s'", p); 1741 } 1742 if (prev_drawing_mode && !render_priv->state.drawing_mode) { 1743 // Drawing mode was just disabled. We must exit and draw it 1744 // immediately, instead of letting further tags affect it. 1745 // See bug #47. 1746 break; 1747 } 1748 } else { 1749 code = get_next_char(render_priv, &p); 1750 if (code && render_priv->state.drawing_mode) { 1751 ass_drawing_add_char(drawing, (char) code); 1752 continue; // skip everything in drawing mode 1753 } 1754 break; 1755 } 1756 } while (*p); 1719 1757 1720 1758 if (text_info->length >= text_info->max_glyphs) { 1721 1759 // Raise maximum number of glyphs … … 1734 1772 render_priv->font_scale; 1735 1773 drawing->scale_y = render_priv->state.scale_y * 1736 1774 render_priv->font_scale; 1737 p--;1738 1775 code = 0xfffc; // object replacement character 1739 1776 glyphs[text_info->length].drawing = drawing; 1740 1777 } … … 1762 1799 render_priv->state.effect_timing; 1763 1800 glyphs[text_info->length].effect_skip_timing = 1764 1801 render_priv->state.effect_skip_timing; 1765 glyphs[text_info->length].font_size = ensure_font_size(render_priv,1766 render_priv->state.font_size * render_priv->font_scale );1802 glyphs[text_info->length].font_size = 1803 render_priv->state.font_size * render_priv->font_scale; 1767 1804 glyphs[text_info->length].be = render_priv->state.be; 1768 1805 glyphs[text_info->length].blur = render_priv->state.blur; 1769 1806 glyphs[text_info->length].shadow_x = render_priv->state.shadow_x; 1770 1807 glyphs[text_info->length].shadow_y = render_priv->state.shadow_y; 1771 1808 glyphs[text_info->length].scale_x= render_priv->state.scale_x; 1772 1809 glyphs[text_info->length].scale_y = render_priv->state.scale_y; 1810 glyphs[text_info->length].border_style = render_priv->state.border_style; 1773 1811 glyphs[text_info->length].border_x= render_priv->state.border_x; 1774 1812 glyphs[text_info->length].border_y = render_priv->state.border_y; 1813 glyphs[text_info->length].hspacing = render_priv->state.hspacing; 1775 1814 glyphs[text_info->length].bold = render_priv->state.bold; 1776 1815 glyphs[text_info->length].italic = render_priv->state.italic; 1777 1816 glyphs[text_info->length].flags = render_priv->state.flags; … … 1829 1868 } 1830 1869 1831 1870 // add horizontal letter spacing 1832 info->cluster_advance.x += double_to_d6( render_priv->state.hspacing *1871 info->cluster_advance.x += double_to_d6(info->hspacing * 1833 1872 render_priv->font_scale * info->scale_x); 1834 1873 1835 1874 // add displacement for vertical shearing 1836 info->cluster_advance.y += (info->fay * info->scale_y) * info->cluster_advance.x;1875 info->cluster_advance.y += (info->fay / info->scale_x * info->scale_y) * info->cluster_advance.x; 1837 1876 1838 1877 } 1839 1878 … … 1906 1945 for (i = 0; i < text_info->length; i++) { 1907 1946 GlyphInfo *info = glyphs + cmap[i]; 1908 1947 if (glyphs[i].linebreak) { 1948 pen.y -= (info->fay / info->scale_x * info->scale_y) * pen.x; 1909 1949 pen.x = 0; 1910 1950 pen.y += double_to_d6(text_info->lines[lineno-1].desc); 1911 1951 pen.y += double_to_d6(text_info->lines[lineno].asc); … … 1995 2035 y2scr(render_priv, render_priv->track->PlayResY / 2.0); 1996 2036 device_y = scr_y - (bbox.yMax + bbox.yMin) / 2.0; 1997 2037 } else { // subtitle 1998 double scr_ y;2038 double scr_top, scr_bottom, scr_y0; 1999 2039 if (valign != VALIGN_SUB) 2000 2040 ass_msg(render_priv->library, MSGL_V, 2001 2041 "Invalid valign, assuming 0 (subtitle)"); 2002 scr_ y=2042 scr_bottom = 2003 2043 y2scr_sub(render_priv, 2004 2044 render_priv->track->PlayResY - MarginV); 2005 device_y = scr_y; 2045 scr_top = y2scr_top(render_priv, 0); //xxx not always 0? 2046 device_y = scr_bottom + (scr_top - scr_bottom) * 2047 render_priv->settings.line_position / 100.0; 2006 2048 device_y -= text_info->height; 2007 2049 device_y += text_info->lines[0].asc; 2050 // clip to top to avoid confusion if line_position is very high, 2051 // turning the subtitle into a toptitle 2052 // also, don't change behavior if line_position is not used 2053 scr_y0 = scr_top + text_info->lines[0].asc; 2054 if (device_y < scr_y0 && render_priv->settings.line_position > 0) { 2055 device_y = scr_y0; 2056 } 2008 2057 } 2009 2058 } else if (render_priv->state.evt_type == EVENT_VSCROLL) { 2010 2059 if (render_priv->state.scroll_direction == SCROLL_TB) … … 2158 2207 ass_cache_empty(cache->composite_cache, 0); 2159 2208 ass_free_images(priv->prev_images_root); 2160 2209 priv->prev_images_root = 0; 2210 priv->cache_cleared = 1; 2161 2211 } 2162 2212 if (ass_cache_empty(cache->outline_cache, cache->glyph_max)) { 2163 2213 ass_cache_empty(cache->bitmap_cache, 0); 2164 2214 ass_cache_empty(cache->composite_cache, 0); 2165 2215 ass_free_images(priv->prev_images_root); 2166 2216 priv->prev_images_root = 0; 2217 priv->cache_cleared = 1; 2167 2218 } 2168 2219 } 2169 2220 … … 2429 2480 ASS_Image *img, *img2; 2430 2481 int diff; 2431 2482 2483 if (priv->cache_cleared) 2484 return 2; 2485 2432 2486 img = priv->prev_images_root; 2433 2487 img2 = priv->images_root; 2434 2488 diff = 0; … … 2474 2528 2475 2529 // init frame 2476 2530 rc = ass_start_frame(priv, track, now); 2477 if (rc != 0) 2531 if (rc != 0) { 2532 if (detect_change) { 2533 *detect_change = 2; 2534 } 2478 2535 return 0; 2536 } 2479 2537 2480 2538 // render events separately 2481 2539 cnt = 0; … … 2525 2583 // free the previous image list 2526 2584 ass_free_images(priv->prev_images_root); 2527 2585 priv->prev_images_root = 0; 2586 priv->cache_cleared = 0; 2528 2587 2529 2588 return priv->images_root; 2530 2589 } -
ass_render.h
67 67 int frame_height; 68 68 double font_size_coeff; // font size multiplier 69 69 double line_spacing; // additional line spacing (in frame pixels) 70 double line_position; // vertical position for subtitles, 0-100 (0 = no change) 70 71 int top_margin; // height of top margin. Everything except toptitles is shifted down by top_margin. 71 72 int bottom_margin; // height of bottom margin. (frame_height - top_margin - bottom_margin) is original video height. 72 73 int left_margin; … … 133 134 double frx, fry, frz; // rotation 134 135 double fax, fay; // text shearing 135 136 double scale_x, scale_y; 137 int border_style; 136 138 double border_x, border_y; 139 double hspacing; 137 140 unsigned italic; 138 141 unsigned bold; 139 142 int flags; … … 174 177 int flags; // decoration flags (underline/strike-through) 175 178 176 179 FT_Stroker stroker; 180 int stroker_radius; // last stroker radius, for caching stroker objects 177 181 int alignment; // alignment overrides go here; if zero, style value will be used 178 182 double frx, fry, frz; 179 183 double fax, fay; // text shearing … … 188 192 char have_origin; // origin is explicitly defined; if 0, get_base_point() is used 189 193 double scale_x, scale_y; 190 194 double hspacing; // distance between letters, in pixels 195 int border_style; 191 196 double border_x; // outline width 192 197 double border_y; 193 198 uint32_t c[4]; // colors(Primary, Secondary, so on) in RGBA … … 248 253 249 254 ASS_Image *images_root; // rendering result is stored here 250 255 ASS_Image *prev_images_root; 256 int cache_cleared; 251 257 252 258 EventImages *eimg; // temporary buffer for sorting rendered events 253 259 int eimg_size; // allocated buffer size … … 289 295 int ha, hb; // left and width 290 296 } Segment; 291 297 292 void reset_render_context(ASS_Renderer *render_priv );298 void reset_render_context(ASS_Renderer *render_priv, ASS_Style *style); 293 299 void ass_free_images(ASS_Image *img); 294 300 295 301 // XXX: this is actually in ass.c, includes should be fixed later on -
ass_render_api.c
116 116 priv->settings.line_spacing = line_spacing; 117 117 } 118 118 119 void ass_set_line_position(ASS_Renderer *priv, double line_position) 120 { 121 if (priv->settings.line_position != line_position) { 122 priv->settings.line_position = line_position; 123 ass_reconfigure(priv); 124 } 125 } 126 119 127 void ass_set_fonts(ASS_Renderer *priv, const char *default_font, 120 128 const char *default_family, int fc, const char *config, 121 129 int update) -
ass_shaper.c
401 401 font->faces[info->face_index], NULL); 402 402 } 403 403 404 ass_face_set_size(font->faces[info->face_index], info->font_size); 404 // XXX: this is a rather crude hack 405 const double ft_size = 256.0; 406 ass_face_set_size(font->faces[info->face_index], ft_size); 405 407 update_hb_size(hb_fonts[info->face_index], font->faces[info->face_index]); 406 408 407 409 // update hash key for cached metrics … … 431 433 hb_buffer_t *buf; 432 434 hb_font_t *font; 433 435 } runs[MAX_RUNS]; 436 const double ft_size = 256.0; 434 437 435 436 438 for (i = 0; i < len && run < MAX_RUNS; i++, run++) { 437 439 // get length and level of the current run 438 440 int k = i; … … 484 486 // set position and advance 485 487 info->skip = 0; 486 488 info->glyph_index = glyph_info[j].codepoint; 487 info->offset.x = pos[j].x_offset * info->scale_x ;488 info->offset.y = -pos[j].y_offset * info->scale_y ;489 info->advance.x = pos[j].x_advance * info->scale_x ;490 info->advance.y = -pos[j].y_advance * info->scale_y ;489 info->offset.x = pos[j].x_offset * info->scale_x * (info->font_size / ft_size); 490 info->offset.y = -pos[j].y_offset * info->scale_y * (info->font_size / ft_size); 491 info->advance.x = pos[j].x_advance * info->scale_x * (info->font_size / ft_size); 492 info->advance.y = -pos[j].y_advance * info->scale_y * (info->font_size / ft_size); 491 493 492 494 // accumulate advance in the root glyph 493 495 root->cluster_advance.x += info->advance.x; … … 602 604 } 603 605 604 606 /** 607 * \brief Remove all zero-width invisible characters from the text. 608 * \param text_info text 609 */ 610 static void ass_shaper_skip_characters(TextInfo *text_info) 611 { 612 int i; 613 GlyphInfo *glyphs = text_info->glyphs; 614 615 for (i = 0; i < text_info->length; i++) { 616 // Skip direction override control characters 617 if ((glyphs[i].symbol <= 0x202e && glyphs[i].symbol >= 0x202a) 618 || (glyphs[i].symbol <= 0x200f && glyphs[i].symbol >= 0x200b) 619 || (glyphs[i].symbol <= 0x2063 && glyphs[i].symbol >= 0x2060) 620 || glyphs[i].symbol == 0xfeff 621 || glyphs[i].symbol == 0x00ad 622 || glyphs[i].symbol == 0x034f) { 623 glyphs[i].symbol = 0; 624 glyphs[i].skip++; 625 } 626 } 627 } 628 629 /** 605 630 * \brief Shape an event's text. Calculates directional runs and shapes them. 606 631 * \param text_info event's text 607 632 */ … … 639 664 #ifdef CONFIG_HARFBUZZ 640 665 switch (shaper->shaping_level) { 641 666 case ASS_SHAPING_SIMPLE: 642 shape_fribidi(shaper, glyphs, text_info->length);667 ass_shaper_skip_characters(text_info); 643 668 break; 644 669 case ASS_SHAPING_COMPLEX: 645 670 shape_harfbuzz(shaper, glyphs, text_info->length); 646 671 break; 647 672 } 648 673 #else 649 shape_fribidi(shaper, glyphs, text_info->length);674 ass_shaper_skip_characters(text_info); 650 675 #endif 651 652 653 // clean up654 for (i = 0; i < text_info->length; i++) {655 // Skip direction override control characters656 // NOTE: Behdad said HarfBuzz is supposed to remove these, but this hasn't657 // been implemented yet658 if (glyphs[i].symbol <= 0x202F && glyphs[i].symbol >= 0x202a) {659 glyphs[i].symbol = 0;660 glyphs[i].skip++;661 }662 }663 676 #endif 664 677 } 665 678 … … 733 746 } 734 747 735 748 /** 736 * \brief Resolve a Windows font encodingnumber to a suitable749 * \brief Resolve a Windows font charset number to a suitable 737 750 * base direction. 177 and 178 are Hebrew and Arabic respectively, and 738 * they map to RTL. 1 is autodetection and is mapped to just that. 739 * Everything else is mapped to LTR. 751 * they map to RTL. Everything else maps to LTR for compatibility 752 * reasons. The special value -1, which is not a legal Windows font charset 753 * number, can be used for autodetection. 740 754 * \param enc Windows font encoding 741 755 */ 742 756 FriBidiParType resolve_base_direction(int enc) 743 757 { 744 758 #ifdef CONFIG_FRIBIDI 745 759 switch (enc) { 746 case 1:760 case -1: 747 761 return FRIBIDI_PAR_ON; 748 762 case 177: 749 763 case 178: -
ass_utils.c
160 160 return c; 161 161 } 162 162 163 /** 164 * \brief find style by name 165 * \param track track 166 * \param name style name 167 * \return index in track->styles 168 * Returnes 0 if no styles found => expects at least 1 style. 169 * Parsing code always adds "Default" style in the end. 170 */ 171 int lookup_style(ASS_Track *track, char *name) 172 { 173 int i; 174 if (*name == '*') 175 ++name; // FIXME: what does '*' really mean ? 176 for (i = track->n_styles - 1; i >= 0; --i) { 177 if (strcmp(track->styles[i].Name, name) == 0) 178 return i; 179 } 180 i = track->default_style; 181 ass_msg(track->library, MSGL_WARN, 182 "[%p]: Warning: no style named '%s' found, using '%s'", 183 track, name, track->styles[i].Name); 184 return i; // use the first style 185 } 186 163 187 #ifdef CONFIG_ENCA 164 188 void *ass_guess_buffer_cp(ASS_Library *library, unsigned char *buffer, 165 189 int buflen, char *preferred_language, -
ass_utils.h
51 51 char parse_bool(char *str); 52 52 unsigned ass_utf8_get_char(char **str); 53 53 void ass_msg(ASS_Library *priv, int lvl, char *fmt, ...); 54 int lookup_style(ASS_Track *track, char *name); 54 55 #ifdef CONFIG_ENCA 55 56 void *ass_guess_buffer_cp(ASS_Library *library, unsigned char *buffer, 56 57 int buflen, char *preferred_language,
