summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libass/ass.h20
-rw-r--r--libass/ass_render.c52
-rw-r--r--libass/ass_render.h1
-rw-r--r--libass/ass_render_api.c9
-rw-r--r--libass/ass_shaper.c34
-rw-r--r--libass/ass_shaper.h1
-rw-r--r--libass/libass.sym1
7 files changed, 86 insertions, 32 deletions
diff --git a/libass/ass.h b/libass/ass.h
index 57faf7d..4986437 100644
--- a/libass/ass.h
+++ b/libass/ass.h
@@ -61,6 +61,19 @@ typedef enum {
} ASS_Hinting;
/**
+ * \brief Text shaping levels.
+ *
+ * SIMPLE is a fast, font-agnostic shaper that can do only substitutions.
+ * COMPLEX is a slower shaper using OpenType for substitutions and positioning.
+ *
+ * libass uses the best shaper available by default.
+ */
+typedef enum {
+ ASS_SHAPING_SIMPLE = 0,
+ ASS_SHAPING_COMPLEX
+} ASS_ShapingLevel;
+
+/**
* \brief Initialize the library.
* \return library handle or NULL if failed
*/
@@ -147,6 +160,13 @@ void ass_renderer_done(ASS_Renderer *priv);
void ass_set_frame_size(ASS_Renderer *priv, int w, int h);
/**
+ * \brief Set shaping level. This is merely a hint, the renderer will use
+ * whatever is available if the request cannot be fulfilled.
+ * \param level shaping level
+ */
+void ass_set_shaper(ASS_Renderer *priv, ASS_ShapingLevel level);
+
+/**
* \brief Set frame margins. These values may be negative if pan-and-scan
* is used.
* \param priv renderer handle
diff --git a/libass/ass_render.c b/libass/ass_render.c
index 719b8bd..85d30b4 100644
--- a/libass/ass_render.c
+++ b/libass/ass_render.c
@@ -77,6 +77,7 @@ ASS_Renderer *ass_renderer_init(ASS_Library *library)
priv->shaper = ass_shaper_new(0);
ass_shaper_info(library);
+ priv->settings.shaper = ASS_SHAPING_COMPLEX;
ass_init_exit:
if (priv)
@@ -1104,21 +1105,21 @@ fill_glyph_hash(ASS_Renderer *priv, OutlineHashKey *outline_key,
* The glyphs are returned in info->glyph and info->outline_glyph
*/
static void
-get_outline_glyph(ASS_Renderer *render_priv, GlyphInfo *info)
+get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info)
{
OutlineHashValue *val;
OutlineHashKey key;
memset(&info->hash_key, 0, sizeof(key));
- fill_glyph_hash(render_priv, &key, info);
- val = ass_cache_get(render_priv->cache.outline_cache, &key);
+ fill_glyph_hash(priv, &key, info);
+ val = ass_cache_get(priv->cache.outline_cache, &key);
if (val) {
info->hash_key.u.outline.outline = val;
info->outline = val->outline;
info->border = val->border;
info->bbox = val->bbox_scaled;
- if (info->drawing) {
+ if (info->drawing || priv->settings.shaper == ASS_SHAPING_SIMPLE) {
info->cluster_advance.x = info->advance.x = val->advance.x;
info->cluster_advance.y = info->advance.y = val->advance.y;
}
@@ -1131,7 +1132,7 @@ get_outline_glyph(ASS_Renderer *render_priv, GlyphInfo *info)
ass_drawing_hash(drawing);
if(!ass_drawing_parse(drawing, 0))
return;
- outline_copy(render_priv->ftlibrary, &drawing->outline,
+ outline_copy(priv->ftlibrary, &drawing->outline,
&info->outline);
info->cluster_advance.x = info->advance.x = drawing->advance.x;
info->cluster_advance.y = info->advance.y = drawing->advance.y;
@@ -1143,19 +1144,17 @@ get_outline_glyph(ASS_Renderer *render_priv, GlyphInfo *info)
info->font_size);
ass_font_set_transform(info->font, info->scale_x,
info->scale_y, NULL);
- // symbol might have been changed. re-get it.
- //if (info->face_index < 0)
- // ass_font_get_index(render_priv->fontconfig_priv, info->font,
- // info->symbol, &info->face_index, &info->glyph_index);
FT_Glyph glyph =
- ass_font_get_glyph(render_priv->fontconfig_priv, info->font,
+ ass_font_get_glyph(priv->fontconfig_priv, info->font,
info->symbol, info->face_index, info->glyph_index,
- render_priv->settings.hinting, info->flags);
+ priv->settings.hinting, info->flags);
if (glyph != NULL) {
- outline_copy(render_priv->ftlibrary,
+ outline_copy(priv->ftlibrary,
&((FT_OutlineGlyph)glyph)->outline, &info->outline);
- //info->advance.x = d16_to_d6(glyph->advance.x);
- //info->advance.y = d16_to_d6(glyph->advance.y);
+ if (priv->settings.shaper == ASS_SHAPING_SIMPLE) {
+ info->cluster_advance.x = d16_to_d6(glyph->advance.x);
+ info->cluster_advance.y = d16_to_d6(glyph->advance.y);
+ }
FT_Done_Glyph(glyph);
ass_font_get_asc_desc(info->font, info->symbol,
&info->asc, &info->desc);
@@ -1168,26 +1167,24 @@ get_outline_glyph(ASS_Renderer *render_priv, GlyphInfo *info)
FT_Outline_Get_CBox(info->outline, &info->bbox);
- if (render_priv->state.style->BorderStyle == 3 &&
+ if (priv->state.style->BorderStyle == 3 &&
(info->border_x > 0|| info->border_y > 0)) {
- outline_copy(render_priv->ftlibrary, info->outline, &info->border);
- draw_opaque_box(render_priv, info->symbol, info->border,
+ outline_copy(priv->ftlibrary, info->outline, &info->border);
+ draw_opaque_box(priv, info->symbol, info->border,
info->advance,
- double_to_d6(info->border_x *
- render_priv->border_scale),
- double_to_d6(info->border_y *
- render_priv->border_scale));
+ double_to_d6(info->border_x * priv->border_scale),
+ double_to_d6(info->border_y * priv->border_scale));
} else if ((info->border_x > 0 || info->border_y > 0)
&& double_to_d6(info->scale_x) && double_to_d6(info->scale_y)) {
- outline_copy(render_priv->ftlibrary, info->outline, &info->border);
- stroke_outline(render_priv, info->border,
- double_to_d6(info->border_x * render_priv->border_scale),
- double_to_d6(info->border_y * render_priv->border_scale));
+ outline_copy(priv->ftlibrary, info->outline, &info->border);
+ stroke_outline(priv, info->border,
+ double_to_d6(info->border_x * priv->border_scale),
+ double_to_d6(info->border_y * priv->border_scale));
}
memset(&v, 0, sizeof(v));
- v.lib = render_priv->ftlibrary;
+ v.lib = priv->ftlibrary;
v.outline = info->outline;
v.border = info->border;
v.advance = info->cluster_advance;
@@ -1195,7 +1192,7 @@ get_outline_glyph(ASS_Renderer *render_priv, GlyphInfo *info)
v.asc = info->asc;
v.desc = info->desc;
info->hash_key.u.outline.outline =
- ass_cache_put(render_priv->cache.outline_cache, &key, &v);
+ ass_cache_put(priv->cache.outline_cache, &key, &v);
}
}
@@ -2269,6 +2266,7 @@ ass_start_frame(ASS_Renderer *render_priv, ASS_Track *track,
ass_shaper_set_kerning(render_priv->shaper, track->Kerning);
if (track->Language)
ass_shaper_set_language(render_priv->shaper, track->Language);
+ ass_shaper_set_level(render_priv->shaper, render_priv->settings.shaper);
// PAR correction
render_priv->font_scale_x = render_priv->settings.aspect /
diff --git a/libass/ass_render.h b/libass/ass_render.h
index 05c4974..d3c1bbb 100644
--- a/libass/ass_render.h
+++ b/libass/ass_render.h
@@ -76,6 +76,7 @@ typedef struct {
double aspect; // frame aspect ratio, d_width / d_height.
double storage_aspect; // pixel ratio of the source image
ASS_Hinting hinting;
+ ASS_ShapingLevel shaper;
char *default_font;
char *default_family;
diff --git a/libass/ass_render_api.c b/libass/ass_render_api.c
index 5b02b46..1d8cba6 100644
--- a/libass/ass_render_api.c
+++ b/libass/ass_render_api.c
@@ -58,6 +58,15 @@ void ass_set_frame_size(ASS_Renderer *priv, int w, int h)
}
}
+void ass_set_shaper(ASS_Renderer *priv, ASS_ShapingLevel level)
+{
+ // select the complex shaper for illegal values
+ if (level == ASS_SHAPING_SIMPLE || level == ASS_SHAPING_COMPLEX)
+ priv->settings.shaper = level;
+ else
+ priv->settings.shaper = ASS_SHAPING_COMPLEX;
+}
+
void ass_set_margins(ASS_Renderer *priv, int t, int b, int l, int r)
{
if (priv->settings.left_margin != l || priv->settings.right_margin != r ||
diff --git a/libass/ass_shaper.c b/libass/ass_shaper.c
index ce6389d..f6724d3 100644
--- a/libass/ass_shaper.c
+++ b/libass/ass_shaper.c
@@ -35,6 +35,7 @@ enum {
#define NUM_FEATURES 3
struct ass_shaper {
+ ASS_ShapingLevel shaping_level;
// FriBidi log2vis
int n_glyphs;
FriBidiChar *event_text;
@@ -487,15 +488,25 @@ static void shape_harfbuzz(ASS_Shaper *shaper, GlyphInfo *glyphs, size_t len)
* Arabic shaping.
* \param len number of clusters
*/
-static void shape_fribidi(ASS_Shaper *shaper, size_t len)
+static void shape_fribidi(ASS_Shaper *shaper, GlyphInfo *glyphs, size_t len)
{
+ int i;
FriBidiJoiningType *joins = calloc(sizeof(*joins), len);
+ // shape on codepoint level
fribidi_get_joining_types(shaper->event_text, len, joins);
fribidi_join_arabic(shaper->ctypes, len, shaper->emblevels, joins);
fribidi_shape(FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC,
shaper->emblevels, len, joins, shaper->event_text);
+ // update indexes
+ for (i = 0; i < len; i++) {
+ GlyphInfo *info = glyphs + i;
+ FT_Face face = info->font->faces[info->face_index];
+ info->symbol = shaper->event_text[i];
+ info->glyph_index = FT_Get_Char_Index(face, shaper->event_text[i]);
+ }
+
free(joins);
}
@@ -557,6 +568,14 @@ void ass_shaper_set_language(ASS_Shaper *shaper, const char *code)
}
/**
+ * Set shaping level. Essentially switches between FriBidi and HarfBuzz.
+ */
+void ass_shaper_set_level(ASS_Shaper *shaper, ASS_ShapingLevel level)
+{
+ shaper->shaping_level = level;
+}
+
+/**
* \brief Shape an event's text. Calculates directional runs and shapes them.
* \param text_info event's text
*/
@@ -588,12 +607,17 @@ void ass_shaper_shape(ASS_Shaper *shaper, TextInfo *text_info)
glyphs[i].shape_run_id += shaper->emblevels[i];
}
- //shape_fribidi(shaper, text_info->length);
- shape_harfbuzz(shaper, glyphs, text_info->length);
+ switch (shaper->shaping_level) {
+ case ASS_SHAPING_SIMPLE:
+ shape_fribidi(shaper, glyphs, text_info->length);
+ break;
+ case ASS_SHAPING_COMPLEX:
+ shape_harfbuzz(shaper, glyphs, text_info->length);
+ break;
+ }
- // Update glyphs
+ // clean up
for (i = 0; i < text_info->length; i++) {
- glyphs[i].symbol = shaper->event_text[i];
// Skip direction override control characters
// NOTE: Behdad said HarfBuzz is supposed to remove these, but this hasn't
// been implemented yet
diff --git a/libass/ass_shaper.h b/libass/ass_shaper.h
index 7e8bcc6..81499dd 100644
--- a/libass/ass_shaper.h
+++ b/libass/ass_shaper.h
@@ -32,6 +32,7 @@ void ass_shaper_find_runs(ASS_Shaper *shaper, ASS_Renderer *render_priv,
GlyphInfo *glyphs, size_t len);
void ass_shaper_set_base_direction(ASS_Shaper *shaper, FriBidiParType dir);
void ass_shaper_set_language(ASS_Shaper *shaper, const char *code);
+void ass_shaper_set_level(ASS_Shaper *shaper, ASS_ShapingLevel level);
void 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);
diff --git a/libass/libass.sym b/libass/libass.sym
index 0ea8792..f8fa145 100644
--- a/libass/libass.sym
+++ b/libass/libass.sym
@@ -34,3 +34,4 @@ ass_set_message_cb
ass_fonts_update
ass_set_cache_limits
ass_flush_events
+ass_set_shaper