summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-11-15 20:21:37 +0100
committerwm4 <wm4@nowhere>2014-11-15 20:21:37 +0100
commit257465d793eae8ef93d98233542746df2b2b0b71 (patch)
tree5f689e0b548e863e082f03c0c50fe7646d2a4aa7
parent65207f1ce43242c4ec004b92fee4aef16b4c31ec (diff)
downloadlibass-257465d793eae8ef93d98233542746df2b2b0b71.tar.bz2
libass-257465d793eae8ef93d98233542746df2b2b0b71.tar.xz
Split some parts of ass_render_event into functions
The split doesn't necessarily follow any logic; for the most part it just moves each processing loop into its own function.
-rw-r--r--libass/ass_render.c608
1 files changed, 332 insertions, 276 deletions
diff --git a/libass/ass_render.c b/libass/ass_render.c
index 27ea418..b88bf22 100644
--- a/libass/ass_render.c
+++ b/libass/ass_render.c
@@ -1824,43 +1824,17 @@ static void make_shadow_bitmap(CombinedBitmapInfo *info, ASS_Renderer *render_pr
shift_bitmap(info->bm_s, offset_x & SUBPIXEL_MASK, offset_y & SUBPIXEL_MASK);
}
-/**
- * \brief Main ass rendering function, glues everything together
- * \param event event to render
- * \param event_images struct containing resulting images, will also be initialized
- * Process event, appending resulting ASS_Image's to images_root.
- */
-static int
-ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
- EventImages *event_images)
+// Parse event text.
+// Fill render_priv->text_info.
+static int parse_events(ASS_Renderer *render_priv, ASS_Event *event)
{
- char *p, *q;
- FT_Vector pen;
- unsigned code;
- DBBox bbox;
- int i, j;
- int MarginL, MarginR, MarginV;
- int last_break;
- int alignment, halign, valign;
- double device_x = 0;
- double device_y = 0;
TextInfo *text_info = &render_priv->text_info;
- GlyphInfo *glyphs = render_priv->text_info.glyphs;
ASS_Drawing *drawing;
-
- if (event->Style >= render_priv->track->n_styles) {
- ass_msg(render_priv->library, MSGL_WARN, "No style found");
- return 1;
- }
- if (!event->Text) {
- ass_msg(render_priv->library, MSGL_WARN, "Empty event");
- return 1;
- }
-
- init_render_context(render_priv, event);
+ unsigned code;
+ char *p, *q;
+ int i;
drawing = render_priv->state.drawing;
- text_info->length = 0;
p = event->Text;
// Event parsing.
@@ -1896,12 +1870,12 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
if (text_info->length >= text_info->max_glyphs) {
// Raise maximum number of glyphs
text_info->max_glyphs *= 2;
- text_info->glyphs = glyphs =
+ text_info->glyphs =
realloc(text_info->glyphs,
sizeof(GlyphInfo) * text_info->max_glyphs);
}
- GlyphInfo *info = &glyphs[text_info->length];
+ GlyphInfo *info = &text_info->glyphs[text_info->length];
// Clear current GlyphInfo
memset(info, 0, sizeof(GlyphInfo));
@@ -1969,28 +1943,18 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
render_priv->state.effect_type = EF_NONE;
render_priv->state.effect_timing = 0;
render_priv->state.effect_skip_timing = 0;
-
}
- if (text_info->length == 0) {
- // no valid symbols in the event; this can be smth like {comment}
- free_render_context(render_priv);
- return 1;
- }
+ return 0;
+}
- // Find shape runs and shape text
- ass_shaper_set_base_direction(render_priv->shaper,
- resolve_base_direction(render_priv->state.font_encoding));
- ass_shaper_find_runs(render_priv->shaper, render_priv, glyphs,
- text_info->length);
- if (ass_shaper_shape(render_priv->shaper, text_info) < 0) {
- ass_msg(render_priv->library, MSGL_ERR, "Failed to shape text");
- free_render_context(render_priv);
- return 1;
- }
+// Process render_priv->text_info and load glyph outlines.
+static void retrieve_glyphs(ASS_Renderer *render_priv)
+{
+ GlyphInfo *glyphs = render_priv->text_info.glyphs;
+ int i;
- // Retrieve glyphs
- for (i = 0; i < text_info->length; i++) {
+ for (i = 0; i < render_priv->text_info.length; i++) {
GlyphInfo *info = glyphs + i;
while (info) {
get_outline_glyph(render_priv, info);
@@ -2015,14 +1979,19 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
// add displacement for vertical shearing
info->cluster_advance.y += (info->fay / info->scale_x * info->scale_y) * info->cluster_advance.x;
-
}
+}
+
+// Preliminary layout (for line wrapping)
+static void preliminary_layout(ASS_Renderer *render_priv)
+{
+ FT_Vector pen;
+ int i;
- // Preliminary layout (for line wrapping)
pen.x = 0;
pen.y = 0;
- for (i = 0; i < text_info->length; i++) {
- GlyphInfo *info = glyphs + i;
+ for (i = 0; i < render_priv->text_info.length; i++) {
+ GlyphInfo *info = render_priv->text_info.glyphs + i;
FT_Vector cluster_pen = pen;
while (info) {
info->pos.x = cluster_pen.x;
@@ -2037,51 +2006,25 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
info = info->next;
}
- info = glyphs + i;
+ info = render_priv->text_info.glyphs + i;
pen.x += info->cluster_advance.x;
pen.y += info->cluster_advance.y;
}
+}
+// Reorder text into visual order
+static void reorder_text(ASS_Renderer *render_priv)
+{
+ TextInfo *text_info = &render_priv->text_info;
+ FT_Vector pen;
+ int i;
- // depends on glyph x coordinates being monotonous, so it should be done before line wrap
- process_karaoke_effects(render_priv);
-
- // alignments
- alignment = render_priv->state.alignment;
- halign = alignment & 3;
- valign = alignment & 12;
-
- MarginL =
- (event->MarginL) ? event->MarginL : render_priv->state.style->MarginL;
- MarginR =
- (event->MarginR) ? event->MarginR : render_priv->state.style->MarginR;
- MarginV =
- (event->MarginV) ? event->MarginV : render_priv->state.style->MarginV;
-
- // calculate max length of a line
- double max_text_width =
- x2scr(render_priv, render_priv->track->PlayResX - MarginR) -
- x2scr(render_priv, MarginL);
-
- // wrap lines
- if (render_priv->state.evt_type != EVENT_HSCROLL) {
- // rearrange text in several lines
- wrap_lines_smart(render_priv, max_text_width);
- } else {
- // no breaking or wrapping, everything in a single line
- text_info->lines[0].offset = 0;
- text_info->lines[0].len = text_info->length;
- text_info->n_lines = 1;
- measure_text(render_priv);
- }
-
- // Reorder text into visual order
FriBidiStrIndex *cmap = ass_shaper_reorder(render_priv->shaper, text_info);
if (!cmap) {
ass_msg(render_priv->library, MSGL_ERR, "Failed to reorder text");
ass_shaper_cleanup(render_priv->shaper, text_info);
free_render_context(render_priv);
- return 1;
+ return;
}
// Reposition according to the map
@@ -2091,8 +2034,8 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
double last_pen_x = 0;
double last_fay = 0;
for (i = 0; i < text_info->length; i++) {
- GlyphInfo *info = glyphs + cmap[i];
- if (glyphs[i].linebreak) {
+ GlyphInfo *info = text_info->glyphs + cmap[i];
+ if (text_info->glyphs[i].linebreak) {
pen.y -= (last_fay / info->scale_x * info->scale_y) * (pen.x - last_pen_x);
last_pen_x = pen.x = 0;
pen.y += double_to_d6(text_info->lines[lineno-1].desc);
@@ -2114,188 +2057,92 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
cluster_pen.y += info->advance.y;
info = info->next;
}
- info = glyphs + cmap[i];
+ info = text_info->glyphs + cmap[i];
pen.x += info->cluster_advance.x;
pen.y += info->cluster_advance.y;
}
+}
- // align lines
- if (render_priv->state.evt_type != EVENT_HSCROLL) {
- last_break = -1;
- double width = 0;
- for (i = 0; i <= text_info->length; ++i) { // (text_info->length + 1) is the end of the last line
- if ((i == text_info->length) || glyphs[i].linebreak) {
- double shift = 0;
- if (halign == HALIGN_LEFT) { // left aligned, no action
- shift = 0;
- } else if (halign == HALIGN_RIGHT) { // right aligned
- shift = max_text_width - width;
- } else if (halign == HALIGN_CENTER) { // centered
- shift = (max_text_width - width) / 2.0;
- }
- for (j = last_break + 1; j < i; ++j) {
- GlyphInfo *info = glyphs + j;
- while (info) {
- info->pos.x += double_to_d6(shift);
- info = info->next;
- }
- }
- last_break = i - 1;
- width = 0;
- }
- if (i < text_info->length && !glyphs[i].skip &&
- glyphs[i].symbol != '\n' && glyphs[i].symbol != 0) {
- width += d6_to_double(glyphs[i].cluster_advance.x);
- }
- }
- }
-
- // determing text bounding box
- compute_string_bbox(text_info, &bbox);
-
- // determine device coordinates for text
+static void align_lines(ASS_Renderer *render_priv, double max_text_width)
+{
+ TextInfo *text_info = &render_priv->text_info;
+ GlyphInfo *glyphs = text_info->glyphs;
+ int i, j;
+ double width = 0;
+ int last_break = -1;
+ int halign = render_priv->state.alignment & 3;
- // x coordinate for everything except positioned events
- if (render_priv->state.evt_type == EVENT_NORMAL ||
- render_priv->state.evt_type == EVENT_VSCROLL) {
- device_x = x2scr(render_priv, MarginL);
- } else if (render_priv->state.evt_type == EVENT_HSCROLL) {
- if (render_priv->state.scroll_direction == SCROLL_RL)
- device_x =
- x2scr(render_priv,
- render_priv->track->PlayResX -
- render_priv->state.scroll_shift);
- else if (render_priv->state.scroll_direction == SCROLL_LR)
- device_x =
- x2scr(render_priv,
- render_priv->state.scroll_shift) - (bbox.xMax -
- bbox.xMin);
- }
+ if (render_priv->state.evt_type == EVENT_HSCROLL)
+ return;
- // y coordinate for everything except positioned events
- if (render_priv->state.evt_type == EVENT_NORMAL ||
- render_priv->state.evt_type == EVENT_HSCROLL) {
- if (valign == VALIGN_TOP) { // toptitle
- device_y =
- y2scr_top(render_priv,
- MarginV) + text_info->lines[0].asc;
- } else if (valign == VALIGN_CENTER) { // midtitle
- double scr_y =
- y2scr(render_priv, render_priv->track->PlayResY / 2.0);
- device_y = scr_y - (bbox.yMax + bbox.yMin) / 2.0;
- } else { // subtitle
- double scr_top, scr_bottom, scr_y0;
- if (valign != VALIGN_SUB)
- ass_msg(render_priv->library, MSGL_V,
- "Invalid valign, assuming 0 (subtitle)");
- scr_bottom =
- y2scr_sub(render_priv,
- render_priv->track->PlayResY - MarginV);
- scr_top = y2scr_top(render_priv, 0); //xxx not always 0?
- device_y = scr_bottom + (scr_top - scr_bottom) *
- render_priv->settings.line_position / 100.0;
- device_y -= text_info->height;
- device_y += text_info->lines[0].asc;
- // clip to top to avoid confusion if line_position is very high,
- // turning the subtitle into a toptitle
- // also, don't change behavior if line_position is not used
- scr_y0 = scr_top + text_info->lines[0].asc;
- if (device_y < scr_y0 && render_priv->settings.line_position > 0) {
- device_y = scr_y0;
+ for (i = 0; i <= text_info->length; ++i) { // (text_info->length + 1) is the end of the last line
+ if ((i == text_info->length) || glyphs[i].linebreak) {
+ double shift = 0;
+ if (halign == HALIGN_LEFT) { // left aligned, no action
+ shift = 0;
+ } else if (halign == HALIGN_RIGHT) { // right aligned
+ shift = max_text_width - width;
+ } else if (halign == HALIGN_CENTER) { // centered
+ shift = (max_text_width - width) / 2.0;
+ }
+ for (j = last_break + 1; j < i; ++j) {
+ GlyphInfo *info = glyphs + j;
+ while (info) {
+ info->pos.x += double_to_d6(shift);
+ info = info->next;
+ }
}
+ last_break = i - 1;
+ width = 0;
+ }
+ if (i < text_info->length && !glyphs[i].skip &&
+ glyphs[i].symbol != '\n' && glyphs[i].symbol != 0) {
+ width += d6_to_double(glyphs[i].cluster_advance.x);
}
- } else if (render_priv->state.evt_type == EVENT_VSCROLL) {
- if (render_priv->state.scroll_direction == SCROLL_TB)
- device_y =
- y2scr(render_priv,
- render_priv->state.clip_y0 +
- render_priv->state.scroll_shift) - (bbox.yMax -
- bbox.yMin);
- else if (render_priv->state.scroll_direction == SCROLL_BT)
- device_y =
- y2scr(render_priv,
- render_priv->state.clip_y1 -
- render_priv->state.scroll_shift);
}
+}
- // positioned events are totally different
- if (render_priv->state.evt_type == EVENT_POSITIONED) {
- double base_x = 0;
- double base_y = 0;
- get_base_point(&bbox, alignment, &base_x, &base_y);
- device_x =
- x2scr_pos(render_priv, render_priv->state.pos_x) - base_x;
- device_y =
- y2scr_pos(render_priv, render_priv->state.pos_y) - base_y;
- }
+static void calculate_rotation_params(ASS_Renderer *render_priv, DBBox *bbox,
+ double device_x, double device_y)
+{
+ TextInfo *text_info = &render_priv->text_info;
+ DVector center;
+ int i;
- // fix clip coordinates (they depend on alignment)
- if (render_priv->state.evt_type == EVENT_NORMAL ||
- render_priv->state.evt_type == EVENT_HSCROLL ||
- render_priv->state.evt_type == EVENT_VSCROLL) {
- render_priv->state.clip_x0 =
- x2scr_scaled(render_priv, render_priv->state.clip_x0);
- render_priv->state.clip_x1 =
- x2scr_scaled(render_priv, render_priv->state.clip_x1);
- if (valign == VALIGN_TOP) {
- render_priv->state.clip_y0 =
- y2scr_top(render_priv, render_priv->state.clip_y0);
- render_priv->state.clip_y1 =
- y2scr_top(render_priv, render_priv->state.clip_y1);
- } else if (valign == VALIGN_CENTER) {
- render_priv->state.clip_y0 =
- y2scr(render_priv, render_priv->state.clip_y0);
- render_priv->state.clip_y1 =
- y2scr(render_priv, render_priv->state.clip_y1);
- } else if (valign == VALIGN_SUB) {
- render_priv->state.clip_y0 =
- y2scr_sub(render_priv, render_priv->state.clip_y0);
- render_priv->state.clip_y1 =
- y2scr_sub(render_priv, render_priv->state.clip_y1);
- }
- } else if (render_priv->state.evt_type == EVENT_POSITIONED) {
- render_priv->state.clip_x0 =
- x2scr_pos_scaled(render_priv, render_priv->state.clip_x0);
- render_priv->state.clip_x1 =
- x2scr_pos_scaled(render_priv, render_priv->state.clip_x1);
- render_priv->state.clip_y0 =
- y2scr_pos(render_priv, render_priv->state.clip_y0);
- render_priv->state.clip_y1 =
- y2scr_pos(render_priv, render_priv->state.clip_y1);
+ if (render_priv->state.have_origin) {
+ center.x = x2scr(render_priv, render_priv->state.org_x);
+ center.y = y2scr(render_priv, render_priv->state.org_y);
+ } else {
+ double bx = 0., by = 0.;
+ get_base_point(bbox, render_priv->state.alignment, &bx, &by);
+ center.x = device_x + bx;
+ center.y = device_y + by;
}
- // calculate rotation parameters
- {
- DVector center;
-
- if (render_priv->state.have_origin) {
- center.x = x2scr(render_priv, render_priv->state.org_x);
- center.y = y2scr(render_priv, render_priv->state.org_y);
- } else {
- double bx = 0., by = 0.;
- get_base_point(&bbox, alignment, &bx, &by);
- center.x = device_x + bx;
- center.y = device_y + by;
- }
+ for (i = 0; i < text_info->length; ++i) {
+ GlyphInfo *info = text_info->glyphs + i;
+ while (info) {
+ OutlineBitmapHashKey *key = &info->hash_key.u.outline;
- for (i = 0; i < text_info->length; ++i) {
- GlyphInfo *info = glyphs + i;
- while (info) {
- OutlineBitmapHashKey *key = &info->hash_key.u.outline;
-
- if (key->frx || key->fry || key->frz || key->fax || key->fay) {
- key->shift_x = info->pos.x + double_to_d6(device_x - center.x);
- key->shift_y = -(info->pos.y + double_to_d6(device_y - center.y));
- } else {
- key->shift_x = 0;
- key->shift_y = 0;
- }
- info = info->next;
+ if (key->frx || key->fry || key->frz || key->fax || key->fay) {
+ key->shift_x = info->pos.x + double_to_d6(device_x - center.x);
+ key->shift_y = -(info->pos.y + double_to_d6(device_y - center.y));
+ } else {
+ key->shift_x = 0;
+ key->shift_y = 0;
}
+ info = info->next;
}
}
+}
+
- // convert glyphs to bitmaps
+// Convert glyphs to bitmaps, combine them, apply blur, generate shadows.
+static void render_and_combine_glyphs(ASS_Renderer *render_priv,
+ double device_x, double device_y)
+{
+ int i;
+ TextInfo *text_info = &render_priv->text_info;
int left = render_priv->settings.left_margin;
device_x = (device_x - left) * render_priv->font_scale_x + left;
unsigned nb_bitmaps = 0;
@@ -2304,7 +2151,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
CombinedBitmapInfo *current_info = NULL;
GlyphInfo *last_info = NULL;
for (i = 0; i < text_info->length; ++i) {
- GlyphInfo *info = glyphs + i;
+ GlyphInfo *info = text_info->glyphs + i;
if (info->linebreak) linebreak = 1;
if (info->skip) continue;
while (info) {
@@ -2477,7 +2324,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
}
for (i = 0; i < text_info->length; ++i) {
- GlyphInfo *info = glyphs + i;
+ GlyphInfo *info = text_info->glyphs + i;
if (info->skip) continue;
while (info) {
current_info = &combined_info[info->bm_run_id];
@@ -2554,6 +2401,230 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
}
text_info->n_bitmaps = nb_bitmaps;
+}
+
+static void add_background(ASS_Renderer *render_priv, EventImages *event_images)
+{
+ void *nbuffer = ass_aligned_alloc(1, event_images->width * event_images->height);
+ if (nbuffer) {
+ free_list_add(render_priv, nbuffer);
+ memset(nbuffer, 0xFF, event_images->width * event_images->height);
+ ASS_Image *img = my_draw_bitmap(nbuffer, event_images->width,
+ event_images->height,
+ event_images->width,
+ event_images->left,
+ event_images->top,
+ render_priv->state.c[3]);
+ if (img) {
+ img->next = event_images->imgs;
+ event_images->imgs = img;
+ }
+ }
+}
+
+/**
+ * \brief Main ass rendering function, glues everything together
+ * \param event event to render
+ * \param event_images struct containing resulting images, will also be initialized
+ * Process event, appending resulting ASS_Image's to images_root.
+ */
+static int
+ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
+ EventImages *event_images)
+{
+ DBBox bbox;
+ int MarginL, MarginR, MarginV;
+ int valign;
+ double device_x = 0;
+ double device_y = 0;
+ TextInfo *text_info = &render_priv->text_info;
+
+ if (event->Style >= render_priv->track->n_styles) {
+ ass_msg(render_priv->library, MSGL_WARN, "No style found");
+ return 1;
+ }
+ if (!event->Text) {
+ ass_msg(render_priv->library, MSGL_WARN, "Empty event");
+ return 1;
+ }
+
+ init_render_context(render_priv, event);
+ text_info->length = 0;
+
+ if (parse_events(render_priv, event))
+ return 1;
+
+ if (text_info->length == 0) {
+ // no valid symbols in the event; this can be smth like {comment}
+ free_render_context(render_priv);
+ return 1;
+ }
+
+ // Find shape runs and shape text
+ ass_shaper_set_base_direction(render_priv->shaper,
+ resolve_base_direction(render_priv->state.font_encoding));
+ ass_shaper_find_runs(render_priv->shaper, render_priv, text_info->glyphs,
+ text_info->length);
+ if (ass_shaper_shape(render_priv->shaper, text_info) < 0) {
+ ass_msg(render_priv->library, MSGL_ERR, "Failed to shape text");
+ free_render_context(render_priv);
+ return 1;
+ }
+
+ retrieve_glyphs(render_priv);
+
+ preliminary_layout(render_priv);
+
+ // depends on glyph x coordinates being monotonous, so it should be done before line wrap
+ process_karaoke_effects(render_priv);
+
+ valign = render_priv->state.alignment & 12;
+
+ MarginL =
+ (event->MarginL) ? event->MarginL : render_priv->state.style->MarginL;
+ MarginR =
+ (event->MarginR) ? event->MarginR : render_priv->state.style->MarginR;
+ MarginV =
+ (event->MarginV) ? event->MarginV : render_priv->state.style->MarginV;
+
+ // calculate max length of a line
+ double max_text_width =
+ x2scr(render_priv, render_priv->track->PlayResX - MarginR) -
+ x2scr(render_priv, MarginL);
+
+ // wrap lines
+ if (render_priv->state.evt_type != EVENT_HSCROLL) {
+ // rearrange text in several lines
+ wrap_lines_smart(render_priv, max_text_width);
+ } else {
+ // no breaking or wrapping, everything in a single line
+ text_info->lines[0].offset = 0;
+ text_info->lines[0].len = text_info->length;
+ text_info->n_lines = 1;
+ measure_text(render_priv);
+ }
+
+ reorder_text(render_priv);
+
+ align_lines(render_priv, max_text_width);
+
+ // determing text bounding box
+ compute_string_bbox(text_info, &bbox);
+
+ // determine device coordinates for text
+
+ // x coordinate for everything except positioned events
+ if (render_priv->state.evt_type == EVENT_NORMAL ||
+ render_priv->state.evt_type == EVENT_VSCROLL) {
+ device_x = x2scr(render_priv, MarginL);
+ } else if (render_priv->state.evt_type == EVENT_HSCROLL) {
+ if (render_priv->state.scroll_direction == SCROLL_RL)
+ device_x =
+ x2scr(render_priv,
+ render_priv->track->PlayResX -
+ render_priv->state.scroll_shift);
+ else if (render_priv->state.scroll_direction == SCROLL_LR)
+ device_x =
+ x2scr(render_priv,
+ render_priv->state.scroll_shift) - (bbox.xMax -
+ bbox.xMin);
+ }
+
+ // y coordinate for everything except positioned events
+ if (render_priv->state.evt_type == EVENT_NORMAL ||
+ render_priv->state.evt_type == EVENT_HSCROLL) {
+ if (valign == VALIGN_TOP) { // toptitle
+ device_y =
+ y2scr_top(render_priv,
+ MarginV) + text_info->lines[0].asc;
+ } else if (valign == VALIGN_CENTER) { // midtitle
+ double scr_y =
+ y2scr(render_priv, render_priv->track->PlayResY / 2.0);
+ device_y = scr_y - (bbox.yMax + bbox.yMin) / 2.0;
+ } else { // subtitle
+ double scr_top, scr_bottom, scr_y0;
+ if (valign != VALIGN_SUB)
+ ass_msg(render_priv->library, MSGL_V,
+ "Invalid valign, assuming 0 (subtitle)");
+ scr_bottom =
+ y2scr_sub(render_priv,
+ render_priv->track->PlayResY - MarginV);
+ scr_top = y2scr_top(render_priv, 0); //xxx not always 0?
+ device_y = scr_bottom + (scr_top - scr_bottom) *
+ render_priv->settings.line_position / 100.0;
+ device_y -= text_info->height;
+ device_y += text_info->lines[0].asc;
+ // clip to top to avoid confusion if line_position is very high,
+ // turning the subtitle into a toptitle
+ // also, don't change behavior if line_position is not used
+ scr_y0 = scr_top + text_info->lines[0].asc;
+ if (device_y < scr_y0 && render_priv->settings.line_position > 0) {
+ device_y = scr_y0;
+ }
+ }
+ } else if (render_priv->state.evt_type == EVENT_VSCROLL) {
+ if (render_priv->state.scroll_direction == SCROLL_TB)
+ device_y =
+ y2scr(render_priv,
+ render_priv->state.clip_y0 +
+ render_priv->state.scroll_shift) - (bbox.yMax -
+ bbox.yMin);
+ else if (render_priv->state.scroll_direction == SCROLL_BT)
+ device_y =
+ y2scr(render_priv,
+ render_priv->state.clip_y1 -
+ render_priv->state.scroll_shift);
+ }
+
+ // positioned events are totally different
+ if (render_priv->state.evt_type == EVENT_POSITIONED) {
+ double base_x = 0;
+ double base_y = 0;
+ get_base_point(&bbox, render_priv->state.alignment, &base_x, &base_y);
+ device_x =
+ x2scr_pos(render_priv, render_priv->state.pos_x) - base_x;
+ device_y =
+ y2scr_pos(render_priv, render_priv->state.pos_y) - base_y;
+ }
+
+ // fix clip coordinates (they depend on alignment)
+ if (render_priv->state.evt_type == EVENT_NORMAL ||
+ render_priv->state.evt_type == EVENT_HSCROLL ||
+ render_priv->state.evt_type == EVENT_VSCROLL) {
+ render_priv->state.clip_x0 =
+ x2scr_scaled(render_priv, render_priv->state.clip_x0);
+ render_priv->state.clip_x1 =
+ x2scr_scaled(render_priv, render_priv->state.clip_x1);
+ if (valign == VALIGN_TOP) {
+ render_priv->state.clip_y0 =
+ y2scr_top(render_priv, render_priv->state.clip_y0);
+ render_priv->state.clip_y1 =
+ y2scr_top(render_priv, render_priv->state.clip_y1);
+ } else if (valign == VALIGN_CENTER) {
+ render_priv->state.clip_y0 =
+ y2scr(render_priv, render_priv->state.clip_y0);
+ render_priv->state.clip_y1 =
+ y2scr(render_priv, render_priv->state.clip_y1);
+ } else if (valign == VALIGN_SUB) {
+ render_priv->state.clip_y0 =
+ y2scr_sub(render_priv, render_priv->state.clip_y0);
+ render_priv->state.clip_y1 =
+ y2scr_sub(render_priv, render_priv->state.clip_y1);
+ }
+ } else if (render_priv->state.evt_type == EVENT_POSITIONED) {
+ render_priv->state.clip_x0 =
+ x2scr_pos_scaled(render_priv, render_priv->state.clip_x0);
+ render_priv->state.clip_x1 =
+ x2scr_pos_scaled(render_priv, render_priv->state.clip_x1);
+ render_priv->state.clip_y0 =
+ y2scr_pos(render_priv, render_priv->state.clip_y0);
+ render_priv->state.clip_y1 =
+ y2scr_pos(render_priv, render_priv->state.clip_y1);
+ }
+
+ calculate_rotation_params(render_priv, &bbox, device_x, device_y);
+
+ render_and_combine_glyphs(render_priv, device_x, device_y);
memset(event_images, 0, sizeof(*event_images));
event_images->top = device_y - text_info->lines[0].asc;
@@ -2567,23 +2638,8 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
event_images->event = event;
event_images->imgs = render_text(render_priv, (int) device_x, (int) device_y);
- if (render_priv->state.border_style == 4) {
- void *nbuffer = ass_aligned_alloc(1, event_images->width * event_images->height);
- if (nbuffer) {
- free_list_add(render_priv, nbuffer);
- memset(nbuffer, 0xFF, event_images->width * event_images->height);
- ASS_Image *img = my_draw_bitmap(nbuffer, event_images->width,
- event_images->height,
- event_images->width,
- event_images->left,
- event_images->top,
- render_priv->state.c[3]);
- if (img) {
- img->next = event_images->imgs;
- event_images->imgs = img;
- }
- }
- }
+ if (render_priv->state.border_style == 4)
+ add_background(render_priv, event_images);
ass_shaper_cleanup(render_priv->shaper, text_info);
free_render_context(render_priv);