Ticket #2099: libass.patch

File libass.patch, 32.6 KB (added by subjunk@…, 14 years ago)

libass 0.10.1 patch

  • ass.c

     
    191191    style->MarginL = style->MarginR = style->MarginV = 20;
    192192}
    193193
    194 /**
    195  * \brief find style by name
    196  * \param track track
    197  * \param name style name
    198  * \return index in track->styles
    199  * 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 style
    216 }
    217 
    218194static uint32_t string2color(ASS_Library *library, char *p)
    219195{
    220196    uint32_t tmp;
  • ass.h

     
    2323#include <stdarg.h>
    2424#include "ass_types.h"
    2525
    26 #define LIBASS_VERSION 0x01000000
     26#define LIBASS_VERSION 0x01010000
    2727
    2828/*
    2929 * A linked list of images produced by an ass renderer.
     
    214214void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing);
    215215
    216216/**
     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 */
     222void ass_set_line_position(ASS_Renderer *priv, double line_position);
     223
     224/**
    217225 * \brief Set font lookup defaults.
    218226 * \param default_font path to default font to use. Must be supplied if
    219227 * fontconfig is disabled or unavailable.
  • ass_drawing.c

     
    8787static void drawing_finish(ASS_Drawing *drawing, int raw_mode)
    8888{
    8989    int i, offset;
     90    double pbo;
    9091    FT_BBox bbox = drawing->cbox;
    9192    FT_Outline *ol = &drawing->outline;
    9293
     
    103104
    104105    drawing->advance.x = bbox.xMax - bbox.xMin;
    105106
    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);
    107109    drawing->asc = bbox.yMax - bbox.yMin + drawing->desc;
    108110
    109111    // 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 *
    111113                                                    drawing->scale_y);
    112114    for (i = 0; i < ol->n_points; i++)
    113115        ol->points[i].y += offset;
  • ass_parse.c

     
    105105}
    106106
    107107/**
    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
    110113 */
    111 void change_border(ASS_Renderer *render_priv, double border_x,
    112                    double border_y)
     114void calc_border(ASS_Renderer *priv, double border_x, double border_y)
    113115{
    114     int bord;
    115     if (!render_priv->state.font)
    116         return;
    117 
    118116    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;
    122120        else
    123121            border_x = border_y = 1.;
    124122    }
    125123
    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}
    128127
    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 */
     134void change_border(ASS_Renderer *render_priv, double border_x, double border_y)
     135{
     136    int bord = 64 * border_x * render_priv->border_scale;
     137
    130138    if (bord > 0 && border_x == border_y) {
    131139        if (!render_priv->state.stroker) {
    132140            int error;
     
    138146                        "failed to get stroker");
    139147                render_priv->state.stroker = 0;
    140148            }
     149            render_priv->state.stroker_radius = -1.0;
    141150        }
    142         if (render_priv->state.stroker)
     151        if (render_priv->state.stroker && render_priv->state.stroker_radius != bord) {
    143152            FT_Stroker_Set(render_priv->state.stroker, bord,
    144153                           FT_STROKER_LINECAP_ROUND,
    145154                           FT_STROKER_LINEJOIN_ROUND, 0);
     155            render_priv->state.stroker_radius = bord;
     156        }
    146157    } else {
    147158        FT_Stroker_Done(render_priv->state.stroker);
    148159        render_priv->state.stroker = 0;
     
    242253 * \param p string to parse
    243254 * \param pwr multiplier for some tag effects (comes from \t tags)
    244255 */
    245 static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
     256char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
    246257{
    247258    skip_to('\\');
    248259    skip('\\');
     
    256267            val = render_priv->state.border_x * (1 - pwr) + val * pwr;
    257268        else
    258269            val = -1.;
    259         change_border(render_priv, val, render_priv->state.border_y);
     270        calc_border(render_priv, val, render_priv->state.border_y);
    260271        render_priv->state.bm_run_id++;
    261272    } else if (mystrcmp(&p, "ybord")) {
    262273        double val;
     
    264275            val = render_priv->state.border_y * (1 - pwr) + val * pwr;
    265276        else
    266277            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++;
    268280    } else if (mystrcmp(&p, "xshad")) {
    269281        double val;
    270282        if (mystrtod(&p, &val))
     
    388400    } else if (mystrcmp(&p, "bord")) {
    389401        double val;
    390402        if (mystrtod(&p, &val)) {
    391             if (render_priv->state.border_x == render_priv->state.border_y)
    392403                val = render_priv->state.border_x * (1 - pwr) + val * pwr;
    393404        } else
    394405            val = -1.;          // reset to default
    395         change_border(render_priv, val, val);
     406        calc_border(render_priv, val, val);
    396407        render_priv->state.bm_run_id++;
    397408    } else if (mystrcmp(&p, "move")) {
    398409        double x1, x2, y1, y2;
     
    730741        ass_msg(render_priv->library, MSGL_DBG2, "single c/a at %f: %c%c = %X",
    731742               pwr, n, cmd, render_priv->state.c[cidx]);
    732743    } 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);
    734756    } else if (mystrcmp(&p, "be")) {
    735757        int val;
    736758        if (mystrtoi(&p, &val)) {
     
    977999
    9781000
    9791001/**
    980  * \brief Get next ucs4 char from string, parsing and executing style overrides
     1002 * \brief Get next ucs4 char from string, parsing UTF-8 and escapes
    9811003 * \param str string pointer
    9821004 * \return ucs4 code of the next char
    9831005 * On return str points to the unparsed part of the string
     
    9861008{
    9871009    char *p = *str;
    9881010    unsigned chr;
    989     if (*p == '{') {            // '\0' goes here
    990         p++;
    991         while (1) {
    992             p = parse_tag(render_priv, p, 1.);
    993             if (*p == '}') {    // end of tag
    994                 p++;
    995                 if (*p == '{') {
    996                     p++;
    997                     continue;
    998                 } else
    999                     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     }
    10071011    if (*p == '\t') {
    10081012        ++p;
    10091013        *str = p;
  • ass_parse.h

     
    2828
    2929void update_font(ASS_Renderer *render_priv);
    3030double ensure_font_size(ASS_Renderer *priv, double size);
     31void calc_border(ASS_Renderer *priv, double border_x, double border_y);
    3132void change_border(ASS_Renderer *render_priv, double border_x,
    3233                   double border_y);
    3334void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event);
    3435void process_karaoke_effects(ASS_Renderer *render_priv);
    3536unsigned get_next_char(ASS_Renderer *render_priv, char **str);
     37char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr);
    3638extern void change_alpha(uint32_t *var, uint32_t new, double pwr);
    3739extern uint32_t mult_alpha(uint32_t a, uint32_t b);
    3840
  • ass_render.c

     
    841841 * \brief partially reset render_context to style values
    842842 * Works like {\r}: resets some style overrides
    843843 */
    844 void reset_render_context(ASS_Renderer *render_priv)
     844void reset_render_context(ASS_Renderer *render_priv, ASS_Style *style)
    845845{
    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;
    850853    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;
    854857
    855858    free(render_priv->state.family);
    856859    render_priv->state.family = NULL;
    857     render_priv->state.family = strdup(render_priv->state.style->FontName);
     860    render_priv->state.family = strdup(style->FontName);
    858861    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;
    862865    update_font(render_priv);
    863866
    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;
    868873    render_priv->state.be = 0;
    869874    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;
    872877    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.;
    874879    render_priv->state.fax = render_priv->state.fay = 0.;
    875880    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;
    877882}
    878883
    879884/**
     
    886891    render_priv->state.style = render_priv->track->styles + event->Style;
    887892    render_priv->state.parsed_tags = 0;
    888893
    889     reset_render_context(render_priv);
     894    reset_render_context(render_priv, render_priv->state.style);
    890895
    891896    render_priv->state.evt_type = EVENT_NORMAL;
    892897    render_priv->state.alignment = render_priv->state.style->Alignment;
     
    10361041        key->scale_y = double_to_d16(info->scale_y);
    10371042        key->outline.x = double_to_d16(info->border_x);
    10381043        key->outline.y = double_to_d16(info->border_y);
    1039         key->border_style = priv->state.style->BorderStyle;
     1044        key->border_style = info->border_style;
    10401045        key->hash = info->drawing->hash;
    10411046        key->text = info->drawing->text;
    10421047        key->pbo = info->drawing->pbo;
     
    10551060        key->outline.x = double_to_d16(info->border_x);
    10561061        key->outline.y = double_to_d16(info->border_y);
    10571062        key->flags = info->flags;
    1058         key->border_style = priv->state.style->BorderStyle;
     1063        key->border_style = info->border_style;
    10591064    }
    10601065}
    10611066
     
    10951100            v.desc = drawing->desc;
    10961101            key.u.drawing.text = strdup(drawing->text);
    10971102        } 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);
    11021111            FT_Glyph glyph =
    11031112                ass_font_get_glyph(priv->fontconfig_priv, info->font,
    11041113                        info->symbol, info->face_index, info->glyph_index,
     
    11131122                FT_Done_Glyph(glyph);
    11141123                ass_font_get_asc_desc(info->font, info->symbol,
    11151124                        &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;
    11181127            }
    11191128        }
    11201129
     
    11231132
    11241133        FT_Outline_Get_CBox(v.outline, &v.bbox_scaled);
    11251134
    1126         if (priv->state.style->BorderStyle == 3 &&
     1135        if (info->border_style == 3 &&
    11271136                (info->border_x > 0 || info->border_y > 0)) {
    11281137            FT_Vector advance;
    11291138
     
    11411150        } else if ((info->border_x > 0 || info->border_y > 0)
    11421151                && double_to_d6(info->scale_x) && double_to_d6(info->scale_y)) {
    11431152
     1153            change_border(priv, info->border_x, info->border_y);
    11441154            outline_copy(priv->ftlibrary, v.outline, &v.border);
    11451155            stroke_outline(priv, v.border,
    11461156                    double_to_d6(info->border_x * priv->border_scale),
     
    12751285        // calculating rotation shift vector (from rotation origin to the glyph basepoint)
    12761286        shift.x = key->shift_x;
    12771287        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;
    12801290
    12811291        // apply rotation
    12821292        transform_3d(shift, outline, border,
     
    13081318                &hash_val.bm_s, info->be,
    13091319                info->blur * render_priv->border_scale,
    13101320                key->shadow_offset,
    1311                 render_priv->state.style->BorderStyle);
     1321                info->border_style);
    13121322        if (error)
    13131323            info->symbol = 0;
    13141324
     
    17071717    num_glyphs = 0;
    17081718    p = event->Text;
    17091719
     1720    int in_tag = 0;
     1721
    17101722    // Event parsing.
    17111723    while (1) {
    17121724        // get next char, executing style override
    17131725        // this affects render_context
    17141726        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);
    17191757
    17201758        if (text_info->length >= text_info->max_glyphs) {
    17211759            // Raise maximum number of glyphs
     
    17341772                                     render_priv->font_scale;
    17351773            drawing->scale_y = render_priv->state.scale_y *
    17361774                                     render_priv->font_scale;
    1737             p--;
    17381775            code = 0xfffc; // object replacement character
    17391776            glyphs[text_info->length].drawing = drawing;
    17401777        }
     
    17621799            render_priv->state.effect_timing;
    17631800        glyphs[text_info->length].effect_skip_timing =
    17641801            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;
    17671804        glyphs[text_info->length].be = render_priv->state.be;
    17681805        glyphs[text_info->length].blur = render_priv->state.blur;
    17691806        glyphs[text_info->length].shadow_x = render_priv->state.shadow_x;
    17701807        glyphs[text_info->length].shadow_y = render_priv->state.shadow_y;
    17711808        glyphs[text_info->length].scale_x= render_priv->state.scale_x;
    17721809        glyphs[text_info->length].scale_y = render_priv->state.scale_y;
     1810        glyphs[text_info->length].border_style = render_priv->state.border_style;
    17731811        glyphs[text_info->length].border_x= render_priv->state.border_x;
    17741812        glyphs[text_info->length].border_y = render_priv->state.border_y;
     1813        glyphs[text_info->length].hspacing = render_priv->state.hspacing;
    17751814        glyphs[text_info->length].bold = render_priv->state.bold;
    17761815        glyphs[text_info->length].italic = render_priv->state.italic;
    17771816        glyphs[text_info->length].flags = render_priv->state.flags;
     
    18291868        }
    18301869
    18311870        // 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 *
    18331872                render_priv->font_scale * info->scale_x);
    18341873
    18351874        // 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;
    18371876
    18381877    }
    18391878
     
    19061945    for (i = 0; i < text_info->length; i++) {
    19071946        GlyphInfo *info = glyphs + cmap[i];
    19081947        if (glyphs[i].linebreak) {
     1948            pen.y -= (info->fay / info->scale_x * info->scale_y) * pen.x;
    19091949            pen.x = 0;
    19101950            pen.y += double_to_d6(text_info->lines[lineno-1].desc);
    19111951            pen.y += double_to_d6(text_info->lines[lineno].asc);
     
    19952035                y2scr(render_priv, render_priv->track->PlayResY / 2.0);
    19962036            device_y = scr_y - (bbox.yMax + bbox.yMin) / 2.0;
    19972037        } else {                // subtitle
    1998             double scr_y;
     2038            double scr_top, scr_bottom, scr_y0;
    19992039            if (valign != VALIGN_SUB)
    20002040                ass_msg(render_priv->library, MSGL_V,
    20012041                       "Invalid valign, assuming 0 (subtitle)");
    2002             scr_y =
     2042            scr_bottom =
    20032043                y2scr_sub(render_priv,
    20042044                          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;
    20062048            device_y -= text_info->height;
    20072049            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            }
    20082057        }
    20092058    } else if (render_priv->state.evt_type == EVENT_VSCROLL) {
    20102059        if (render_priv->state.scroll_direction == SCROLL_TB)
     
    21582207        ass_cache_empty(cache->composite_cache, 0);
    21592208        ass_free_images(priv->prev_images_root);
    21602209        priv->prev_images_root = 0;
     2210        priv->cache_cleared = 1;
    21612211    }
    21622212    if (ass_cache_empty(cache->outline_cache, cache->glyph_max)) {
    21632213        ass_cache_empty(cache->bitmap_cache, 0);
    21642214        ass_cache_empty(cache->composite_cache, 0);
    21652215        ass_free_images(priv->prev_images_root);
    21662216        priv->prev_images_root = 0;
     2217        priv->cache_cleared = 1;
    21672218    }
    21682219}
    21692220
     
    24292480    ASS_Image *img, *img2;
    24302481    int diff;
    24312482
     2483    if (priv->cache_cleared)
     2484        return 2;
     2485
    24322486    img = priv->prev_images_root;
    24332487    img2 = priv->images_root;
    24342488    diff = 0;
     
    24742528
    24752529    // init frame
    24762530    rc = ass_start_frame(priv, track, now);
    2477     if (rc != 0)
     2531    if (rc != 0) {
     2532        if (detect_change) {
     2533            *detect_change = 2;
     2534        }
    24782535        return 0;
     2536    }
    24792537
    24802538    // render events separately
    24812539    cnt = 0;
     
    25252583    // free the previous image list
    25262584    ass_free_images(priv->prev_images_root);
    25272585    priv->prev_images_root = 0;
     2586    priv->cache_cleared = 0;
    25282587
    25292588    return priv->images_root;
    25302589}
  • ass_render.h

     
    6767    int frame_height;
    6868    double font_size_coeff;     // font size multiplier
    6969    double line_spacing;        // additional line spacing (in frame pixels)
     70    double line_position;       // vertical position for subtitles, 0-100 (0 = no change)
    7071    int top_margin;             // height of top margin. Everything except toptitles is shifted down by top_margin.
    7172    int bottom_margin;          // height of bottom margin. (frame_height - top_margin - bottom_margin) is original video height.
    7273    int left_margin;
     
    133134    double frx, fry, frz;       // rotation
    134135    double fax, fay;            // text shearing
    135136    double scale_x, scale_y;
     137    int border_style;
    136138    double border_x, border_y;
     139    double hspacing;
    137140    unsigned italic;
    138141    unsigned bold;
    139142    int flags;
     
    174177    int flags;                  // decoration flags (underline/strike-through)
    175178
    176179    FT_Stroker stroker;
     180    int stroker_radius;         // last stroker radius, for caching stroker objects
    177181    int alignment;              // alignment overrides go here; if zero, style value will be used
    178182    double frx, fry, frz;
    179183    double fax, fay;            // text shearing
     
    188192    char have_origin;           // origin is explicitly defined; if 0, get_base_point() is used
    189193    double scale_x, scale_y;
    190194    double hspacing;            // distance between letters, in pixels
     195    int border_style;
    191196    double border_x;            // outline width
    192197    double border_y;
    193198    uint32_t c[4];              // colors(Primary, Secondary, so on) in RGBA
     
    248253
    249254    ASS_Image *images_root;     // rendering result is stored here
    250255    ASS_Image *prev_images_root;
     256    int cache_cleared;
    251257
    252258    EventImages *eimg;          // temporary buffer for sorting rendered events
    253259    int eimg_size;              // allocated buffer size
     
    289295    int ha, hb;                 // left and width
    290296} Segment;
    291297
    292 void reset_render_context(ASS_Renderer *render_priv);
     298void reset_render_context(ASS_Renderer *render_priv, ASS_Style *style);
    293299void ass_free_images(ASS_Image *img);
    294300
    295301// XXX: this is actually in ass.c, includes should be fixed later on
  • ass_render_api.c

     
    116116    priv->settings.line_spacing = line_spacing;
    117117}
    118118
     119void 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
    119127void ass_set_fonts(ASS_Renderer *priv, const char *default_font,
    120128                   const char *default_family, int fc, const char *config,
    121129                   int update)
  • ass_shaper.c

     
    401401                font->faces[info->face_index], NULL);
    402402    }
    403403
    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);
    405407    update_hb_size(hb_fonts[info->face_index], font->faces[info->face_index]);
    406408
    407409    // update hash key for cached metrics
     
    431433        hb_buffer_t *buf;
    432434        hb_font_t *font;
    433435    } runs[MAX_RUNS];
     436    const double ft_size = 256.0;
    434437
    435 
    436438    for (i = 0; i < len && run < MAX_RUNS; i++, run++) {
    437439        // get length and level of the current run
    438440        int k = i;
     
    484486            // set position and advance
    485487            info->skip = 0;
    486488            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);
    491493
    492494            // accumulate advance in the root glyph
    493495            root->cluster_advance.x += info->advance.x;
     
    602604}
    603605
    604606/**
     607  * \brief Remove all zero-width invisible characters from the text.
     608  * \param text_info text
     609  */
     610static 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/**
    605630 * \brief Shape an event's text. Calculates directional runs and shapes them.
    606631 * \param text_info event's text
    607632 */
     
    639664#ifdef CONFIG_HARFBUZZ
    640665    switch (shaper->shaping_level) {
    641666    case ASS_SHAPING_SIMPLE:
    642         shape_fribidi(shaper, glyphs, text_info->length);
     667        ass_shaper_skip_characters(text_info);
    643668        break;
    644669    case ASS_SHAPING_COMPLEX:
    645670        shape_harfbuzz(shaper, glyphs, text_info->length);
    646671        break;
    647672    }
    648673#else
    649         shape_fribidi(shaper, glyphs, text_info->length);
     674        ass_shaper_skip_characters(text_info);
    650675#endif
    651 
    652 
    653     // clean up
    654     for (i = 0; i < text_info->length; i++) {
    655         // Skip direction override control characters
    656         // NOTE: Behdad said HarfBuzz is supposed to remove these, but this hasn't
    657         // been implemented yet
    658         if (glyphs[i].symbol <= 0x202F && glyphs[i].symbol >= 0x202a) {
    659             glyphs[i].symbol = 0;
    660             glyphs[i].skip++;
    661         }
    662     }
    663676#endif
    664677}
    665678
     
    733746}
    734747
    735748/**
    736  * \brief Resolve a Windows font encoding number to a suitable
     749 * \brief Resolve a Windows font charset number to a suitable
    737750 * 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.
    740754 * \param enc Windows font encoding
    741755 */
    742756FriBidiParType resolve_base_direction(int enc)
    743757{
    744758#ifdef CONFIG_FRIBIDI
    745759    switch (enc) {
    746         case 1:
     760        case -1:
    747761            return FRIBIDI_PAR_ON;
    748762        case 177:
    749763        case 178:
  • ass_utils.c

     
    160160    return c;
    161161}
    162162
     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 */
     171int 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
    163187#ifdef CONFIG_ENCA
    164188void *ass_guess_buffer_cp(ASS_Library *library, unsigned char *buffer,
    165189                          int buflen, char *preferred_language,
  • ass_utils.h

     
    5151char parse_bool(char *str);
    5252unsigned ass_utf8_get_char(char **str);
    5353void ass_msg(ASS_Library *priv, int lvl, char *fmt, ...);
     54int lookup_style(ASS_Track *track, char *name);
    5455#ifdef CONFIG_ENCA
    5556void *ass_guess_buffer_cp(ASS_Library *library, unsigned char *buffer,
    5657                          int buflen, char *preferred_language,