summaryrefslogtreecommitdiffstats
path: root/libass/ass_render.c
diff options
context:
space:
mode:
authorGrigori Goronzy <greg@blackbox>2011-07-11 20:35:16 +0200
committerGrigori Goronzy <greg@blackbox>2011-07-11 20:35:16 +0200
commit8e87db144289d8f7418f4b0dcd2a02d2f7b1d7eb (patch)
tree60bd7f0a0e8354fb0e9e76969f626ac64f029ed6 /libass/ass_render.c
parentdb6ccb3634db5ccbce1a2fdaa383085242d52c82 (diff)
downloadlibass-8e87db144289d8f7418f4b0dcd2a02d2f7b1d7eb.tar.bz2
libass-8e87db144289d8f7418f4b0dcd2a02d2f7b1d7eb.tar.xz
Support glyph clusters of multiple glyphs
Sometimes a glyph cluster resolves to multiple glyphs, for example when diacritics are used with Arabic script. This doesn't map well to the list of glyphs expected by libass. Extend the glyph list to a list of singly-linked glyph clusters of glyphs and adapt the renderer to support this.
Diffstat (limited to 'libass/ass_render.c')
-rw-r--r--libass/ass_render.c252
1 files changed, 152 insertions, 100 deletions
diff --git a/libass/ass_render.c b/libass/ass_render.c
index b634577..d0f089d 100644
--- a/libass/ass_render.c
+++ b/libass/ass_render.c
@@ -698,22 +698,31 @@ static ASS_Image *render_text(ASS_Renderer *render_priv, int dst_x, int dst_y)
|| (info->shadow_x == 0 && info->shadow_y == 0) || info->skip)
continue;
- pen_x =
- dst_x + (info->pos.x >> 6) +
- (int) (info->shadow_x * render_priv->border_scale);
- pen_y =
- dst_y + (info->pos.y >> 6) +
- (int) (info->shadow_y * render_priv->border_scale);
- bm = info->bm_s;
+ while (info) {
+ if (!info->bm_s) {
+ info = info->next;
+ continue;
+ }
+
+ pen_x =
+ dst_x + (info->pos.x >> 6) +
+ (int) (info->shadow_x * render_priv->border_scale);
+ pen_y =
+ dst_y + (info->pos.y >> 6) +
+ (int) (info->shadow_y * render_priv->border_scale);
+ bm = info->bm_s;
+
+ here_tail = tail;
+ tail =
+ render_glyph(render_priv, bm, pen_x, pen_y, info->c[3], 0,
+ 1000000, tail);
- here_tail = tail;
- tail =
- render_glyph(render_priv, bm, pen_x, pen_y, info->c[3], 0,
- 1000000, tail);
- if (last_tail && tail != here_tail && ((info->c[3] & 0xff) > 0))
- render_overlap(render_priv, last_tail, here_tail);
+ if (last_tail && tail != here_tail && ((info->c[3] & 0xff) > 0))
+ render_overlap(render_priv, last_tail, here_tail);
+ last_tail = here_tail;
- last_tail = here_tail;
+ info = info->next;
+ }
}
last_tail = 0;
@@ -723,22 +732,30 @@ static ASS_Image *render_text(ASS_Renderer *render_priv, int dst_x, int dst_y)
|| info->skip)
continue;
- pen_x = dst_x + (info->pos.x >> 6);
- pen_y = dst_y + (info->pos.y >> 6);
- bm = info->bm_o;
+ while (info) {
+ if (!info->bm_o) {
+ info = info->next;
+ continue;
+ }
- if ((info->effect_type == EF_KARAOKE_KO)
- && (info->effect_timing <= (info->bbox.xMax >> 6))) {
- // do nothing
- } else {
- here_tail = tail;
- tail =
- render_glyph(render_priv, bm, pen_x, pen_y, info->c[2],
- 0, 1000000, tail);
- if (last_tail && tail != here_tail && ((info->c[2] & 0xff) > 0))
- render_overlap(render_priv, last_tail, here_tail);
+ pen_x = dst_x + (info->pos.x >> 6);
+ pen_y = dst_y + (info->pos.y >> 6);
+ bm = info->bm_o;
- last_tail = here_tail;
+ if ((info->effect_type == EF_KARAOKE_KO)
+ && (info->effect_timing <= (info->bbox.xMax >> 6))) {
+ // do nothing
+ } else {
+ here_tail = tail;
+ tail =
+ render_glyph(render_priv, bm, pen_x, pen_y, info->c[2],
+ 0, 1000000, tail);
+ if (last_tail && tail != here_tail && ((info->c[2] & 0xff) > 0))
+ render_overlap(render_priv, last_tail, here_tail);
+
+ last_tail = here_tail;
+ }
+ info = info->next;
}
}
@@ -748,28 +765,36 @@ static ASS_Image *render_text(ASS_Renderer *render_priv, int dst_x, int dst_y)
|| info->skip)
continue;
- pen_x = dst_x + (info->pos.x >> 6);
- pen_y = dst_y + (info->pos.y >> 6);
- bm = info->bm;
+ while (info) {
+ if (!info->bm) {
+ info = info->next;
+ continue;
+ }
- if ((info->effect_type == EF_KARAOKE)
- || (info->effect_type == EF_KARAOKE_KO)) {
- if (info->effect_timing > (info->bbox.xMax >> 6))
+ pen_x = dst_x + (info->pos.x >> 6);
+ pen_y = dst_y + (info->pos.y >> 6);
+ bm = info->bm;
+
+ if ((info->effect_type == EF_KARAOKE)
+ || (info->effect_type == EF_KARAOKE_KO)) {
+ if (info->effect_timing > (info->bbox.xMax >> 6))
+ tail =
+ render_glyph(render_priv, bm, pen_x, pen_y,
+ info->c[0], 0, 1000000, tail);
+ else
+ tail =
+ render_glyph(render_priv, bm, pen_x, pen_y,
+ info->c[1], 0, 1000000, tail);
+ } else if (info->effect_type == EF_KARAOKE_KF) {
tail =
- render_glyph(render_priv, bm, pen_x, pen_y,
- info->c[0], 0, 1000000, tail);
- else
+ render_glyph(render_priv, bm, pen_x, pen_y, info->c[0],
+ info->c[1], info->effect_timing, tail);
+ } else
tail =
- render_glyph(render_priv, bm, pen_x, pen_y,
- info->c[1], 0, 1000000, tail);
- } else if (info->effect_type == EF_KARAOKE_KF) {
- tail =
- render_glyph(render_priv, bm, pen_x, pen_y, info->c[0],
- info->c[1], info->effect_timing, tail);
- } else
- tail =
- render_glyph(render_priv, bm, pen_x, pen_y, info->c[0],
- 0, 1000000, tail);
+ render_glyph(render_priv, bm, pen_x, pen_y, info->c[0],
+ 0, 1000000, tail);
+ info = info->next;
+ }
}
*tail = 0;
@@ -778,23 +803,27 @@ static ASS_Image *render_text(ASS_Renderer *render_priv, int dst_x, int dst_y)
return head;
}
-static void compute_string_bbox(TextInfo *info, DBBox *bbox)
+static void compute_string_bbox(TextInfo *text, DBBox *bbox)
{
int i;
- if (info->length > 0) {
+ if (text->length > 0) {
bbox->xMin = 32000;
bbox->xMax = -32000;
- bbox->yMin = -1 * info->lines[0].asc + d6_to_double(info->glyphs[0].pos.y);
- bbox->yMax = info->height - info->lines[0].asc +
- d6_to_double(info->glyphs[0].pos.y);
-
- for (i = 0; i < info->length; ++i) {
- if (info->glyphs[i].skip) continue;
- double s = d6_to_double(info->glyphs[i].pos.x);
- double e = s + d6_to_double(info->glyphs[i].advance.x);
- bbox->xMin = FFMIN(bbox->xMin, s);
- bbox->xMax = FFMAX(bbox->xMax, e);
+ bbox->yMin = -1 * text->lines[0].asc + d6_to_double(text->glyphs[0].pos.y);
+ bbox->yMax = text->height - text->lines[0].asc +
+ d6_to_double(text->glyphs[0].pos.y);
+
+ for (i = 0; i < text->length; ++i) {
+ GlyphInfo *info = text->glyphs + i;
+ if (info->skip) continue;
+ while (info) {
+ double s = d6_to_double(info->pos.x);
+ double e = s + d6_to_double(info->advance.x);
+ bbox->xMin = FFMIN(bbox->xMin, s);
+ bbox->xMax = FFMAX(bbox->xMax, e);
+ info = info->next;
+ }
}
} else
bbox->xMin = bbox->xMax = bbox->yMin = bbox->yMax = 0.;
@@ -1845,7 +1874,11 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
// Retrieve glyphs
for (i = 0; i < text_info->length; i++) {
GlyphInfo *info = glyphs + i;
- get_outline_glyph(render_priv, info);
+ while (info) {
+ get_outline_glyph(render_priv, info);
+ info = info->next;
+ }
+ info = glyphs + i;
// add displacement for vertical shearing
info->advance.y += (info->fay * info->scale_y) * info->advance.x;
@@ -1862,33 +1895,36 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
pen.y = 0;
for (i = 0; i < text_info->length; i++) {
GlyphInfo *info = glyphs + i;
+ while (info) {
#if 0
- // Add additional space after italic to non-italic style changes
- if (i && glyphs[i - 1].italic && !info->italic) {
- int back = i - 1;
- GlyphInfo *og = &glyphs[back];
- while (back && og->bbox.xMax - og->bbox.xMin == 0
- && og->italic)
- og = &glyphs[--back];
- if (og->bbox.xMax > og->advance.x) {
- // The FreeType oblique slants by 6/16
- pen.x += og->bbox.yMax * 0.375;
+ // Add additional space after italic to non-italic style changes
+ if (i && glyphs[i - 1].italic && !info->italic) {
+ int back = i - 1;
+ GlyphInfo *og = &glyphs[back];
+ while (back && og->bbox.xMax - og->bbox.xMin == 0
+ && og->italic)
+ og = &glyphs[--back];
+ if (og->bbox.xMax > og->advance.x) {
+ // The FreeType oblique slants by 6/16
+ pen.x += og->bbox.yMax * 0.375;
+ }
}
- }
#endif
- info->pos.x = pen.x;
- info->pos.y = pen.y;
+ info->pos.x = pen.x;
+ info->pos.y = pen.y;
+
+ // fill bitmap hash
+ info->hash_key.type = BITMAP_OUTLINE;
+ fill_bitmap_hash(render_priv, info, &info->hash_key.u.outline);
+ info = info->next;
+ }
+ info = glyphs + i;
pen.x += info->advance.x;
pen.y += info->advance.y;
-
previous = info->symbol;
-
- // fill bitmap hash
- info->hash_key.type = BITMAP_OUTLINE;
- fill_bitmap_hash(render_priv, info, &info->hash_key.u.outline);
}
@@ -1941,8 +1977,12 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
lineno++;
}
if (info->skip) continue;
- info->pos.x = info->offset.x + pen.x;
- info->pos.y = info->offset.y + pen.y;
+ while (info) {
+ info->pos.x = info->offset.x + pen.x;
+ info->pos.y = info->offset.y + pen.y;
+ info = info->next;
+ }
+ info = glyphs + cmap[i];
pen.x += info->advance.x;
pen.y += info->advance.y;
}
@@ -1962,14 +2002,19 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
shift = (max_text_width - width) / 2.0;
}
for (j = last_break + 1; j < i; ++j) {
- glyphs[j].pos.x += double_to_d6(shift);
+ 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)
+ glyphs[i].symbol != '\n' && glyphs[i].symbol != 0) {
width += d6_to_double(glyphs[i].advance.x);
+ }
}
}
@@ -2096,14 +2141,17 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
for (i = 0; i < text_info->length; ++i) {
GlyphInfo *info = glyphs + i;
- 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;
+ 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;
}
}
}
@@ -2111,16 +2159,19 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
// convert glyphs to bitmaps
device_x *= render_priv->font_scale_x;
for (i = 0; i < text_info->length; ++i) {
- GlyphInfo *g = glyphs + i;
- OutlineBitmapHashKey *key = &g->hash_key.u.outline;
- g->pos.x *= render_priv->font_scale_x;
- key->advance.x =
- double_to_d6(device_x - (int) device_x +
- d6_to_double(g->pos.x & SUBPIXEL_MASK)) & ~SUBPIXEL_ACCURACY;
- key->advance.y =
- double_to_d6(device_y - (int) device_y +
- d6_to_double(g->pos.y & SUBPIXEL_MASK)) & ~SUBPIXEL_ACCURACY;
- get_bitmap_glyph(render_priv, glyphs + i);
+ GlyphInfo *info = glyphs + i;
+ while (info) {
+ OutlineBitmapHashKey *key = &info->hash_key.u.outline;
+ info->pos.x *= render_priv->font_scale_x;
+ key->advance.x =
+ double_to_d6(device_x - (int) device_x +
+ d6_to_double(info->pos.x & SUBPIXEL_MASK)) & ~SUBPIXEL_ACCURACY;
+ key->advance.y =
+ double_to_d6(device_y - (int) device_y +
+ d6_to_double(info->pos.y & SUBPIXEL_MASK)) & ~SUBPIXEL_ACCURACY;
+ get_bitmap_glyph(render_priv, info);
+ info = info->next;
+ }
}
// Compute runs and their bboxes
@@ -2164,6 +2215,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
free(emblevels);
free(cmap);
+ ass_shaper_cleanup(text_info);
free_render_context(render_priv);
return 0;