diff options
-rw-r--r-- | Changelog | 10 | ||||
-rw-r--r-- | README.md | 5 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | libass/Makefile.am | 4 | ||||
-rw-r--r-- | libass/ass.c | 13 | ||||
-rw-r--r-- | libass/ass.h | 87 | ||||
-rw-r--r-- | libass/ass_bitmap.c | 13 | ||||
-rw-r--r-- | libass/ass_cache_template.h | 6 | ||||
-rw-r--r-- | libass/ass_drawing.c | 7 | ||||
-rw-r--r-- | libass/ass_parse.c | 141 | ||||
-rw-r--r-- | libass/ass_parse.h | 4 | ||||
-rw-r--r-- | libass/ass_rasterizer.c | 17 | ||||
-rw-r--r-- | libass/ass_rasterizer.h | 6 | ||||
-rw-r--r-- | libass/ass_rasterizer_c.c | 8 | ||||
-rw-r--r-- | libass/ass_render.c | 229 | ||||
-rw-r--r-- | libass/ass_render.h | 9 | ||||
-rw-r--r-- | libass/ass_render_api.c | 1 | ||||
-rw-r--r-- | libass/ass_shaper.c | 4 | ||||
-rw-r--r-- | libass/ass_utils.c | 123 | ||||
-rw-r--r-- | libass/ass_utils.h | 22 | ||||
-rw-r--r-- | libass/x86/rasterizer.asm | 15 | ||||
-rw-r--r-- | libass/x86/rasterizer.h | 8 |
22 files changed, 484 insertions, 250 deletions
@@ -1,3 +1,13 @@ +libass (0.12.2) + * Add extern "C" guards to the public headers for C++ compatibility + * Improvements to style override API and implementation + * Bugfixes + * Fix some rasterizer bugs of unknown severity + * Fix a broken memset() of unknown severity + * Make timestamp parsing more lenient, which makes libass accept invalid + files accepted by most other ASS parsers + * Increase compatibility with broken ASS drawings accepted by VSFilter + libass (0.12.1) * Make ASS drawings with an extremely high number of control points work This change increases compatibility with VSFilter. @@ -8,7 +8,7 @@ libass is a portable subtitle renderer for the ASS/SSA (Advanced Substation Alph Get it ====== -See [GitHub releases](https://github.com/libass/libass/releases) for the latest release 0.12.1 (released 2015-01-07). This release contains bugfixes and compatibility fixes. See the [changelog](https://github.com/libass/libass/blob/master/Changelog) for a detailed list of changes. +See [GitHub releases](https://github.com/libass/libass/releases) for the latest release 0.12.2 (released 2015-05-07). This release contains bugfixes and compatibility fixes. See the [changelog](https://github.com/libass/libass/blob/master/Changelog) for a detailed list of changes. Source code is available from our [GitHub repository](https://github.com/libass/libass). @@ -24,7 +24,7 @@ The following projects/companies use libass: - [mplayer2](http://www.mplayer2.org/) - [mpv](http://mpv.io/) - [VLC](http://www.videolan.org/) -- [GStreamer](http://www.gstreamer.org/) (assrender plugin) +- [GStreamer](http://gstreamer.freedesktop.org/) (assrender plugin) - [Libav](http://libav.org/) - [FFmpeg](http://ffmpeg.org/) - [Aegisub](http://www.aegisub.org/) @@ -53,3 +53,4 @@ Other ASS/SSA implementations: - [ffdshow](http://ffdshow-tryout.sourceforge.net/) - [Perian](https://github.com/MaddTheSane/perian) - [asa](http://git.spaceboyz.net/asa.git) (defunct) +- [libjass](https://github.com/Arnavion/libjass) diff --git a/configure.ac b/configure.ac index 102e143..4b024ce 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(libass, 0.12.1) +AC_INIT(libass, 0.12.2) AM_INIT_AUTOMAKE AC_CONFIG_MACRO_DIR([m4]) # Disable C++/Fortran checks diff --git a/libass/Makefile.am b/libass/Makefile.am index 599c281..31dd9aa 100644 --- a/libass/Makefile.am +++ b/libass/Makefile.am @@ -1,9 +1,9 @@ AM_CFLAGS = -std=gnu99 -Wall -Wextra -Wno-sign-compare -Wno-unused-parameter \ -Werror-implicit-function-declaration -Wstrict-prototypes \ - -Wpointer-arith -Wredundant-decls + -Wpointer-arith -Wredundant-decls -D_GNU_SOURCE LIBASS_LT_CURRENT = 6 -LIBASS_LT_REVISION = 0 +LIBASS_LT_REVISION = 1 LIBASS_LT_AGE = 1 yasm_verbose = $(yasm_verbose_$(V)) diff --git a/libass/ass.c b/libass/ass.c index 04ce895..01dd2eb 100644 --- a/libass/ass.c +++ b/libass/ass.c @@ -183,12 +183,12 @@ static long long string2timecode(ASS_Library *library, char *p) { unsigned h, m, s, ms; long long tm; - int res = sscanf(p, "%1d:%2d:%2d.%2d", &h, &m, &s, &ms); + int res = sscanf(p, "%d:%d:%d.%d", &h, &m, &s, &ms); if (res < 4) { ass_msg(library, MSGL_WARN, "Bad timestamp"); return 0; } - tm = ((h * 60 + m) * 60 + s) * 1000 + ms * 10; + tm = ((h * 60LL + m) * 60 + s) * 1000 + ms * 10; return tm; } @@ -242,10 +242,7 @@ static int numpad2align(int val) while (*token == '*') ++token; \ target->name = strdup(token); -#define COLORVAL(name) \ - } else if (strcasecmp(tname, #name) == 0) { \ - target->name = string2color(track->library, token, 0); - +#define COLORVAL(name) ANYVAL(name,parse_color_header) #define INTVAL(name) ANYVAL(name,atoi) #define FPVAL(name) ANYVAL(name,ass_atof) #define TIMEVAL(name) \ @@ -1021,7 +1018,6 @@ static char *sub_recode(ASS_Library *library, char *data, size_t size, out: if (icdsc != (iconv_t) (-1)) { (void) iconv_close(icdsc); - icdsc = (iconv_t) (-1); ass_msg(library, MSGL_V, "Closed iconv descriptor"); } @@ -1232,12 +1228,13 @@ int ass_read_styles(ASS_Track *track, char *fname, char *codepage) buf = tmpbuf; } if (!buf) - return 0; + return 1; #endif old_state = track->parser_priv->state; track->parser_priv->state = PST_STYLES; process_text(track, buf); + free(buf); track->parser_priv->state = old_state; return 0; diff --git a/libass/ass.h b/libass/ass.h index ca9d8af..029b96c 100644 --- a/libass/ass.h +++ b/libass/ass.h @@ -23,7 +23,7 @@ #include <stdarg.h> #include "ass_types.h" -#define LIBASS_VERSION 0x01201000 +#define LIBASS_VERSION 0x01202000 #ifdef __cplusplus extern "C" { @@ -96,8 +96,75 @@ typedef enum { * ass_set_selective_style_override_enabled() for details. */ typedef enum { - ASS_OVERRIDE_BIT_STYLE = 1, - ASS_OVERRIDE_BIT_FONT_SIZE = 2, + /** + * Default mode (with no other bits set). All selective override features + * as well as the style set with ass_set_selective_style_override() are + * disabled, but traditional overrides like ass_set_font_scale() are + * applied unconditionally. + */ + ASS_OVERRIDE_DEFAULT = 0, + /** + * Apply the style as set with ass_set_selective_style_override() on events + * which look like dialogue. Other style overrides are also applied this + * way, except ass_set_font_scale(). How ass_set_font_scale() is applied + * depends on the ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE flag. + * + * This is equivalent to setting all of the following bits: + * + * ASS_OVERRIDE_BIT_FONT_NAME + * ASS_OVERRIDE_BIT_FONT_SIZE_FIELDS + * ASS_OVERRIDE_BIT_COLORS + * ASS_OVERRIDE_BIT_BORDER + * ASS_OVERRIDE_BIT_ATTRIBUTES + */ + ASS_OVERRIDE_BIT_STYLE = 1 << 0, + /** + * Apply ass_set_font_scale() only on events which look like dialogue. + * If not set, the font scale is applied to all events. (The behavior and + * name of this flag are unintuitive, but exist for compatibility) + */ + ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE = 1 << 1, + /** + * Old alias for ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE. Deprecated. Do not use. + */ + ASS_OVERRIDE_BIT_FONT_SIZE = 1 << 1, + /** + * On dialogue events override: FontSize, Spacing, Blur, ScaleX, ScaleY + */ + ASS_OVERRIDE_BIT_FONT_SIZE_FIELDS = 1 << 2, + /** + * On dialogue events override: FontName, treat_fontname_as_pattern + */ + ASS_OVERRIDE_BIT_FONT_NAME = 1 << 3, + /** + * On dialogue events override: PrimaryColour, SecondaryColour, OutlineColour, BackColour + */ + ASS_OVERRIDE_BIT_COLORS = 1 << 4, + /** + * On dialogue events override: Bold, Italic, Underline, StrikeOut + */ + ASS_OVERRIDE_BIT_ATTRIBUTES = 1 << 5, + /** + * On dialogue events override: BorderStyle, Outline, Shadow + */ + ASS_OVERRIDE_BIT_BORDER = 1 << 6, + /** + * On dialogue events override: Alignment + */ + ASS_OVERRIDE_BIT_ALIGNMENT = 1 << 7, + /** + * On dialogue events override: MarginL, MarginR, MarginV + */ + ASS_OVERRIDE_BIT_MARGINS = 1 << 8, + /** + * Unconditionally replace all fields of all styles with the one provided + * with ass_set_selective_style_override(). + * Does not apply ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE. + * Add ASS_OVERRIDE_BIT_FONT_SIZE_FIELDS and ASS_OVERRIDE_BIT_BORDER if + * you want FontSize, Spacing, Outline, Shadow to be scaled to the script + * resolution given by the ASS_Track. + */ + ASS_OVERRIDE_FULL_STYLE = 1 << 9, } ASS_OverrideBits; /** @@ -345,19 +412,7 @@ void ass_set_fonts(ASS_Renderer *priv, const char *default_font, * only be implemented on "best effort" basis, and has to rely on * heuristics that can easily break. * \param priv renderer handle - * \param bits bit mask comprised of ASS_OverrideBits values. If the value is - * 0, all override features are disabled, and libass will behave like libass - * versions before this feature was introduced. Possible values: - * ASS_OVERRIDE_BIT_STYLE: apply the style as set with - * ass_set_selective_style_override() on events which look like - * dialogue. Other style overrides are also applied this way, except - * ass_set_font_scale(). How ass_set_font_scale() is applied depends - * on the ASS_OVERRIDE_BIT_FONT_SIZE flag. - * ASS_OVERRIDE_BIT_FONT_SIZE: apply ass_set_font_scale() only on events - * which look like dialogue. If not set, it is applied to all - * events. - * 0: ignore ass_set_selective_style_override(), but apply all other - * overrides (traditional behavior). + * \param bits bit mask comprised of ASS_OverrideBits values. */ void ass_set_selective_style_override_enabled(ASS_Renderer *priv, int bits); diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c index d1ba819..aa92d50 100644 --- a/libass/ass_bitmap.c +++ b/libass/ass_bitmap.c @@ -336,20 +336,15 @@ Bitmap *outline_to_bitmap(ASS_Renderer *render_priv, int tile_w = (w + 2 * bord + mask) & ~mask; int tile_h = (h + 2 * bord + mask) & ~mask; - Bitmap *bm = alloc_bitmap(tile_w, tile_h); + Bitmap *bm = alloc_bitmap_raw(tile_w, tile_h); if (!bm) return NULL; bm->left = x_min - bord; bm->top = y_min - bord; - int offs = bord & ~mask; - if (!rasterizer_fill(rst, - bm->buffer + offs * (bm->stride + 1), - x_min - bord + offs, - y_min - bord + offs, - ((w + bord + mask) & ~mask) - offs, - ((h + bord + mask) & ~mask) - offs, - bm->stride)) { + if (!rasterizer_fill(rst, bm->buffer, + x_min - bord, y_min - bord, + bm->stride, tile_h, bm->stride)) { ass_msg(render_priv->library, MSGL_WARN, "Failed to rasterize glyph!\n"); ass_free_bitmap(bm); return NULL; diff --git a/libass/ass_cache_template.h b/libass/ass_cache_template.h index dbf724c..da49f50 100644 --- a/libass/ass_cache_template.h +++ b/libass/ass_cache_template.h @@ -70,9 +70,9 @@ // describes an outline bitmap START(outline_bitmap, outline_bitmap_hash_key) GENERIC(OutlineHashValue *, outline) - GENERIC(int, frx) // signed 16.16 - GENERIC(int, fry) // signed 16.16 - GENERIC(int, frz) // signed 16.16 + GENERIC(int, frx) // signed 10.22 + GENERIC(int, fry) // signed 10.22 + GENERIC(int, frz) // signed 10.22 GENERIC(int, fax) // signed 16.16 GENERIC(int, fay) // signed 16.16 // shift vector that was added to glyph before applying rotation diff --git a/libass/ass_drawing.c b/libass/ass_drawing.c index e2676df..51bca83 100644 --- a/libass/ass_drawing.c +++ b/libass/ass_drawing.c @@ -140,6 +140,7 @@ static ASS_DrawingToken *drawing_tokenize(char *str) ASS_DrawingToken *root = NULL, *tail = NULL, *spline_start = NULL; while (p && *p) { + int got_coord = 0; if (*p == 'c' && spline_start) { // Close b-splines: add the first three points of the b-spline // back to the end @@ -157,10 +158,12 @@ static ASS_DrawingToken *drawing_tokenize(char *str) } else if (!is_set && mystrtod(&p, &val)) { point.x = double_to_d6(val); is_set = 1; + got_coord = 1; p--; } else if (is_set == 1 && mystrtod(&p, &val)) { point.y = double_to_d6(val); is_set = 2; + got_coord = 1; p--; } else if (*p == 'm') type = TOKEN_MOVE; @@ -178,6 +181,10 @@ static ASS_DrawingToken *drawing_tokenize(char *str) // This is not harmful at all, since it can be ommitted with // similar result (the spline is extended anyway). + // Ignore the odd extra value, it makes no sense. + if (!got_coord) + is_set = 0; + if (type != -1 && is_set == 2) { if (root) { tail->next = calloc(1, sizeof(ASS_DrawingToken)); diff --git a/libass/ass_parse.c b/libass/ass_parse.c index 641d42c..b99ed48 100644 --- a/libass/ass_parse.c +++ b/libass/ass_parse.c @@ -178,17 +178,15 @@ void change_border(ASS_Renderer *render_priv, double border_x, double border_y) */ static void change_color(uint32_t *var, uint32_t new, double pwr) { - (*var) = ((uint32_t) (_r(*var) * (1 - pwr) + _r(new) * pwr) << 24) + - ((uint32_t) (_g(*var) * (1 - pwr) + _g(new) * pwr) << 16) + - ((uint32_t) (_b(*var) * (1 - pwr) + _b(new) * pwr) << 8) + _a(*var); + (*var) = ((uint32_t) (_r(*var) * (1 - pwr) + _r(new) * pwr) << 24) | + ((uint32_t) (_g(*var) * (1 - pwr) + _g(new) * pwr) << 16) | + ((uint32_t) (_b(*var) * (1 - pwr) + _b(new) * pwr) << 8) | _a(*var); } // like change_color, but for alpha component only -inline void change_alpha(uint32_t *var, uint32_t new, double pwr) +inline void change_alpha(uint32_t *var, int32_t new, double pwr) { - *var = - (_r(*var) << 24) + (_g(*var) << 16) + (_b(*var) << 8) + - (uint32_t) (_a(*var) * (1 - pwr) + _a(new) * pwr); + *var = (*var & 0xFFFFFF00) | (uint8_t) (_a(*var) * (1 - pwr) + new * pwr); } /** @@ -207,11 +205,11 @@ inline uint32_t mult_alpha(uint32_t a, uint32_t b) * \brief Calculate alpha value by piecewise linear function * Used for \fad, \fade implementation. */ -static unsigned +static int interpolate_alpha(long long now, long long t1, long long t2, long long t3, - long long t4, unsigned a1, unsigned a2, unsigned a3) + long long t4, int a1, int a2, int a3) { - unsigned a; + int a; double cf; if (now < t1) { @@ -545,23 +543,20 @@ char *parse_tag(ASS_Renderer *render_priv, char *p, char *end, double pwr) render_priv->state.family = family; update_font(render_priv); } else if (tag("alpha")) { - uint32_t val; int i; - int hex = render_priv->track->track_type == TRACK_TYPE_ASS; if (nargs) { - val = string2color(render_priv->library, args->start, hex); - unsigned char a = val >> 24; + int32_t a = parse_alpha_tag(args->start); for (i = 0; i < 4; ++i) change_alpha(&render_priv->state.c[i], a, pwr); } else { change_alpha(&render_priv->state.c[0], - render_priv->state.style->PrimaryColour, 1); + _a(render_priv->state.style->PrimaryColour), 1); change_alpha(&render_priv->state.c[1], - render_priv->state.style->SecondaryColour, 1); + _a(render_priv->state.style->SecondaryColour), 1); change_alpha(&render_priv->state.c[2], - render_priv->state.style->OutlineColour, 1); + _a(render_priv->state.style->OutlineColour), 1); change_alpha(&render_priv->state.c[3], - render_priv->state.style->BackColour, 1); + _a(render_priv->state.style->BackColour), 1); } // FIXME: simplify } else if (tag("an")) { @@ -714,59 +709,62 @@ char *parse_tag(ASS_Renderer *render_priv, char *p, char *end, double pwr) if (parse_vector_clip(render_priv, args, nargs)) render_priv->state.clip_drawing_mode = 0; } - } else if (tag("c")) { - uint32_t val; - int hex = render_priv->track->track_type == TRACK_TYPE_ASS; + } else if (tag("c") || tag("1c")) { if (nargs) { - val = string2color(render_priv->library, args->start, hex); + uint32_t val = parse_color_tag(args->start); change_color(&render_priv->state.c[0], val, pwr); } else change_color(&render_priv->state.c[0], render_priv->state.style->PrimaryColour, 1); - } else if ((*p >= '1') && (*p <= '4') && (++p) - && (tag("c") || tag("a"))) { - char n = *(p - 2); - int cidx = n - '1'; - char cmd = *(p - 1); - uint32_t val; - int hex = render_priv->track->track_type == TRACK_TYPE_ASS; - assert((n >= '1') && (n <= '4')); - if (nargs) - val = string2color(render_priv->library, args->start, hex); - else { - switch (n) { - case '1': - val = render_priv->state.style->PrimaryColour; - break; - case '2': - val = render_priv->state.style->SecondaryColour; - break; - case '3': - val = render_priv->state.style->OutlineColour; - break; - case '4': - val = render_priv->state.style->BackColour; - break; - default: - val = 0; - break; // impossible due to assert; avoid compilation warning - } - if (cmd == 'a') - val <<= 24; - pwr = 1; - } - switch (cmd) { - case 'c': - change_color(render_priv->state.c + cidx, val, pwr); - break; - case 'a': - change_alpha(render_priv->state.c + cidx, val >> 24, pwr); - break; - default: - ass_msg(render_priv->library, MSGL_WARN, "Bad command: %c%c", - n, cmd); - break; - } + } else if (tag("2c")) { + if (nargs) { + uint32_t val = parse_color_tag(args->start); + change_color(&render_priv->state.c[1], val, pwr); + } else + change_color(&render_priv->state.c[1], + render_priv->state.style->SecondaryColour, 1); + } else if (tag("3c")) { + if (nargs) { + uint32_t val = parse_color_tag(args->start); + change_color(&render_priv->state.c[2], val, pwr); + } else + change_color(&render_priv->state.c[2], + render_priv->state.style->OutlineColour, 1); + } else if (tag("4c")) { + if (nargs) { + uint32_t val = parse_color_tag(args->start); + change_color(&render_priv->state.c[3], val, pwr); + } else + change_color(&render_priv->state.c[3], + render_priv->state.style->BackColour, 1); + } else if (tag("1a")) { + if (nargs) { + uint32_t val = parse_alpha_tag(args->start); + change_alpha(&render_priv->state.c[0], val, pwr); + } else + change_alpha(&render_priv->state.c[0], + _a(render_priv->state.style->PrimaryColour), 1); + } else if (tag("2a")) { + if (nargs) { + uint32_t val = parse_alpha_tag(args->start); + change_alpha(&render_priv->state.c[1], val, pwr); + } else + change_alpha(&render_priv->state.c[1], + _a(render_priv->state.style->SecondaryColour), 1); + } else if (tag("3a")) { + if (nargs) { + uint32_t val = parse_alpha_tag(args->start); + change_alpha(&render_priv->state.c[2], val, pwr); + } else + change_alpha(&render_priv->state.c[2], + _a(render_priv->state.style->OutlineColour), 1); + } else if (tag("4a")) { + if (nargs) { + uint32_t val = parse_alpha_tag(args->start); + change_alpha(&render_priv->state.c[3], val, pwr); + } else + change_alpha(&render_priv->state.c[3], + _a(render_priv->state.style->BackColour), 1); } else if (tag("r")) { if (nargs) { int len = args->end - args->start; @@ -1070,9 +1068,9 @@ unsigned get_next_char(ASS_Renderer *render_priv, char **str) return chr; } -// Return 1 if the event contains tags that will put the renderer into the -// EVENT_POSITIONED state. Return 0 otherwise. -int event_is_positioned(char *str) +// Return 1 if the event contains tags that will apply overrides the selective +// style override code should not touch. Return 0 otherwise. +int event_has_hard_overrides(char *str) { // look for \pos and \move tags inside {...} // mirrors get_next_char, but is faster and doesn't change any global state @@ -1084,7 +1082,10 @@ int event_is_positioned(char *str) while (*str && *str != '}') { if (*str == '\\') { char *p = str + 1; - if (mystrcmp(&p, "pos") || mystrcmp(&p, "move")) + if (mystrcmp(&p, "pos") || mystrcmp(&p, "move") || + mystrcmp(&p, "clip") || mystrcmp(&p, "iclip") || + mystrcmp(&p, "org") || mystrcmp(&p, "pbo") || + mystrcmp(&p, "p")) return 1; } str++; diff --git a/libass/ass_parse.h b/libass/ass_parse.h index e932238..2b4cee0 100644 --- a/libass/ass_parse.h +++ b/libass/ass_parse.h @@ -35,8 +35,8 @@ 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, char *end, double pwr); -int event_is_positioned(char *str); -extern void change_alpha(uint32_t *var, uint32_t new, double pwr); +int event_has_hard_overrides(char *str); +extern void change_alpha(uint32_t *var, int32_t new, double pwr); extern uint32_t mult_alpha(uint32_t a, uint32_t b); diff --git a/libass/ass_rasterizer.c b/libass/ass_rasterizer.c index ee19ad4..bf217a7 100644 --- a/libass/ass_rasterizer.c +++ b/libass/ass_rasterizer.c @@ -592,7 +592,8 @@ static int polyline_split_vert(const struct segment *src, size_t n_src, static inline void rasterizer_fill_solid(ASS_Rasterizer *rst, - uint8_t *buf, int width, int height, ptrdiff_t stride) + uint8_t *buf, int width, int height, ptrdiff_t stride, + int set) { assert(!(width & ((1 << rst->tile_order) - 1))); assert(!(height & ((1 << rst->tile_order) - 1))); @@ -604,7 +605,7 @@ static inline void rasterizer_fill_solid(ASS_Rasterizer *rst, height >>= rst->tile_order; for (j = 0; j < height; ++j) { for (i = 0; i < width; ++i) - rst->fill_solid(buf + i * step, stride); + rst->fill_solid(buf + i * step, stride, set); buf += tile_stride; } } @@ -637,8 +638,9 @@ static inline void rasterizer_fill_halfplane(ASS_Rasterizer *rst, int64_t abs_c = offs_c < 0 ? -offs_c : offs_c; if (abs_c < size) rst->fill_halfplane(buf + i * step, stride, a, b, cc, scale); - else if (((uint32_t)(offs_c >> 32) ^ scale) & 0x80000000) - rst->fill_solid(buf + i * step, stride); + else + rst->fill_solid(buf + i * step, stride, + ((uint32_t)(offs_c >> 32) ^ scale) & 0x80000000); } buf += tile_stride; } @@ -664,8 +666,7 @@ static int rasterizer_fill_level(ASS_Rasterizer *rst, size_t n = rst->size[index] - offs; struct segment *line = rst->linebuf[index] + offs; if (!n) { - if (winding) - rasterizer_fill_solid(rst, buf, width, height, stride); + rasterizer_fill_solid(rst, buf, width, height, stride, winding); return 1; } if (n == 1) { @@ -682,8 +683,8 @@ static int rasterizer_fill_level(ASS_Rasterizer *rst, rasterizer_fill_halfplane(rst, buf, width, height, stride, line->a, line->b, line->c, flag & 2 ? -line->scale : line->scale); - else if (flag & 2) - rasterizer_fill_solid(rst, buf, width, height, stride); + else + rasterizer_fill_solid(rst, buf, width, height, stride, flag & 2); rst->size[index] = offs; return 1; } diff --git a/libass/ass_rasterizer.h b/libass/ass_rasterizer.h index 6630317..d20feb3 100644 --- a/libass/ass_rasterizer.h +++ b/libass/ass_rasterizer.h @@ -43,15 +43,15 @@ struct segment { }; -typedef void (*FillSolidTileFunc)(uint8_t *buf, ptrdiff_t stride); +typedef void (*FillSolidTileFunc)(uint8_t *buf, ptrdiff_t stride, int set); typedef void (*FillHalfplaneTileFunc)(uint8_t *buf, ptrdiff_t stride, int32_t a, int32_t b, int64_t c, int32_t scale); typedef void (*FillGenericTileFunc)(uint8_t *buf, ptrdiff_t stride, const struct segment *line, size_t n_lines, int winding); -void ass_fill_solid_tile16_c(uint8_t *buf, ptrdiff_t stride); -void ass_fill_solid_tile32_c(uint8_t *buf, ptrdiff_t stride); +void ass_fill_solid_tile16_c(uint8_t *buf, ptrdiff_t stride, int set); +void ass_fill_solid_tile32_c(uint8_t *buf, ptrdiff_t stride, int set); void ass_fill_halfplane_tile16_c(uint8_t *buf, ptrdiff_t stride, int32_t a, int32_t b, int64_t c, int32_t scale); void ass_fill_halfplane_tile32_c(uint8_t *buf, ptrdiff_t stride, diff --git a/libass/ass_rasterizer_c.c b/libass/ass_rasterizer_c.c index f15f91b..38d4050 100644 --- a/libass/ass_rasterizer_c.c +++ b/libass/ass_rasterizer_c.c @@ -22,10 +22,10 @@ -void ass_fill_solid_tile16_c(uint8_t *buf, ptrdiff_t stride) +void ass_fill_solid_tile16_c(uint8_t *buf, ptrdiff_t stride, int set) { int i, j; - int8_t value = 255; + int8_t value = set ? 255 : 0; for (j = 0; j < 16; ++j) { for (i = 0; i < 16; ++i) buf[i] = value; @@ -33,10 +33,10 @@ void ass_fill_solid_tile16_c(uint8_t *buf, ptrdiff_t stride) } } -void ass_fill_solid_tile32_c(uint8_t *buf, ptrdiff_t stride) +void ass_fill_solid_tile32_c(uint8_t *buf, ptrdiff_t stride, int set) { int i, j; - int8_t value = 255; + int8_t value = set ? 255 : 0; for (j = 0; j < 32; ++j) { for (i = 0; i < 32; ++i) buf[i] = value; diff --git a/libass/ass_render.c b/libass/ass_render.c index a02bcab..357e1cc 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -139,6 +139,7 @@ ASS_Renderer *ass_renderer_init(ASS_Library *library) priv->text_info.lines = calloc(MAX_LINES_INITIAL, sizeof(LineInfo)); priv->settings.font_size_coeff = 1.; + priv->settings.selective_style_overrides = ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE; priv->shaper = ass_shaper_new(0); ass_shaper_info(library); @@ -237,46 +238,54 @@ static ASS_Image *my_draw_bitmap(unsigned char *bitmap, int bitmap_w, /** * \brief Mapping between script and screen coordinates */ +static double x2scr_pos(ASS_Renderer *render_priv, double x) +{ + return x * render_priv->orig_width / render_priv->font_scale_x / render_priv->track->PlayResX + + render_priv->settings.left_margin; +} static double x2scr(ASS_Renderer *render_priv, double x) { + if (render_priv->state.explicit) + return x2scr_pos(render_priv, x); return x * render_priv->orig_width_nocrop / render_priv->font_scale_x / render_priv->track->PlayResX + FFMAX(render_priv->settings.left_margin, 0); } -static double x2scr_pos(ASS_Renderer *render_priv, double x) +static double x2scr_pos_scaled(ASS_Renderer *render_priv, double x) { - return x * render_priv->orig_width / render_priv->font_scale_x / render_priv->track->PlayResX + + return x * render_priv->orig_width / render_priv->track->PlayResX + render_priv->settings.left_margin; } static double x2scr_scaled(ASS_Renderer *render_priv, double x) { + if (render_priv->state.explicit) + return x2scr_pos_scaled(render_priv, x); return x * render_priv->orig_width_nocrop / render_priv->track->PlayResX + FFMAX(render_priv->settings.left_margin, 0); } -static double x2scr_pos_scaled(ASS_Renderer *render_priv, double x) -{ - return x * render_priv->orig_width / render_priv->track->PlayResX + - render_priv->settings.left_margin; -} /** * \brief Mapping between script and screen coordinates */ +static double y2scr_pos(ASS_Renderer *render_priv, double y) +{ + return y * render_priv->orig_height / render_priv->track->PlayResY + + render_priv->settings.top_margin; +} static double y2scr(ASS_Renderer *render_priv, double y) { + if (render_priv->state.explicit) + return y2scr_pos(render_priv, y); return y * render_priv->orig_height_nocrop / render_priv->track->PlayResY + FFMAX(render_priv->settings.top_margin, 0); } -static double y2scr_pos(ASS_Renderer *render_priv, double y) -{ - return y * render_priv->orig_height / render_priv->track->PlayResY + - render_priv->settings.top_margin; -} // the same for toptitles static double y2scr_top(ASS_Renderer *render_priv, double y) { + if (render_priv->state.explicit) + return y2scr_pos(render_priv, y); if (render_priv->settings.use_margins) return y * render_priv->orig_height_nocrop / render_priv->track->PlayResY; @@ -288,6 +297,8 @@ static double y2scr_top(ASS_Renderer *render_priv, double y) // the same for subtitles static double y2scr_sub(ASS_Renderer *render_priv, double y) { + if (render_priv->state.explicit) + return y2scr_pos(render_priv, y); if (render_priv->settings.use_margins) return y * render_priv->orig_height_nocrop / render_priv->track->PlayResY + @@ -750,55 +761,98 @@ static ASS_Style *handle_selective_style_overrides(ASS_Renderer *render_priv, ASS_Style *rstyle) { // The script style is the one the event was declared with. - // The rstyle is either NULL, or the style used with a \r tag. ASS_Style *script = render_priv->track->styles + render_priv->state.event->Style; + // The user style was set with ass_set_selective_style_override(). + ASS_Style *user = &render_priv->user_override_style; ASS_Style *new = &render_priv->state.override_style_temp_storage; - int explicit = event_is_positioned(render_priv->state.event->Text); + int explicit = event_has_hard_overrides(render_priv->state.event->Text) || + render_priv->state.evt_type != EVENT_NORMAL; int requested = render_priv->settings.selective_style_overrides; double scale; |