diff options
author | Oleg Oshmyan <chortos@inbox.lv> | 2020-10-29 02:16:01 +0200 |
---|---|---|
committer | Oleg Oshmyan <chortos@inbox.lv> | 2021-04-29 03:15:40 +0300 |
commit | 3f95d1701159e86b75dc49c8eaa1dfc03819bc32 (patch) | |
tree | ac2c70bb1a294b938a1c56919e00ae9fb592e58c | |
parent | 03a7c9e63bbf7e6b77631b1b291f8d95b27d890e (diff) | |
download | libass-3f95d1701159e86b75dc49c8eaa1dfc03819bc32.tar.bz2 libass-3f95d1701159e86b75dc49c8eaa1dfc03819bc32.tar.xz |
Delay \fay baseline shear until last text layout step
The current code calculates the effect of \fay on advances
early in retrieve_glyph, only to ignore it until reorder_text,
which then partially undoes these calculations.
Instead, just calculate it once, when all the necessary
properties have been fully determined.
The earliest point to do this would be within reorder_text,
but to simplify future logic changes, delay this until all
other text layout steps are done. This matches VSFilter, which
applies shear after alignment. This would also have neutralized
the bug that the previous commit fixed, because glyphs[0].pos.y
really is always 0 until shear is applied. This also opens
the door for another commit to skip glyphs that are invisible
but affect layout.
In addition to simplifying code and calculations, this commit fixes
a bug: the current code for undoing shear assumes constant scale_x/y
from the last \fay change or line break point to the next such point,
producing strange, wrong positions when scale_x/y do change.
This fixes https://github.com/libass/libass/issues/465.
-rw-r--r-- | libass/ass_render.c | 34 | ||||
-rw-r--r-- | libass/ass_shaper.c | 5 | ||||
-rw-r--r-- | libass/ass_shaper.h | 1 |
3 files changed, 28 insertions, 12 deletions
diff --git a/libass/ass_render.c b/libass/ass_render.c index 3a335fa..058e0ac 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -2064,9 +2064,6 @@ static void retrieve_glyphs(ASS_Renderer *render_priv) // add horizontal letter spacing info->cluster_advance.x += info->hspacing_scaled; - - // add displacement for vertical shearing - info->cluster_advance.y += (info->fay / info->scale_x * info->scale_y) * info->cluster_advance.x; } } @@ -2107,23 +2104,15 @@ static void reorder_text(ASS_Renderer *render_priv) // Reposition according to the map ASS_Vector pen = { 0, 0 }; int lineno = 1; - double last_pen_x = 0; - double last_fay = 0; for (int i = 0; i < text_info->length; i++) { 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.x = 0; pen.y += double_to_d6(text_info->lines[lineno-1].desc); pen.y += double_to_d6(text_info->lines[lineno].asc); pen.y += double_to_d6(render_priv->settings.line_spacing); lineno++; } - else if (last_fay != info->fay) { - pen.y -= (last_fay / info->scale_x * info->scale_y) * (pen.x - last_pen_x); - last_pen_x = pen.x; - } - last_fay = info->fay; if (info->skip) continue; ASS_Vector cluster_pen = pen; @@ -2139,6 +2128,25 @@ static void reorder_text(ASS_Renderer *render_priv) } } +static void apply_baseline_shear(ASS_Renderer *render_priv) +{ + TextInfo *text_info = &render_priv->text_info; + FriBidiStrIndex *cmap = ass_shaper_get_reorder_map(render_priv->shaper); + int32_t shear = 0; + double last_fay = 0; + for (int i = 0; i < text_info->length; i++) { + GlyphInfo *info = text_info->glyphs + cmap[i]; + if (text_info->glyphs[i].linebreak || last_fay != info->fay) + shear = 0; + last_fay = info->fay; + if (info->skip) + continue; + for (GlyphInfo *cur = info; cur; cur = cur->next) + cur->pos.y += shear; + shear += (info->fay / info->scale_x * info->scale_y) * info->cluster_advance.x; + } +} + static void align_lines(ASS_Renderer *render_priv, double max_text_width) { TextInfo *text_info = &render_priv->text_info; @@ -2679,6 +2687,8 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, ASS_DRect bbox; compute_string_bbox(text_info, &bbox); + apply_baseline_shear(render_priv); + // determine device coordinates for text double device_x = 0; double device_y = 0; diff --git a/libass/ass_shaper.c b/libass/ass_shaper.c index 4665e7a..ffcb36b 100644 --- a/libass/ass_shaper.c +++ b/libass/ass_shaper.c @@ -1020,6 +1020,11 @@ FriBidiStrIndex *ass_shaper_reorder(ASS_Shaper *shaper, TextInfo *text_info) return shaper->cmap; } +FriBidiStrIndex *ass_shaper_get_reorder_map(ASS_Shaper *shaper) +{ + return shaper->cmap; +} + /** * \brief Resolve a Windows font charset number to a suitable base * direction. Generally, use LTR for compatibility with VSFilter. The diff --git a/libass/ass_shaper.h b/libass/ass_shaper.h index 2c4166d..70bec9a 100644 --- a/libass/ass_shaper.h +++ b/libass/ass_shaper.h @@ -45,6 +45,7 @@ void ass_shaper_set_bidi_brackets(ASS_Shaper *shaper, bool match_brackets); bool ass_shaper_shape(ASS_Shaper *shaper, TextInfo *text_info); void ass_shaper_cleanup(ASS_Shaper *shaper, TextInfo *text_info); FriBidiStrIndex *ass_shaper_reorder(ASS_Shaper *shaper, TextInfo *text_info); +FriBidiStrIndex *ass_shaper_get_reorder_map(ASS_Shaper *shaper); FriBidiParType resolve_base_direction(int font_encoding); void ass_shaper_font_data_free(ASS_ShaperFontData *priv); |