[MPlayer-cvslog] r31932 - in trunk: Makefile libass/ass.c libass/ass.h libass/ass_bitmap.c libass/ass_bitmap.h libass/ass_cache.c libass/ass_drawing.c libass/ass_drawing.h libass/ass_font.c libass/ass_font.h libass...
greg
subversion at mplayerhq.hu
Fri Aug 6 23:13:41 CEST 2010
Author: greg
Date: Fri Aug 6 23:13:41 2010
New Revision: 31932
Log:
Import libass 0.9.10
Added:
trunk/libass/ass_render_api.c
Modified:
trunk/Makefile
trunk/libass/ass.c
trunk/libass/ass.h
trunk/libass/ass_bitmap.c
trunk/libass/ass_bitmap.h
trunk/libass/ass_cache.c
trunk/libass/ass_drawing.c
trunk/libass/ass_drawing.h
trunk/libass/ass_font.c
trunk/libass/ass_font.h
trunk/libass/ass_fontconfig.c
trunk/libass/ass_parse.c
trunk/libass/ass_render.c
trunk/libass/ass_render.h
trunk/libass/ass_strtod.c
Modified: trunk/Makefile
==============================================================================
--- trunk/Makefile Fri Aug 6 12:48:16 2010 (r31931)
+++ trunk/Makefile Fri Aug 6 23:13:41 2010 (r31932)
@@ -119,6 +119,7 @@ SRCS_COMMON-$(LIBASS_INTERNAL) +=
libass/ass_library.c \
libass/ass_parse.c \
libass/ass_render.c \
+ libass/ass_render_api.c \
libass/ass_strtod.c \
libass/ass_utils.c \
Modified: trunk/libass/ass.c
==============================================================================
--- trunk/libass/ass.c Fri Aug 6 12:48:16 2010 (r31931)
+++ trunk/libass/ass.c Fri Aug 6 23:13:41 2010 (r31932)
@@ -38,6 +38,8 @@
#include "ass_utils.h"
#include "ass_library.h"
+#define ass_atof(STR) (ass_strtod((STR),NULL))
+
typedef enum {
PST_UNKNOWN = 0,
PST_INFO,
@@ -250,7 +252,7 @@ static int numpad2align(int val)
ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token);
#define INTVAL(name) ANYVAL(name,atoi)
-#define FPVAL(name) ANYVAL(name,atof)
+#define FPVAL(name) ANYVAL(name,ass_atof)
#define TIMEVAL(name) \
} else if (strcasecmp(tname, #name) == 0) { \
target->name = string2timecode(track->library, token); \
@@ -384,7 +386,7 @@ void ass_process_force_style(ASS_Track *
else if (!strcasecmp(*fs, "PlayResY"))
track->PlayResY = atoi(token);
else if (!strcasecmp(*fs, "Timer"))
- track->Timer = atof(token);
+ track->Timer = ass_atof(token);
else if (!strcasecmp(*fs, "WrapStyle"))
track->WrapStyle = atoi(token);
else if (!strcasecmp(*fs, "ScaledBorderAndShadow"))
@@ -534,12 +536,6 @@ static int process_style(ASS_Track *trac
style->Name = strdup("Default");
if (!style->FontName)
style->FontName = strdup("Arial");
- // skip '@' at the start of the font name
- if (*style->FontName == '@') {
- p = style->FontName;
- style->FontName = strdup(p + 1);
- free(p);
- }
free(format);
return 0;
@@ -568,7 +564,7 @@ static int process_info_line(ASS_Track *
} else if (!strncmp(str, "PlayResY:", 9)) {
track->PlayResY = atoi(str + 9);
} else if (!strncmp(str, "Timer:", 6)) {
- track->Timer = atof(str + 6);
+ track->Timer = ass_atof(str + 6);
} else if (!strncmp(str, "WrapStyle:", 10)) {
track->WrapStyle = atoi(str + 10);
} else if (!strncmp(str, "ScaledBorderAndShadow:", 22)) {
@@ -618,7 +614,7 @@ static int process_events_line(ASS_Track
process_event_tail(track, event, str, 0);
} else {
- ass_msg(track->library, MSGL_V, "Not understood: '%s'", str);
+ ass_msg(track->library, MSGL_V, "Not understood: '%.30s'", str);
}
return 0;
}
@@ -1033,14 +1029,6 @@ static char *read_file(ASS_Library *libr
sz = ftell(fp);
rewind(fp);
- if (sz > 10 * 1024 * 1024) {
- ass_msg(library, MSGL_INFO,
- "ass_read_file(%s): Refusing to load subtitles "
- "larger than 10MiB", fname);
- fclose(fp);
- return 0;
- }
-
ass_msg(library, MSGL_V, "File size: %ld", sz);
buf = malloc(sz + 1);
Modified: trunk/libass/ass.h
==============================================================================
--- trunk/libass/ass.h Fri Aug 6 12:48:16 2010 (r31931)
+++ trunk/libass/ass.h Fri Aug 6 23:13:41 2010 (r31932)
@@ -75,11 +75,13 @@ ASS_Library *ass_library_init(void);
void ass_library_done(ASS_Library *priv);
/**
- * \brief Set private font directory.
- * It is used for saving embedded fonts and also in font lookup.
+ * \brief Set additional fonts directory.
+ * Optional directory that will be scanned for fonts recursively. The fonts
+ * found are used for font lookup.
+ * NOTE: A valid font directory is not needed to support embedded fonts.
*
* \param priv library handle
- * \param fonts_dir private directory for font extraction
+ * \param fonts_dir directory with additional fonts
*/
void ass_set_fonts_dir(ASS_Library *priv, const char *fonts_dir);
@@ -203,6 +205,8 @@ void ass_set_line_spacing(ASS_Renderer *
* if fontconfig is used.
* \param update whether fontconfig cache should be built/updated now. Only
* relevant if fontconfig is used.
+ *
+ * NOTE: font lookup must be configured before an ASS_Renderer can be used.
*/
void ass_set_fonts(ASS_Renderer *priv, const char *default_font,
const char *default_family, int fc, const char *config,
@@ -297,7 +301,8 @@ void ass_free_event(ASS_Track *track, in
void ass_process_data(ASS_Track *track, char *data, int size);
/**
- * \brief Parse Codec Private section of subtitle stream.
+ * \brief Parse Codec Private section of the subtitle stream, in Matroska
+ * format. See the Matroska specification for details.
* \param track target track
* \param data string to parse
* \param size length of data
@@ -305,8 +310,8 @@ void ass_process_data(ASS_Track *track,
void ass_process_codec_private(ASS_Track *track, char *data, int size);
/**
- * \brief Parse a chunk of subtitle stream data. In Matroska,
- * this contains exactly 1 event (or a commentary).
+ * \brief Parse a chunk of subtitle stream data. A chunk contains exactly one
+ * event in Matroska format. See the Matroska specification for details.
* \param track track
* \param data string to parse
* \param size length of data
Modified: trunk/libass/ass_bitmap.c
==============================================================================
--- trunk/libass/ass_bitmap.c Fri Aug 6 12:48:16 2010 (r31931)
+++ trunk/libass/ass_bitmap.c Fri Aug 6 23:13:41 2010 (r31932)
@@ -139,8 +139,8 @@ void ass_synth_done(ASS_SynthPriv *priv)
static Bitmap *alloc_bitmap(int w, int h)
{
Bitmap *bm;
- bm = calloc(1, sizeof(Bitmap));
- bm->buffer = malloc(w * h);
+ bm = malloc(sizeof(Bitmap));
+ bm->buffer = calloc(w, h);
bm->w = w;
bm->h = h;
bm->left = bm->top = 0;
@@ -165,7 +165,7 @@ static Bitmap *copy_bitmap(const Bitmap
return dst;
}
-static int check_glyph_area(ASS_Library *library, FT_Glyph glyph)
+int check_glyph_area(ASS_Library *library, FT_Glyph glyph)
{
FT_BBox bbox;
long long dx, dy;
@@ -213,7 +213,6 @@ static Bitmap *glyph_to_bitmap_internal(
w = bit->width;
h = bit->rows;
bm = alloc_bitmap(w + 2 * bord, h + 2 * bord);
- memset(bm->buffer, 0, bm->w * bm->h);
bm->left = bg->left - bord;
bm->top = -bg->top - bord;
Modified: trunk/libass/ass_bitmap.h
==============================================================================
--- trunk/libass/ass_bitmap.h Fri Aug 6 12:48:16 2010 (r31931)
+++ trunk/libass/ass_bitmap.h Fri Aug 6 23:13:41 2010 (r31932)
@@ -53,5 +53,6 @@ int glyph_to_bitmap(ASS_Library *library
int border_style);
void ass_free_bitmap(Bitmap *bm);
+int check_glyph_area(ASS_Library *library, FT_Glyph glyph);
#endif /* LIBASS_BITMAP_H */
Modified: trunk/libass/ass_cache.c
==============================================================================
--- trunk/libass/ass_cache.c Fri Aug 6 12:48:16 2010 (r31931)
+++ trunk/libass/ass_cache.c Fri Aug 6 23:13:41 2010 (r31932)
@@ -156,6 +156,8 @@ static int font_compare(void *key1, void
return 0;
if (a->treat_family_as_pattern != b->treat_family_as_pattern)
return 0;
+ if (a->vertical != b->vertical)
+ return 0;
return 1;
}
@@ -286,6 +288,11 @@ static void glyph_hash_dtor(void *key, s
void *cache_add_glyph(Hashmap *glyph_cache, GlyphHashKey *key,
GlyphHashValue *val)
{
+ if (val->glyph && val->glyph->format == FT_GLYPH_FORMAT_BITMAP) {
+ FT_Bitmap *bitmap = &((FT_BitmapGlyph) val->glyph)->bitmap;
+ glyph_cache->cache_size += bitmap->rows * bitmap->pitch;
+ }
+
return hashmap_insert(glyph_cache, key, val);
}
Modified: trunk/libass/ass_drawing.c
==============================================================================
--- trunk/libass/ass_drawing.c Fri Aug 6 12:48:16 2010 (r31931)
+++ trunk/libass/ass_drawing.c Fri Aug 6 23:13:41 2010 (r31932)
@@ -112,24 +112,12 @@ static void drawing_prepare(ASS_Drawing
static void drawing_finish(ASS_Drawing *drawing, int raw_mode)
{
int i, offset;
- FT_BBox bbox;
+ FT_BBox bbox = drawing->cbox;
FT_Outline *ol = &drawing->glyph->outline;
// Close the last contour
drawing_close_shape(drawing);
-#if 0
- // Dump points
- for (i = 0; i < ol->n_points; i++) {
- printf("point (%d, %d)\n", (int) ol->points[i].x,
- (int) ol->points[i].y);
- }
-
- // Dump contours
- for (i = 0; i < ol->n_contours; i++)
- printf("contour %d\n", ol->contours[i]);
-#endif
-
ass_msg(drawing->library, MSGL_V,
"Parsed drawing with %d points and %d contours", ol->n_points,
ol->n_contours);
@@ -137,7 +125,6 @@ static void drawing_finish(ASS_Drawing *
if (raw_mode)
return;
- FT_Outline_Get_CBox(&drawing->glyph->outline, &bbox);
drawing->glyph->root.advance.x = d6_to_d16(bbox.xMax - bbox.xMin);
drawing->desc = double_to_d6(-drawing->pbo * drawing->scale_y);
@@ -231,15 +218,6 @@ static ASS_DrawingToken *drawing_tokeniz
p++;
}
-#if 0
- // Check tokens
- ASS_DrawingToken *t = root;
- while(t) {
- printf("token %d point (%d, %d)\n", t->type, t->point.x, t->point.y);
- t = t->next;
- }
-#endif
-
return root;
}
@@ -256,6 +234,19 @@ static void drawing_free_tokens(ASS_Draw
}
/*
+ * \brief Update drawing cbox
+ */
+static inline void update_cbox(ASS_Drawing *drawing, FT_Vector *point)
+{
+ FT_BBox *box = &drawing->cbox;
+
+ box->xMin = FFMIN(box->xMin, point->x);
+ box->xMax = FFMAX(box->xMax, point->x);
+ box->yMin = FFMIN(box->yMin, point->y);
+ box->yMax = FFMAX(box->yMax, point->y);
+}
+
+/*
* \brief Translate and scale a point coordinate according to baseline
* offset and scale.
*/
@@ -263,6 +254,8 @@ static inline void translate_point(ASS_D
{
point->x = drawing->point_scale_x * point->x;
point->y = drawing->point_scale_y * -point->y;
+
+ update_cbox(drawing, point);
}
/*
@@ -369,6 +362,8 @@ ASS_Drawing *ass_drawing_new(void *fontc
drawing = calloc(1, sizeof(*drawing));
drawing->text = calloc(1, DRAWING_INITIAL_SIZE);
drawing->size = DRAWING_INITIAL_SIZE;
+ drawing->cbox.xMin = drawing->cbox.yMin = INT_MAX;
+ drawing->cbox.xMax = drawing->cbox.yMax = INT_MIN;
drawing->ftlibrary = lib;
if (font) {
@@ -390,8 +385,6 @@ ASS_Drawing *ass_drawing_new(void *fontc
void ass_drawing_free(ASS_Drawing* drawing)
{
if (drawing) {
- if (drawing->glyph)
- FT_Done_Glyph((FT_Glyph) drawing->glyph);
free(drawing->text);
}
free(drawing);
Modified: trunk/libass/ass_drawing.h
==============================================================================
--- trunk/libass/ass_drawing.h Fri Aug 6 12:48:16 2010 (r31931)
+++ trunk/libass/ass_drawing.h Fri Aug 6 23:13:41 2010 (r31932)
@@ -65,6 +65,7 @@ typedef struct {
int max_contours;
double point_scale_x;
double point_scale_y;
+ FT_BBox cbox; // bounding box, or let's say... VSFilter's idea of it
} ASS_Drawing;
ASS_Drawing *ass_drawing_new(void *fontconfig_priv, ASS_Font *font,
Modified: trunk/libass/ass_font.c
==============================================================================
--- trunk/libass/ass_font.c Fri Aug 6 12:48:16 2010 (r31931)
+++ trunk/libass/ass_font.c Fri Aug 6 23:13:41 2010 (r31932)
@@ -36,13 +36,18 @@
#include "ass_fontconfig.h"
#include "ass_utils.h"
+#define VERTICAL_LOWER_BOUND 0x02f1
+
/**
- * Select Microfost Unicode CharMap, if the font has one.
+ * Select a good charmap, prefer Microsoft Unicode charmaps.
* Otherwise, let FreeType decide.
*/
static void charmap_magic(ASS_Library *library, FT_Face face)
{
int i;
+ int ms_cmap = -1;
+
+ // Search for a Microsoft Unicode cmap
for (i = 0; i < face->num_charmaps; ++i) {
FT_CharMap cmap = face->charmaps[i];
unsigned pid = cmap->platform_id;
@@ -52,7 +57,15 @@ static void charmap_magic(ASS_Library *l
|| eid == 10 /*full unicode */ )) {
FT_Set_Charmap(face, cmap);
return;
- }
+ } else if (pid == 3 && ms_cmap < 0)
+ ms_cmap = i;
+ }
+
+ // Try the first Microsoft cmap if no Microsoft Unicode cmap was found
+ if (ms_cmap >= 0) {
+ FT_CharMap cmap = face->charmaps[ms_cmap];
+ FT_Set_Charmap(face, cmap);
+ return;
}
if (!face->charmap) {
@@ -67,17 +80,6 @@ static void charmap_magic(ASS_Library *l
}
}
-static void update_transform(ASS_Font *font)
-{
- int i;
- FT_Matrix m;
- m.xx = double_to_d16(font->scale_x);
- m.yy = double_to_d16(font->scale_y);
- m.xy = m.yx = 0;
- for (i = 0; i < font->n_faces; ++i)
- FT_Set_Transform(font->faces[i], &m, &font->v);
-}
-
/**
* \brief find a memory font by name
*/
@@ -139,7 +141,7 @@ static int add_face(void *fc_priv, ASS_F
FT_New_Memory_Face(font->ftlibrary,
(unsigned char *) font->library->
fontdata[mem_idx].data,
- font->library->fontdata[mem_idx].size, 0,
+ font->library->fontdata[mem_idx].size, index,
&face);
if (error) {
ass_msg(font->library, MSGL_WARN,
@@ -160,7 +162,6 @@ static int add_face(void *fc_priv, ASS_F
buggy_font_workaround(face);
font->faces[font->n_faces++] = face;
- update_transform(font);
face_set_size(face, font->size);
free(path);
return font->n_faces - 1;
@@ -188,6 +189,7 @@ ASS_Font *ass_font_new(void *font_cache,
font.desc.treat_family_as_pattern = desc->treat_family_as_pattern;
font.desc.bold = desc->bold;
font.desc.italic = desc->italic;
+ font.desc.vertical = desc->vertical;
font.scale_x = font.scale_y = 1.;
font.v.x = font.v.y = 0;
@@ -213,7 +215,6 @@ void ass_font_set_transform(ASS_Font *fo
font->v.x = v->x;
font->v.y = v->y;
}
- update_transform(font);
}
static void face_set_size(FT_Face face, double size)
@@ -276,6 +277,9 @@ void ass_font_get_asc_desc(ASS_Font *fon
*asc = FT_MulFix(face->ascender, y_scale);
*desc = FT_MulFix(-face->descender, y_scale);
}
+ if (font->desc.vertical && ch >= VERTICAL_LOWER_BOUND) {
+ *asc = FT_MulFix(face->max_advance_width, y_scale);
+ }
return;
}
}
@@ -414,6 +418,7 @@ FT_Glyph ass_font_get_glyph(void *fontco
FT_Glyph glyph;
FT_Face face = 0;
int flags = 0;
+ int vertical = font->desc.vertical;
if (ch < 0x20)
return 0;
@@ -441,6 +446,14 @@ FT_Glyph ass_font_get_glyph(void *fontco
if (face_idx >= 0) {
face = font->faces[face_idx];
index = FT_Get_Char_Index(face, ch);
+ if (index == 0 && face->num_charmaps > 0) {
+ ass_msg(font->library, MSGL_WARN,
+ "Glyph 0x%X not found, falling back to first charmap", ch);
+ FT_CharMap cur = face->charmap;
+ FT_Set_Charmap(face, face->charmaps[0]);
+ index = FT_Get_Char_Index(face, ch);
+ FT_Set_Charmap(face, cur);
+ }
if (index == 0) {
ass_msg(font->library, MSGL_ERR,
"Glyph 0x%X not found in font for (%s, %d, %d)",
@@ -451,22 +464,23 @@ FT_Glyph ass_font_get_glyph(void *fontco
}
#endif
+ flags = FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
+ | FT_LOAD_IGNORE_TRANSFORM;
switch (hinting) {
case ASS_HINTING_NONE:
- flags = FT_LOAD_NO_HINTING;
+ flags |= FT_LOAD_NO_HINTING;
break;
case ASS_HINTING_LIGHT:
- flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
+ flags |= FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
break;
case ASS_HINTING_NORMAL:
- flags = FT_LOAD_FORCE_AUTOHINT;
+ flags |= FT_LOAD_FORCE_AUTOHINT;
break;
case ASS_HINTING_NATIVE:
- flags = 0;
break;
}
- error = FT_Load_Glyph(face, index, FT_LOAD_NO_BITMAP | flags);
+ error = FT_Load_Glyph(face, index, flags);
if (error) {
ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d",
index);
@@ -488,6 +502,24 @@ FT_Glyph ass_font_get_glyph(void *fontco
return 0;
}
+ // Rotate glyph, if needed
+ if (vertical && ch >= VERTICAL_LOWER_BOUND) {
+ FT_Matrix m = { 0, double_to_d16(-1.0), double_to_d16(1.0), 0 };
+ FT_Outline_Transform(&((FT_OutlineGlyph) glyph)->outline, &m);
+ FT_Outline_Translate(&((FT_OutlineGlyph) glyph)->outline,
+ face->glyph->metrics.vertAdvance,
+ 0);
+ glyph->advance.x = face->glyph->linearVertAdvance;
+ }
+
+ // Apply scaling and shift
+ FT_Matrix scale = { double_to_d16(font->scale_x), 0, 0,
+ double_to_d16(font->scale_y) };
+ FT_Outline *outl = &((FT_OutlineGlyph) glyph)->outline;
+ FT_Outline_Transform(outl, &scale);
+ FT_Outline_Translate(outl, font->v.x, font->v.y);
+ glyph->advance.x *= font->scale_x;
+
ass_strike_outline_glyph(face, font, glyph, deco & DECO_UNDERLINE,
deco & DECO_STRIKETHROUGH);
@@ -502,6 +534,9 @@ FT_Vector ass_font_get_kerning(ASS_Font
FT_Vector v = { 0, 0 };
int i;
+ if (font->desc.vertical)
+ return v;
+
for (i = 0; i < font->n_faces; ++i) {
FT_Face face = font->faces[i];
int i1 = FT_Get_Char_Index(face, c1);
@@ -530,3 +565,130 @@ void ass_font_free(ASS_Font *font)
free(font->desc.family);
free(font);
}
+
+/**
+ * \brief Calculate the cbox of a series of points
+ */
+static void
+get_contour_cbox(FT_BBox *box, FT_Vector *points, int start, int end)
+{
+ box->xMin = box->yMin = INT_MAX;
+ box->xMax = box->yMax = INT_MIN;
+ int i;
+
+ for (i = start; i <= end; i++) {
+ box->xMin = (points[i].x < box->xMin) ? points[i].x : box->xMin;
+ box->xMax = (points[i].x > box->xMax) ? points[i].x : box->xMax;
+ box->yMin = (points[i].y < box->yMin) ? points[i].y : box->yMin;
+ box->yMax = (points[i].y > box->yMax) ? points[i].y : box->yMax;
+ }
+}
+
+/**
+ * \brief Determine winding direction of a contour
+ * \return direction; 0 = clockwise
+ */
+static int get_contour_direction(FT_Vector *points, int start, int end)
+{
+ int i;
+ long long sum = 0;
+ int x = points[start].x;
+ int y = points[start].y;
+ for (i = start + 1; i <= end; i++) {
+ sum += x * (points[i].y - y) - y * (points[i].x - x);
+ x = points[i].x;
+ y = points[i].y;
+ }
+ sum += x * (points[start].y - y) - y * (points[start].x - x);
+ return sum > 0;
+}
+
+/**
+ * \brief Fix-up stroker result for huge borders by removing inside contours
+ * that would reverse in size
+ */
+void fix_freetype_stroker(FT_OutlineGlyph glyph, int border_x, int border_y)
+{
+ int nc = glyph->outline.n_contours;
+ int begin, stop;
+ char modified = 0;
+ char *valid_cont = malloc(nc);
+ int start = 0;
+ int end = -1;
+ FT_BBox *boxes = malloc(nc * sizeof(FT_BBox));
+ int i, j;
+ int inside_direction;
+
+ inside_direction = FT_Outline_Get_Orientation(&glyph->outline) ==
+ FT_ORIENTATION_TRUETYPE;
+
+ // create a list of cboxes of the contours
+ for (i = 0; i < nc; i++) {
+ start = end + 1;
+ end = glyph->outline.contours[i];
+ get_contour_cbox(&boxes[i], glyph->outline.points, start, end);
+ }
+
+ // for each contour, check direction and whether it's "outside"
+ // or contained in another contour
+ end = -1;
+ for (i = 0; i < nc; i++) {
+ start = end + 1;
+ end = glyph->outline.contours[i];
+ int dir = get_contour_direction(glyph->outline.points, start, end);
+ valid_cont[i] = 1;
+ if (dir == inside_direction) {
+ for (j = 0; j < nc; j++) {
+ if (i == j)
+ continue;
+ if (boxes[i].xMin >= boxes[j].xMin &&
+ boxes[i].xMax <= boxes[j].xMax &&
+ boxes[i].yMin >= boxes[j].yMin &&
+ boxes[i].yMax <= boxes[j].yMax)
+ goto check_inside;
+ }
+ /* "inside" contour but we can't find anything it could be
+ * inside of - assume the font is buggy and it should be
+ * an "outside" contour, and reverse it */
+ for (j = 0; j < (end + 1 - start) / 2; j++) {
+ FT_Vector temp = glyph->outline.points[start + j];
+ char temp2 = glyph->outline.tags[start + j];
+ glyph->outline.points[start + j] = glyph->outline.points[end - j];
+ glyph->outline.points[end - j] = temp;
+ glyph->outline.tags[start + j] = glyph->outline.tags[end - j];
+ glyph->outline.tags[end - j] = temp2;
+ }
+ dir ^= 1;
+ }
+ check_inside:
+ if (dir == inside_direction) {
+ FT_BBox box;
+ get_contour_cbox(&box, glyph->outline.points, start, end);
+ int width = box.xMax - box.xMin;
+ int height = box.yMax - box.yMin;
+ if (width < border_x * 2 || height < border_y * 2) {
+ valid_cont[i] = 0;
+ modified = 1;
+ }
+ }
+ }
+
+ // zero-out contours that can be removed; much simpler than copying
+ if (modified) {
+ for (i = 0; i < nc; i++) {
+ if (valid_cont[i])
+ continue;
+ begin = (i == 0) ? 0 : glyph->outline.contours[i - 1] + 1;
+ stop = glyph->outline.contours[i];
+ for (j = begin; j <= stop; j++) {
+ glyph->outline.points[j].x = 0;
+ glyph->outline.points[j].y = 0;
+ glyph->outline.tags[j] = 0;
+ }
+ }
+ }
+
+ free(boxes);
+ free(valid_cont);
+}
+
Modified: trunk/libass/ass_font.h
==============================================================================
--- trunk/libass/ass_font.h Fri Aug 6 12:48:16 2010 (r31931)
+++ trunk/libass/ass_font.h Fri Aug 6 23:13:41 2010 (r31932)
@@ -36,6 +36,7 @@ typedef struct {
unsigned bold;
unsigned italic;
int treat_family_as_pattern;
+ int vertical; // @font vertical layout
} ASS_FontDesc;
typedef struct {
@@ -62,5 +63,6 @@ FT_Glyph ass_font_get_glyph(void *fontco
uint32_t ch, ASS_Hinting hinting, int flags);
FT_Vector ass_font_get_kerning(ASS_Font *font, uint32_t c1, uint32_t c2);
void ass_font_free(ASS_Font *font);
+void fix_freetype_stroker(FT_OutlineGlyph glyph, int border_x, int border_y);
#endif /* LIBASS_FONT_H */
Modified: trunk/libass/ass_fontconfig.c
==============================================================================
--- trunk/libass/ass_fontconfig.c Fri Aug 6 12:48:16 2010 (r31931)
+++ trunk/libass/ass_fontconfig.c Fri Aug 6 23:13:41 2010 (r31932)
@@ -52,6 +52,61 @@ struct fc_instance {
#ifdef CONFIG_FONTCONFIG
/**
+ * \brief Case-insensitive match ASS/SSA font family against full name. (also
+ * known as "name for humans")
+ *
+ * \param lib library instance
+ * \param priv fontconfig instance
+ * \param family font fullname
+ * \param bold weight attribute
+ * \param italic italic attribute
+ * \return font set
+ */
+static FcFontSet *
+match_fullname(ASS_Library *lib, FCInstance *priv, const char *family,
+ unsigned bold, unsigned italic)
+{
+ FcFontSet *sets[2];
+ FcFontSet *result = FcFontSetCreate();
+ int nsets = 0;
+ int i, fi;
+
+ if ((sets[nsets] = FcConfigGetFonts(priv->config, FcSetSystem)))
+ nsets++;
+ if ((sets[nsets] = FcConfigGetFonts(priv->config, FcSetApplication)))
+ nsets++;
+
+ // Run over font sets and patterns and try to match against full name
+ for (i = 0; i < nsets; i++) {
+ FcFontSet *set = sets[i];
+ for (fi = 0; fi < set->nfont; fi++) {
+ FcPattern *pat = set->fonts[fi];
+ char *fullname;
+ int pi = 0, at;
+ FcBool ol;
+ while (FcPatternGetString(pat, FC_FULLNAME, pi++,
+ (FcChar8 **) &fullname) == FcResultMatch) {
+ if (FcPatternGetBool(pat, FC_OUTLINE, 0, &ol) != FcResultMatch
+ || ol != FcTrue)
+ continue;
+ if (FcPatternGetInteger(pat, FC_SLANT, 0, &at) != FcResultMatch
+ || at < italic)
+ continue;
+ if (FcPatternGetInteger(pat, FC_WEIGHT, 0, &at) != FcResultMatch
+ || at < bold)
+ continue;
+ if (strcasecmp(fullname, family) == 0) {
+ FcFontSetAdd(result, FcPatternDuplicate(pat));
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
* \brief Low-level font selection.
* \param priv private data
* \param family font family
@@ -62,7 +117,7 @@ struct fc_instance {
* \param code: the character that should be present in the font, can be 0
* \return font file path
*/
-static char *_select_font(ASS_Library *library, FCInstance *priv,
+static char *select_font(ASS_Library *library, FCInstance *priv,
const char *family, int treat_family_as_pattern,
unsigned bold, unsigned italic, int *index,
uint32_t code)
@@ -74,7 +129,7 @@ static char *_select_font(ASS_Library *l
FcChar8 *r_family, *r_style, *r_file, *r_fullname;
FcBool r_outline, r_embolden;
FcCharSet *r_charset;
- FcFontSet *fset = NULL;
+ FcFontSet *ffullname = NULL, *fsorted = NULL, *fset = NULL;
int curf;
char *retval = NULL;
int family_cnt = 0;
@@ -126,10 +181,23 @@ static char *_select_font(ASS_Library *l
if (!rc)
goto error;
- fset = FcFontSort(priv->config, pat, FcTrue, NULL, &result);
- if (!fset)
+ fsorted = FcFontSort(priv->config, pat, FcTrue, NULL, &result);
+ ffullname = match_fullname(library, priv, family, bold, italic);
+ if (!fsorted || !ffullname)
goto error;
+ fset = FcFontSetCreate();
+ for (curf = 0; curf < ffullname->nfont; ++curf) {
+ FcPattern *curp = ffullname->fonts[curf];
+ FcPatternReference(curp);
+ FcFontSetAdd(fset, curp);
+ }
+ for (curf = 0; curf < fsorted->nfont; ++curf) {
+ FcPattern *curp = fsorted->fonts[curf];
+ FcPatternReference(curp);
+ FcFontSetAdd(fset, curp);
+ }
+
for (curf = 0; curf < fset->nfont; ++curf) {
FcPattern *curp = fset->fonts[curf];
@@ -215,6 +283,10 @@ static char *_select_font(ASS_Library *l
FcPatternDestroy(pat);
if (rpat)
FcPatternDestroy(rpat);
+ if (fsorted)
+ FcFontSetDestroy(fsorted);
+ if (ffullname)
+ FcFontSetDestroy(ffullname);
if (fset)
FcFontSetDestroy(fset);
return retval;
@@ -244,11 +316,11 @@ char *fontconfig_select(ASS_Library *lib
}
if (family && *family)
res =
- _select_font(library, priv, family, treat_family_as_pattern,
+ select_font(library, priv, family, treat_family_as_pattern,
bold, italic, index, code);
if (!res && priv->family_default) {
res =
- _select_font(library, priv, priv->family_default, 0, bold,
+ select_font(library, priv, priv->family_default, 0, bold,
italic, index, code);
if (res)
ass_msg(library, MSGL_WARN, "fontconfig_select: Using default "
@@ -263,7 +335,7 @@ char *fontconfig_select(ASS_Library *lib
res, *index);
}
if (!res) {
- res = _select_font(library, priv, "Arial", 0, bold, italic,
+ res = select_font(library, priv, "Arial", 0, bold, italic,
index, code);
if (res)
ass_msg(library, MSGL_WARN, "fontconfig_select: Using 'Arial' "
@@ -283,8 +355,8 @@ char *fontconfig_select(ASS_Library *lib
* \param library library object
* \param ftlibrary freetype library object
* \param idx index of the processed font in library->fontdata
- * With FontConfig >= 2.4.2, builds a font pattern in memory via FT_New_Memory_Face/FcFreeTypeQueryFace.
- * With older FontConfig versions, save the font to ~/.mplayer/fonts.
+ *
+ * Builds a font pattern in memory via FT_New_Memory_Face/FcFreeTypeQueryFace.
*/
static void process_fontdata(FCInstance *priv, ASS_Library *library,
FT_Library ftlibrary, int idx)
@@ -311,7 +383,7 @@ static void process_fontdata(FCInstance
num_faces = face->num_faces;
pattern =
- FcFreeTypeQueryFace(face, (unsigned char *) name, 0,
+ FcFreeTypeQueryFace(face, (unsigned char *) name, face_index,
FcConfigGetBlanks(priv->config));
if (!pattern) {
ass_msg(library, MSGL_WARN, "%s failed", "FcFreeTypeQueryFace");
@@ -388,7 +460,7 @@ FCInstance *fontconfig_init(ASS_Library
process_fontdata(priv, library, ftlibrary, i);
if (dir) {
- ass_msg(library, MSGL_INFO, "Updating font cache");
+ ass_msg(library, MSGL_V, "Updating font cache");
rc = FcConfigAppFontAddDir(priv->config, (const FcChar8 *) dir);
if (!rc) {
Modified: trunk/libass/ass_parse.c
==============================================================================
--- trunk/libass/ass_parse.c Fri Aug 6 12:48:16 2010 (r31931)
+++ trunk/libass/ass_parse.c Fri Aug 6 23:13:41 2010 (r31932)
@@ -68,9 +68,15 @@ void update_font(ASS_Renderer *render_pr
{
unsigned val;
ASS_FontDesc desc;
- desc.family = strdup(render_priv->state.family);
- desc.treat_family_as_pattern =
- render_priv->state.treat_family_as_pattern;
+ desc.treat_family_as_pattern = render_priv->state.treat_family_as_pattern;
+
+ if (render_priv->state.family[0] == '@') {
+ desc.vertical = 1;
+ desc.family = strdup(render_priv->state.family + 1);
+ } else {
+ desc.vertical = 0;
+ desc.family = strdup(render_priv->state.family);
+ }
val = render_priv->state.bold;
// 0 = normal, 1 = bold, >1 = exact weight
@@ -210,6 +216,7 @@ static char *parse_vector_clip(ASS_Rende
int res = 0;
ASS_Drawing *drawing;
+ ass_drawing_free(render_priv->state.clip_drawing);
render_priv->state.clip_drawing = ass_drawing_new(
render_priv->fontconfig_priv,
render_priv->state.font,
@@ -227,20 +234,6 @@ static char *parse_vector_clip(ASS_Rende
while (*p != ')' && *p != '}' && p != 0)
ass_drawing_add_char(drawing, *p++);
skipopt(')');
- if (ass_drawing_parse(drawing, 1)) {
- // We need to translate the clip according to screen borders
- if (render_priv->settings.left_margin != 0 ||
- render_priv->settings.top_margin != 0) {
- FT_Vector trans = {
- .x = int_to_d6(render_priv->settings.left_margin),
- .y = -int_to_d6(render_priv->settings.top_margin),
- };
- FT_Outline_Translate(&drawing->glyph->outline, trans.x, trans.y);
- }
- ass_msg(render_priv->library, MSGL_DBG2,
- "Parsed vector clip: scale %d, scales (%f, %f) string [%s]\n",
- scale, drawing->scale_x, drawing->scale_y, drawing->text);
- }
return p;
}
@@ -586,7 +579,7 @@ static char *parse_tag(ASS_Renderer *ren
for (cnt = 0; cnt < 3; ++cnt) {
if (*p == '\\')
break;
- v[cnt] = strtod(p, &p);
+ mystrtod(&p, &v[cnt]);
skip(',');
}
if (cnt == 3) {
@@ -836,7 +829,7 @@ void apply_transition_effects(ASS_Render
} else if (strncmp(event->Effect, "Scroll down;", 12) == 0) {
render_priv->state.scroll_direction = SCROLL_TB;
} else {
- ass_msg(render_priv->library, MSGL_V,
+ ass_msg(render_priv->library, MSGL_DBG2,
"Unknown transition effect: '%s'", event->Effect);
return;
}
@@ -894,7 +887,7 @@ unsigned get_next_char(ASS_Renderer *ren
break;
} else if (*p != '\\')
ass_msg(render_priv->library, MSGL_V,
- "Unable to parse: '%s'", p);
+ "Unable to parse: '%.30s'", p);
if (*p == 0)
break;
}
@@ -918,6 +911,14 @@ unsigned get_next_char(ASS_Renderer *ren
p += 2;
*str = p;
return NBSP;
+ } else if (p[1] == '{') {
+ p += 2;
+ *str = p;
+ return '{';
+ } else if (p[1] == '}') {
+ p += 2;
+ *str = p;
+ return '}';
}
}
chr = ass_utf8_get_char((char **) &p);
Modified: trunk/libass/ass_render.c
==============================================================================
--- trunk/libass/ass_render.c Fri Aug 6 12:48:16 2010 (r31931)
+++ trunk/libass/ass_render.c Fri Aug 6 23:13:41 2010 (r31932)
@@ -22,30 +22,14 @@
#include <assert.h>
#include <math.h>
-#include <inttypes.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_STROKER_H
-#include FT_GLYPH_H
-#include FT_SYNTHESIS_H
-#include "ass.h"
-#include "ass_font.h"
-#include "ass_bitmap.h"
-#include "ass_cache.h"
-#include "ass_utils.h"
-#include "ass_fontconfig.h"
-#include "ass_library.h"
-#include "ass_drawing.h"
#include "ass_render.h"
#include "ass_parse.h"
#define MAX_GLYPHS_INITIAL 1024
#define MAX_LINES_INITIAL 64
#define SUBPIXEL_MASK 63
-#define SUBPIXEL_ACCURACY 7 // d6 mask for subpixel accuracy adjustment
-#define GLYPH_CACHE_MAX 1000
-#define BITMAP_CACHE_MAX_SIZE 50 * 1048576
+#define SUBPIXEL_ACCURACY 7
static void ass_lazy_track_init(ASS_Renderer *render_priv)
{
@@ -119,27 +103,20 @@ ASS_Renderer *ass_renderer_init(ASS_Libr
priv->text_info.max_glyphs = MAX_GLYPHS_INITIAL;
priv->text_info.max_lines = MAX_LINES_INITIAL;
- priv->text_info.glyphs =
- calloc(MAX_GLYPHS_INITIAL, sizeof(GlyphInfo));
+ priv->text_info.glyphs = calloc(MAX_GLYPHS_INITIAL, sizeof(GlyphInfo));
priv->text_info.lines = calloc(MAX_LINES_INITIAL, sizeof(LineInfo));
+ priv->settings.font_size_coeff = 1.;
+
ass_init_exit:
if (priv)
- ass_msg(library, MSGL_INFO, "Init");
+ ass_msg(library, MSGL_V, "Init");
else
ass_msg(library, MSGL_ERR, "Init failed");
return priv;
}
-void ass_set_cache_limits(ASS_Renderer *render_priv, int glyph_max,
- int bitmap_max)
-{
- render_priv->cache.glyph_max = glyph_max ? glyph_max : GLYPH_CACHE_MAX;
- render_priv->cache.bitmap_max_size = bitmap_max ? 1048576 * bitmap_max :
- BITMAP_CACHE_MAX_SIZE;
-}
-
static void free_list_clear(ASS_Renderer *render_priv)
{
if (render_priv->free_head) {
@@ -154,8 +131,6 @@ static void free_list_clear(ASS_Renderer
}
}
-static void ass_free_images(ASS_Image *img);
-
void ass_renderer_done(ASS_Renderer *render_priv)
{
ass_font_cache_done(render_priv->cache.font_cache);
@@ -196,21 +171,85 @@ static ASS_Image *my_draw_bitmap(unsigne
int bitmap_h, int stride, int dst_x,
int dst_y, uint32_t color)
{
- ASS_Image *img = calloc(1, sizeof(ASS_Image));
+ ASS_Image *img = malloc(sizeof(ASS_Image));
- img->w = bitmap_w;
- img->h = bitmap_h;
- img->stride = stride;
- img->bitmap = bitmap;
- img->color = color;
- img->dst_x = dst_x;
- img->dst_y = dst_y;
+ if (img) {
+ img->w = bitmap_w;
+ img->h = bitmap_h;
+ img->stride = stride;
+ img->bitmap = bitmap;
+ img->color = color;
+ img->dst_x = dst_x;
+ img->dst_y = dst_y;
+ }
return img;
}
-static double x2scr_pos(ASS_Renderer *render_priv, double x);
-static double y2scr_pos(ASS_Renderer *render_priv, double y);
+/**
+ * \brief Mapping between script and screen coordinates
+ */
+static double x2scr(ASS_Renderer *render_priv, double x)
+{
+ return x * render_priv->orig_width_nocrop / render_priv->font_scale_x /
+ render_priv->track->PlayResX +
+ FFMAX(render_priv->settings.left_margin, 0);
+}
+static double x2scr_pos(ASS_Renderer *render_priv, double x)
+{
+ return x * render_priv->orig_width / render_priv->font_scale_x / render_priv->track->PlayResX +
+ render_priv->settings.left_margin;
+}
+static double x2scr_scaled(ASS_Renderer *render_priv, double x)
+{
+ return x * render_priv->orig_width_nocrop /
+ render_priv->track->PlayResX +
+ FFMAX(render_priv->settings.left_margin, 0);
+}
+static double x2scr_pos_scaled(ASS_Renderer *render_priv, double x)
+{
+ return x * render_priv->orig_width / render_priv->track->PlayResX +
+ render_priv->settings.left_margin;
+}
+/**
+ * \brief Mapping between script and screen coordinates
+ */
+static double y2scr(ASS_Renderer *render_priv, double y)
+{
+ return y * render_priv->orig_height_nocrop /
+ render_priv->track->PlayResY +
+ FFMAX(render_priv->settings.top_margin, 0);
+}
+static double y2scr_pos(ASS_Renderer *render_priv, double y)
+{
+ return y * render_priv->orig_height / render_priv->track->PlayResY +
+ render_priv->settings.top_margin;
+}
+
+// the same for toptitles
+static double y2scr_top(ASS_Renderer *render_priv, double y)
+{
+ if (render_priv->settings.use_margins)
+ return y * render_priv->orig_height_nocrop /
+ render_priv->track->PlayResY;
+ else
+ return y * render_priv->orig_height_nocrop /
+ render_priv->track->PlayResY +
+ FFMAX(render_priv->settings.top_margin, 0);
+}
+// the same for subtitles
+static double y2scr_sub(ASS_Renderer *render_priv, double y)
+{
+ if (render_priv->settings.use_margins)
+ return y * render_priv->orig_height_nocrop /
+ render_priv->track->PlayResY +
+ FFMAX(render_priv->settings.top_margin, 0)
+ + FFMAX(render_priv->settings.bottom_margin, 0);
+ else
+ return y * render_priv->orig_height_nocrop /
+ render_priv->track->PlayResY +
+ FFMAX(render_priv->settings.top_margin, 0);
+}
/*
* \brief Convert bitmap glyphs into ASS_Image list with inverse clipping
@@ -238,9 +277,9 @@ static ASS_Image **render_glyph_i(ASS_Re
dst_y += bm->top;
// we still need to clip against screen boundaries
- zx = x2scr_pos(render_priv, 0);
+ zx = x2scr_pos_scaled(render_priv, 0);
zy = y2scr_pos(render_priv, 0);
- sx = x2scr_pos(render_priv, render_priv->track->PlayResX);
+ sx = x2scr_pos_scaled(render_priv, render_priv->track->PlayResX);
sy = y2scr_pos(render_priv, render_priv->track->PlayResY);
x0 = 0;
@@ -295,6 +334,7 @@ static ASS_Image **render_glyph_i(ASS_Re
img = my_draw_bitmap(bm->buffer + r[j].y0 * bm->w + r[j].x0,
lbrk - r[j].x0, r[j].y1 - r[j].y0,
bm->w, dst_x + r[j].x0, dst_y + r[j].y0, color);
+ if (!img) break;
*tail = img;
tail = &img->next;
}
@@ -303,6 +343,7 @@ static ASS_Image **render_glyph_i(ASS_Re
img = my_draw_bitmap(bm->buffer + r[j].y0 * bm->w + lbrk,
r[j].x1 - lbrk, r[j].y1 - r[j].y0,
bm->w, dst_x + lbrk, dst_y + r[j].y0, color2);
+ if (!img) break;
*tail = img;
tail = &img->next;
}
@@ -384,6 +425,7 @@ render_glyph(ASS_Renderer *render_priv,
img = my_draw_bitmap(bm->buffer + bm->w * b_y0 + b_x0,
brk - b_x0, b_y1 - b_y0, bm->w,
dst_x + b_x0, dst_y + b_y0, color);
+ if (!img) return tail;
*tail = img;
tail = &img->next;
}
@@ -393,6 +435,7 @@ render_glyph(ASS_Renderer *render_priv,
img = my_draw_bitmap(bm->buffer + bm->w * b_y0 + brk,
b_x1 - brk, b_y1 - b_y0, bm->w,
dst_x + brk, dst_y + b_y0, color2);
+ if (!img) return tail;
*tail = img;
tail = &img->next;
}
@@ -464,7 +507,6 @@ render_overlap(ASS_Renderer *render_priv
cur_top = top - by;
// Query cache
- memset(&hk, 0, sizeof(hk));
hk.a = (*last_tail)->bitmap;
hk.b = (*tail)->bitmap;
hk.aw = aw;
@@ -529,23 +571,73 @@ static void blend_vector_clip(ASS_Render
FT_BitmapGlyph clip_bm;
ASS_Image *cur;
ASS_Drawing *drawing = render_priv->state.clip_drawing;
+ GlyphHashKey key;
+ GlyphHashValue *val;
int error;
if (!drawing)
return;
- // Rasterize it
- FT_Glyph_Copy((FT_Glyph) drawing->glyph, &glyph);
- error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
- if (error) {
- ass_msg(render_priv->library, MSGL_V,
- "Clip vector rasterization failed: %d. Skipping.", error);
- goto blend_vector_exit;
+ // Try to get mask from cache
+ ass_drawing_hash(drawing);
+ memset(&key, 0, sizeof(key));
+ key.ch = -2;
+ key.drawing_hash = drawing->hash;
+ val = cache_find_glyph(render_priv->cache.glyph_cache, &key);
+
+ if (val) {
+ clip_bm = (FT_BitmapGlyph) val->glyph;
+ } else {
+ GlyphHashValue v;
+
+ // Not found in cache, parse and rasterize it
+ glyph = (FT_Glyph) *ass_drawing_parse(drawing, 1);
+ if (!glyph) {
+ ass_msg(render_priv->library, MSGL_WARN,
+ "Clip vector parsing failed. Skipping.");
+ goto blend_vector_error;
+ }
+
+ // We need to translate the clip according to screen borders
+ if (render_priv->settings.left_margin != 0 ||
+ render_priv->settings.top_margin != 0) {
+ FT_Vector trans = {
+ .x = int_to_d6(render_priv->settings.left_margin),
+ .y = -int_to_d6(render_priv->settings.top_margin),
+ };
+ FT_Outline_Translate(&drawing->glyph->outline,
+ trans.x, trans.y);
+ }
+
+ // Check glyph bounding box size
+ if (check_glyph_area(render_priv->library, glyph)) {
+ FT_Done_Glyph(glyph);
+ glyph = 0;
+ goto blend_vector_error;
+ }
+
+ ass_msg(render_priv->library, MSGL_DBG2,
+ "Parsed vector clip: scales (%f, %f) string [%s]\n",
+ drawing->scale_x, drawing->scale_y, drawing->text);
+
+ error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
+ if (error) {
+ ass_msg(render_priv->library, MSGL_WARN,
+ "Clip vector rasterization failed: %d. Skipping.", error);
+ FT_Done_Glyph(glyph);
+ glyph = 0;
+ }
+
+blend_vector_error:
+ clip_bm = (FT_BitmapGlyph) glyph;
+
+ // Add to cache
+ memset(&v, 0, sizeof(v));
+ v.glyph = glyph;
+ cache_add_glyph(render_priv->cache.glyph_cache, &key, &v);
}
- clip_bm = (FT_BitmapGlyph) glyph;
- clip_bm->top = -clip_bm->top;
- assert(clip_bm->bitmap.pitch >= 0);
+ if (!clip_bm) goto blend_vector_exit;
// Iterate through bitmaps and blend/clip them
for (cur = head; cur; cur = cur->next) {
@@ -563,7 +655,7 @@ static void blend_vector_clip(ASS_Render
ah = cur->h;
as = cur->stride;
bx = clip_bm->left;
- by = clip_bm->top;
+ by = -clip_bm->top;
bw = clip_bm->bitmap.width;
bh = clip_bm->bitmap.rows;
bs = clip_bm->bitmap.pitch;
@@ -589,6 +681,7 @@ static void blend_vector_clip(ASS_Render
// Allocate new buffer and add to free list
nbuffer = malloc(as * ah);
+ if (!nbuffer) goto blend_vector_exit;
free_list_add(render_priv, nbuffer);
// Blend together
@@ -609,6 +702,7 @@ static void blend_vector_clip(ASS_Render
// Allocate new buffer and add to free list
nbuffer = calloc(as, ah);
+ if (!nbuffer) goto blend_vector_exit;
free_list_add(render_priv, nbuffer);
// Blend together
@@ -622,8 +716,6 @@ static void blend_vector_clip(ASS_Render
cur->bitmap = nbuffer;
}
- // Free clip vector and its bitmap, we don't need it anymore
- FT_Done_Glyph(glyph);
blend_vector_exit:
ass_drawing_free(render_priv->state.clip_drawing);
render_priv->state.clip_drawing = 0;
@@ -633,8 +725,7 @@ blend_vector_exit:
* \brief Convert TextInfo struct to ASS_Image list
* Splits glyphs in halves when needed (for \kf karaoke).
*/
-static ASS_Image *render_text(ASS_Renderer *render_priv, int dst_x,
- int dst_y)
+static ASS_Image *render_text(ASS_Renderer *render_priv, int dst_x, int dst_y)
{
int pen_x, pen_y;
int i;
@@ -731,62 +822,6 @@ static ASS_Image *render_text(ASS_Render
return head;
}
-/**
- * \brief Mapping between script and screen coordinates
- */
-static double x2scr(ASS_Renderer *render_priv, double x)
-{
- return x * render_priv->orig_width_nocrop /
- render_priv->track->PlayResX +
- FFMAX(render_priv->settings.left_margin, 0);
-}
-static double x2scr_pos(ASS_Renderer *render_priv, double x)
-{
- return x * render_priv->orig_width / render_priv->track->PlayResX +
- render_priv->settings.left_margin;
-}
-
-/**
- * \brief Mapping between script and screen coordinates
- */
-static double y2scr(ASS_Renderer *render_priv, double y)
-{
- return y * render_priv->orig_height_nocrop /
- render_priv->track->PlayResY +
- FFMAX(render_priv->settings.top_margin, 0);
-}
-static double y2scr_pos(ASS_Renderer *render_priv, double y)
-{
- return y * render_priv->orig_height / render_priv->track->PlayResY +
- render_priv->settings.top_margin;
-}
-
-// the same for toptitles
-static double y2scr_top(ASS_Renderer *render_priv, double y)
-{
- if (render_priv->settings.use_margins)
- return y * render_priv->orig_height_nocrop /
- render_priv->track->PlayResY;
- else
- return y * render_priv->orig_height_nocrop /
- render_priv->track->PlayResY +
- FFMAX(render_priv->settings.top_margin, 0);
-}
-
-// the same for subtitles
-static double y2scr_sub(ASS_Renderer *render_priv, double y)
-{
- if (render_priv->settings.use_margins)
- return y * render_priv->orig_height_nocrop /
- render_priv->track->PlayResY +
- FFMAX(render_priv->settings.top_margin,
- 0) + FFMAX(render_priv->settings.bottom_margin, 0);
- else
- return y * render_priv->orig_height_nocrop /
- render_priv->track->PlayResY +
- FFMAX(render_priv->settings.top_margin, 0);
-}
-
static void compute_string_bbox(TextInfo *info, DBBox *bbox)
{
int i;
@@ -845,8 +880,6 @@ void reset_render_context(ASS_Renderer *
render_priv->state.frz = M_PI * render_priv->state.style->Angle / 180.;
render_priv->state.fax = render_priv->state.fay = 0.;
render_priv->state.wrap_style = render_priv->track->WrapStyle;
-
- // FIXME: does not reset unsupported attributes.
}
/**
@@ -878,11 +911,10 @@ init_render_context(ASS_Renderer *render
render_priv->state.effect_type = EF_NONE;
render_priv->state.effect_timing = 0;
render_priv->state.effect_skip_timing = 0;
- render_priv->state.drawing =
- ass_drawing_new(render_priv->fontconfig_priv,
- render_priv->state.font,
- render_priv->settings.hinting,
- render_priv->ftlibrary);
+ render_priv->state.drawing = ass_drawing_new(render_priv->fontconfig_priv,
+ render_priv->state.font,
+ render_priv->settings.hinting,
+ render_priv->ftlibrary);
apply_transition_effects(render_priv, event);
}
@@ -896,88 +928,6 @@ static void free_render_context(ASS_Rend
render_priv->state.drawing = NULL;
}
-// Calculate the cbox of a series of points
-static void
-get_contour_cbox(FT_BBox *box, FT_Vector *points, int start, int end)
-{
- box->xMin = box->yMin = INT_MAX;
- box->xMax = box->yMax = INT_MIN;
- int i;
-
- for (i = start; i < end; i++) {
- box->xMin = (points[i].x < box->xMin) ? points[i].x : box->xMin;
- box->xMax = (points[i].x > box->xMax) ? points[i].x : box->xMax;
- box->yMin = (points[i].y < box->yMin) ? points[i].y : box->yMin;
- box->yMax = (points[i].y > box->yMax) ? points[i].y : box->yMax;
- }
-}
-
-/**
- * \brief Fix-up stroker result for huge borders by removing the contours from
- * the outline that are harmful.
-*/
-static void fix_freetype_stroker(FT_OutlineGlyph glyph, int border_x,
- int border_y)
-{
- int nc = glyph->outline.n_contours;
- int begin, stop;
- char modified = 0;
- char *valid_cont;
- int start = 0;
- int end = -1;
- FT_BBox *boxes = calloc(nc, sizeof(FT_BBox));
- int i, j;
-
- // Create a list of cboxes of the contours
- for (i = 0; i < nc; i++) {
- start = end + 1;
- end = glyph->outline.contours[i];
- get_contour_cbox(&boxes[i], glyph->outline.points, start, end);
- }
-
- // if a) contour's cbox is contained in another contours cbox
- // b) contour's height or width is smaller than the border*2
- // the contour can be safely removed.
- valid_cont = calloc(1, nc);
- for (i = 0; i < nc; i++) {
- valid_cont[i] = 1;
- for (j = 0; j < nc; j++) {
- if (i == j)
- continue;
- if (boxes[i].xMin >= boxes[j].xMin &&
- boxes[i].xMax <= boxes[j].xMax &&
- boxes[i].yMin >= boxes[j].yMin &&
- boxes[i].yMax <= boxes[j].yMax) {
- int width = boxes[i].xMax - boxes[i].xMin;
- int height = boxes[i].yMax - boxes[i].yMin;
- if (width < border_x * 2 || height < border_y * 2) {
- valid_cont[i] = 0;
- modified = 1;
- break;
- }
- }
- }
- }
-
- // Zero-out contours that can be removed; much simpler than copying
- if (modified) {
- for (i = 0; i < nc; i++) {
- if (valid_cont[i])
- continue;
- begin = (i == 0) ? 0 : glyph->outline.contours[i - 1] + 1;
- stop = glyph->outline.contours[i];
- for (j = begin; j <= stop; j++) {
- glyph->outline.points[j].x = 0;
- glyph->outline.points[j].y = 0;
- glyph->outline.tags[j] = 0;
- }
- }
- }
-
- free(boxes);
- free(valid_cont);
-}
-
/*
* Replace the outline of a glyph by a contour which makes up a simple
* opaque rectangle.
@@ -989,8 +939,7 @@ static void draw_opaque_box(ASS_Renderer
int i;
int adv = d16_to_d6(glyph->advance.x);
double scale_y = render_priv->state.scale_y;
- double scale_x = render_priv->state.scale_x
- * render_priv->font_scale_x;
+ double scale_x = render_priv->state.scale_x;
FT_OutlineGlyph og = (FT_OutlineGlyph) glyph;
FT_Outline *ol;
@@ -1080,6 +1029,38 @@ static void stroke_outline_glyph(ASS_Ren
}
/**
+ * \brief Prepare glyph hash
+ */
+static void
+fill_glyph_hash(ASS_Renderer *priv, GlyphHashKey *key,
+ ASS_Drawing *drawing, uint32_t ch)
+{
+ if (drawing->hash) {
+ key->scale_x = double_to_d16(priv->state.scale_x);
+ key->scale_y = double_to_d16(priv->state.scale_y);
+ key->outline.x = priv->state.border_x * 0xFFFF;
+ key->outline.y = priv->state.border_y * 0xFFFF;
+ key->border_style = priv->state.style->BorderStyle;
+ key->drawing_hash = drawing->hash;
+ // not very clean, but works
+ key->size = drawing->scale;
+ key->ch = -1;
+ } else {
+ key->font = priv->state.font;
+ key->size = priv->state.font_size;
+ key->ch = ch;
+ key->bold = priv->state.bold;
+ key->italic = priv->state.italic;
+ key->scale_x = double_to_d16(priv->state.scale_x);
+ key->scale_y = double_to_d16(priv->state.scale_y);
+ key->outline.x = priv->state.border_x * 0xFFFF;
+ key->outline.y = priv->state.border_y * 0xFFFF;
+ key->flags = priv->state.flags;
+ key->border_style = priv->state.style->BorderStyle;
+ }
+}
+
+/**
* \brief Get normal and outline (border) glyphs
* \param symbol ucs4 char
* \param info out: struct filled with extracted data
@@ -1094,35 +1075,15 @@ get_outline_glyph(ASS_Renderer *render_p
{
GlyphHashValue *val;
GlyphHashKey key;
- memset(&key, 0, sizeof(key));
- if (drawing->hash) {
- key.scale_x = double_to_d16(render_priv->state.scale_x);
- key.scale_y = double_to_d16(render_priv->state.scale_y);
- key.outline.x = render_priv->state.border_x * 0xFFFF;
- key.outline.y = render_priv->state.border_y * 0xFFFF;
- key.border_style = render_priv->state.style->BorderStyle;
- key.drawing_hash = drawing->hash;
- } else {
- key.font = render_priv->state.font;
- key.size = render_priv->state.font_size;
- key.ch = symbol;
- key.bold = render_priv->state.bold;
- key.italic = render_priv->state.italic;
- key.scale_x = double_to_d16(render_priv->state.scale_x);
- key.scale_y = double_to_d16(render_priv->state.scale_y);
- key.outline.x = render_priv->state.border_x * 0xFFFF;
- key.outline.y = render_priv->state.border_y * 0xFFFF;
- key.flags = render_priv->state.flags;
- key.border_style = render_priv->state.style->BorderStyle;
- }
+ memset(&key, 0, sizeof(key));
memset(info, 0, sizeof(GlyphInfo));
+ fill_glyph_hash(render_priv, &key, drawing, symbol);
val = cache_find_glyph(render_priv->cache.glyph_cache, &key);
if (val) {
- FT_Glyph_Copy(val->glyph, &info->glyph);
- if (val->outline_glyph)
- FT_Glyph_Copy(val->outline_glyph, &info->outline_glyph);
+ info->glyph = val->glyph;
+ info->outline_glyph = val->outline_glyph;
info->bbox = val->bbox_scaled;
info->advance.x = val->advance.x;
info->advance.y = val->advance.y;
@@ -1135,7 +1096,7 @@ get_outline_glyph(ASS_Renderer *render_p
if (drawing->hash) {
if(!ass_drawing_parse(drawing, 0))
return;
- FT_Glyph_Copy((FT_Glyph) drawing->glyph, &info->glyph);
+ info->glyph = (FT_Glyph) drawing->glyph;
} else {
info->glyph =
ass_font_get_glyph(render_priv->fontconfig_priv,
@@ -1145,6 +1106,7 @@ get_outline_glyph(ASS_Renderer *render_p
}
if (!info->glyph)
return;
+
info->advance.x = d16_to_d6(info->glyph->advance.x);
info->advance.y = d16_to_d6(info->glyph->advance.y);
FT_Glyph_Get_CBox(info->glyph, FT_GLYPH_BBOX_SUBPIXELS, &info->bbox);
@@ -1158,8 +1120,9 @@ get_outline_glyph(ASS_Renderer *render_p
render_priv->border_scale),
double_to_d6(render_priv->state.border_y *
render_priv->border_scale));
- } else if (render_priv->state.border_x > 0 ||
- render_priv->state.border_y > 0) {
+ } else if ((render_priv->state.border_x > 0
+ || render_priv->state.border_y > 0)
+ && key.scale_x && key.scale_y) {
FT_Glyph_Copy(info->glyph, &info->outline_glyph);
stroke_outline_glyph(render_priv,
@@ -1171,9 +1134,8 @@ get_outline_glyph(ASS_Renderer *render_p
}
memset(&v, 0, sizeof(v));
- FT_Glyph_Copy(info->glyph, &v.glyph);
- if (info->outline_glyph)
- FT_Glyph_Copy(info->outline_glyph, &v.outline_glyph);
+ v.glyph = info->glyph;
+ v.outline_glyph = info->outline_glyph;
v.advance = info->advance;
v.bbox_scaled = info->bbox;
if (drawing->hash) {
@@ -1184,10 +1146,81 @@ get_outline_glyph(ASS_Renderer *render_p
}
}
-static void transform_3d(FT_Vector shift, FT_Glyph *glyph,
- FT_Glyph *glyph2, double frx, double fry,
- double frz, double fax, double fay, double scale,
- int yshift);
+/**
+ * \brief Apply transformation to outline points of a glyph
+ * Applies rotations given by frx, fry and frz and projects the points back
+ * onto the screen plane.
+ */
+static void
+transform_3d_points(FT_Vector shift, FT_Glyph glyph, double frx, double fry,
+ double frz, double fax, double fay, double scale,
+ int yshift)
+{
+ double sx = sin(frx);
+ double sy = sin(fry);
+ double sz = sin(frz);
+ double cx = cos(frx);
+ double cy = cos(fry);
+ double cz = cos(frz);
+ FT_Outline *outline = &((FT_OutlineGlyph) glyph)->outline;
+ FT_Vector *p = outline->points;
+ double x, y, z, xx, yy, zz;
+ int i, dist;
+
+ dist = 20000 * scale;
+ for (i = 0; i < outline->n_points; i++) {
+ x = (double) p[i].x + shift.x + (fax * (yshift - p[i].y));
+ y = (double) p[i].y + shift.y + (-fay * p[i].x);
+ z = 0.;
+
+ xx = x * cz + y * sz;
+ yy = -(x * sz - y * cz);
+ zz = z;
+
+ x = xx;
+ y = yy * cx + zz * sx;
+ z = yy * sx - zz * cx;
+
+ xx = x * cy + z * sy;
+ yy = y;
+ zz = x * sy - z * cy;
+
+ zz = FFMAX(zz, 1000 - dist);
+
+ x = (xx * dist) / (zz + dist);
+ y = (yy * dist) / (zz + dist);
+ p[i].x = x - shift.x + 0.5;
+ p[i].y = y - shift.y + 0.5;
+ }
+}
+
+/**
+ * \brief Apply 3d transformation to several objects
+ * \param shift FreeType vector
+ * \param glyph FreeType glyph
+ * \param glyph2 FreeType glyph
+ * \param frx x-axis rotation angle
+ * \param fry y-axis rotation angle
+ * \param frz z-axis rotation angle
+ * Rotates both glyphs by frx, fry and frz. Shift vector is added before rotation and subtracted after it.
+ */
+static void
+transform_3d(FT_Vector shift, FT_Glyph *glyph, FT_Glyph *glyph2,
+ double frx, double fry, double frz, double fax, double fay,
+ double scale, int yshift)
+{
+ frx = -frx;
+ frz = -frz;
+ if (frx != 0. || fry != 0. || frz != 0. || fax != 0. || fay != 0.) {
+ if (glyph && *glyph)
+ transform_3d_points(shift, *glyph, frx, fry, frz,
+ fax, fay, scale, yshift);
+
+ if (glyph2 && *glyph2)
+ transform_3d_points(shift, *glyph2, frx, fry, frz,
+ fax, fay, scale, yshift);
+ }
+}
/**
* \brief Get bitmaps for a glyph
@@ -1217,38 +1250,48 @@ get_bitmap_glyph(ASS_Renderer *render_pr
info->bm = info->bm_o = info->bm_s = 0;
if (info->glyph && info->symbol != '\n' && info->symbol != 0
&& !info->skip) {
+ FT_Glyph glyph;
+ FT_Glyph outline;
+ double scale_x = render_priv->font_scale_x;
+
+ FT_Glyph_Copy(info->glyph, &glyph);
+ FT_Glyph_Copy(info->outline_glyph, &outline);
// calculating rotation shift vector (from rotation origin to the glyph basepoint)
- shift.x = info->hash_key.shift_x;
- shift.y = info->hash_key.shift_y;
- fax_scaled = info->fax * render_priv->font_scale_x *
+ shift.x = key->shift_x;
+ shift.y = key->shift_y;
+ fax_scaled = info->fax *
render_priv->state.scale_x;
fay_scaled = info->fay * render_priv->state.scale_y;
// apply rotation
- transform_3d(shift, &info->glyph, &info->outline_glyph,
+ transform_3d(shift, &glyph, &outline,
info->frx, info->fry, info->frz, fax_scaled,
fay_scaled, render_priv->font_scale, info->asc);
- // subpixel shift
- if (info->glyph)
- FT_Outline_Translate(
- &((FT_OutlineGlyph) info->glyph)->outline,
- info->hash_key.advance.x,
- -info->hash_key.advance.y);
- if (info->outline_glyph)
- FT_Outline_Translate(
- &((FT_OutlineGlyph) info->outline_glyph)->outline,
- info->hash_key.advance.x,
- -info->hash_key.advance.y);
+ // PAR correction scaling
+ FT_Matrix m = { double_to_d16(scale_x), 0,
+ 0, double_to_d16(1.0) };
+ // subpixel shift
+ if (glyph) {
+ FT_Outline *outl = &((FT_OutlineGlyph) glyph)->outline;
+ if (scale_x != 1.0)
+ FT_Outline_Transform(outl, &m);
+ FT_Outline_Translate(outl, key->advance.x, -key->advance.y);
+ }
+ if (outline) {
+ FT_Outline *outl = &((FT_OutlineGlyph) outline)->outline;
+ if (scale_x != 1.0)
+ FT_Outline_Transform(outl, &m);
+ FT_Outline_Translate(outl, key->advance.x, -key->advance.y);
+ }
// render glyph
error = glyph_to_bitmap(render_priv->library,
render_priv->synth_priv,
- info->glyph, info->outline_glyph,
+ glyph, outline,
&info->bm, &info->bm_o,
&info->bm_s, info->be,
info->blur * render_priv->border_scale,
- info->hash_key.shadow_offset,
- info->hash_key.border_style);
+ key->shadow_offset, key->border_style);
if (error)
info->symbol = 0;
@@ -1256,15 +1299,12 @@ get_bitmap_glyph(ASS_Renderer *render_pr
hash_val.bm_o = info->bm_o;
hash_val.bm = info->bm;
hash_val.bm_s = info->bm_s;
- cache_add_bitmap(render_priv->cache.bitmap_cache,
- &(info->hash_key), &hash_val);
+ cache_add_bitmap(render_priv->cache.bitmap_cache, key, &hash_val);
+
+ FT_Done_Glyph(glyph);
+ FT_Done_Glyph(outline);
}
}
- // deallocate glyphs
- if (info->glyph)
- FT_Done_Glyph(info->glyph);
- if (info->outline_glyph)
- FT_Done_Glyph(info->outline_glyph);
}
/**
@@ -1377,7 +1417,7 @@ static void trim_whitespace(ASS_Renderer
* the difference in lengths between this two lines.
* The result may not be optimal, but usually is good enough.
*
- * FIXME: implement style 0 and 3 correctly, add support for style 1
+ * FIXME: implement style 0 and 3 correctly
*/
static void
wrap_lines_smart(ASS_Renderer *render_priv, double max_text_width)
@@ -1646,82 +1686,43 @@ static void get_base_point(DBBox *bbox,
}
/**
- * \brief Apply transformation to outline points of a glyph
- * Applies rotations given by frx, fry and frz and projects the points back
- * onto the screen plane.
- */
-static void
-transform_3d_points(FT_Vector shift, FT_Glyph glyph, double frx, double fry,
- double frz, double fax, double fay, double scale,
- int yshift)
-{
- double sx = sin(frx);
- double sy = sin(fry);
- double sz = sin(frz);
- double cx = cos(frx);
- double cy = cos(fry);
- double cz = cos(frz);
- FT_Outline *outline = &((FT_OutlineGlyph) glyph)->outline;
- FT_Vector *p = outline->points;
- double x, y, z, xx, yy, zz;
- int i, dist;
-
- dist = 20000 * scale;
- for (i = 0; i < outline->n_points; i++) {
- x = (double) p[i].x + shift.x + (fax * (yshift - p[i].y));
- y = (double) p[i].y + shift.y + (-fay * p[i].x);
- z = 0.;
-
- xx = x * cz + y * sz;
- yy = -(x * sz - y * cz);
- zz = z;
-
- x = xx;
- y = yy * cx + zz * sx;
- z = yy * sx - zz * cx;
-
- xx = x * cy + z * sy;
- yy = y;
- zz = x * sy - z * cy;
-
- zz = FFMAX(zz, 1000 - dist);
-
- x = (xx * dist) / (zz + dist);
- y = (yy * dist) / (zz + dist);
- p[i].x = x - shift.x + 0.5;
- p[i].y = y - shift.y + 0.5;
- }
-}
-
-/**
- * \brief Apply 3d transformation to several objects
- * \param shift FreeType vector
- * \param glyph FreeType glyph
- * \param glyph2 FreeType glyph
- * \param frx x-axis rotation angle
- * \param fry y-axis rotation angle
- * \param frz z-axis rotation angle
- * Rotates both glyphs by frx, fry and frz. Shift vector is added before rotation and subtracted after it.
+ * Prepare bitmap hash key of a glyph
*/
static void
-transform_3d(FT_Vector shift, FT_Glyph *glyph, FT_Glyph *glyph2,
- double frx, double fry, double frz, double fax, double fay,
- double scale, int yshift)
+fill_bitmap_hash(ASS_Renderer *priv, BitmapHashKey *hash_key,
+ ASS_Drawing *drawing, FT_Vector pen, uint32_t code)
{
- frx = -frx;
- frz = -frz;
- if (frx != 0. || fry != 0. || frz != 0. || fax != 0. || fay != 0.) {
- if (glyph && *glyph)
- transform_3d_points(shift, *glyph, frx, fry, frz,
- fax, fay, scale, yshift);
-
- if (glyph2 && *glyph2)
- transform_3d_points(shift, *glyph2, frx, fry, frz,
- fax, fay, scale, yshift);
+ if (!drawing->hash) {
+ hash_key->font = priv->state.font;
+ hash_key->size = priv->state.font_size;
+ hash_key->bold = priv->state.bold;
+ hash_key->italic = priv->state.italic;
+ } else {
+ hash_key->drawing_hash = drawing->hash;
+ hash_key->size = drawing->scale;
}
+ hash_key->ch = code;
+ hash_key->outline.x = double_to_d16(priv->state.border_x);
+ hash_key->outline.y = double_to_d16(priv->state.border_y);
+ hash_key->scale_x = double_to_d16(priv->state.scale_x);
+ hash_key->scale_y = double_to_d16(priv->state.scale_y);
+ hash_key->frx = rot_key(priv->state.frx);
+ hash_key->fry = rot_key(priv->state.fry);
+ hash_key->frz = rot_key(priv->state.frz);
+ hash_key->fax = double_to_d16(priv->state.fax);
+ hash_key->fay = double_to_d16(priv->state.fay);
+ hash_key->be = priv->state.be;
+ hash_key->blur = priv->state.blur;
+ hash_key->border_style = priv->state.style->BorderStyle;
+ hash_key->shadow_offset.x = double_to_d6(
+ priv->state.shadow_x * priv->border_scale -
+ (int) (priv->state.shadow_x * priv->border_scale));
+ hash_key->shadow_offset.y = double_to_d6(
+ priv->state.shadow_y * priv->border_scale -
+ (int) (priv->state.shadow_y * priv->border_scale));
+ hash_key->flags = priv->state.flags;
}
-
/**
* \brief Main ass rendering function, glues everything together
* \param event event to render
@@ -1746,6 +1747,7 @@ ass_render_event(ASS_Renderer *render_pr
double device_x = 0;
double device_y = 0;
TextInfo *text_info = &render_priv->text_info;
+ GlyphInfo *glyphs = render_priv->text_info.glyphs;
ASS_Drawing *drawing;
if (event->Style >= render_priv->track->n_styles) {
@@ -1779,7 +1781,6 @@ ass_render_event(ASS_Renderer *render_pr
// Parse drawing
if (drawing->i) {
drawing->scale_x = render_priv->state.scale_x *
- render_priv->font_scale_x *
render_priv->font_scale;
drawing->scale_y = render_priv->state.scale_y *
render_priv->font_scale;
@@ -1800,7 +1801,7 @@ ass_render_event(ASS_Renderer *render_pr
if (text_info->length >= text_info->max_glyphs) {
// Raise maximum number of glyphs
text_info->max_glyphs *= 2;
- text_info->glyphs =
+ text_info->glyphs = glyphs =
realloc(text_info->glyphs,
sizeof(GlyphInfo) * text_info->max_glyphs);
}
@@ -1811,139 +1812,82 @@ ass_render_event(ASS_Renderer *render_pr
delta =
ass_font_get_kerning(render_priv->state.font, previous,
code);
- pen.x += delta.x * render_priv->state.scale_x
- * render_priv->font_scale_x;
- pen.y += delta.y * render_priv->state.scale_y
- * render_priv->font_scale_x;
+ pen.x += delta.x * render_priv->state.scale_x;
+ pen.y += delta.y * render_priv->state.scale_y;
}
ass_font_set_transform(render_priv->state.font,
- render_priv->state.scale_x *
- render_priv->font_scale_x,
+ render_priv->state.scale_x,
render_priv->state.scale_y, NULL);
get_outline_glyph(render_priv, code,
- text_info->glyphs + text_info->length, drawing);
+ glyphs + text_info->length, drawing);
// Add additional space after italic to non-italic style changes
if (text_info->length &&
- text_info->glyphs[text_info->length - 1].hash_key.italic &&
+ glyphs[text_info->length - 1].hash_key.italic &&
!render_priv->state.italic) {
int back = text_info->length - 1;
- GlyphInfo *og = &text_info->glyphs[back];
+ GlyphInfo *og = &glyphs[back];
while (back && og->bbox.xMax - og->bbox.xMin == 0
&& og->hash_key.italic)
- og = &text_info->glyphs[--back];
+ og = &glyphs[--back];
if (og->bbox.xMax > og->advance.x) {
// The FreeType oblique slants by 6/16
pen.x += og->bbox.yMax * 0.375;
}
}
- text_info->glyphs[text_info->length].pos.x = pen.x;
- text_info->glyphs[text_info->length].pos.y = pen.y;
+ glyphs[text_info->length].pos.x = pen.x;
+ glyphs[text_info->length].pos.y = pen.y;
- pen.x += text_info->glyphs[text_info->length].advance.x;
+ pen.x += glyphs[text_info->length].advance.x;
pen.x += double_to_d6(render_priv->state.hspacing *
render_priv->font_scale
* render_priv->state.scale_x);
- pen.y += text_info->glyphs[text_info->length].advance.y;
+ pen.y += glyphs[text_info->length].advance.y;
pen.y += (render_priv->state.fay * render_priv->state.scale_y) *
- text_info->glyphs[text_info->length].advance.x;
+ glyphs[text_info->length].advance.x;
previous = code;
- text_info->glyphs[text_info->length].symbol = code;
- text_info->glyphs[text_info->length].linebreak = 0;
+ glyphs[text_info->length].symbol = code;
+ glyphs[text_info->length].linebreak = 0;
for (i = 0; i < 4; ++i) {
uint32_t clr = render_priv->state.c[i];
change_alpha(&clr,
mult_alpha(_a(clr), render_priv->state.fade), 1.);
- text_info->glyphs[text_info->length].c[i] = clr;
+ glyphs[text_info->length].c[i] = clr;
}
- text_info->glyphs[text_info->length].effect_type =
- render_priv->state.effect_type;
- text_info->glyphs[text_info->length].effect_timing =
+ glyphs[text_info->length].effect_type = render_priv->state.effect_type;
+ glyphs[text_info->length].effect_timing =
render_priv->state.effect_timing;
- text_info->glyphs[text_info->length].effect_skip_timing =
+ glyphs[text_info->length].effect_skip_timing =
render_priv->state.effect_skip_timing;
- text_info->glyphs[text_info->length].be = render_priv->state.be;
- text_info->glyphs[text_info->length].blur = render_priv->state.blur;
- text_info->glyphs[text_info->length].shadow_x =
- render_priv->state.shadow_x;
- text_info->glyphs[text_info->length].shadow_y =
- render_priv->state.shadow_y;
- text_info->glyphs[text_info->length].frx = render_priv->state.frx;
- text_info->glyphs[text_info->length].fry = render_priv->state.fry;
- text_info->glyphs[text_info->length].frz = render_priv->state.frz;
- text_info->glyphs[text_info->length].fax = render_priv->state.fax;
- text_info->glyphs[text_info->length].fay = render_priv->state.fay;
+ glyphs[text_info->length].be = render_priv->state.be;
+ glyphs[text_info->length].blur = render_priv->state.blur;
+ glyphs[text_info->length].shadow_x = render_priv->state.shadow_x;
+ glyphs[text_info->length].shadow_y = render_priv->state.shadow_y;
+ glyphs[text_info->length].frx = render_priv->state.frx;
+ glyphs[text_info->length].fry = render_priv->state.fry;
+ glyphs[text_info->length].frz = render_priv->state.frz;
+ glyphs[text_info->length].fax = render_priv->state.fax;
+ glyphs[text_info->length].fay = render_priv->state.fay;
if (drawing->hash) {
- text_info->glyphs[text_info->length].asc = drawing->asc;
- text_info->glyphs[text_info->length].desc = drawing->desc;
+ glyphs[text_info->length].asc = drawing->asc;
+ glyphs[text_info->length].desc = drawing->desc;
} else {
ass_font_get_asc_desc(render_priv->state.font, code,
- &text_info->glyphs[text_info->length].asc,
- &text_info->glyphs[text_info->length].desc);
+ &glyphs[text_info->length].asc,
+ &glyphs[text_info->length].desc);
- text_info->glyphs[text_info->length].asc *=
- render_priv->state.scale_y;
- text_info->glyphs[text_info->length].desc *=
- render_priv->state.scale_y;
+ glyphs[text_info->length].asc *= render_priv->state.scale_y;
+ glyphs[text_info->length].desc *= render_priv->state.scale_y;
}
- // fill bitmap_hash_key
- if (!drawing->hash) {
- text_info->glyphs[text_info->length].hash_key.font =
- render_priv->state.font;
- text_info->glyphs[text_info->length].hash_key.size =
- render_priv->state.font_size;
- text_info->glyphs[text_info->length].hash_key.bold =
- render_priv->state.bold;
- text_info->glyphs[text_info->length].hash_key.italic =
- render_priv->state.italic;
- } else
- text_info->glyphs[text_info->length].hash_key.drawing_hash =
- drawing->hash;
- text_info->glyphs[text_info->length].hash_key.ch = code;
- text_info->glyphs[text_info->length].hash_key.outline.x =
- double_to_d16(render_priv->state.border_x);
- text_info->glyphs[text_info->length].hash_key.outline.y =
- double_to_d16(render_priv->state.border_y);
- text_info->glyphs[text_info->length].hash_key.scale_x =
- double_to_d16(render_priv->state.scale_x);
- text_info->glyphs[text_info->length].hash_key.scale_y =
- double_to_d16(render_priv->state.scale_y);
- text_info->glyphs[text_info->length].hash_key.frx =
- rot_key(render_priv->state.frx);
- text_info->glyphs[text_info->length].hash_key.fry =
- rot_key(render_priv->state.fry);
- text_info->glyphs[text_info->length].hash_key.frz =
- rot_key(render_priv->state.frz);
- text_info->glyphs[text_info->length].hash_key.fax =
- double_to_d16(render_priv->state.fax);
- text_info->glyphs[text_info->length].hash_key.fay =
- double_to_d16(render_priv->state.fay);
- text_info->glyphs[text_info->length].hash_key.advance.x = pen.x;
- text_info->glyphs[text_info->length].hash_key.advance.y = pen.y;
- text_info->glyphs[text_info->length].hash_key.be =
- render_priv->state.be;
- text_info->glyphs[text_info->length].hash_key.blur =
- render_priv->state.blur;
- text_info->glyphs[text_info->length].hash_key.border_style =
- render_priv->state.style->BorderStyle;
- text_info->glyphs[text_info->length].hash_key.shadow_offset.x =
- double_to_d6(
- render_priv->state.shadow_x * render_priv->border_scale -
- (int) (render_priv->state.shadow_x *
- render_priv->border_scale));
- text_info->glyphs[text_info->length].hash_key.shadow_offset.y =
- double_to_d6(
- render_priv->state.shadow_y * render_priv->border_scale -
- (int) (render_priv->state.shadow_y *
- render_priv->border_scale));
- text_info->glyphs[text_info->length].hash_key.flags =
- render_priv->state.flags;
+ // fill bitmap hash
+ fill_bitmap_hash(render_priv, &glyphs[text_info->length].hash_key,
+ drawing, pen, code);
text_info->length++;
@@ -1967,6 +1911,7 @@ ass_render_event(ASS_Renderer *render_pr
free_render_context(render_priv);
return 1;
}
+
// depends on glyph x coordinates being monotonous, so it should be done before line wrap
process_karaoke_effects(render_priv);
@@ -1976,14 +1921,11 @@ ass_render_event(ASS_Renderer *render_pr
valign = alignment & 12;
MarginL =
- (event->MarginL) ? event->MarginL : render_priv->state.style->
- MarginL;
+ (event->MarginL) ? event->MarginL : render_priv->state.style->MarginL;
MarginR =
- (event->MarginR) ? event->MarginR : render_priv->state.style->
- MarginR;
+ (event->MarginR) ? event->MarginR : render_priv->state.style->MarginR;
MarginV =
- (event->MarginV) ? event->MarginV : render_priv->state.style->
- MarginV;
+ (event->MarginV) ? event->MarginV : render_priv->state.style->MarginV;
if (render_priv->state.evt_type != EVENT_HSCROLL) {
double max_text_width;
@@ -2001,11 +1943,11 @@ ass_render_event(ASS_Renderer *render_pr
last_break = -1;
for (i = 1; i < text_info->length + 1; ++i) { // (text_info->length + 1) is the end of the last line
if ((i == text_info->length)
- || text_info->glyphs[i].linebreak) {
+ || glyphs[i].linebreak) {
double width, shift = 0;
GlyphInfo *first_glyph =
- text_info->glyphs + last_break + 1;
- GlyphInfo *last_glyph = text_info->glyphs + i - 1;
+ glyphs + last_break + 1;
+ GlyphInfo *last_glyph = glyphs + i - 1;
while (first_glyph < last_glyph && first_glyph->skip)
first_glyph++;
@@ -2027,7 +1969,7 @@ ass_render_event(ASS_Renderer *render_pr
shift = (max_text_width - width) / 2.0;
}
for (j = last_break + 1; j < i; ++j) {
- text_info->glyphs[j].pos.x += double_to_d6(shift);
+ glyphs[j].pos.x += double_to_d6(shift);
}
last_break = i - 1;
}
@@ -2057,6 +1999,7 @@ ass_render_event(ASS_Renderer *render_pr
render_priv->state.scroll_shift) - (bbox.xMax -
bbox.xMin);
}
+
// y coordinate for everything except positioned events
if (render_priv->state.evt_type == EVENT_NORMAL ||
render_priv->state.evt_type == EVENT_HSCROLL) {
@@ -2072,7 +2015,7 @@ ass_render_event(ASS_Renderer *render_pr
double scr_y;
if (valign != VALIGN_SUB)
ass_msg(render_priv->library, MSGL_V,
- "Invalid valign, supposing 0 (subtitle)");
+ "Invalid valign, assuming 0 (subtitle)");
scr_y =
y2scr_sub(render_priv,
render_priv->track->PlayResY - MarginV);
@@ -2093,6 +2036,7 @@ ass_render_event(ASS_Renderer *render_pr
render_priv->state.clip_y1 -
render_priv->state.scroll_shift);
}
+
// positioned events are totally different
if (render_priv->state.evt_type == EVENT_POSITIONED) {
double base_x = 0;
@@ -2105,14 +2049,15 @@ ass_render_event(ASS_Renderer *render_pr
device_y =
y2scr_pos(render_priv, render_priv->state.pos_y) - base_y;
}
+
// fix clip coordinates (they depend on alignment)
if (render_priv->state.evt_type == EVENT_NORMAL ||
render_priv->state.evt_type == EVENT_HSCROLL ||
render_priv->state.evt_type == EVENT_VSCROLL) {
render_priv->state.clip_x0 =
- x2scr(render_priv, render_priv->state.clip_x0);
+ x2scr_scaled(render_priv, render_priv->state.clip_x0);
render_priv->state.clip_x1 =
- x2scr(render_priv, render_priv->state.clip_x1);
+ x2scr_scaled(render_priv, render_priv->state.clip_x1);
if (valign == VALIGN_TOP) {
render_priv->state.clip_y0 =
y2scr_top(render_priv, render_priv->state.clip_y0);
@@ -2131,14 +2076,15 @@ ass_render_event(ASS_Renderer *render_pr
}
} else if (render_priv->state.evt_type == EVENT_POSITIONED) {
render_priv->state.clip_x0 =
- x2scr_pos(render_priv, render_priv->state.clip_x0);
+ x2scr_pos_scaled(render_priv, render_priv->state.clip_x0);
render_priv->state.clip_x1 =
- x2scr_pos(render_priv, render_priv->state.clip_x1);
+ x2scr_pos_scaled(render_priv, render_priv->state.clip_x1);
render_priv->state.clip_y0 =
y2scr_pos(render_priv, render_priv->state.clip_y0);
render_priv->state.clip_y1 =
y2scr_pos(render_priv, render_priv->state.clip_y1);
}
+
// calculate rotation parameters
{
DVector center;
@@ -2154,7 +2100,7 @@ ass_render_event(ASS_Renderer *render_pr
}
for (i = 0; i < text_info->length; ++i) {
- GlyphInfo *info = text_info->glyphs + i;
+ GlyphInfo *info = glyphs + i;
if (info->hash_key.frx || info->hash_key.fry
|| info->hash_key.frz || info->hash_key.fax
@@ -2170,22 +2116,26 @@ ass_render_event(ASS_Renderer *render_pr
}
// convert glyphs to bitmaps
+ device_x *= render_priv->font_scale_x;
for (i = 0; i < text_info->length; ++i) {
- GlyphInfo *g = text_info->glyphs + i;
+ GlyphInfo *g = glyphs + i;
+ g->pos.x *= render_priv->font_scale_x;
g->hash_key.advance.x =
double_to_d6(device_x - (int) device_x +
d6_to_double(g->pos.x & SUBPIXEL_MASK)) & ~SUBPIXEL_ACCURACY;
g->hash_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, text_info->glyphs + i);
+ get_bitmap_glyph(render_priv, glyphs + i);
}
memset(event_images, 0, sizeof(*event_images));
event_images->top = device_y - text_info->lines[0].asc;
event_images->height = text_info->height;
- event_images->left = device_x + bbox.xMin + 0.5;
- event_images->width = bbox.xMax - bbox.xMin + 0.5;
+ event_images->left =
+ (device_x + bbox.xMin * render_priv->font_scale_x) + 0.5;
+ event_images->width =
+ (bbox.xMax - bbox.xMin) * render_priv->font_scale_x + 0.5;
event_images->detect_collisions = render_priv->state.detect_collisions;
event_images->shift_direction = (valign == VALIGN_TOP) ? 1 : -1;
event_images->event = event;
@@ -2200,7 +2150,7 @@ ass_render_event(ASS_Renderer *render_pr
* \brief deallocate image list
* \param img list pointer
*/
-static void ass_free_images(ASS_Image *img)
+void ass_free_images(ASS_Image *img)
{
while (img) {
ASS_Image *next = img->next;
@@ -2209,103 +2159,32 @@ static void ass_free_images(ASS_Image *i
}
}
-static void ass_reconfigure(ASS_Renderer *priv)
-{
- priv->render_id++;
- priv->cache.glyph_cache =
- ass_glyph_cache_reset(priv->cache.glyph_cache);
- priv->cache.bitmap_cache =
- ass_bitmap_cache_reset(priv->cache.bitmap_cache);
- priv->cache.composite_cache =
- ass_composite_cache_reset(priv->cache.composite_cache);
- ass_free_images(priv->prev_images_root);
- priv->prev_images_root = 0;
-}
-
-void ass_set_frame_size(ASS_Renderer *priv, int w, int h)
-{
- if (priv->settings.frame_width != w || priv->settings.frame_height != h) {
- priv->settings.frame_width = w;
- priv->settings.frame_height = h;
- if (priv->settings.aspect == 0.) {
- priv->settings.aspect = ((double) w) / h;
- priv->settings.storage_aspect = ((double) w) / h;
- }
- ass_reconfigure(priv);
- }
-}
-
-void ass_set_margins(ASS_Renderer *priv, int t, int b, int l, int r)
-{
- if (priv->settings.left_margin != l ||
- priv->settings.right_margin != r ||
- priv->settings.top_margin != t
- || priv->settings.bottom_margin != b) {
- priv->settings.left_margin = l;
- priv->settings.right_margin = r;
- priv->settings.top_margin = t;
- priv->settings.bottom_margin = b;
- ass_reconfigure(priv);
- }
-}
-
-void ass_set_use_margins(ASS_Renderer *priv, int use)
-{
- priv->settings.use_margins = use;
-}
-
-void ass_set_aspect_ratio(ASS_Renderer *priv, double dar, double sar)
-{
- if (priv->settings.aspect != dar || priv->settings.storage_aspect != sar) {
- priv->settings.aspect = dar;
- priv->settings.storage_aspect = sar;
- ass_reconfigure(priv);
- }
-}
-
-void ass_set_font_scale(ASS_Renderer *priv, double font_scale)
+/**
+ * \brief Check cache limits and reset cache if they are exceeded
+ */
+static void check_cache_limits(ASS_Renderer *priv, CacheStore *cache)
{
- if (priv->settings.font_size_coeff != font_scale) {
- priv->settings.font_size_coeff = font_scale;
- ass_reconfigure(priv);
+ if (cache->bitmap_cache->cache_size > cache->bitmap_max_size) {
+ ass_msg(priv->library, MSGL_V,
+ "Hitting hard bitmap cache limit (was: %ld bytes), "
+ "resetting.", (long) cache->bitmap_cache->cache_size);
+ cache->bitmap_cache = ass_bitmap_cache_reset(cache->bitmap_cache);
+ cache->composite_cache = ass_composite_cache_reset(
+ cache->composite_cache);
+ ass_free_images(priv->prev_images_root);
+ priv->prev_images_root = 0;
}
-}
-void ass_set_hinting(ASS_Renderer *priv, ASS_Hinting ht)
-{
- if (priv->settings.hinting != ht) {
- priv->settings.hinting = ht;
- ass_reconfigure(priv);
+ if (cache->glyph_cache->count > cache->glyph_max
+ || cache->glyph_cache->cache_size > cache->bitmap_max_size) {
+ ass_msg(priv->library, MSGL_V,
+ "Hitting hard glyph cache limit (was: %d glyphs, %ld bytes), "
+ "resetting.",
+ cache->glyph_cache->count, (long) cache->glyph_cache->cache_size);
+ cache->glyph_cache = ass_glyph_cache_reset(cache->glyph_cache);
}
}
-void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing)
-{
- priv->settings.line_spacing = line_spacing;
-}
-
-void ass_set_fonts(ASS_Renderer *priv, const char *default_font,
- const char *default_family, int fc, const char *config,
- int update)
-{
- free(priv->settings.default_font);
- free(priv->settings.default_family);
- priv->settings.default_font = default_font ? strdup(default_font) : 0;
- priv->settings.default_family =
- default_family ? strdup(default_family) : 0;
-
- if (priv->fontconfig_priv)
- fontconfig_done(priv->fontconfig_priv);
- priv->fontconfig_priv =
- fontconfig_init(priv->library, priv->ftlibrary, default_family,
- default_font, fc, config, update);
-}
-
-int ass_fonts_update(ASS_Renderer *render_priv)
-{
- return fontconfig_update(render_priv->fontconfig_priv);
-}
-
/**
* \brief Start a new frame
*/
@@ -2314,7 +2193,6 @@ ass_start_frame(ASS_Renderer *render_pri
long long now)
{
ASS_Settings *settings_priv = &render_priv->settings;
- CacheStore *cache = &render_priv->cache;
if (!render_priv->settings.frame_width
&& !render_priv->settings.frame_height)
@@ -2323,27 +2201,14 @@ ass_start_frame(ASS_Renderer *render_pri
if (render_priv->library != track->library)
return 1;
+ if (!render_priv->fontconfig_priv)
+ return 1;
+
free_list_clear(render_priv);
if (track->n_events == 0)
return 1; // nothing to do
- render_priv->width = settings_priv->frame_width;
- render_priv->height = settings_priv->frame_height;
- render_priv->orig_width =
- settings_priv->frame_width - settings_priv->left_margin -
- settings_priv->right_margin;
- render_priv->orig_height =
- settings_priv->frame_height - settings_priv->top_margin -
- settings_priv->bottom_margin;
- render_priv->orig_width_nocrop =
- settings_priv->frame_width - FFMAX(settings_priv->left_margin,
- 0) -
- FFMAX(settings_priv->right_margin, 0);
- render_priv->orig_height_nocrop =
- settings_priv->frame_height - FFMAX(settings_priv->top_margin,
- 0) -
- FFMAX(settings_priv->bottom_margin, 0);
render_priv->track = track;
render_priv->time = now;
@@ -2365,23 +2230,7 @@ ass_start_frame(ASS_Renderer *render_pri
render_priv->prev_images_root = render_priv->images_root;
render_priv->images_root = 0;
- if (cache->bitmap_cache->cache_size > cache->bitmap_max_size) {
- ass_msg(render_priv->library, MSGL_V,
- "Hitting hard bitmap cache limit (was: %ld bytes), "
- "resetting.", (long) cache->bitmap_cache->cache_size);
- cache->bitmap_cache = ass_bitmap_cache_reset(cache->bitmap_cache);
- cache->composite_cache = ass_composite_cache_reset(
- cache->composite_cache);
- ass_free_images(render_priv->prev_images_root);
- render_priv->prev_images_root = 0;
- }
-
- if (cache->glyph_cache->count > cache->glyph_max) {
- ass_msg(render_priv->library, MSGL_V,
- "Hitting hard glyph cache limit (was: %ld glyphs), resetting.",
- (long) cache->glyph_cache->count);
- cache->glyph_cache = ass_glyph_cache_reset(cache->glyph_cache);
- }
+ check_cache_limits(render_priv, &render_priv->cache);
return 0;
}
@@ -2505,7 +2354,7 @@ fix_collisions(ASS_Renderer *render_priv
s.hb = priv->left + priv->width;
if (priv->height != imgs[i].height) { // no, it's not
ass_msg(render_priv->library, MSGL_WARN,
- "Warning! Event height has changed");
+ "Event height has changed");
priv->top = 0;
priv->height = 0;
priv->left = 0;
Modified: trunk/libass/ass_render.h
==============================================================================
--- trunk/libass/ass_render.h Fri Aug 6 12:48:16 2010 (r31931)
+++ trunk/libass/ass_render.h Fri Aug 6 23:13:41 2010 (r31932)
@@ -38,6 +38,9 @@
#include "ass_library.h"
#include "ass_drawing.h"
+#define GLYPH_CACHE_MAX 1000
+#define BITMAP_CACHE_MAX_SIZE 30 * 1048576
+
typedef struct {
double xMin;
double xMax;
@@ -258,5 +261,6 @@ typedef struct {
} Segment;
void reset_render_context(ASS_Renderer *render_priv);
+void ass_free_images(ASS_Image *img);
#endif /* LIBASS_RENDER_H */
Added: trunk/libass/ass_render_api.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/libass/ass_render_api.c Fri Aug 6 23:13:41 2010 (r31932)
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov at gmail.com>
+ * Copyright (C) 2010 Grigori Goronzy <greg at geekmind.org>
+ *
+ * This file is part of libass.
+ *
+ * libass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with libass; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "ass_render.h"
+
+static void ass_reconfigure(ASS_Renderer *priv)
+{
+ ASS_Settings *settings = &priv->settings;
+
+ priv->render_id++;
+ priv->cache.glyph_cache =
+ ass_glyph_cache_reset(priv->cache.glyph_cache);
+ priv->cache.bitmap_cache =
+ ass_bitmap_cache_reset(priv->cache.bitmap_cache);
+ priv->cache.composite_cache =
+ ass_composite_cache_reset(priv->cache.composite_cache);
+ ass_free_images(priv->prev_images_root);
+ priv->prev_images_root = 0;
+
+ priv->width = settings->frame_width;
+ priv->height = settings->frame_height;
+ priv->orig_width = settings->frame_width - settings->left_margin -
+ settings->right_margin;
+ priv->orig_height = settings->frame_height - settings->top_margin -
+ settings->bottom_margin;
+ priv->orig_width_nocrop =
+ settings->frame_width - FFMAX(settings->left_margin, 0) -
+ FFMAX(settings->right_margin, 0);
+ priv->orig_height_nocrop =
+ settings->frame_height - FFMAX(settings->top_margin, 0) -
+ FFMAX(settings->bottom_margin, 0);
+}
+
+void ass_set_frame_size(ASS_Renderer *priv, int w, int h)
+{
+ if (priv->settings.frame_width != w || priv->settings.frame_height != h) {
+ priv->settings.frame_width = w;
+ priv->settings.frame_height = h;
+ if (priv->settings.aspect == 0.) {
+ priv->settings.aspect = ((double) w) / h;
+ priv->settings.storage_aspect = ((double) w) / h;
+ }
+ ass_reconfigure(priv);
+ }
+}
+
+void ass_set_margins(ASS_Renderer *priv, int t, int b, int l, int r)
+{
+ if (priv->settings.left_margin != l || priv->settings.right_margin != r ||
+ priv->settings.top_margin != t || priv->settings.bottom_margin != b) {
+ priv->settings.left_margin = l;
+ priv->settings.right_margin = r;
+ priv->settings.top_margin = t;
+ priv->settings.bottom_margin = b;
+ ass_reconfigure(priv);
+ }
+}
+
+void ass_set_use_margins(ASS_Renderer *priv, int use)
+{
+ priv->settings.use_margins = use;
+}
+
+void ass_set_aspect_ratio(ASS_Renderer *priv, double dar, double sar)
+{
+ if (priv->settings.aspect != dar || priv->settings.storage_aspect != sar) {
+ priv->settings.aspect = dar;
+ priv->settings.storage_aspect = sar;
+ ass_reconfigure(priv);
+ }
+}
+
+void ass_set_font_scale(ASS_Renderer *priv, double font_scale)
+{
+ if (priv->settings.font_size_coeff != font_scale) {
+ priv->settings.font_size_coeff = font_scale;
+ ass_reconfigure(priv);
+ }
+}
+
+void ass_set_hinting(ASS_Renderer *priv, ASS_Hinting ht)
+{
+ if (priv->settings.hinting != ht) {
+ priv->settings.hinting = ht;
+ ass_reconfigure(priv);
+ }
+}
+
+void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing)
+{
+ priv->settings.line_spacing = line_spacing;
+}
+
+void ass_set_fonts(ASS_Renderer *priv, const char *default_font,
+ const char *default_family, int fc, const char *config,
+ int update)
+{
+ free(priv->settings.default_font);
+ free(priv->settings.default_family);
+ priv->settings.default_font = default_font ? strdup(default_font) : 0;
+ priv->settings.default_family =
+ default_family ? strdup(default_family) : 0;
+
+ if (priv->fontconfig_priv)
+ fontconfig_done(priv->fontconfig_priv);
+ priv->fontconfig_priv =
+ fontconfig_init(priv->library, priv->ftlibrary, default_family,
+ default_font, fc, config, update);
+}
+
+int ass_fonts_update(ASS_Renderer *render_priv)
+{
+ return fontconfig_update(render_priv->fontconfig_priv);
+}
+
+void ass_set_cache_limits(ASS_Renderer *render_priv, int glyph_max,
+ int bitmap_max)
+{
+ render_priv->cache.glyph_max = glyph_max ? glyph_max : GLYPH_CACHE_MAX;
+ render_priv->cache.bitmap_max_size = bitmap_max ? 1048576 * bitmap_max :
+ BITMAP_CACHE_MAX_SIZE;
+}
Modified: trunk/libass/ass_strtod.c
==============================================================================
--- trunk/libass/ass_strtod.c Fri Aug 6 12:48:16 2010 (r31931)
+++ trunk/libass/ass_strtod.c Fri Aug 6 23:13:41 2010 (r31932)
@@ -16,12 +16,14 @@
#include <ctype.h>
#include <errno.h>
+const
static int maxExponent = 511; /* Largest possible base 10 exponent. Any
* exponent larger than this will already
* produce underflow or overflow, so there's
* no need to worry about additional digits.
*/
+const
static double powersOf10[] = { /* Table giving binary powers of 10. Entry */
10., /* is 10^2^i. Used to convert decimal */
100., /* exponents into floating-point numbers. */
@@ -224,7 +226,7 @@ ass_strtod(string, endPtr)
errno = ERANGE;
}
dblExp = 1.0;
- for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
+ for (d = (double *) powersOf10; exp != 0; exp >>= 1, d += 1) {
if (exp & 01) {
dblExp *= *d;
}
More information about the MPlayer-cvslog
mailing list