summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libass/ass_cache_template.c1
-rw-r--r--libass/ass_drawing.c2
-rw-r--r--libass/ass_font.c86
-rw-r--r--libass/ass_font.h8
-rw-r--r--libass/ass_render.c20
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;