summaryrefslogtreecommitdiffstats
path: root/libass/ass_shaper.c
diff options
context:
space:
mode:
Diffstat (limited to 'libass/ass_shaper.c')
-rw-r--r--libass/ass_shaper.c83
1 files changed, 78 insertions, 5 deletions
diff --git a/libass/ass_shaper.c b/libass/ass_shaper.c
index 6efc177..911732c 100644
--- a/libass/ass_shaper.c
+++ b/libass/ass_shaper.c
@@ -17,17 +17,20 @@
*/
#include <fribidi/fribidi.h>
+#include <hb-ft.h>
#include "ass_render.h"
#include "ass_shaper.h"
+#define MAX_RUNS 30
+
/**
* \brief Print version information
*/
void ass_shaper_info(ASS_Library *lib)
{
ass_msg(lib, MSGL_V, "Complex text layout enabled, using FriBidi "
- FRIBIDI_VERSION);
+ FRIBIDI_VERSION " HarfBuzz-ng %s", hb_version_string());
}
/**
@@ -39,11 +42,18 @@ void ass_shaper_info(ASS_Library *lib)
void ass_shaper_shape(TextInfo *text_info, FriBidiCharType *ctypes,
FriBidiLevel *emblevels)
{
- int i, last_break;
+ int i, j, last_break;
FriBidiParType dir;
FriBidiChar *event_text = calloc(sizeof(*event_text), text_info->length);
FriBidiJoiningType *joins = calloc(sizeof(*joins), text_info->length);
GlyphInfo *glyphs = text_info->glyphs;
+ // XXX: dynamically allocate
+ struct {
+ int offset;
+ int end;
+ hb_buffer_t *buf;
+ hb_font_t *font;
+ } runs[MAX_RUNS];
// Get bidi character types and embedding levels
last_break = 0;
@@ -61,26 +71,89 @@ void ass_shaper_shape(TextInfo *text_info, FriBidiCharType *ctypes,
}
}
+ // add embedding levels to shape runs for final runs
+ for (i = 0; i < text_info->length; i++) {
+ glyphs[i].shape_run_id += emblevels[i];
+ }
+
#if 0
printf("levels ");
for (i = 0; i < text_info->length; i++) {
- printf("%d:%d ", ctypes[i], emblevels[i]);
+ printf("%d ", glyphs[i].shape_run_id);
}
printf("\n");
#endif
+#if 0
// Use FriBidi's shaper for mirroring and simple Arabic shaping
fribidi_get_joining_types(event_text, text_info->length, joins);
fribidi_join_arabic(ctypes, text_info->length, emblevels, joins);
fribidi_shape(FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC, emblevels,
text_info->length, joins, event_text);
+#endif
+
+ // Shape runs with HarfBuzz-ng
+ int run = 0;
+ for (i = 0; i < text_info->length && run < MAX_RUNS; i++, run++) {
+ // get length and level of the current run
+ int k = i;
+ int level = glyphs[i].shape_run_id;
+ while (i < (text_info->length - 1) && level == glyphs[i+1].shape_run_id)
+ i++;
+ //printf("run %d from %d to %d with level %d\n", run, k, i, level);
+ FT_Face run_font = glyphs[k].font->faces[glyphs[k].face_index];
+ runs[run].offset = k;
+ runs[run].end = i;
+ runs[run].buf = hb_buffer_create(i - k + 1);
+ runs[run].font = hb_ft_font_create(run_font, NULL);
+ hb_buffer_set_direction(runs[run].buf, (level % 2) ? HB_DIRECTION_RTL :
+ HB_DIRECTION_LTR);
+ hb_buffer_add_utf32(runs[run].buf, event_text + k, i - k + 1,
+ 0, i - k + 1);
+ hb_shape(runs[run].font, runs[run].buf, NULL, 0);
+ }
+ //printf("shaped %d runs\n", run);
- // XXX: insert HarfBuzz shaper here
+ // Initialize: skip all glyphs, this is undone later as needed
+ for (i = 0; i < text_info->length; i++)
+ glyphs[i].skip = 1;
+
+ // Update glyph indexes, positions and advances from the shaped runs
+ for (i = 0; i < run; i++) {
+ int num_glyphs = hb_buffer_get_length(runs[i].buf);
+ hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(runs[i].buf, NULL);
+ hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(runs[i].buf, NULL);
+ //printf("run text len %d num_glyphs %d\n", runs[i].end - runs[i].offset + 1,
+ // num_glyphs);
+ // Update glyphs
+ for (j = 0; j < num_glyphs; j++) {
+ int idx = glyph_info[j].cluster + runs[i].offset;
+#if 0
+ printf("run %d cluster %d codepoint %d -> '%c'\n", i, idx,
+ glyph_info[j].codepoint, event_text[idx]);
+ printf("position %d %d advance %d %d\n",
+ pos[j].x_offset, pos[j].y_offset,
+ pos[j].x_advance, pos[j].y_advance);
+#endif
+ glyphs[idx].skip = 0;
+ glyphs[idx].glyph_index = glyph_info[j].codepoint;
+ glyphs[idx].offset.x = pos[j].x_offset * glyphs[idx].scale_x;
+ glyphs[idx].offset.y = pos[j].y_offset * glyphs[idx].scale_y;
+ glyphs[idx].advance.x = pos[j].x_advance * glyphs[idx].scale_x;
+ glyphs[idx].advance.y = pos[j].y_advance * glyphs[idx].scale_y;
+ }
+ }
+
+ // Free runs and associated data
+ for (i = 0; i < run; i++) {
+ hb_buffer_destroy(runs[i].buf);
+ hb_font_destroy(runs[i].font);
+ }
// Update glyphs
for (i = 0; i < text_info->length; i++) {
glyphs[i].symbol = event_text[i];
- // Skip direction override characters
+ // Skip direction override control characters
// NOTE: Behdad said HarfBuzz is supposed to remove these, but this hasn't
// been implemented yet
if (glyphs[i].symbol <= 0x202F && glyphs[i].symbol >= 0x202a) {