diff options
-rw-r--r-- | libass/ass_cache_template.c | 1 | ||||
-rw-r--r-- | libass/ass_drawing.c | 2 | ||||
-rw-r--r-- | libass/ass_font.c | 86 | ||||
-rw-r--r-- | libass/ass_font.h | 8 | ||||
-rw-r--r-- | libass/ass_render.c | 20 |
5 files changed, 111 insertions, 6 deletions
diff --git a/libass/ass_cache_template.c b/libass/ass_cache_template.c index bccb6db..eae9807 100644 --- a/libass/ass_cache_template.c +++ b/libass/ass_cache_template.c @@ -93,6 +93,7 @@ START(glyph, glyph_hash_key_s) FTVECTOR(advance) // subpixel shift vector FTVECTOR(outline) // border width, 16.16 GENERIC(unsigned, drawing_hash) // hashcode of a drawing + GENERIC(unsigned, flags) // glyph decoration flags END(glyph_hash_key_t) // Cache for composited bitmaps diff --git a/libass/ass_drawing.c b/libass/ass_drawing.c index 30d742f..09cf2d0 100644 --- a/libass/ass_drawing.c +++ b/libass/ass_drawing.c @@ -40,7 +40,7 @@ static void drawing_make_glyph(ass_drawing_t *drawing, void *fontconfig_priv, // This is hacky... glyph = (FT_OutlineGlyph) ass_font_get_glyph(fontconfig_priv, font, - (uint32_t) ' ', hint); + (uint32_t) ' ', hint, 0); FT_Outline_Done(drawing->ftlibrary, &glyph->outline); FT_Outline_New(drawing->ftlibrary, GLYPH_INITIAL_POINTS, diff --git a/libass/ass_font.c b/libass/ass_font.c index 52e6d3a..0aeeec6 100644 --- a/libass/ass_font.c +++ b/libass/ass_font.c @@ -276,12 +276,93 @@ void ass_font_get_asc_desc(ass_font_t *font, uint32_t ch, int *asc, *asc = *desc = 0; } +/* + * Strike a glyph with a horizontal line; it's possible to underline it + * and/or strike through it. For the line's position and size, truetype + * tables are consulted. Obviously this relies on the data in the tables + * being accurate. + * + */ +static int ass_strike_outline_glyph(FT_Face face, ass_font_t *font, + FT_Glyph glyph, int under, int through) +{ + TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); + TT_Postscript *ps = FT_Get_Sfnt_Table(face, ft_sfnt_post); + FT_Outline *ol = &((FT_OutlineGlyph) glyph)->outline; + int bear, advance, y_scale, i; + + // Grow outline + i = (under ? 4 : 0) + (through ? 4 : 0); + ol->points = realloc(ol->points, sizeof(FT_Vector) * + (ol->n_points + i)); + ol->tags = realloc(ol->tags, ol->n_points + i); + i = !!under + !!through; + ol->contours = realloc(ol->contours, sizeof(short) * + (ol->n_contours + i)); + + // If the bearing is negative, the glyph starts left of the current + // pen position + bear = FFMIN(face->glyph->metrics.horiBearingX, 0); + // We're adding half a pixel to avoid small gaps + advance = d16_to_d6(glyph->advance.x) + 32; + y_scale = face->size->metrics.y_scale; + + // Add points to the outline + if (under) { + int pos, size; + pos = FT_MulFix(ps->underlinePosition, y_scale * font->scale_y); + size = FT_MulFix(ps->underlineThickness, + y_scale * font->scale_y / 2); + + if (pos > 0 || size <= 0) + return 0; + + FT_Vector points[4] = { + {.x = bear, .y = pos + size}, + {.x = advance, .y = pos + size}, + {.x = advance, .y = pos - size}, + {.x = bear, .y = pos - size}, + }; + + for (i = 0; i < 4; i++) { + ol->points[ol->n_points] = points[i]; + ol->tags[ol->n_points++] = 1; + } + ol->contours[ol->n_contours++] = ol->n_points - 1; + } + + if (through) { + int pos, size; + pos = FT_MulFix(os2->yStrikeoutPosition, y_scale * font->scale_y); + size = FT_MulFix(os2->yStrikeoutSize, y_scale * font->scale_y / 2); + + if (pos < 0 || size <= 0) + return 0; + + FT_Vector points[4] = { + {.x = bear, .y = pos + size}, + {.x = advance, .y = pos + size}, + {.x = advance, .y = pos - size}, + {.x = bear, .y = pos - size}, + }; + + for (i = 0; i < 4; i++) { + ol->points[ol->n_points] = points[i]; + ol->tags[ol->n_points++] = 1; + } + + ol->contours[ol->n_contours++] = ol->n_points - 1; + } + + return 1; +} + /** * \brief Get a glyph * \param ch character code **/ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ass_font_t *font, - uint32_t ch, ass_hinting_t hinting) + uint32_t ch, ass_hinting_t hinting, int deco) { int error; int index = 0; @@ -356,6 +437,9 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ass_font_t *font, return 0; } + ass_strike_outline_glyph(face, font, glyph, deco & DECO_UNDERLINE, + deco & DECO_STRIKETHROUGH); + return glyph; } diff --git a/libass/ass_font.h b/libass/ass_font.h index b208064..8fe4c1e 100644 --- a/libass/ass_font.h +++ b/libass/ass_font.h @@ -27,6 +27,10 @@ #include "ass.h" #include "ass_types.h" +#define ASS_FONT_MAX_FACES 10 +#define DECO_UNDERLINE 1 +#define DECO_STRIKETHROUGH 2 + typedef struct ass_font_desc_s { char *family; unsigned bold; @@ -34,8 +38,6 @@ typedef struct ass_font_desc_s { int treat_family_as_pattern; } ass_font_desc_t; -#define ASS_FONT_MAX_FACES 10 - typedef struct ass_font_s { ass_font_desc_t desc; ass_library_t *library; @@ -57,7 +59,7 @@ void ass_font_set_size(ass_font_t *font, double size); void ass_font_get_asc_desc(ass_font_t *font, uint32_t ch, int *asc, int *desc); FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ass_font_t *font, - uint32_t ch, ass_hinting_t hinting); + uint32_t ch, ass_hinting_t hinting, int flags); FT_Vector ass_font_get_kerning(ass_font_t *font, uint32_t c1, uint32_t c2); void ass_font_free(ass_font_t *font); diff --git a/libass/ass_render.c b/libass/ass_render.c index c112399..19870a5 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -144,6 +144,7 @@ typedef struct render_context_s { ass_font_t *font; char *font_path; double font_size; + int flags; // decoration flags (underline/strike-through) FT_Stroker stroker_x; FT_Stroker stroker_y; @@ -1561,6 +1562,18 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr) } else val = 0.; render_priv->state.shadow_x = render_priv->state.shadow_y = val; + } else if (mystrcmp(&p, "s")) { + int val; + if (mystrtoi(&p, &val) && val) + render_priv->state.flags |= DECO_STRIKETHROUGH; + else + render_priv->state.flags &= ~DECO_STRIKETHROUGH; + } else if (mystrcmp(&p, "u")) { + int val; + if (mystrtoi(&p, &val) && val) + render_priv->state.flags |= DECO_UNDERLINE; + else + render_priv->state.flags &= ~DECO_UNDERLINE; } else if (mystrcmp(&p, "pbo")) { double val = 0; if (mystrtod(&p, &val)) @@ -1716,6 +1729,9 @@ static void reset_render_context(ass_renderer_t *render_priv) render_priv->state.c[1] = render_priv->state.style->SecondaryColour; render_priv->state.c[2] = render_priv->state.style->OutlineColour; render_priv->state.c[3] = render_priv->state.style->BackColour; + render_priv->state.flags = + (render_priv->state.style->Underline ? DECO_UNDERLINE : 0) | + (render_priv->state.style->StrikeOut ? DECO_STRIKETHROUGH : 0); render_priv->state.font_size = render_priv->state.style->FontSize; if (render_priv->state.family) @@ -1904,6 +1920,7 @@ get_outline_glyph(ass_renderer_t *render_priv, int symbol, key.advance = *advance; key.outline.x = render_priv->state.border_x * 0xFFFF; key.outline.y = render_priv->state.border_y * 0xFFFF; + key.flags = render_priv->state.flags; } memset(info, 0, sizeof(glyph_info_t)); @@ -1928,7 +1945,8 @@ get_outline_glyph(ass_renderer_t *render_priv, int symbol, info->glyph = ass_font_get_glyph(render_priv->fontconfig_priv, render_priv->state.font, symbol, - render_priv->settings.hinting); + render_priv->settings.hinting, + render_priv->state.flags); } if (!info->glyph) return; |