summaryrefslogtreecommitdiffstats
path: root/libass
diff options
context:
space:
mode:
authorDr.Smile <vabnick@gmail.com>2018-12-02 22:43:52 +0300
committerDr.Smile <vabnick@gmail.com>2019-05-19 20:25:09 +0300
commitf4b0721d815de8df1e6d95be4769ffc57fe4da1d (patch)
tree5c8c04052e4d385a8ef4b4f2561e88f432e6e4e8 /libass
parent66251384705a5bd93928680448f847298389156c (diff)
downloadlibass-f4b0721d815de8df1e6d95be4769ffc57fe4da1d.tar.bz2
libass-f4b0721d815de8df1e6d95be4769ffc57fe4da1d.tar.xz
drawing: extract transformation from parsing
Diffstat (limited to 'libass')
-rw-r--r--libass/ass_drawing.c127
-rw-r--r--libass/ass_drawing.h21
-rw-r--r--libass/ass_render.c66
3 files changed, 80 insertions, 134 deletions
diff --git a/libass/ass_drawing.c b/libass/ass_drawing.c
index 11ff399..fb71e15 100644
--- a/libass/ass_drawing.c
+++ b/libass/ass_drawing.c
@@ -29,67 +29,29 @@
#include "ass_drawing.h"
#include "ass_font.h"
-#define GLYPH_INITIAL_POINTS 100
-#define GLYPH_INITIAL_SEGMENTS 100
-
-/*
- * \brief Prepare drawing for parsing. This just sets a few parameters.
- */
-static void drawing_prepare(ASS_Drawing *drawing)
-{
- // Scaling parameters
- drawing->point_scale_x = drawing->scale_x / (1 << (drawing->scale - 1));
- drawing->point_scale_y = drawing->scale_y / (1 << (drawing->scale - 1));
-}
-
-/*
- * \brief Finish a drawing. This only sets the horizontal advance according
- * to the outline's bbox at the moment.
- */
-static void drawing_finish(ASS_Drawing *drawing, bool raw_mode)
-{
- ASS_Rect bbox = drawing->cbox;
- ASS_Outline *ol = &drawing->outline;
-
- if (drawing->library)
- ass_msg(drawing->library, MSGL_V,
- "Parsed drawing with %d points and %d segments",
- ol->n_points, ol->n_segments);
-
- if (raw_mode)
- return;
-
- drawing->advance = bbox.x_max - bbox.x_min;
-
- double pbo = drawing->pbo / (1 << (drawing->scale - 1));
- drawing->desc = double_to_d6(pbo * drawing->scale_y);
- drawing->asc = bbox.y_max - bbox.y_min - drawing->desc;
-
- // Place it onto the baseline
- for (size_t i = 0; i < ol->n_points; i++)
- ol->points[i].y -= drawing->asc;
-}
+#define DRAWING_INITIAL_POINTS 100
+#define DRAWING_INITIAL_SEGMENTS 100
/*
* \brief Check whether a number of items on the list is available
*/
-static int token_check_values(ASS_DrawingToken *token, int i, int type)
+static bool token_check_values(ASS_DrawingToken *token, int i, int type)
{
for (int j = 0; j < i; j++) {
- if (!token || token->type != type) return 0;
+ if (!token || token->type != type) return false;
token = token->next;
}
- return 1;
+ return true;
}
/*
* \brief Tokenize a drawing string into a list of ASS_DrawingToken
* This also expands points for closing b-splines
*/
-static ASS_DrawingToken *drawing_tokenize(char *str)
+static ASS_DrawingToken *drawing_tokenize(const char *str)
{
- char *p = str;
+ char *p = (char *) str;
int type = -1, is_set = 0;
double val;
ASS_Vector point = {0, 0};
@@ -174,27 +136,15 @@ static void drawing_free_tokens(ASS_DrawingToken *token)
}
/*
- * \brief Translate and scale a point coordinate according to baseline
- * offset and scale.
- */
-static inline void translate_point(ASS_Drawing *drawing, ASS_Vector *point)
-{
- point->x = lrint(drawing->point_scale_x * point->x);
- point->y = lrint(drawing->point_scale_y * point->y);
-
- rectangle_update(&drawing->cbox, point->x, point->y, point->x, point->y);
-}
-
-/*
* \brief Add curve to drawing
*/
-static bool drawing_add_curve(ASS_Drawing *drawing, ASS_DrawingToken *token,
- bool spline, int started)
+static bool drawing_add_curve(ASS_Outline *outline, ASS_Rect *cbox,
+ ASS_DrawingToken *token, bool spline, int started)
{
ASS_Vector p[4];
for (int i = 0; i < 4; ++i) {
p[i] = token->point;
- translate_point(drawing, &p[i]);
+ rectangle_update(cbox, p[i].x, p[i].y, p[i].x, p[i].y);
token = token->next;
}
@@ -217,25 +167,24 @@ static bool drawing_add_curve(ASS_Drawing *drawing, ASS_DrawingToken *token,
}
return (started ||
- outline_add_point(&drawing->outline, p[0], 0)) &&
- outline_add_point(&drawing->outline, p[1], 0) &&
- outline_add_point(&drawing->outline, p[2], 0) &&
- outline_add_point(&drawing->outline, p[3], OUTLINE_CUBIC_SPLINE);
+ outline_add_point(outline, p[0], 0)) &&
+ outline_add_point(outline, p[1], 0) &&
+ outline_add_point(outline, p[2], 0) &&
+ outline_add_point(outline, p[3], OUTLINE_CUBIC_SPLINE);
}
/*
* \brief Convert token list to outline. Calls the line and curve evaluators.
*/
-ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, ASS_Library *lib, bool raw_mode)
+bool ass_drawing_parse(ASS_Outline *outline, ASS_Rect *cbox,
+ const char *text, ASS_Library *lib)
{
- drawing->library = lib;
- rectangle_reset(&drawing->cbox);
- if (!outline_alloc(&drawing->outline, GLYPH_INITIAL_POINTS, GLYPH_INITIAL_SEGMENTS))
- return NULL;
- drawing->outline.n_points = drawing->outline.n_segments = 0;
+ if (!outline_alloc(outline, DRAWING_INITIAL_POINTS, DRAWING_INITIAL_SEGMENTS))
+ return false;
+ outline->n_points = outline->n_segments = 0;
+ rectangle_reset(cbox);
- ASS_DrawingToken *tokens = drawing_tokenize(drawing->text);
- drawing_prepare(drawing);
+ ASS_DrawingToken *tokens = drawing_tokenize(text);
bool started = false;
ASS_Vector pen = {0, 0};
@@ -245,16 +194,16 @@ ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, ASS_Library *lib, bool raw_
switch (token->type) {
case TOKEN_MOVE_NC:
pen = token->point;
- translate_point(drawing, &pen);
+ rectangle_update(cbox, pen.x, pen.y, pen.x, pen.y);
token = token->next;
break;
case TOKEN_MOVE:
pen = token->point;
- translate_point(drawing, &pen);
+ rectangle_update(cbox, pen.x, pen.y, pen.x, pen.y);
if (started) {
- if (!outline_add_segment(&drawing->outline, OUTLINE_LINE_SEGMENT))
+ if (!outline_add_segment(outline, OUTLINE_LINE_SEGMENT))
goto error;
- if (!outline_close_contour(&drawing->outline))
+ if (!outline_close_contour(outline))
goto error;
started = false;
}
@@ -262,10 +211,10 @@ ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, ASS_Library *lib, bool raw_
break;
case TOKEN_LINE: {
ASS_Vector to = token->point;
- translate_point(drawing, &to);
- if (!started && !outline_add_point(&drawing->outline, pen, 0))
+ rectangle_update(cbox, to.x, to.y, to.x, to.y);
+ if (!started && !outline_add_point(outline, pen, 0))
goto error;
- if (!outline_add_point(&drawing->outline, to, OUTLINE_LINE_SEGMENT))
+ if (!outline_add_point(outline, to, OUTLINE_LINE_SEGMENT))
goto error;
started = true;
token = token->next;
@@ -274,7 +223,7 @@ ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, ASS_Library *lib, bool raw_
case TOKEN_CUBIC_BEZIER:
if (token_check_values(token, 3, TOKEN_CUBIC_BEZIER) &&
token->prev) {
- if (!drawing_add_curve(drawing, token->prev, false, started))
+ if (!drawing_add_curve(outline, cbox, token->prev, false, started))
goto error;
token = token->next;
token = token->next;
@@ -286,7 +235,7 @@ ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, ASS_Library *lib, bool raw_
case TOKEN_B_SPLINE:
if (token_check_values(token, 3, TOKEN_B_SPLINE) &&
token->prev) {
- if (!drawing_add_curve(drawing, token->prev, true, started))
+ if (!drawing_add_curve(outline, cbox, token->prev, true, started))
goto error;
token = token->next;
started = true;
@@ -301,18 +250,22 @@ ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, ASS_Library *lib, bool raw_
// Close the last contour
if (started) {
- if (!outline_add_segment(&drawing->outline, OUTLINE_LINE_SEGMENT))
+ if (!outline_add_segment(outline, OUTLINE_LINE_SEGMENT))
goto error;
- if (!outline_close_contour(&drawing->outline))
+ if (!outline_close_contour(outline))
goto error;
}
- drawing_finish(drawing, raw_mode);
+ if (lib)
+ ass_msg(lib, MSGL_V,
+ "Parsed drawing with %d points and %d segments",
+ outline->n_points, outline->n_segments);
+
drawing_free_tokens(tokens);
- return &drawing->outline;
+ return true;
error:
drawing_free_tokens(tokens);
- outline_free(&drawing->outline);
- return NULL;
+ outline_free(outline);
+ return false;
}
diff --git a/libass/ass_drawing.h b/libass/ass_drawing.h
index 16d85ed..ea65ac6 100644
--- a/libass/ass_drawing.h
+++ b/libass/ass_drawing.h
@@ -41,24 +41,7 @@ typedef struct ass_drawing_token {
struct ass_drawing_token *prev;
} ASS_DrawingToken;
-typedef struct {
- char *text; // drawing string
- int scale; // scale (1-64) for subpixel accuracy
- double pbo; // drawing will be shifted in y direction by this amount
- double scale_x; // FontScaleX
- double scale_y; // FontScaleY
- int asc; // ascender
- int desc; // descender
- ASS_Outline outline; // target outline
- int advance; // advance (from cbox)
-
- // private
- ASS_Library *library;
- double point_scale_x;
- double point_scale_y;
- ASS_Rect cbox; // bounding box, or let's say... VSFilter's idea of it
-} ASS_Drawing;
-
-ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, ASS_Library *lib, bool raw_mode);
+bool ass_drawing_parse(ASS_Outline *outline, ASS_Rect *cbox,
+ const char *text, ASS_Library *lib);
#endif /* LIBASS_DRAWING_H */
diff --git a/libass/ass_render.c b/libass/ass_render.c
index 5b790c9..f8dee8e 100644
--- a/libass/ass_render.c
+++ b/libass/ass_render.c
@@ -1025,18 +1025,27 @@ size_t ass_outline_construct(void *key, void *value, void *priv)
if (outline_key->type == OUTLINE_DRAWING) {
DrawingHashKey *k = &outline_key->u.drawing;
- ASS_Drawing drawing;
- drawing.text = k->text;
- drawing.scale = k->scale;
- drawing.pbo = k->pbo;
- drawing.scale_x = scale_x * render_priv->font_scale;
- drawing.scale_y = scale_y * render_priv->font_scale;
- if (!ass_drawing_parse(&drawing, render_priv->library, false))
+ ASS_Rect bbox;
+ if (!ass_drawing_parse(&v->outline, &bbox, k->text, render_priv->library))
return 1;
- outline_move(&v->outline, &drawing.outline);
- v->advance = drawing.advance;
- v->asc = drawing.asc;
- v->desc = drawing.desc;
+
+ ASS_DVector scale, offset = {0};
+ double w = render_priv->font_scale / (1 << (k->scale - 1));
+ scale.x = scale_x * w;
+ scale.y = scale_y * w;
+
+ v->advance = (bbox.x_max - bbox.x_min) * scale.x;
+
+ double pbo = (double) k->pbo / (1 << (k->scale - 1));
+ v->desc = double_to_d6(pbo * scale_y * render_priv->font_scale);
+ v->asc = (bbox.y_max - bbox.y_min) * scale.y - v->desc;
+ offset.y = -v->asc;
+
+ ASS_Outline *ol = &v->outline;
+ for (size_t i = 0; i < ol->n_points; i++) {
+ ol->points[i].x = lrint(ol->points[i].x * scale.x + offset.x);
+ ol->points[i].y = lrint(ol->points[i].y * scale.y + offset.y);
+ }
} else {
GlyphHashKey *k = &outline_key->u.glyph;
ass_face_set_size(k->font->faces[k->face_index], k->size);
@@ -1198,30 +1207,31 @@ size_t ass_bitmap_construct(void *key, void *value, void *priv)
const size_t hdr = sizeof(BitmapHashKey) + sizeof(BitmapHashValue);
if (bitmap_key->type == BITMAP_CLIP) {
- ASS_Drawing drawing;
- drawing.text = bitmap_key->u.clip.text;
- drawing.scale = bitmap_key->u.clip.scale;
- drawing.pbo = 0;
- drawing.scale_x = render_priv->font_scale_x * render_priv->font_scale;
- drawing.scale_y = render_priv->font_scale;
- if (!ass_drawing_parse(&drawing, render_priv->library, true)) {
+ ASS_Rect cbox;
+ ASS_Outline outline;
+ if (!ass_drawing_parse(&outline, &cbox, bitmap_key->u.clip.text, render_priv->library)) {
ass_msg(render_priv->library, MSGL_WARN,
"Clip vector parsing failed. Skipping.");
return hdr;
}
- // We need to translate the clip according to screen borders
- if (render_priv->settings.left_margin != 0 ||
- render_priv->settings.top_margin != 0) {
- ASS_Vector trans = {
- .x = int_to_d6(render_priv->settings.left_margin),
- .y = int_to_d6(render_priv->settings.top_margin),
- };
- outline_translate(&drawing.outline, trans.x, trans.y);
+ ASS_DVector scale;
+ double w = render_priv->font_scale / (1 << (bitmap_key->u.clip.scale - 1));
+ scale.x = render_priv->font_scale_x * w;
+ scale.y = w;
+
+ ASS_DVector offset;
+ offset.x = int_to_d6(render_priv->settings.left_margin);
+ offset.y = int_to_d6(render_priv->settings.top_margin);
+
+ ASS_Outline *ol = &outline;
+ for (size_t i = 0; i < ol->n_points; i++) {
+ ol->points[i].x = lrint(ol->points[i].x * scale.x + offset.x);
+ ol->points[i].y = lrint(ol->points[i].y * scale.y + offset.y);
}
- v->bm = outline_to_bitmap(render_priv, &drawing.outline, NULL, 1);
- outline_free(&drawing.outline);
+ v->bm = outline_to_bitmap(render_priv, &outline, NULL, 1);
+ outline_free(&outline);
v->valid = !!v->bm;
return bitmap_size(v->bm) + hdr;