]> granicus.if.org Git - libass/commitdiff
Runtime shaper selection
authorGrigori Goronzy <greg@blackbox>
Sun, 7 Aug 2011 22:22:32 +0000 (00:22 +0200)
committerGrigori Goronzy <greg@blackbox>
Sun, 7 Aug 2011 22:22:32 +0000 (00:22 +0200)
Add an API call, ass_set_shaper, and infrastructure to make shapers
selectable at runtime. Currently, this allows to switch between two
shapers: a SIMPLE shaper that maps to FriBidi and a COMPLEX shaper that
maps to HarfBuzz.

libass/ass.h
libass/ass_render.c
libass/ass_render.h
libass/ass_render_api.c
libass/ass_shaper.c
libass/ass_shaper.h
libass/libass.sym

index 57faf7d0513afe47860561dab496d6ed367e7955..49864379878afd4f99ca136a98bcd5845a8e964b 100644 (file)
@@ -60,6 +60,19 @@ typedef enum {
     ASS_HINTING_NATIVE
 } 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
@@ -146,6 +159,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.
index 719b8bdbdeca918d75abaf73d2939abb47da0dec..85d30b49bdc830e8c426e549e493ed955dedd912 100644 (file)
@@ -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 /
index 05c4974133b7aaeefa870e7e38f9b4ad21277156..d3c1bbbfc35cbb7ce18e5dcb1e9d6a6c056745bc 100644 (file)
@@ -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;
index 5b02b46ccc0ee4fdf5a2fd609640624cbf89eac1..1d8cba652320dffb59608a5f77a7c75e2d819327 100644 (file)
@@ -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 ||
index ce6389d4c236af5de8ea866bb744cc6bc4bc84b0..f6724d3784fc45ad726ff42ce61e5eccf635aef5 100644 (file)
@@ -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);
 }
 
@@ -556,6 +567,14 @@ void ass_shaper_set_language(ASS_Shaper *shaper, const char *code)
     shaper->language = hb_language_from_string(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
index 7e8bcc6696a14a71eedd469a98ec68ab7d555d7f..81499dde8eb0af40f84f89a51577c51c7f21ee69 100644 (file)
@@ -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);
index 0ea8792ca021df6b57df44b2228b47a7406fcb97..f8fa1458a15e8d8340c89da185fcd1d8c9a44260 100644 (file)
@@ -34,3 +34,4 @@ ass_set_message_cb
 ass_fonts_update
 ass_set_cache_limits
 ass_flush_events
+ass_set_shaper