summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog10
-rw-r--r--README.md5
-rw-r--r--configure.ac2
-rw-r--r--libass/Makefile.am4
-rw-r--r--libass/ass.c13
-rw-r--r--libass/ass.h87
-rw-r--r--libass/ass_bitmap.c13
-rw-r--r--libass/ass_cache_template.h6
-rw-r--r--libass/ass_drawing.c7
-rw-r--r--libass/ass_parse.c141
-rw-r--r--libass/ass_parse.h4
-rw-r--r--libass/ass_rasterizer.c17
-rw-r--r--libass/ass_rasterizer.h6
-rw-r--r--libass/ass_rasterizer_c.c8
-rw-r--r--libass/ass_render.c229
-rw-r--r--libass/ass_render.h9
-rw-r--r--libass/ass_render_api.c1
-rw-r--r--libass/ass_shaper.c4
-rw-r--r--libass/ass_utils.c123
-rw-r--r--libass/ass_utils.h22
-rw-r--r--libass/x86/rasterizer.asm15
-rw-r--r--libass/x86/rasterizer.h8
22 files changed, 484 insertions, 250 deletions
diff --git a/Changelog b/Changelog
index ec68d5f..cac2e6a 100644
--- a/Changelog
+++ b/Changelog
@@ -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.
diff --git a/README.md b/README.md
index 22642b1..739a898 100644
--- a/README.md
+++ b/README.md
@@ -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;