Mercurial > mplayer.hg
changeset 35262:49fc594fda43
Updated libass to 0.10.1
This closes #2099
author | SubJunk |
---|---|
date | Tue, 06 Nov 2012 05:41:14 +0000 |
parents | 1c18199bbf7c |
children | a893e72567ca |
files | libass/ass.c libass/ass.h libass/ass_drawing.c libass/ass_parse.c libass/ass_parse.h libass/ass_render.c libass/ass_render.h libass/ass_render_api.c libass/ass_shaper.c libass/ass_utils.c libass/ass_utils.h |
diffstat | 11 files changed, 242 insertions(+), 138 deletions(-) [+] |
line wrap: on
line diff
--- a/libass/ass.c Mon Nov 05 21:41:39 2012 +0000 +++ b/libass/ass.c Tue Nov 06 05:41:14 2012 +0000 @@ -191,30 +191,6 @@ style->MarginL = style->MarginR = style->MarginV = 20; } -/** - * \brief find style by name - * \param track track - * \param name style name - * \return index in track->styles - * Returnes 0 if no styles found => expects at least 1 style. - * Parsing code always adds "Default" style in the end. - */ -static int lookup_style(ASS_Track *track, char *name) -{ - int i; - if (*name == '*') - ++name; // FIXME: what does '*' really mean ? - for (i = track->n_styles - 1; i >= 0; --i) { - if (strcmp(track->styles[i].Name, name) == 0) - return i; - } - i = track->default_style; - ass_msg(track->library, MSGL_WARN, - "[%p]: Warning: no style named '%s' found, using '%s'", - track, name, track->styles[i].Name); - return i; // use the first style -} - static uint32_t string2color(ASS_Library *library, char *p) { uint32_t tmp;
--- a/libass/ass.h Mon Nov 05 21:41:39 2012 +0000 +++ b/libass/ass.h Tue Nov 06 05:41:14 2012 +0000 @@ -23,7 +23,7 @@ #include <stdarg.h> #include "ass_types.h" -#define LIBASS_VERSION 0x01000000 +#define LIBASS_VERSION 0x01010000 /* * A linked list of images produced by an ass renderer. @@ -214,6 +214,14 @@ void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing); /** + * \brief Set vertical line position. + * \param priv renderer handle + * \param line_position vertical line position of subtitles in percent + * (0-100: 0 = on the bottom (default), 100 = on top) + */ +void ass_set_line_position(ASS_Renderer *priv, double line_position); + +/** * \brief Set font lookup defaults. * \param default_font path to default font to use. Must be supplied if * fontconfig is disabled or unavailable.
--- a/libass/ass_drawing.c Mon Nov 05 21:41:39 2012 +0000 +++ b/libass/ass_drawing.c Tue Nov 06 05:41:14 2012 +0000 @@ -87,6 +87,7 @@ static void drawing_finish(ASS_Drawing *drawing, int raw_mode) { int i, offset; + double pbo; FT_BBox bbox = drawing->cbox; FT_Outline *ol = &drawing->outline; @@ -103,11 +104,12 @@ drawing->advance.x = bbox.xMax - bbox.xMin; - drawing->desc = double_to_d6(-drawing->pbo * drawing->scale_y); + pbo = drawing->pbo / (64.0 / (1 << (drawing->scale - 1))); + drawing->desc = double_to_d6(-pbo * drawing->scale_y); drawing->asc = bbox.yMax - bbox.yMin + drawing->desc; // Place it onto the baseline - offset = (bbox.yMax - bbox.yMin) + double_to_d6(-drawing->pbo * + offset = (bbox.yMax - bbox.yMin) + double_to_d6(-pbo * drawing->scale_y); for (i = 0; i < ol->n_points; i++) ol->points[i].y += offset;
--- a/libass/ass_parse.c Mon Nov 05 21:41:39 2012 +0000 +++ b/libass/ass_parse.c Tue Nov 06 05:41:14 2012 +0000 @@ -105,28 +105,36 @@ } /** - * \brief Change border width - * negative value resets border to style value + * \brief Calculate valid border size. Makes sure the border sizes make sense. + * + * \param priv renderer state object + * \param border_x requested x border size + * \param border_y requested y border size */ -void change_border(ASS_Renderer *render_priv, double border_x, - double border_y) +void calc_border(ASS_Renderer *priv, double border_x, double border_y) { - int bord; - if (!render_priv->state.font) - return; - if (border_x < 0 && border_y < 0) { - if (render_priv->state.style->BorderStyle == 1 || - render_priv->state.style->BorderStyle == 3) - border_x = border_y = render_priv->state.style->Outline; + if (priv->state.border_style == 1 || + priv->state.border_style == 3) + border_x = border_y = priv->state.style->Outline; else border_x = border_y = 1.; } - render_priv->state.border_x = border_x; - render_priv->state.border_y = border_y; + priv->state.border_x = border_x; + priv->state.border_y = border_y; +} - bord = 64 * border_x * render_priv->border_scale; +/** + * \brief Change border width + * + * \param render_priv renderer state object + * \param info glyph state object + */ +void change_border(ASS_Renderer *render_priv, double border_x, double border_y) +{ + int bord = 64 * border_x * render_priv->border_scale; + if (bord > 0 && border_x == border_y) { if (!render_priv->state.stroker) { int error; @@ -138,11 +146,14 @@ "failed to get stroker"); render_priv->state.stroker = 0; } + render_priv->state.stroker_radius = -1.0; } - if (render_priv->state.stroker) + if (render_priv->state.stroker && render_priv->state.stroker_radius != bord) { FT_Stroker_Set(render_priv->state.stroker, bord, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); + render_priv->state.stroker_radius = bord; + } } else { FT_Stroker_Done(render_priv->state.stroker); render_priv->state.stroker = 0; @@ -242,7 +253,7 @@ * \param p string to parse * \param pwr multiplier for some tag effects (comes from \t tags) */ -static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr) +char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr) { skip_to('\\'); skip('\\'); @@ -256,7 +267,7 @@ val = render_priv->state.border_x * (1 - pwr) + val * pwr; else val = -1.; - change_border(render_priv, val, render_priv->state.border_y); + calc_border(render_priv, val, render_priv->state.border_y); render_priv->state.bm_run_id++; } else if (mystrcmp(&p, "ybord")) { double val; @@ -264,7 +275,8 @@ val = render_priv->state.border_y * (1 - pwr) + val * pwr; else val = -1.; - change_border(render_priv, render_priv->state.border_x, val); + calc_border(render_priv, render_priv->state.border_x, val); + render_priv->state.bm_run_id++; } else if (mystrcmp(&p, "xshad")) { double val; if (mystrtod(&p, &val)) @@ -388,11 +400,10 @@ } else if (mystrcmp(&p, "bord")) { double val; if (mystrtod(&p, &val)) { - if (render_priv->state.border_x == render_priv->state.border_y) val = render_priv->state.border_x * (1 - pwr) + val * pwr; } else val = -1.; // reset to default - change_border(render_priv, val, val); + calc_border(render_priv, val, val); render_priv->state.bm_run_id++; } else if (mystrcmp(&p, "move")) { double x1, x2, y1, y2; @@ -730,7 +741,18 @@ ass_msg(render_priv->library, MSGL_DBG2, "single c/a at %f: %c%c = %X", pwr, n, cmd, render_priv->state.c[cidx]); } else if (mystrcmp(&p, "r")) { - reset_render_context(render_priv); + char *start = p; + char *style; + skip_to('\\'); + if (p > start) { + style = malloc(p - start + 1); + strncpy(style, start, p - start); + style[p - start] = '\0'; + reset_render_context(render_priv, + render_priv->track->styles + lookup_style(render_priv->track, style)); + free(style); + } else + reset_render_context(render_priv, NULL); } else if (mystrcmp(&p, "be")) { int val; if (mystrtoi(&p, &val)) { @@ -977,7 +999,7 @@ /** - * \brief Get next ucs4 char from string, parsing and executing style overrides + * \brief Get next ucs4 char from string, parsing UTF-8 and escapes * \param str string pointer * \return ucs4 code of the next char * On return str points to the unparsed part of the string @@ -986,24 +1008,6 @@ { char *p = *str; unsigned chr; - if (*p == '{') { // '\0' goes here - p++; - while (1) { - p = parse_tag(render_priv, p, 1.); - if (*p == '}') { // end of tag - p++; - if (*p == '{') { - p++; - continue; - } else - break; - } else if (*p != '\\') - ass_msg(render_priv->library, MSGL_V, - "Unable to parse: '%.30s'", p); - if (*p == 0) - break; - } - } if (*p == '\t') { ++p; *str = p;
--- a/libass/ass_parse.h Mon Nov 05 21:41:39 2012 +0000 +++ b/libass/ass_parse.h Tue Nov 06 05:41:14 2012 +0000 @@ -28,11 +28,13 @@ void update_font(ASS_Renderer *render_priv); double ensure_font_size(ASS_Renderer *priv, double size); +void calc_border(ASS_Renderer *priv, double border_x, double border_y); void change_border(ASS_Renderer *render_priv, double border_x, double border_y); void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event); void process_karaoke_effects(ASS_Renderer *render_priv); unsigned get_next_char(ASS_Renderer *render_priv, char **str); +char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr); extern void change_alpha(uint32_t *var, uint32_t new, double pwr); extern uint32_t mult_alpha(uint32_t a, uint32_t b);
--- a/libass/ass_render.c Mon Nov 05 21:41:39 2012 +0000 +++ b/libass/ass_render.c Tue Nov 06 05:41:14 2012 +0000 @@ -841,39 +841,44 @@ * \brief partially reset render_context to style values * Works like {\r}: resets some style overrides */ -void reset_render_context(ASS_Renderer *render_priv) +void reset_render_context(ASS_Renderer *render_priv, ASS_Style *style) { - render_priv->state.c[0] = render_priv->state.style->PrimaryColour; - render_priv->state.c[1] = render_priv->state.style->SecondaryColour; - render_priv->state.c[2] = render_priv->state.style->OutlineColour; - render_priv->state.c[3] = render_priv->state.style->BackColour; + if (!style) + style = render_priv->state.style; + + render_priv->state.c[0] = style->PrimaryColour; + render_priv->state.c[1] = style->SecondaryColour; + render_priv->state.c[2] = style->OutlineColour; + render_priv->state.c[3] = style->BackColour; render_priv->state.flags = - (render_priv->state.style->Underline ? DECO_UNDERLINE : 0) | - (render_priv->state.style->StrikeOut ? DECO_STRIKETHROUGH : 0); - render_priv->state.font_size = render_priv->state.style->FontSize; + (style->Underline ? DECO_UNDERLINE : 0) | + (style->StrikeOut ? DECO_STRIKETHROUGH : 0); + render_priv->state.font_size = style->FontSize; free(render_priv->state.family); render_priv->state.family = NULL; - render_priv->state.family = strdup(render_priv->state.style->FontName); + render_priv->state.family = strdup(style->FontName); render_priv->state.treat_family_as_pattern = - render_priv->state.style->treat_fontname_as_pattern; - render_priv->state.bold = render_priv->state.style->Bold; - render_priv->state.italic = render_priv->state.style->Italic; + style->treat_fontname_as_pattern; + render_priv->state.bold = style->Bold; + render_priv->state.italic = style->Italic; update_font(render_priv); - change_border(render_priv, -1., -1.); - render_priv->state.scale_x = render_priv->state.style->ScaleX; - render_priv->state.scale_y = render_priv->state.style->ScaleY; - render_priv->state.hspacing = render_priv->state.style->Spacing; + render_priv->state.border_style = style->BorderStyle; + calc_border(render_priv, style->Outline, style->Outline); + change_border(render_priv, render_priv->state.border_x, render_priv->state.border_y); + render_priv->state.scale_x = style->ScaleX; + render_priv->state.scale_y = style->ScaleY; + render_priv->state.hspacing = style->Spacing; render_priv->state.be = 0; render_priv->state.blur = 0.0; - render_priv->state.shadow_x = render_priv->state.style->Shadow; - render_priv->state.shadow_y = render_priv->state.style->Shadow; + render_priv->state.shadow_x = style->Shadow; + render_priv->state.shadow_y = style->Shadow; render_priv->state.frx = render_priv->state.fry = 0.; - render_priv->state.frz = M_PI * render_priv->state.style->Angle / 180.; + render_priv->state.frz = M_PI * style->Angle / 180.; render_priv->state.fax = render_priv->state.fay = 0.; render_priv->state.wrap_style = render_priv->track->WrapStyle; - render_priv->state.font_encoding = render_priv->state.style->Encoding; + render_priv->state.font_encoding = style->Encoding; } /** @@ -886,7 +891,7 @@ render_priv->state.style = render_priv->track->styles + event->Style; render_priv->state.parsed_tags = 0; - reset_render_context(render_priv); + reset_render_context(render_priv, render_priv->state.style); render_priv->state.evt_type = EVENT_NORMAL; render_priv->state.alignment = render_priv->state.style->Alignment; @@ -1036,7 +1041,7 @@ key->scale_y = double_to_d16(info->scale_y); key->outline.x = double_to_d16(info->border_x); key->outline.y = double_to_d16(info->border_y); - key->border_style = priv->state.style->BorderStyle; + key->border_style = info->border_style; key->hash = info->drawing->hash; key->text = info->drawing->text; key->pbo = info->drawing->pbo; @@ -1055,7 +1060,7 @@ key->outline.x = double_to_d16(info->border_x); key->outline.y = double_to_d16(info->border_y); key->flags = info->flags; - key->border_style = priv->state.style->BorderStyle; + key->border_style = info->border_style; } } @@ -1095,10 +1100,14 @@ v.desc = drawing->desc; key.u.drawing.text = strdup(drawing->text); } else { - ass_face_set_size(info->font->faces[info->face_index], - info->font_size); - ass_font_set_transform(info->font, info->scale_x, - info->scale_y, NULL); + // arbitrary, not too small to prevent grid fitting rounding effects + // XXX: this is a rather crude hack + const double ft_size = 256.0; + ass_face_set_size(info->font->faces[info->face_index], ft_size); + ass_font_set_transform(info->font, + info->scale_x * info->font_size / ft_size, + info->scale_y * info->font_size / ft_size, + NULL); FT_Glyph glyph = ass_font_get_glyph(priv->fontconfig_priv, info->font, info->symbol, info->face_index, info->glyph_index, @@ -1113,8 +1122,8 @@ FT_Done_Glyph(glyph); ass_font_get_asc_desc(info->font, info->symbol, &v.asc, &v.desc); - v.asc *= info->scale_y; - v.desc *= info->scale_y; + v.asc *= info->scale_y * info->font_size / ft_size; + v.desc *= info->scale_y * info->font_size / ft_size; } } @@ -1123,7 +1132,7 @@ FT_Outline_Get_CBox(v.outline, &v.bbox_scaled); - if (priv->state.style->BorderStyle == 3 && + if (info->border_style == 3 && (info->border_x > 0 || info->border_y > 0)) { FT_Vector advance; @@ -1141,6 +1150,7 @@ } else if ((info->border_x > 0 || info->border_y > 0) && double_to_d6(info->scale_x) && double_to_d6(info->scale_y)) { + change_border(priv, info->border_x, info->border_y); outline_copy(priv->ftlibrary, v.outline, &v.border); stroke_outline(priv, v.border, double_to_d6(info->border_x * priv->border_scale), @@ -1275,8 +1285,8 @@ // calculating rotation shift vector (from rotation origin to the glyph basepoint) shift.x = key->shift_x; shift.y = key->shift_y; - fax_scaled = info->fax * render_priv->state.scale_x; - fay_scaled = info->fay * render_priv->state.scale_y; + fax_scaled = info->fax / info->scale_y * info->scale_x; + fay_scaled = info->fay / info->scale_x * info->scale_y; // apply rotation transform_3d(shift, outline, border, @@ -1308,7 +1318,7 @@ &hash_val.bm_s, info->be, info->blur * render_priv->border_scale, key->shadow_offset, - render_priv->state.style->BorderStyle); + info->border_style); if (error) info->symbol = 0; @@ -1707,15 +1717,43 @@ num_glyphs = 0; p = event->Text; + int in_tag = 0; + // Event parsing. while (1) { // get next char, executing style override // this affects render_context do { - code = get_next_char(render_priv, &p); - if (render_priv->state.drawing_mode && code) - ass_drawing_add_char(drawing, (char) code); - } while (code && render_priv->state.drawing_mode); // skip everything in drawing mode + code = 0; + if (!in_tag && *p == '{') { // '\0' goes here + p++; + in_tag = 1; + } + if (in_tag) { + int prev_drawing_mode = render_priv->state.drawing_mode; + p = parse_tag(render_priv, p, 1.); + if (*p == '}') { // end of tag + p++; + in_tag = 0; + } else if (*p != '\\') { + ass_msg(render_priv->library, MSGL_V, + "Unable to parse: '%.30s'", p); + } + if (prev_drawing_mode && !render_priv->state.drawing_mode) { + // Drawing mode was just disabled. We must exit and draw it + // immediately, instead of letting further tags affect it. + // See bug #47. + break; + } + } else { + code = get_next_char(render_priv, &p); + if (code && render_priv->state.drawing_mode) { + ass_drawing_add_char(drawing, (char) code); + continue; // skip everything in drawing mode + } + break; + } + } while (*p); if (text_info->length >= text_info->max_glyphs) { // Raise maximum number of glyphs @@ -1734,7 +1772,6 @@ render_priv->font_scale; drawing->scale_y = render_priv->state.scale_y * render_priv->font_scale; - p--; code = 0xfffc; // object replacement character glyphs[text_info->length].drawing = drawing; } @@ -1762,16 +1799,18 @@ render_priv->state.effect_timing; glyphs[text_info->length].effect_skip_timing = render_priv->state.effect_skip_timing; - glyphs[text_info->length].font_size = ensure_font_size(render_priv, - render_priv->state.font_size * render_priv->font_scale); + glyphs[text_info->length].font_size = + render_priv->state.font_size * render_priv->font_scale; glyphs[text_info->length].be = render_priv->state.be; glyphs[text_info->length].blur = render_priv->state.blur; glyphs[text_info->length].shadow_x = render_priv->state.shadow_x; glyphs[text_info->length].shadow_y = render_priv->state.shadow_y; glyphs[text_info->length].scale_x= render_priv->state.scale_x; glyphs[text_info->length].scale_y = render_priv->state.scale_y; + glyphs[text_info->length].border_style = render_priv->state.border_style; glyphs[text_info->length].border_x= render_priv->state.border_x; glyphs[text_info->length].border_y = render_priv->state.border_y; + glyphs[text_info->length].hspacing = render_priv->state.hspacing; glyphs[text_info->length].bold = render_priv->state.bold; glyphs[text_info->length].italic = render_priv->state.italic; glyphs[text_info->length].flags = render_priv->state.flags; @@ -1829,11 +1868,11 @@ } // add horizontal letter spacing - info->cluster_advance.x += double_to_d6(render_priv->state.hspacing * + info->cluster_advance.x += double_to_d6(info->hspacing * render_priv->font_scale * info->scale_x); // add displacement for vertical shearing - info->cluster_advance.y += (info->fay * info->scale_y) * info->cluster_advance.x; + info->cluster_advance.y += (info->fay / info->scale_x * info->scale_y) * info->cluster_advance.x; } @@ -1906,6 +1945,7 @@ for (i = 0; i < text_info->length; i++) { GlyphInfo *info = glyphs + cmap[i]; if (glyphs[i].linebreak) { + pen.y -= (info->fay / info->scale_x * info->scale_y) * pen.x; pen.x = 0; pen.y += double_to_d6(text_info->lines[lineno-1].desc); pen.y += double_to_d6(text_info->lines[lineno].asc); @@ -1995,16 +2035,25 @@ y2scr(render_priv, render_priv->track->PlayResY / 2.0); device_y = scr_y - (bbox.yMax + bbox.yMin) / 2.0; } else { // subtitle - double scr_y; + double scr_top, scr_bottom, scr_y0; if (valign != VALIGN_SUB) ass_msg(render_priv->library, MSGL_V, "Invalid valign, assuming 0 (subtitle)"); - scr_y = + scr_bottom = y2scr_sub(render_priv, render_priv->track->PlayResY - MarginV); - device_y = scr_y; + scr_top = y2scr_top(render_priv, 0); //xxx not always 0? + device_y = scr_bottom + (scr_top - scr_bottom) * + render_priv->settings.line_position / 100.0; device_y -= text_info->height; device_y += text_info->lines[0].asc; + // clip to top to avoid confusion if line_position is very high, + // turning the subtitle into a toptitle + // also, don't change behavior if line_position is not used + scr_y0 = scr_top + text_info->lines[0].asc; + if (device_y < scr_y0 && render_priv->settings.line_position > 0) { + device_y = scr_y0; + } } } else if (render_priv->state.evt_type == EVENT_VSCROLL) { if (render_priv->state.scroll_direction == SCROLL_TB) @@ -2158,12 +2207,14 @@ ass_cache_empty(cache->composite_cache, 0); ass_free_images(priv->prev_images_root); priv->prev_images_root = 0; + priv->cache_cleared = 1; } if (ass_cache_empty(cache->outline_cache, cache->glyph_max)) { ass_cache_empty(cache->bitmap_cache, 0); ass_cache_empty(cache->composite_cache, 0); ass_free_images(priv->prev_images_root); priv->prev_images_root = 0; + priv->cache_cleared = 1; } } @@ -2429,6 +2480,9 @@ ASS_Image *img, *img2; int diff; + if (priv->cache_cleared) + return 2; + img = priv->prev_images_root; img2 = priv->images_root; diff = 0; @@ -2474,8 +2528,12 @@ // init frame rc = ass_start_frame(priv, track, now); - if (rc != 0) + if (rc != 0) { + if (detect_change) { + *detect_change = 2; + } return 0; + } // render events separately cnt = 0; @@ -2525,6 +2583,7 @@ // free the previous image list ass_free_images(priv->prev_images_root); priv->prev_images_root = 0; + priv->cache_cleared = 0; return priv->images_root; }
--- a/libass/ass_render.h Mon Nov 05 21:41:39 2012 +0000 +++ b/libass/ass_render.h Tue Nov 06 05:41:14 2012 +0000 @@ -67,6 +67,7 @@ int frame_height; double font_size_coeff; // font size multiplier double line_spacing; // additional line spacing (in frame pixels) + double line_position; // vertical position for subtitles, 0-100 (0 = no change) int top_margin; // height of top margin. Everything except toptitles is shifted down by top_margin. int bottom_margin; // height of bottom margin. (frame_height - top_margin - bottom_margin) is original video height. int left_margin; @@ -133,7 +134,9 @@ double frx, fry, frz; // rotation double fax, fay; // text shearing double scale_x, scale_y; + int border_style; double border_x, border_y; + double hspacing; unsigned italic; unsigned bold; int flags; @@ -174,6 +177,7 @@ int flags; // decoration flags (underline/strike-through) FT_Stroker stroker; + int stroker_radius; // last stroker radius, for caching stroker objects int alignment; // alignment overrides go here; if zero, style value will be used double frx, fry, frz; double fax, fay; // text shearing @@ -188,6 +192,7 @@ char have_origin; // origin is explicitly defined; if 0, get_base_point() is used double scale_x, scale_y; double hspacing; // distance between letters, in pixels + int border_style; double border_x; // outline width double border_y; uint32_t c[4]; // colors(Primary, Secondary, so on) in RGBA @@ -248,6 +253,7 @@ ASS_Image *images_root; // rendering result is stored here ASS_Image *prev_images_root; + int cache_cleared; EventImages *eimg; // temporary buffer for sorting rendered events int eimg_size; // allocated buffer size @@ -289,7 +295,7 @@ int ha, hb; // left and width } Segment; -void reset_render_context(ASS_Renderer *render_priv); +void reset_render_context(ASS_Renderer *render_priv, ASS_Style *style); void ass_free_images(ASS_Image *img); // XXX: this is actually in ass.c, includes should be fixed later on
--- a/libass/ass_render_api.c Mon Nov 05 21:41:39 2012 +0000 +++ b/libass/ass_render_api.c Tue Nov 06 05:41:14 2012 +0000 @@ -116,6 +116,14 @@ priv->settings.line_spacing = line_spacing; } +void ass_set_line_position(ASS_Renderer *priv, double line_position) +{ + if (priv->settings.line_position != line_position) { + priv->settings.line_position = line_position; + ass_reconfigure(priv); + } +} + void ass_set_fonts(ASS_Renderer *priv, const char *default_font, const char *default_family, int fc, const char *config, int update)
--- a/libass/ass_shaper.c Mon Nov 05 21:41:39 2012 +0000 +++ b/libass/ass_shaper.c Tue Nov 06 05:41:14 2012 +0000 @@ -401,7 +401,9 @@ font->faces[info->face_index], NULL); } - ass_face_set_size(font->faces[info->face_index], info->font_size); + // XXX: this is a rather crude hack + const double ft_size = 256.0; + ass_face_set_size(font->faces[info->face_index], ft_size); update_hb_size(hb_fonts[info->face_index], font->faces[info->face_index]); // update hash key for cached metrics @@ -431,7 +433,7 @@ hb_buffer_t *buf; hb_font_t *font; } runs[MAX_RUNS]; - + const double ft_size = 256.0; for (i = 0; i < len && run < MAX_RUNS; i++, run++) { // get length and level of the current run @@ -484,10 +486,10 @@ // set position and advance info->skip = 0; info->glyph_index = glyph_info[j].codepoint; - info->offset.x = pos[j].x_offset * info->scale_x; - info->offset.y = -pos[j].y_offset * info->scale_y; - info->advance.x = pos[j].x_advance * info->scale_x; - info->advance.y = -pos[j].y_advance * info->scale_y; + info->offset.x = pos[j].x_offset * info->scale_x * (info->font_size / ft_size); + info->offset.y = -pos[j].y_offset * info->scale_y * (info->font_size / ft_size); + info->advance.x = pos[j].x_advance * info->scale_x * (info->font_size / ft_size); + info->advance.y = -pos[j].y_advance * info->scale_y * (info->font_size / ft_size); // accumulate advance in the root glyph root->cluster_advance.x += info->advance.x; @@ -602,6 +604,29 @@ } /** + * \brief Remove all zero-width invisible characters from the text. + * \param text_info text + */ +static void ass_shaper_skip_characters(TextInfo *text_info) +{ + int i; + GlyphInfo *glyphs = text_info->glyphs; + + for (i = 0; i < text_info->length; i++) { + // Skip direction override control characters + if ((glyphs[i].symbol <= 0x202e && glyphs[i].symbol >= 0x202a) + || (glyphs[i].symbol <= 0x200f && glyphs[i].symbol >= 0x200b) + || (glyphs[i].symbol <= 0x2063 && glyphs[i].symbol >= 0x2060) + || glyphs[i].symbol == 0xfeff + || glyphs[i].symbol == 0x00ad + || glyphs[i].symbol == 0x034f) { + glyphs[i].symbol = 0; + glyphs[i].skip++; + } + } +} + +/** * \brief Shape an event's text. Calculates directional runs and shapes them. * \param text_info event's text */ @@ -639,27 +664,15 @@ #ifdef CONFIG_HARFBUZZ switch (shaper->shaping_level) { case ASS_SHAPING_SIMPLE: - shape_fribidi(shaper, glyphs, text_info->length); + ass_shaper_skip_characters(text_info); break; case ASS_SHAPING_COMPLEX: shape_harfbuzz(shaper, glyphs, text_info->length); break; } #else - shape_fribidi(shaper, glyphs, text_info->length); + ass_shaper_skip_characters(text_info); #endif - - - // clean up - for (i = 0; i < text_info->length; i++) { - // Skip direction override control characters - // NOTE: Behdad said HarfBuzz is supposed to remove these, but this hasn't - // been implemented yet - if (glyphs[i].symbol <= 0x202F && glyphs[i].symbol >= 0x202a) { - glyphs[i].symbol = 0; - glyphs[i].skip++; - } - } #endif } @@ -733,17 +746,18 @@ } /** - * \brief Resolve a Windows font encoding number to a suitable + * \brief Resolve a Windows font charset number to a suitable * base direction. 177 and 178 are Hebrew and Arabic respectively, and - * they map to RTL. 1 is autodetection and is mapped to just that. - * Everything else is mapped to LTR. + * they map to RTL. Everything else maps to LTR for compatibility + * reasons. The special value -1, which is not a legal Windows font charset + * number, can be used for autodetection. * \param enc Windows font encoding */ FriBidiParType resolve_base_direction(int enc) { #ifdef CONFIG_FRIBIDI switch (enc) { - case 1: + case -1: return FRIBIDI_PAR_ON; case 177: case 178:
--- a/libass/ass_utils.c Mon Nov 05 21:41:39 2012 +0000 +++ b/libass/ass_utils.c Tue Nov 06 05:41:14 2012 +0000 @@ -160,6 +160,30 @@ return c; } +/** + * \brief find style by name + * \param track track + * \param name style name + * \return index in track->styles + * Returnes 0 if no styles found => expects at least 1 style. + * Parsing code always adds "Default" style in the end. + */ +int lookup_style(ASS_Track *track, char *name) +{ + int i; + if (*name == '*') + ++name; // FIXME: what does '*' really mean ? + for (i = track->n_styles - 1; i >= 0; --i) { + if (strcmp(track->styles[i].Name, name) == 0) + return i; + } + i = track->default_style; + ass_msg(track->library, MSGL_WARN, + "[%p]: Warning: no style named '%s' found, using '%s'", + track, name, track->styles[i].Name); + return i; // use the first style +} + #ifdef CONFIG_ENCA void *ass_guess_buffer_cp(ASS_Library *library, unsigned char *buffer, int buflen, char *preferred_language,
--- a/libass/ass_utils.h Mon Nov 05 21:41:39 2012 +0000 +++ b/libass/ass_utils.h Tue Nov 06 05:41:14 2012 +0000 @@ -51,6 +51,7 @@ char parse_bool(char *str); unsigned ass_utf8_get_char(char **str); void ass_msg(ASS_Library *priv, int lvl, char *fmt, ...); +int lookup_style(ASS_Track *track, char *name); #ifdef CONFIG_ENCA void *ass_guess_buffer_cp(ASS_Library *library, unsigned char *buffer, int buflen, char *preferred_language,