Updated libass to the "latest" standalone version (from almost a year ago...), + h4x for it to build on MSVC

Originally committed to SVN as r1751.
This commit is contained in:
Rodrigo Braz Monteiro 2008-01-17 16:50:19 +00:00
parent f4c2ffac54
commit 44da8de898
16 changed files with 1146 additions and 376 deletions

View File

@ -27,7 +27,7 @@
#include <errno.h> #include <errno.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> //#include <unistd.h>
#include <inttypes.h> #include <inttypes.h>
#ifdef USE_ICONV #ifdef USE_ICONV
@ -347,7 +347,7 @@ void process_force_style(ass_track_t* track) {
COLORVAL(SecondaryColour) COLORVAL(SecondaryColour)
COLORVAL(OutlineColour) COLORVAL(OutlineColour)
COLORVAL(BackColour) COLORVAL(BackColour)
INTVAL(FontSize) FPVAL(FontSize)
INTVAL(Bold) INTVAL(Bold)
INTVAL(Italic) INTVAL(Italic)
INTVAL(Underline) INTVAL(Underline)
@ -435,7 +435,7 @@ static int process_style(ass_track_t* track, char *str)
// this will destroy SSA's TertiaryColour, but i'm not going to use it anyway // this will destroy SSA's TertiaryColour, but i'm not going to use it anyway
if (track->track_type == TRACK_TYPE_SSA) if (track->track_type == TRACK_TYPE_SSA)
target->OutlineColour = target->BackColour; target->OutlineColour = target->BackColour;
INTVAL(FontSize) FPVAL(FontSize)
INTVAL(Bold) INTVAL(Bold)
INTVAL(Italic) INTVAL(Italic)
INTVAL(Underline) INTVAL(Underline)
@ -572,8 +572,10 @@ static int decode_font(ass_track_t* track)
dsize = q - buf; dsize = q - buf;
assert(dsize <= size / 4 * 3 + 2); assert(dsize <= size / 4 * 3 + 2);
if (track->library->extract_fonts) if (track->library->extract_fonts) {
ass_add_font(track->library, track->parser_priv->fontname, (char*)buf, dsize); ass_add_font(track->library, track->parser_priv->fontname, (char*)buf, dsize);
buf = 0;
}
error_decode_font: error_decode_font:
if (buf) free(buf); if (buf) free(buf);

View File

@ -37,6 +37,13 @@ typedef struct ass_image_s {
struct ass_image_s* next; // linked list struct ass_image_s* next; // linked list
} ass_image_t; } ass_image_t;
/// Hinting type
typedef enum {ASS_HINTING_NONE = 0,
ASS_HINTING_LIGHT,
ASS_HINTING_NORMAL,
ASS_HINTING_NATIVE
} ass_hinting_t;
/** /**
* \brief initialize the library * \brief initialize the library
* \return library handle or NULL if failed * \return library handle or NULL if failed
@ -77,6 +84,7 @@ void ass_set_margins(ass_renderer_t* priv, int t, int b, int l, int r);
void ass_set_use_margins(ass_renderer_t* priv, int use); void ass_set_use_margins(ass_renderer_t* priv, int use);
void ass_set_aspect_ratio(ass_renderer_t* priv, double ar); void ass_set_aspect_ratio(ass_renderer_t* priv, double ar);
void ass_set_font_scale(ass_renderer_t* priv, double font_scale); void ass_set_font_scale(ass_renderer_t* priv, double font_scale);
void ass_set_hinting(ass_renderer_t* priv, ass_hinting_t ht);
/** /**
* \brief set font lookup defaults * \brief set font lookup defaults

View File

@ -104,7 +104,7 @@ static void resize_tmp(ass_synth_priv_t* priv, int w, int h)
priv->tmp = malloc((priv->tmp_w + 1) * priv->tmp_h * sizeof(short)); priv->tmp = malloc((priv->tmp_w + 1) * priv->tmp_h * sizeof(short));
} }
ass_synth_priv_t* ass_synth_init() ass_synth_priv_t* ass_synth_init(void)
{ {
ass_synth_priv_t* priv = calloc(1, sizeof(ass_synth_priv_t)); ass_synth_priv_t* priv = calloc(1, sizeof(ass_synth_priv_t));
generate_tables(priv, blur_radius); generate_tables(priv, blur_radius);

View File

@ -23,7 +23,7 @@
typedef struct ass_synth_priv_s ass_synth_priv_t; typedef struct ass_synth_priv_s ass_synth_priv_t;
ass_synth_priv_t* ass_synth_init(); ass_synth_priv_t* ass_synth_init(void);
void ass_synth_done(ass_synth_priv_t* priv); void ass_synth_done(ass_synth_priv_t* priv);
typedef struct bitmap_s { typedef struct bitmap_s {

View File

@ -34,12 +34,156 @@
#include "ass_bitmap.h" #include "ass_bitmap.h"
#include "ass_cache.h" #include "ass_cache.h"
#define MAX_FONT_CACHE_SIZE 100
static ass_font_t** font_cache; typedef struct hashmap_item_s {
static int font_cache_size; void* key;
void* value;
struct hashmap_item_s* next;
} hashmap_item_t;
typedef hashmap_item_t* hashmap_item_p;
static int font_compare(ass_font_desc_t* a, ass_font_desc_t* b) { struct hashmap_s {
int nbuckets;
size_t key_size, value_size;
hashmap_item_p* root;
hashmap_item_dtor_t item_dtor; // a destructor for hashmap key/value pairs
hashmap_key_compare_t key_compare;
hashmap_hash_t hash;
// stats
int hit_count;
int miss_count;
int count;
};
#define FNV1_32A_INIT (unsigned)0x811c9dc5
static unsigned fnv_32a_buf(void* buf, size_t len, unsigned hval)
{
unsigned char *bp = buf;
unsigned char *be = bp + len;
while (bp < be) {
hval ^= (unsigned)*bp++;
hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24);
}
return hval;
}
static unsigned fnv_32a_str(char* str, unsigned hval)
{
unsigned char* s = (unsigned char*)str;
while (*s) {
hval ^= (unsigned)*s++;
hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24);
}
return hval;
}
static unsigned hashmap_hash(void* buf, size_t len)
{
return fnv_32a_buf(buf, len, FNV1_32A_INIT);
}
static int hashmap_key_compare(void* a, void* b, size_t size)
{
return (memcmp(a, b, size) == 0);
}
static void hashmap_item_dtor(void* key, size_t key_size, void* value, size_t value_size)
{
free(key);
free(value);
}
hashmap_t* hashmap_init(size_t key_size, size_t value_size, int nbuckets,
hashmap_item_dtor_t item_dtor, hashmap_key_compare_t key_compare,
hashmap_hash_t hash)
{
hashmap_t* map = calloc(1, sizeof(hashmap_t));
map->nbuckets = nbuckets;
map->key_size = key_size;
map->value_size = value_size;
map->root = calloc(nbuckets, sizeof(hashmap_item_p));
map->item_dtor = item_dtor ? item_dtor : hashmap_item_dtor;
map->key_compare = key_compare ? key_compare : hashmap_key_compare;
map->hash = hash ? hash : hashmap_hash;
return map;
}
void hashmap_done(hashmap_t* map)
{
int i;
// print stats
if (map->count > 0 || map->hit_count + map->miss_count > 0)
mp_msg(MSGT_ASS, MSGL_V, "cache statistics: \n total accesses: %d\n hits: %d\n misses: %d\n object count: %d\n",
map->hit_count + map->miss_count, map->hit_count, map->miss_count, map->count);
for (i = 0; i < map->nbuckets; ++i) {
hashmap_item_t* item = map->root[i];
while (item) {
hashmap_item_t* next = item->next;
map->item_dtor(item->key, map->key_size, item->value, map->value_size);
free(item);
item = next;
}
}
free(map->root);
free(map);
}
// does nothing if key already exists
void* hashmap_insert(hashmap_t* map, void* key, void* value)
{
unsigned hash = map->hash(key, map->key_size);
hashmap_item_t** next = map->root + (hash % map->nbuckets);
while (*next) {
if (map->key_compare(key, (*next)->key, map->key_size))
return (*next)->value;
next = &((*next)->next);
assert(next);
}
(*next) = malloc(sizeof(hashmap_item_t));
(*next)->key = malloc(map->key_size);
(*next)->value = malloc(map->value_size);
memcpy((*next)->key, key, map->key_size);
memcpy((*next)->value, value, map->value_size);
(*next)->next = 0;
map->count ++;
return (*next)->value;
}
void* hashmap_find(hashmap_t* map, void* key)
{
unsigned hash = map->hash(key, map->key_size);
hashmap_item_t* item = map->root[hash % map->nbuckets];
while (item) {
if (map->key_compare(key, item->key, map->key_size)) {
map->hit_count++;
return item->value;
}
item = item->next;
}
map->miss_count++;
return 0;
}
//---------------------------------
// font cache
hashmap_t* font_cache;
static unsigned font_desc_hash(void* buf, size_t len)
{
ass_font_desc_t* desc = buf;
unsigned hval;
hval = fnv_32a_str(desc->family, FNV1_32A_INIT);
hval = fnv_32a_buf(&desc->bold, sizeof(desc->bold), hval);
hval = fnv_32a_buf(&desc->italic, sizeof(desc->italic), hval);
return hval;
}
static int font_compare(void* key1, void* key2, size_t key_size) {
ass_font_desc_t* a = key1;
ass_font_desc_t* b = key2;
if (strcmp(a->family, b->family) != 0) if (strcmp(a->family, b->family) != 0)
return 0; return 0;
if (a->bold != b->bold) if (a->bold != b->bold)
@ -49,125 +193,105 @@ static int font_compare(ass_font_desc_t* a, ass_font_desc_t* b) {
return 1; return 1;
} }
/** static void font_hash_dtor(void* key, size_t key_size, void* value, size_t value_size)
* \brief Get a face struct from cache. {
* \param desc required face description ass_font_free(value);
* \return font struct free(key);
*/ }
ass_font_t* ass_font_cache_find(ass_font_desc_t* desc) ass_font_t* ass_font_cache_find(ass_font_desc_t* desc)
{ {
int i; return hashmap_find(font_cache, desc);
for (i=0; i<font_cache_size; ++i)
if (font_compare(desc, &(font_cache[i]->desc)))
return font_cache[i];
return 0;
} }
/** /**
* \brief Add a face struct to cache. * \brief Add a face struct to cache.
* \param font font struct * \param font font struct
*/ */
void ass_font_cache_add(ass_font_t* font) void* ass_font_cache_add(ass_font_t* font)
{ {
if (font_cache_size == MAX_FONT_CACHE_SIZE) { return hashmap_insert(font_cache, &(font->desc), font);
mp_msg(MSGT_ASS, MSGL_FATAL, MSGTR_LIBASS_TooManyFonts);
// FIXME: possible memory leak
return;
}
font_cache[font_cache_size] = font;
font_cache_size++;
} }
void ass_font_cache_init(void) void ass_font_cache_init(void)
{ {
font_cache = calloc(MAX_FONT_CACHE_SIZE, sizeof(ass_font_t*)); font_cache = hashmap_init(sizeof(ass_font_desc_t),
font_cache_size = 0; sizeof(ass_font_t),
1000,
font_hash_dtor, font_compare, font_desc_hash);
} }
void ass_font_cache_done(void) void ass_font_cache_done(void)
{ {
int i; hashmap_done(font_cache);
for (i = 0; i < font_cache_size; ++i) {
ass_font_t* item = font_cache[i];
ass_font_free(item);
} }
free(font_cache);
font_cache_size = 0; //---------------------------------
// bitmap cache
hashmap_t* bitmap_cache;
static void bitmap_hash_dtor(void* key, size_t key_size, void* value, size_t value_size)
{
bitmap_hash_val_t* v = value;
if (v->bm) ass_free_bitmap(v->bm);
if (v->bm_o) ass_free_bitmap(v->bm_o);
if (v->bm_s) ass_free_bitmap(v->bm_s);
free(key);
free(value);
}
void* cache_add_bitmap(bitmap_hash_key_t* key, bitmap_hash_val_t* val)
{
return hashmap_insert(bitmap_cache, key, val);
}
/**
* \brief Get a bitmap from bitmap cache.
* \param key hash key
* \return requested hash val or 0 if not found
*/
bitmap_hash_val_t* cache_find_bitmap(bitmap_hash_key_t* key)
{
return hashmap_find(bitmap_cache, key);
}
void ass_bitmap_cache_init(void)
{
bitmap_cache = hashmap_init(sizeof(bitmap_hash_key_t),
sizeof(bitmap_hash_val_t),
0xFFFF + 13,
bitmap_hash_dtor, NULL, NULL);
}
void ass_bitmap_cache_done(void)
{
hashmap_done(bitmap_cache);
}
void ass_bitmap_cache_reset(void)
{
ass_bitmap_cache_done();
ass_bitmap_cache_init();
} }
//--------------------------------- //---------------------------------
// glyph cache // glyph cache
#define GLYPH_HASH_SIZE (0xFFFF + 13) hashmap_t* glyph_cache;
typedef struct glyph_hash_item_s { static void glyph_hash_dtor(void* key, size_t key_size, void* value, size_t value_size)
glyph_hash_key_t key;
glyph_hash_val_t val;
struct glyph_hash_item_s* next;
} glyph_hash_item_t;
typedef glyph_hash_item_t* glyph_hash_item_p;
static glyph_hash_item_p* glyph_hash_root;
static int glyph_hash_size;
static int glyph_compare(glyph_hash_key_t* a, glyph_hash_key_t* b) {
if (memcmp(a, b, sizeof(glyph_hash_key_t)) == 0)
return 1;
else
return 0;
}
static unsigned glyph_hash(glyph_hash_key_t* key) {
unsigned val = 0;
unsigned i;
for (i = 0; i < sizeof(key->font); ++i)
val += *(unsigned char *)(&(key->font) + i);
val <<= 21;
if (key->bitmap) val &= 0x80000000;
if (key->be) val &= 0x40000000;
val += key->ch;
val += key->size << 8;
val += key->outline << 3;
val += key->advance.x << 10;
val += key->advance.y << 16;
val += key->bold << 1;
val += key->italic << 20;
val += key->frx;
val += key->fry << 1;
val += key->frz << 2;
return val;
}
/**
* \brief Add a glyph to glyph cache.
* \param key hash key
* \param val hash val: 2 bitmap glyphs + some additional info
*/
void cache_add_glyph(glyph_hash_key_t* key, glyph_hash_val_t* val)
{ {
unsigned hash = glyph_hash(key); glyph_hash_val_t* v = value;
glyph_hash_item_t** next = glyph_hash_root + (hash % GLYPH_HASH_SIZE); if (v->glyph) FT_Done_Glyph(v->glyph);
while (*next) { if (v->outline_glyph) FT_Done_Glyph(v->outline_glyph);
if (glyph_compare(key, &((*next)->key))) free(key);
return; free(value);
next = &((*next)->next);
assert(next);
} }
(*next) = malloc(sizeof(glyph_hash_item_t));
// (*next)->desc = glyph_key_copy(key, &((*next)->key));
memcpy(&((*next)->key), key, sizeof(glyph_hash_key_t));
memcpy(&((*next)->val), val, sizeof(glyph_hash_val_t));
(*next)->next = 0;
glyph_hash_size ++; void* cache_add_glyph(glyph_hash_key_t* key, glyph_hash_val_t* val)
/* if (glyph_hash_size && (glyph_hash_size % 25 == 0)) { {
printf("\nGlyph cache: %d entries, %d bytes\n", glyph_hash_size, glyph_hash_size * sizeof(glyph_hash_item_t)); return hashmap_insert(glyph_cache, key, val);
} */
} }
/** /**
@ -177,39 +301,20 @@ void cache_add_glyph(glyph_hash_key_t* key, glyph_hash_val_t* val)
*/ */
glyph_hash_val_t* cache_find_glyph(glyph_hash_key_t* key) glyph_hash_val_t* cache_find_glyph(glyph_hash_key_t* key)
{ {
unsigned hash = glyph_hash(key); return hashmap_find(glyph_cache, key);
glyph_hash_item_t* item = glyph_hash_root[hash % GLYPH_HASH_SIZE];
while (item) {
if (glyph_compare(key, &(item->key))) {
return &(item->val);
}
item = item->next;
}
return 0;
} }
void ass_glyph_cache_init(void) void ass_glyph_cache_init(void)
{ {
glyph_hash_root = calloc(GLYPH_HASH_SIZE, sizeof(glyph_hash_item_p)); glyph_cache = hashmap_init(sizeof(glyph_hash_key_t),
glyph_hash_size = 0; sizeof(glyph_hash_val_t),
0xFFFF + 13,
glyph_hash_dtor, NULL, NULL);
} }
void ass_glyph_cache_done(void) void ass_glyph_cache_done(void)
{ {
int i; hashmap_done(glyph_cache);
for (i = 0; i < GLYPH_HASH_SIZE; ++i) {
glyph_hash_item_t* item = glyph_hash_root[i];
while (item) {
glyph_hash_item_t* next = item->next;
if (item->val.bm) ass_free_bitmap(item->val.bm);
if (item->val.bm_o) ass_free_bitmap(item->val.bm_o);
if (item->val.bm_s) ass_free_bitmap(item->val.bm_s);
free(item);
item = next;
}
}
free(glyph_hash_root);
glyph_hash_size = 0;
} }
void ass_glyph_cache_reset(void) void ass_glyph_cache_reset(void)
@ -217,4 +322,3 @@ void ass_glyph_cache_reset(void)
ass_glyph_cache_done(); ass_glyph_cache_done();
ass_glyph_cache_init(); ass_glyph_cache_init();
} }

View File

@ -23,40 +23,76 @@
void ass_font_cache_init(void); void ass_font_cache_init(void);
ass_font_t* ass_font_cache_find(ass_font_desc_t* desc); ass_font_t* ass_font_cache_find(ass_font_desc_t* desc);
void ass_font_cache_add(ass_font_t* font); void* ass_font_cache_add(ass_font_t* font);
void ass_font_cache_done(void); void ass_font_cache_done(void);
// describes a glyph; glyphs with equivalents structs are considered identical // describes a bitmap; bitmaps with equivalents structs are considered identical
typedef struct glyph_hash_key_s { typedef struct bitmap_hash_key_s {
char bitmap; // bool : true = bitmap, false = outline char bitmap; // bool : true = bitmap, false = outline
ass_font_t* font; ass_font_t* font;
int size; // font size double size; // font size
uint32_t ch; // character code uint32_t ch; // character code
unsigned outline; // border width, 16.16 fixed point value unsigned outline; // border width, 16.16 fixed point value
int bold, italic; int bold, italic;
char be; // blur edges char be; // blur edges
// the following affects bitmap glyphs only
unsigned scale_x, scale_y; // 16.16 unsigned scale_x, scale_y; // 16.16
int frx, fry, frz; // signed 16.16 int frx, fry, frz; // signed 16.16
int shift_x, shift_y; // shift vector that was added to glyph before applying rotation
// = 0, if frx = fry = frx = 0
// = (glyph base point) - (rotation origin), otherwise
FT_Vector advance; // subpixel shift vector FT_Vector advance; // subpixel shift vector
} bitmap_hash_key_t;
typedef struct bitmap_hash_val_s {
bitmap_t* bm; // the actual bitmaps
bitmap_t* bm_o;
bitmap_t* bm_s;
} bitmap_hash_val_t;
void ass_bitmap_cache_init(void);
void* cache_add_bitmap(bitmap_hash_key_t* key, bitmap_hash_val_t* val);
bitmap_hash_val_t* cache_find_bitmap(bitmap_hash_key_t* key);
void ass_bitmap_cache_reset(void);
void ass_bitmap_cache_done(void);
// describes an outline glyph
typedef struct glyph_hash_key_s {
ass_font_t* font;
double size; // font size
uint32_t ch; // character code
int bold, italic;
unsigned scale_x, scale_y; // 16.16
FT_Vector advance; // subpixel shift vector
unsigned outline; // border width, 16.16
} glyph_hash_key_t; } glyph_hash_key_t;
typedef struct glyph_hash_val_s { typedef struct glyph_hash_val_s {
bitmap_t* bm; // the actual glyph bitmaps FT_Glyph glyph;
bitmap_t* bm_o; FT_Glyph outline_glyph;
bitmap_t* bm_s;
FT_BBox bbox_scaled; // bbox after scaling, but before rotation FT_BBox bbox_scaled; // bbox after scaling, but before rotation
FT_Vector advance; // 26.6, advance distance to the next glyph in line FT_Vector advance; // 26.6, advance distance to the next bitmap in line
} glyph_hash_val_t; } glyph_hash_val_t;
void ass_glyph_cache_init(void); void ass_glyph_cache_init(void);
void cache_add_glyph(glyph_hash_key_t* key, glyph_hash_val_t* val); void* cache_add_glyph(glyph_hash_key_t* key, glyph_hash_val_t* val);
glyph_hash_val_t* cache_find_glyph(glyph_hash_key_t* key); glyph_hash_val_t* cache_find_glyph(glyph_hash_key_t* key);
void ass_glyph_cache_reset(void); void ass_glyph_cache_reset(void);
void ass_glyph_cache_done(void); void ass_glyph_cache_done(void);
typedef struct hashmap_s hashmap_t;
typedef void (*hashmap_item_dtor_t)(void* key, size_t key_size, void* value, size_t value_size);
typedef int (*hashmap_key_compare_t)(void* key1, void* key2, size_t key_size);
typedef unsigned (*hashmap_hash_t)(void* key, size_t key_size);
hashmap_t* hashmap_init(size_t key_size, size_t value_size, int nbuckets,
hashmap_item_dtor_t item_dtor, hashmap_key_compare_t key_compare,
hashmap_hash_t hash);
void hashmap_done(hashmap_t* map);
void* hashmap_insert(hashmap_t* map, void* key, void* value);
void* hashmap_find(hashmap_t* map, void* key);
#endif #endif

View File

@ -25,6 +25,7 @@
#include FT_FREETYPE_H #include FT_FREETYPE_H
#include FT_SYNTHESIS_H #include FT_SYNTHESIS_H
#include FT_GLYPH_H #include FT_GLYPH_H
#include FT_TRUETYPE_TABLES_H
#include "ass.h" #include "ass.h"
#include "ass_library.h" #include "ass_library.h"
@ -32,6 +33,7 @@
#include "ass_bitmap.h" #include "ass_bitmap.h"
#include "ass_cache.h" #include "ass_cache.h"
#include "ass_fontconfig.h" #include "ass_fontconfig.h"
#include "ass_utils.h"
#include "mputils.h" #include "mputils.h"
/** /**
@ -62,6 +64,17 @@ static void charmap_magic(FT_Face face)
} }
} }
static void update_transform(ass_font_t* 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 * \brief find a memory font by name
*/ */
@ -83,12 +96,13 @@ ass_font_t* ass_font_new(ass_library_t* library, FT_Library ftlibrary, void* fc_
int index; int index;
FT_Face face; FT_Face face;
int error; int error;
ass_font_t* font; ass_font_t* fontp;
ass_font_t font;
int mem_idx; int mem_idx;
font = ass_font_cache_find(desc); fontp = ass_font_cache_find(desc);
if (font) if (fontp)
return font; return fontp;
path = fontconfig_select(fc_priv, desc->family, desc->bold, desc->italic, &index); path = fontconfig_select(fc_priv, desc->family, desc->bold, desc->italic, &index);
@ -110,54 +124,72 @@ ass_font_t* ass_font_new(ass_library_t* library, FT_Library ftlibrary, void* fc_
charmap_magic(face); charmap_magic(face);
font = calloc(1, sizeof(ass_font_t)); font.ftlibrary = ftlibrary;
font->ftlibrary = ftlibrary; font.faces[0] = face;
font->faces[0] = face; font.n_faces = 1;
font->n_faces = 1; font.desc.family = strdup(desc->family);
font->desc.family = strdup(desc->family); font.desc.bold = desc->bold;
font->desc.bold = desc->bold; font.desc.italic = desc->italic;
font->desc.italic = desc->italic;
font->m.xx = font->m.yy = (FT_Fixed)0x10000L; font.scale_x = font.scale_y = 1.;
font->m.xy = font->m.yy = 0; font.v.x = font.v.y = 0;
font->v.x = font->v.y = 0; font.size = 0.;
font->size = 0;
#ifdef HAVE_FONTCONFIG #ifdef HAVE_FONTCONFIG
font->charset = FcCharSetCreate(); font.charset = FcCharSetCreate();
#endif #endif
ass_font_cache_add(font); return ass_font_cache_add(&font);
return font;
} }
/** /**
* \brief Set font transformation matrix and shift vector * \brief Set font transformation matrix and shift vector
**/ **/
void ass_font_set_transform(ass_font_t* font, FT_Matrix* m, FT_Vector* v) void ass_font_set_transform(ass_font_t* font, double scale_x, double scale_y, FT_Vector* v)
{ {
int i; font->scale_x = scale_x;
font->m.xx = m->xx; font->scale_y = scale_y;
font->m.xy = m->xy;
font->m.yx = m->yx;
font->m.yy = m->yy;
font->v.x = v->x; font->v.x = v->x;
font->v.y = v->y; font->v.y = v->y;
for (i = 0; i < font->n_faces; ++i) update_transform(font);
FT_Set_Transform(font->faces[i], &font->m, &font->v); }
static void face_set_size(FT_Face face, double size)
{
#if (FREETYPE_MAJOR > 2) || ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR > 1))
TT_HoriHeader *hori = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
double mscale = 1.;
FT_Size_RequestRec rq;
FT_Size_Metrics *m = &face->size->metrics;
// VSFilter uses metrics from TrueType OS/2 table
// The idea was borrowed from asa (http://asa.diac24.net)
if (hori && os2)
mscale = ((double)(hori->Ascender - hori->Descender)) / (os2->usWinAscent + os2->usWinDescent);
memset(&rq, 0, sizeof(rq));
rq.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
rq.width = 0;
rq.height = double_to_d6(size * mscale);
rq.horiResolution = rq.vertResolution = 0;
FT_Request_Size(face, &rq);
m->ascender /= mscale;
m->descender /= mscale;
m->height /= mscale;
#else
FT_Set_Char_Size(face, 0, double_to_d6(size), 0, 0);
#endif
} }
/** /**
* \brief Set font size * \brief Set font size
**/ **/
void ass_font_set_size(ass_font_t* font, int size) void ass_font_set_size(ass_font_t* font, double size)
{ {
int i; int i;
if (font->size != size) { if (font->size != size) {
font->size = size; font->size = size;
for (i = 0; i < font->n_faces; ++i) for (i = 0; i < font->n_faces; ++i)
FT_Set_Pixel_Sizes(font->faces[i], 0, size); face_set_size(font->faces[i], size);
} }
} }
@ -193,9 +225,8 @@ static void ass_font_reselect(void* fontconfig_priv, ass_font_t* font, uint32_t
} }
font->faces[font->n_faces++] = face; font->faces[font->n_faces++] = face;
update_transform(font);
FT_Set_Transform(face, &font->m, &font->v); FT_Set_Pixel_Sizes(face, 0, (int)font->size);
FT_Set_Pixel_Sizes(face, 0, font->size);
} }
#endif #endif
@ -229,13 +260,14 @@ void ass_font_get_asc_desc(ass_font_t* font, uint32_t ch, int* asc, int* desc)
* \brief Get a glyph * \brief Get a glyph
* \param ch character code * \param ch character code
**/ **/
FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch) FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch, ass_hinting_t hinting)
{ {
int error; int error;
int index = 0; int index = 0;
int i; int i;
FT_Glyph glyph; FT_Glyph glyph;
FT_Face face = 0; FT_Face face = 0;
int flags = 0;
if (ch < 0x20) if (ch < 0x20)
return 0; return 0;
@ -264,7 +296,14 @@ FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch
} }
#endif #endif
error = FT_Load_Glyph(face, index, FT_LOAD_NO_BITMAP ); switch (hinting) {
case ASS_HINTING_NONE: flags = FT_LOAD_NO_HINTING; break;
case ASS_HINTING_LIGHT: flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT; break;
case ASS_HINTING_NORMAL: flags = FT_LOAD_FORCE_AUTOHINT; break;
case ASS_HINTING_NATIVE: flags = 0; break;
}
error = FT_Load_Glyph(face, index, FT_LOAD_NO_BITMAP | flags);
if (error) { if (error) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph); mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph);
return 0; return 0;

View File

@ -38,19 +38,19 @@ typedef struct ass_font_s {
FT_Library ftlibrary; FT_Library ftlibrary;
FT_Face faces[ASS_FONT_MAX_FACES]; FT_Face faces[ASS_FONT_MAX_FACES];
int n_faces; int n_faces;
FT_Matrix m; // current transformation double scale_x, scale_y; // current transform
FT_Vector v; // current shift FT_Vector v; // current shift
int size; double size;
#ifdef HAVE_FONTCONFIG #ifdef HAVE_FONTCONFIG
FcCharSet* charset; FcCharSet* charset;
#endif #endif
} ass_font_t; } ass_font_t;
ass_font_t* ass_font_new(ass_library_t* library, FT_Library ftlibrary, void* fc_priv, ass_font_desc_t* desc); ass_font_t* ass_font_new(ass_library_t* library, FT_Library ftlibrary, void* fc_priv, ass_font_desc_t* desc);
void ass_font_set_transform(ass_font_t* font, FT_Matrix* m, FT_Vector* v); void ass_font_set_transform(ass_font_t* font, double scale_x, double scale_y, FT_Vector* v);
void ass_font_set_size(ass_font_t* font, int size); void ass_font_set_size(ass_font_t* font, double size);
void ass_font_get_asc_desc(ass_font_t* font, uint32_t ch, int* asc, int* desc); void ass_font_get_asc_desc(ass_font_t* font, uint32_t ch, int* asc, int* desc);
FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch); FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch, ass_hinting_t hinting);
FT_Vector ass_font_get_kerning(ass_font_t* font, uint32_t c1, uint32_t c2); FT_Vector ass_font_get_kerning(ass_font_t* font, uint32_t c1, uint32_t c2);
void ass_font_free(ass_font_t* font); void ass_font_free(ass_font_t* font);

View File

@ -65,19 +65,20 @@ static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold
{ {
FcBool rc; FcBool rc;
FcResult result; FcResult result;
FcPattern *pat, *rpat; FcPattern *pat = 0, *rpat;
int val_i; int val_i;
FcChar8* val_s; FcChar8* val_s;
FcBool val_b; FcBool val_b;
FcCharSet* val_cs; FcCharSet* val_cs;
FcFontSet* fset; FcFontSet* fset = 0;
int curf, bestf, bestdiff = 0; int curf, bestf, bestdiff = 0;
char* retval = 0;
*index = 0; *index = 0;
pat = FcPatternCreate(); pat = FcPatternCreate();
if (!pat) if (!pat)
return 0; goto error;
FcPatternAddString(pat, FC_FAMILY, (const FcChar8*)family); FcPatternAddString(pat, FC_FAMILY, (const FcChar8*)family);
FcPatternAddBool(pat, FC_OUTLINE, FcTrue); FcPatternAddBool(pat, FC_OUTLINE, FcTrue);
@ -88,7 +89,7 @@ static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold
rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern); rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern);
if (!rc) if (!rc)
return 0; goto error;
fset = FcFontSort(priv->config, pat, FcTrue, NULL, &result); fset = FcFontSort(priv->config, pat, FcTrue, NULL, &result);
@ -123,18 +124,18 @@ static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold
} }
if (bestf < 0) if (bestf < 0)
return 0; goto error;
rpat = fset->fonts[bestf]; rpat = fset->fonts[bestf];
result = FcPatternGetInteger(rpat, FC_INDEX, 0, &val_i); result = FcPatternGetInteger(rpat, FC_INDEX, 0, &val_i);
if (result != FcResultMatch) if (result != FcResultMatch)
return 0; goto error;
*index = val_i; *index = val_i;
result = FcPatternGetString(rpat, FC_FAMILY, 0, &val_s); result = FcPatternGetString(rpat, FC_FAMILY, 0, &val_s);
if (result != FcResultMatch) if (result != FcResultMatch)
return 0; goto error;
if (strcasecmp((const char*)val_s, family) != 0) if (strcasecmp((const char*)val_s, family) != 0)
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_SelectedFontFamilyIsNotTheRequestedOne, mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_SelectedFontFamilyIsNotTheRequestedOne,
@ -142,9 +143,13 @@ static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold
result = FcPatternGetString(rpat, FC_FILE, 0, &val_s); result = FcPatternGetString(rpat, FC_FILE, 0, &val_s);
if (result != FcResultMatch) if (result != FcResultMatch)
return 0; goto error;
return strdup((const char*)val_s); retval = strdup((const char*)val_s);
error:
if (pat) FcPatternDestroy(pat);
if (fset) FcFontSetDestroy(fset);
return retval;
} }
/** /**
@ -192,6 +197,7 @@ char* fontconfig_select(fc_instance_t* priv, const char* family, unsigned bold,
return fontconfig_select_with_charset(priv, family, bold, italic, index, 0); return fontconfig_select_with_charset(priv, family, bold, italic, index, 0);
} }
#if (FC_VERSION < 20402)
static char* validate_fname(char* name) static char* validate_fname(char* name)
{ {
char* fname; char* fname;
@ -227,6 +233,7 @@ static char* validate_fname(char* name)
*q = 0; *q = 0;
return fname; return fname;
} }
#endif
/** /**
* \brief Process memory font. * \brief Process memory font.
@ -239,21 +246,18 @@ static char* validate_fname(char* name)
*/ */
static void process_fontdata(fc_instance_t* priv, ass_library_t* library, FT_Library ftlibrary, int idx) static void process_fontdata(fc_instance_t* priv, ass_library_t* library, FT_Library ftlibrary, int idx)
{ {
char buf[1000];
FILE* fp = 0;
int rc; int rc;
struct stat st;
char* fname;
const char* name = library->fontdata[idx].name; const char* name = library->fontdata[idx].name;
const char* data = library->fontdata[idx].data; const char* data = library->fontdata[idx].data;
int data_size = library->fontdata[idx].size; int data_size = library->fontdata[idx].size;
const char* fonts_dir = library->fonts_dir;
FT_Face face;
FcPattern* pattern;
FcFontSet* fset;
FcBool res;
#if (FC_VERSION < 20402) #if (FC_VERSION < 20402)
struct stat st;
char* fname;
const char* fonts_dir = library->fonts_dir;
char buf[1000];
FILE* fp = 0;
if (!fonts_dir) if (!fonts_dir)
return; return;
rc = stat(fonts_dir, &st); rc = stat(fonts_dir, &st);
@ -283,6 +287,10 @@ static void process_fontdata(fc_instance_t* priv, ass_library_t* library, FT_Lib
fclose(fp); fclose(fp);
#else // (FC_VERSION >= 20402) #else // (FC_VERSION >= 20402)
FT_Face face;
FcPattern* pattern;
FcFontSet* fset;
FcBool res;
rc = FT_New_Memory_Face(ftlibrary, (unsigned char*)data, data_size, 0, &face); rc = FT_New_Memory_Face(ftlibrary, (unsigned char*)data, data_size, 0, &face);
if (rc) { if (rc) {
@ -326,7 +334,6 @@ static void process_fontdata(fc_instance_t* priv, ass_library_t* library, FT_Lib
fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, const char* family, const char* path) fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, const char* family, const char* path)
{ {
int rc; int rc;
struct stat st;
fc_instance_t* priv = calloc(1, sizeof(fc_instance_t)); fc_instance_t* priv = calloc(1, sizeof(fc_instance_t));
const char* dir = library->fonts_dir; const char* dir = library->fonts_dir;
int i; int i;
@ -383,17 +390,8 @@ fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, con
} }
priv->family_default = family ? strdup(family) : 0; priv->family_default = family ? strdup(family) : 0;
priv->index_default = 0;
#ifdef __VISUALC__
priv->path_default = path;
#else
rc = stat(path, &st);
if (!rc && S_ISREG(st.st_mode))
priv->path_default = path ? strdup(path) : 0; priv->path_default = path ? strdup(path) : 0;
else priv->index_default = 0;
priv->path_default = 0;
#endif
return priv; return priv;
} }

View File

@ -56,6 +56,7 @@ typedef struct ass_settings_s {
int use_margins; // 0 - place all subtitles inside original frame int use_margins; // 0 - place all subtitles inside original frame
// 1 - use margins for placing toptitles and subtitles // 1 - use margins for placing toptitles and subtitles
double aspect; // frame aspect ratio, d_width / d_height. double aspect; // frame aspect ratio, d_width / d_height.
ass_hinting_t hinting;
char* default_font; char* default_font;
char* default_family; char* default_family;
@ -112,7 +113,7 @@ typedef struct glyph_info_s {
int shadow; int shadow;
double frx, fry, frz; // rotation double frx, fry, frz; // rotation
glyph_hash_key_t hash_key; bitmap_hash_key_t hash_key;
} glyph_info_t; } glyph_info_t;
typedef struct line_info_s { typedef struct line_info_s {
@ -136,7 +137,7 @@ typedef struct render_context_s {
ass_font_t* font; ass_font_t* font;
char* font_path; char* font_path;
int font_size; double font_size;
FT_Stroker stroker; FT_Stroker stroker;
int alignment; // alignment overrides go here; if zero, style value will be used int alignment; // alignment overrides go here; if zero, style value will be used
@ -252,6 +253,7 @@ ass_renderer_t* ass_renderer_init(ass_library_t* library)
// images_root and related stuff is zero-filled in calloc // images_root and related stuff is zero-filled in calloc
ass_font_cache_init(); ass_font_cache_init();
ass_bitmap_cache_init();
ass_glyph_cache_init(); ass_glyph_cache_init();
text_info.glyphs = calloc(MAX_GLYPHS, sizeof(glyph_info_t)); text_info.glyphs = calloc(MAX_GLYPHS, sizeof(glyph_info_t));
@ -266,6 +268,7 @@ ass_init_exit:
void ass_renderer_done(ass_renderer_t* priv) void ass_renderer_done(ass_renderer_t* priv)
{ {
ass_font_cache_done(); ass_font_cache_done();
ass_bitmap_cache_done();
ass_glyph_cache_done(); ass_glyph_cache_done();
if (render_context.stroker) { if (render_context.stroker) {
FT_Stroker_Done(render_context.stroker); FT_Stroker_Done(render_context.stroker);
@ -378,44 +381,17 @@ static ass_image_t** render_glyph(bitmap_t* bm, int dst_x, int dst_y, uint32_t c
} }
/** /**
* \brief Render text_info_t struct into ass_image_t list * \brief Convert text_info_t struct to ass_image_t list
* Rasterize glyphs and put them in glyph cache. * Splits glyphs in halves when needed (for \kf karaoke).
*/ */
static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y) static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y)
{ {
int pen_x, pen_y; int pen_x, pen_y;
int i, error; int i;
bitmap_t* bm; bitmap_t* bm;
glyph_hash_val_t hash_val;
ass_image_t* head; ass_image_t* head;
ass_image_t** tail = &head; ass_image_t** tail = &head;
for (i = 0; i < text_info->length; ++i) {
if (text_info->glyphs[i].glyph) {
if ((text_info->glyphs[i].symbol == '\n') || (text_info->glyphs[i].symbol == 0))
continue;
error = glyph_to_bitmap(ass_renderer->synth_priv,
text_info->glyphs[i].glyph, text_info->glyphs[i].outline_glyph,
&text_info->glyphs[i].bm, &text_info->glyphs[i].bm_o,
&text_info->glyphs[i].bm_s, text_info->glyphs[i].be);
if (error)
text_info->glyphs[i].symbol = 0;
FT_Done_Glyph(text_info->glyphs[i].glyph);
if (text_info->glyphs[i].outline_glyph)
FT_Done_Glyph(text_info->glyphs[i].outline_glyph);
// cache
hash_val.bbox_scaled = text_info->glyphs[i].bbox;
hash_val.bm_o = text_info->glyphs[i].bm_o;
hash_val.bm = text_info->glyphs[i].bm;
hash_val.bm_s = text_info->glyphs[i].bm_s;
hash_val.advance.x = text_info->glyphs[i].advance.x;
hash_val.advance.y = text_info->glyphs[i].advance.y;
cache_add_glyph(&(text_info->glyphs[i].hash_key), &hash_val);
}
}
for (i = 0; i < text_info->length; ++i) { for (i = 0; i < text_info->length; ++i) {
glyph_info_t* info = text_info->glyphs + i; glyph_info_t* info = text_info->glyphs + i;
if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_s || (info->shadow == 0)) if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_s || (info->shadow == 0))
@ -521,7 +497,7 @@ static void compute_string_bbox( text_info_t* info, FT_BBox *abbox ) {
/** /**
* \brief Check if starting part of (*p) matches sample. If true, shift p to the first symbol after the matching part. * \brief Check if starting part of (*p) matches sample. If true, shift p to the first symbol after the matching part.
*/ */
static inline int mystrcmp(char** p, const char* sample) { static int mystrcmp(char** p, const char* sample) {
int len = strlen(sample); int len = strlen(sample);
if (strncmp(*p, sample, len) == 0) { if (strncmp(*p, sample, len) == 0) {
(*p) += len; (*p) += len;
@ -530,9 +506,7 @@ static inline int mystrcmp(char** p, const char* sample) {
return 0; return 0;
} }
double ass_internal_font_size_coeff = 0.8; static void change_font_size(double sz)
static void change_font_size(int sz)
{ {
double size = sz * frame_context.font_scale; double size = sz * frame_context.font_scale;
@ -568,6 +542,7 @@ static void update_font(void)
desc.italic = val; desc.italic = val;
render_context.font = ass_font_new(priv->library, priv->ftlibrary, priv->fontconfig_priv, &desc); render_context.font = ass_font_new(priv->library, priv->ftlibrary, priv->fontconfig_priv, &desc);
free(desc.family);
if (render_context.font) if (render_context.font)
change_font_size(render_context.font_size); change_font_size(render_context.font_size);
@ -680,7 +655,7 @@ static unsigned interpolate_alpha(long long now,
return a; return a;
} }
static void reset_render_context(); static void reset_render_context(void);
/** /**
* \brief Parse style override tag. * \brief Parse style override tag.
@ -719,8 +694,8 @@ static char* parse_tag(char* p, double pwr) {
else else
render_context.hspacing = render_context.style->Spacing; render_context.hspacing = render_context.style->Spacing;
} else if (mystrcmp(&p, "fs")) { } else if (mystrcmp(&p, "fs")) {
int val; double val;
if (mystrtoi(&p, 10, &val)) if (mystrtod(&p, &val))
val = render_context.font_size * ( 1 - pwr ) + val * pwr; val = render_context.font_size * ( 1 - pwr ) + val * pwr;
else else
val = render_context.style->FontSize; val = render_context.style->FontSize;
@ -834,7 +809,7 @@ static char* parse_tag(char* p, double pwr) {
} else } else
render_context.alignment = render_context.style->Alignment; render_context.alignment = render_context.style->Alignment;
} else if (mystrcmp(&p, "a")) { } else if (mystrcmp(&p, "a")) {
int val = strtol(p, &p, 10); int val;
if (mystrtoi(&p, 10, &val) && val) if (mystrtoi(&p, 10, &val) && val)
render_context.alignment = val; render_context.alignment = val;
else else
@ -927,11 +902,14 @@ static char* parse_tag(char* p, double pwr) {
if (v3 < 0.) if (v3 < 0.)
v3 = 0.; v3 = 0.;
t = frame_context.time - render_context.event->Start; // FIXME: move to render_context t = frame_context.time - render_context.event->Start; // FIXME: move to render_context
if (t < t1) if (t <= t1)
k = 0.; k = 0.;
else if (t > t2) else if (t >= t2)
k = 1.; k = 1.;
else k = pow(((double)(t - t1)) / delta_t, v3); else {
assert(delta_t != 0.);
k = pow(((double)(t - t1)) / delta_t, v3);
}
while (*p == '\\') while (*p == '\\')
p = parse_tag(p, k); // maybe k*pwr ? no, specs forbid nested \t's p = parse_tag(p, k); // maybe k*pwr ? no, specs forbid nested \t's
skip_all(')'); // FIXME: better skip(')'), but much more tags support required skip_all(')'); // FIXME: better skip(')'), but much more tags support required
@ -1219,70 +1197,121 @@ static void free_render_context(void)
} }
/** /**
* \brief Get normal and outline glyphs from cache (if possible) or font face * \brief Get normal and outline (border) glyphs
* \param index face glyph index
* \param symbol ucs4 char * \param symbol ucs4 char
* \param info out: struct filled with extracted data * \param info out: struct filled with extracted data
* \param advance advance vector of the extracted glyph * \param advance subpixel shift vector used for cache lookup
* \return 0 on success * Tries to get both glyphs from cache.
* If they can't be found, gets a glyph from font face, generates outline with FT_Stroker,
* and add them to cache.
* The glyphs are returned in info->glyph and info->outline_glyph
*/ */
static int get_glyph(int symbol, glyph_info_t* info, FT_Vector* advance) static void get_outline_glyph(int symbol, glyph_info_t* info, FT_Vector* advance)
{ {
int error; int error;
glyph_hash_val_t* val; glyph_hash_val_t* val;
glyph_hash_key_t* key = &(info->hash_key); glyph_hash_key_t key;
key.font = render_context.font;
key.size = render_context.font_size;
key.ch = symbol;
key.scale_x = (render_context.scale_x * 0xFFFF);
key.scale_y = (render_context.scale_y * 0xFFFF);
key.advance = *advance;
key.bold = render_context.bold;
key.italic = render_context.italic;
key.outline = render_context.border * 0xFFFF;
key->font = render_context.font;
key->size = render_context.font_size;
key->ch = symbol;
key->outline = (render_context.border * 0xFFFF); // convert to 16.16
key->scale_x = (render_context.scale_x * 0xFFFF);
key->scale_y = (render_context.scale_y * 0xFFFF);
key->frx = (render_context.frx * 0xFFFF);
key->fry = (render_context.fry * 0xFFFF);
key->frz = (render_context.frz * 0xFFFF);
key->advance = *advance;
key->bold = render_context.bold;
key->italic = render_context.italic;
key->be = render_context.be;
val = cache_find_glyph(key);
// val = 0;
if (val) {
info->glyph = info->outline_glyph = 0; info->glyph = info->outline_glyph = 0;
info->bm = val->bm;
info->bm_o = val->bm_o; val = cache_find_glyph(&key);
info->bm_s = val->bm_s; if (val) {
FT_Glyph_Copy(val->glyph, &info->glyph);
if (val->outline_glyph)
FT_Glyph_Copy(val->outline_glyph, &info->outline_glyph);
info->bbox = val->bbox_scaled; info->bbox = val->bbox_scaled;
info->advance.x = val->advance.x; info->advance.x = val->advance.x;
info->advance.y = val->advance.y; info->advance.y = val->advance.y;
} else {
return 0; glyph_hash_val_t v;
} info->glyph = ass_font_get_glyph(frame_context.ass_priv->fontconfig_priv, render_context.font, symbol, global_settings->hinting);
// not found, get a new outline glyph from face
// mp_msg(MSGT_ASS, MSGL_INFO, "miss, index = %d, symbol = %c, adv = (%d, %d)\n", index, symbol, advance->x, advance->y);
info->outline_glyph = 0;
info->bm = info->bm_o = info->bm_s = 0;
info->glyph = ass_font_get_glyph(frame_context.ass_priv->fontconfig_priv, render_context.font, symbol);
if (!info->glyph) if (!info->glyph)
return 0; return;
info->advance.x = d16_to_d6(info->glyph->advance.x); info->advance.x = d16_to_d6(info->glyph->advance.x);
info->advance.y = d16_to_d6(info->glyph->advance.y); info->advance.y = d16_to_d6(info->glyph->advance.y);
FT_Glyph_Get_CBox( info->glyph, FT_GLYPH_BBOX_PIXELS, &info->bbox);
if (render_context.stroker) { if (render_context.stroker) {
info->outline_glyph = info->glyph; info->outline_glyph = info->glyph;
error = FT_Glyph_Stroke( &(info->outline_glyph), render_context.stroker, 0 ); // don't destroy original error = FT_Glyph_StrokeBorder( &(info->outline_glyph), render_context.stroker, 0 , 0 ); // don't destroy original
if (error) { if (error) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FT_Glyph_Stroke_Error, error); mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FT_Glyph_Stroke_Error, error);
} }
} }
return 0; 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.advance = info->advance;
v.bbox_scaled = info->bbox;
cache_add_glyph(&key, &v);
}
}
static void transform_3d(FT_Vector shift, FT_Glyph* glyph, FT_Glyph* glyph2, double frx, double fry, double frz);
/**
* \brief Get bitmaps for a glyph
* \param info glyph info
* Tries to get glyph bitmaps from bitmap cache.
* If they can't be found, they are generated by rotating and rendering the glyph.
* After that, bitmaps are added to the cache.
* They are returned in info->bm (glyph), info->bm_o (outline) and info->bm_s (shadow).
*/
static void get_bitmap_glyph(glyph_info_t* info)
{
bitmap_hash_val_t* val;
bitmap_hash_key_t* key = &info->hash_key;
val = cache_find_bitmap(key);
/* val = 0; */
if (val) {
info->bm = val->bm;
info->bm_o = val->bm_o;
info->bm_s = val->bm_s;
} else {
FT_Vector shift;
bitmap_hash_val_t hash_val;
int error;
info->bm = info->bm_o = info->bm_s = 0;
if (info->glyph && info->symbol != '\n' && info->symbol != 0) {
// calculating rotation shift vector (from rotation origin to the glyph basepoint)
shift.x = int_to_d6(info->hash_key.shift_x);
shift.y = int_to_d6(info->hash_key.shift_y);
// apply rotation
transform_3d(shift, &info->glyph, &info->outline_glyph, info->frx, info->fry, info->frz);
// render glyph
error = glyph_to_bitmap(ass_renderer->synth_priv,
info->glyph, info->outline_glyph,
&info->bm, &info->bm_o,
&info->bm_s, info->be);
if (error)
info->symbol = 0;
// add bitmaps to cache
hash_val.bm_o = info->bm_o;
hash_val.bm = info->bm;
hash_val.bm_s = info->bm_s;
cache_add_bitmap(&(info->hash_key), &hash_val);
}
}
// deallocate glyphs
if (info->glyph)
FT_Done_Glyph(info->glyph);
if (info->outline_glyph)
FT_Done_Glyph(info->outline_glyph);
} }
/** /**
@ -1294,7 +1323,7 @@ static int get_glyph(int symbol, glyph_info_t* info, FT_Vector* advance)
* lines[].asc * lines[].asc
* lines[].desc * lines[].desc
*/ */
static void measure_text() static void measure_text(void)
{ {
int cur_line = 0, max_asc = 0, max_desc = 0; int cur_line = 0, max_asc = 0, max_desc = 0;
int i; int i;
@ -1386,6 +1415,11 @@ static void wrap_lines_smart(int max_text_width)
if (cur->symbol == ' ') if (cur->symbol == ' ')
last_space = i; last_space = i;
// make sure the hard linebreak is not forgotten when
// there was a new soft linebreak just inserted
if (cur->symbol == '\n' && break_type == 1)
i--;
} }
#define DIFF(x,y) (((x) < (y)) ? (y - x) : (x - y)) #define DIFF(x,y) (((x) < (y)) ? (y - x) : (x - y))
exit = 0; exit = 0;
@ -1558,7 +1592,7 @@ static void get_base_point(FT_BBox bbox, int alignment, int* bx, int* by)
* \param b out: 4-vector * \param b out: 4-vector
* Calculates a * m and stores result in b * Calculates a * m and stores result in b
*/ */
static inline void transform_point_3d(double *a, double *m, double *b) static void transform_point_3d(double *a, double *m, double *b)
{ {
b[0] = a[0] * m[0] + a[1] * m[4] + a[2] * m[8] + a[3] * m[12]; b[0] = a[0] * m[0] + a[1] * m[4] + a[2] * m[8] + a[3] * m[12];
b[1] = a[0] * m[1] + a[1] * m[5] + a[2] * m[9] + a[3] * m[13]; b[1] = a[0] * m[1] + a[1] * m[5] + a[2] * m[9] + a[3] * m[13];
@ -1573,13 +1607,26 @@ static inline void transform_point_3d(double *a, double *m, double *b)
* Transforms v by m, projects the result back to the screen plane * Transforms v by m, projects the result back to the screen plane
* Result is returned in v. * Result is returned in v.
*/ */
static inline void transform_vector_3d(FT_Vector* v, double *m) { static void transform_vector_3d(FT_Vector* v, double *m) {
const double camera = 2500 * frame_context.border_scale; // camera distance
double a[4], b[4]; double a[4], b[4];
a[0] = d6_to_double(v->x); a[0] = d6_to_double(v->x);
a[1] = d6_to_double(v->y); a[1] = d6_to_double(v->y);
a[2] = 0.; a[2] = 0.;
a[3] = 1.; a[3] = 1.;
transform_point_3d(a, m, b); transform_point_3d(a, m, b);
/* Apply perspective projection with the following matrix:
2500 0 0 0
0 2500 0 0
0 0 0 0
0 0 8 2500
where 2500 is camera distance, 8 - z-axis scale.
Camera is always located in (org_x, org_y, -2500). This means
that different subtitle events can be displayed at the same time
using different cameras. */
b[0] *= camera;
b[1] *= camera;
b[3] = 8 * b[2] + camera;
if (b[3] < 0.001 && b[3] > -0.001) if (b[3] < 0.001 && b[3] > -0.001)
b[3] = b[3] < 0. ? -0.001 : 0.001; b[3] = b[3] < 0. ? -0.001 : 0.001;
v->x = double_to_d6(b[0] / b[3]); v->x = double_to_d6(b[0] / b[3]);
@ -1593,28 +1640,35 @@ static inline void transform_vector_3d(FT_Vector* v, double *m) {
* Transforms glyph by m, projects the result back to the screen plane * Transforms glyph by m, projects the result back to the screen plane
* Result is returned in glyph. * Result is returned in glyph.
*/ */
static inline void transform_glyph_3d(FT_Glyph glyph, double *m) { static void transform_glyph_3d(FT_Glyph glyph, double *m, FT_Vector shift) {
int i; int i;
FT_Outline* outline = &((FT_OutlineGlyph)glyph)->outline; FT_Outline* outline = &((FT_OutlineGlyph)glyph)->outline;
FT_Vector* p = outline->points;
for (i=0; i<outline->n_points; i++) for (i=0; i<outline->n_points; i++) {
transform_vector_3d(outline->points + i, m); p[i].x += shift.x;
p[i].y += shift.y;
transform_vector_3d(p + i, m);
p[i].x -= shift.x;
p[i].y -= shift.y;
}
transform_vector_3d(&glyph->advance, m); //transform_vector_3d(&glyph->advance, m);
} }
/** /**
* \brief Apply 3d transformation to several objects * \brief Apply 3d transformation to several objects
* \param vec FreeType vector * \param shift FreeType vector
* \param glyph FreeType glyph * \param glyph FreeType glyph
* \param glyph2 FreeType glyph * \param glyph2 FreeType glyph
* \param frx x-axis rotation angle * \param frx x-axis rotation angle
* \param fry y-axis rotation angle * \param fry y-axis rotation angle
* \param frz z-axis rotation angle * \param frz z-axis rotation angle
* Rotates the given vector and both glyphs by frx, fry and frz. * Rotates both glyphs by frx, fry and frz. Shift vector is added before rotation and subtracted after it.
*/ */
void transform_3d(FT_Vector* vec, FT_Glyph* glyph, FT_Glyph* glyph2, double frx, double fry, double frz) static void transform_3d(FT_Vector shift, FT_Glyph* glyph, FT_Glyph* glyph2, double frx, double fry, double frz)
{ {
fry = - fry; // FreeType's y axis goes in the opposite direction
if (frx != 0. || fry != 0. || frz != 0.) { if (frx != 0. || fry != 0. || frz != 0.) {
double m[16]; double m[16];
double sx = sin(frx); double sx = sin(frx);
@ -1623,19 +1677,16 @@ void transform_3d(FT_Vector* vec, FT_Glyph* glyph, FT_Glyph* glyph2, double frx,
double cx = cos(frx); double cx = cos(frx);
double cy = cos(fry); double cy = cos(fry);
double cz = cos(frz); double cz = cos(frz);
m[0] = cy * cz; m[1] = cz*sx*sy + sz*cx; m[2] = sz*sx - cz*cx*sy; m[3] = 0.0; m[0] = cy * cz; m[1] = cy*sz; m[2] = -sy; m[3] = 0.0;
m[4] = -sz*cy; m[5] = cz*cx - sz*sy*sx; m[6] = sz*sy*cx + cz*sx; m[7] = 0.0; m[4] = -cx*sz + sx*sy*cz; m[5] = cx*cz + sx*sy*sz; m[6] = sx*cy; m[7] = 0.0;
m[8] = sy; m[9] = -sx*cy; m[10] = cx*cy; m[11] = 0.0; m[8] = sx*sz + cx*sy*cz; m[9] = -sx*cz + cx*sy*sz; m[10] = cx*cy; m[11] = 0.0;
m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0;
if (glyph && *glyph) if (glyph && *glyph)
transform_glyph_3d(*glyph, m); transform_glyph_3d(*glyph, m, shift);
if (glyph2 && *glyph2) if (glyph2 && *glyph2)
transform_glyph_3d(*glyph2, m); transform_glyph_3d(*glyph2, m, shift);
if (vec)
transform_vector_3d(vec, m);
} }
} }
@ -1650,7 +1701,6 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images)
FT_UInt previous; FT_UInt previous;
FT_UInt num_glyphs; FT_UInt num_glyphs;
FT_Vector pen; FT_Vector pen;
int error;
unsigned code; unsigned code;
FT_BBox bbox; FT_BBox bbox;
int i, j; int i, j;
@ -1708,34 +1758,20 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images)
shift.x = pen.x & 63; shift.x = pen.x & 63;
shift.y = pen.y & 63; shift.y = pen.y & 63;
{ ass_font_set_transform(render_context.font,
FT_Matrix matrix; render_context.scale_x * frame_context.font_scale_x,
matrix.xx = (FT_Fixed)( render_context.scale_x * frame_context.font_scale_x * 0x10000L ); render_context.scale_y,
matrix.xy = (FT_Fixed)( 0 * 0x10000L ); &shift );
matrix.yx = (FT_Fixed)( 0 * 0x10000L );
matrix.yy = (FT_Fixed)( render_context.scale_y * 0x10000L );
ass_font_set_transform(render_context.font, &matrix, &shift ); get_outline_glyph(code, text_info.glyphs + text_info.length, &shift);
}
error = get_glyph(code, text_info.glyphs + text_info.length, &shift); text_info.glyphs[text_info.length].pos.x = pen.x >> 6;
text_info.glyphs[text_info.length].pos.y = pen.y >> 6;
if (error) {
continue;
}
text_info.glyphs[text_info.length].pos.x = d6_to_int(pen.x);
text_info.glyphs[text_info.length].pos.y = d6_to_int(pen.y);
pen.x += text_info.glyphs[text_info.length].advance.x; pen.x += text_info.glyphs[text_info.length].advance.x;
pen.x += double_to_d6(render_context.hspacing); pen.x += double_to_d6(render_context.hspacing);
pen.y += text_info.glyphs[text_info.length].advance.y; pen.y += text_info.glyphs[text_info.length].advance.y;
// if it's an outline glyph, we still need to fill the bbox
if (text_info.glyphs[text_info.length].glyph) {
FT_Glyph_Get_CBox( text_info.glyphs[text_info.length].glyph, FT_GLYPH_BBOX_PIXELS, &(text_info.glyphs[text_info.length].bbox) );
}
previous = code; previous = code;
text_info.glyphs[text_info.length].symbol = code; text_info.glyphs[text_info.length].symbol = code;
@ -1759,6 +1795,21 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images)
text_info.glyphs[text_info.length].asc *= render_context.scale_y; text_info.glyphs[text_info.length].asc *= render_context.scale_y;
text_info.glyphs[text_info.length].desc *= render_context.scale_y; text_info.glyphs[text_info.length].desc *= render_context.scale_y;
// fill bitmap_hash_key
text_info.glyphs[text_info.length].hash_key.font = render_context.font;
text_info.glyphs[text_info.length].hash_key.size = render_context.font_size;
text_info.glyphs[text_info.length].hash_key.outline = render_context.border * 0xFFFF;
text_info.glyphs[text_info.length].hash_key.scale_x = render_context.scale_x * 0xFFFF;
text_info.glyphs[text_info.length].hash_key.scale_y = render_context.scale_y * 0xFFFF;
text_info.glyphs[text_info.length].hash_key.frx = render_context.frx * 0xFFFF;
text_info.glyphs[text_info.length].hash_key.fry = render_context.fry * 0xFFFF;
text_info.glyphs[text_info.length].hash_key.frz = render_context.frz * 0xFFFF;
text_info.glyphs[text_info.length].hash_key.bold = render_context.bold;
text_info.glyphs[text_info.length].hash_key.italic = render_context.italic;
text_info.glyphs[text_info.length].hash_key.ch = code;
text_info.glyphs[text_info.length].hash_key.advance = shift;
text_info.glyphs[text_info.length].hash_key.be = render_context.be;
text_info.length++; text_info.length++;
render_context.effect_type = EF_NONE; render_context.effect_type = EF_NONE;
@ -1797,16 +1848,16 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images)
last_break = -1; last_break = -1;
for (i = 1; i < text_info.length + 1; ++i) { // (text_info.length + 1) is the end of the last line 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) { if ((i == text_info.length) || text_info.glyphs[i].linebreak) {
int width, shift; int width, shift = 0;
glyph_info_t* first_glyph = text_info.glyphs + last_break + 1; glyph_info_t* first_glyph = text_info.glyphs + last_break + 1;
glyph_info_t* last_glyph = text_info.glyphs + i - 1; glyph_info_t* last_glyph = text_info.glyphs + i - 1;
while ((last_glyph > first_glyph) && ((last_glyph->symbol == '\n') || (last_glyph->symbol == 0))) while ((last_glyph > first_glyph) && ((last_glyph->symbol == '\n') || (last_glyph->symbol == 0)))
last_glyph --; last_glyph --;
width = last_glyph->pos.x + last_glyph->bbox.xMax - first_glyph->pos.x - first_glyph->bbox.xMin; width = last_glyph->pos.x + d6_to_int(last_glyph->advance.x) - first_glyph->pos.x;
shift = - first_glyph->bbox.xMin; // now text line starts exactly at 0 (left margin)
if (halign == HALIGN_LEFT) { // left aligned, no action if (halign == HALIGN_LEFT) { // left aligned, no action
shift = 0;
} else if (halign == HALIGN_RIGHT) { // right aligned } else if (halign == HALIGN_RIGHT) { // right aligned
shift = max_text_width - width; shift = max_text_width - width;
} else if (halign == HALIGN_CENTER) { // centered } else if (halign == HALIGN_CENTER) { // centered
@ -1893,13 +1944,13 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images)
render_context.clip_y1 = y2scr(render_context.clip_y1); render_context.clip_y1 = y2scr(render_context.clip_y1);
} }
// rotate glyphs if needed // calculate rotation parameters
{ {
FT_Vector center; FT_Vector center;
if (render_context.have_origin) { if (render_context.have_origin) {
center.x = render_context.org_x; center.x = x2scr(render_context.org_x);
center.y = render_context.org_y; center.y = y2scr(render_context.org_y);
} else { } else {
int bx, by; int bx, by;
get_base_point(bbox, alignment, &bx, &by); get_base_point(bbox, alignment, &bx, &by);
@ -1908,27 +1959,21 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images)
} }
for (i = 0; i < text_info.length; ++i) { for (i = 0; i < text_info.length; ++i) {
FT_Vector start;
FT_Vector start_old;
glyph_info_t* info = text_info.glyphs + i; glyph_info_t* info = text_info.glyphs + i;
// calculating shift vector if (info->hash_key.frx || info->hash_key.fry || info->hash_key.frz) {
// shift = (position - center)*M - (position - center) info->hash_key.shift_x = info->pos.x + device_x - center.x;
start.x = int_to_d6(info->pos.x + device_x - center.x); info->hash_key.shift_y = - (info->pos.y + device_y - center.y);
start.y = - int_to_d6(info->pos.y + device_y - center.y); } else {
start_old.x = start.x; info->hash_key.shift_x = 0;
start_old.y = start.y; info->hash_key.shift_y = 0;
transform_3d(&start, &info->glyph, &info->outline_glyph, info->frx, info->fry, info->frz);
start.x -= start_old.x;
start.y -= start_old.y;
info->pos.x += d6_to_int(start.x);
info->pos.y -= d6_to_int(start.y);
} }
} }
}
// convert glyphs to bitmaps
for (i = 0; i < text_info.length; ++i)
get_bitmap_glyph(text_info.glyphs + i);
event_images->top = device_y - d6_to_int(text_info.lines[0].asc); event_images->top = device_y - d6_to_int(text_info.lines[0].asc);
event_images->height = d6_to_int(text_info.height); event_images->height = d6_to_int(text_info.height);
@ -1959,6 +2004,7 @@ static void ass_reconfigure(ass_renderer_t* priv)
{ {
priv->render_id = ++last_render_id; priv->render_id = ++last_render_id;
ass_glyph_cache_reset(); ass_glyph_cache_reset();
ass_bitmap_cache_reset();
ass_free_images(priv->prev_images_root); ass_free_images(priv->prev_images_root);
priv->prev_images_root = 0; priv->prev_images_root = 0;
} }
@ -2009,6 +2055,14 @@ void ass_set_font_scale(ass_renderer_t* priv, double font_scale)
} }
} }
void ass_set_hinting(ass_renderer_t* priv, ass_hinting_t ht)
{
if (priv->settings.hinting != ht) {
priv->settings.hinting = ht;
ass_reconfigure(priv);
}
}
int ass_set_fonts(ass_renderer_t* priv, const char* default_font, const char* default_family) int ass_set_fonts(ass_renderer_t* priv, const char* default_font, const char* default_family)
{ {
if (priv->settings.default_font) if (priv->settings.default_font)
@ -2047,7 +2101,7 @@ static int ass_start_frame(ass_renderer_t *priv, ass_track_t* track, long long n
ass_lazy_track_init(); ass_lazy_track_init();
frame_context.font_scale = global_settings->font_size_coeff * ass_internal_font_size_coeff * frame_context.font_scale = global_settings->font_size_coeff *
frame_context.orig_height / frame_context.track->PlayResY; frame_context.orig_height / frame_context.track->PlayResY;
frame_context.border_scale = ((double)frame_context.orig_height) / frame_context.track->PlayResY; frame_context.border_scale = ((double)frame_context.orig_height) / frame_context.track->PlayResY;

View File

@ -32,7 +32,7 @@
typedef struct ass_style_s { typedef struct ass_style_s {
char* Name; char* Name;
char* FontName; char* FontName;
int FontSize; double FontSize;
uint32_t PrimaryColour; uint32_t PrimaryColour;
uint32_t SecondaryColour; uint32_t SecondaryColour;
uint32_t OutlineColour; uint32_t OutlineColour;

View File

@ -22,10 +22,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <inttypes.h> #include <inttypes.h>
#ifndef __VISUALC__
#include <sys/time.h>
#endif
#include <time.h>
#include "mputils.h" #include "mputils.h"
#include "ass_utils.h" #include "ass_utils.h"

View File

@ -26,30 +26,36 @@ int mystrtou32(char** p, int base, uint32_t* res);
int mystrtod(char** p, double* res); int mystrtod(char** p, double* res);
int strtocolor(char** q, uint32_t* res); int strtocolor(char** q, uint32_t* res);
static inline int d6_to_int(int x) { static int d6_to_int(int x) {
return (x + 32) >> 6; return (x + 32) >> 6;
} }
static inline int d16_to_int(int x) { static int d16_to_int(int x) {
return (x + 32768) >> 16; return (x + 32768) >> 16;
} }
static inline int int_to_d6(int x) { static int int_to_d6(int x) {
return x << 6; return x << 6;
} }
static inline int int_to_d16(int x) { static int int_to_d16(int x) {
return x << 16; return x << 16;
} }
static inline int d16_to_d6(int x) { static int d16_to_d6(int x) {
return (x + 512) >> 10; return (x + 512) >> 10;
} }
static inline int d6_to_d16(int x) { static int d6_to_d16(int x) {
return x << 10; return x << 10;
} }
static inline double d6_to_double(int x) { static double d6_to_double(int x) {
return x / 64.; return x / 64.;
} }
static inline int double_to_d6(double x) { static int double_to_d6(double x) {
return (int)(x * 64); return (int)(x * 64);
} }
static double d16_to_double(int x) {
return ((double)x) / 0x10000;
}
static int double_to_d16(double x) {
return (int)(x * 0x10000);
}
#endif #endif

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="Windows-1252"?> <?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject <VisualStudioProject
ProjectType="Visual C++" ProjectType="Visual C++"
Version="8.00" Version="8,00"
Name="libass" Name="libass"
ProjectGUID="{8B19F154-54BC-46D6-8443-6BDEF1D438CF}" ProjectGUID="{8B19F154-54BC-46D6-8443-6BDEF1D438CF}"
RootNamespace="libass" RootNamespace="libass"
@ -40,7 +40,7 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="0" Optimization="0"
AdditionalIncludeDirectories="" AdditionalIncludeDirectories=".;win32"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB" PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
MinimalRebuild="true" MinimalRebuild="true"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
@ -107,7 +107,7 @@
/> />
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
AdditionalIncludeDirectories="" AdditionalIncludeDirectories=".;win32"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB" PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
RuntimeLibrary="2" RuntimeLibrary="2"
UsePrecompiledHeader="0" UsePrecompiledHeader="0"

305
libass/win32/inttypes.h Normal file
View File

@ -0,0 +1,305 @@
// ISO C9x compliant inttypes.h for Microsoft Visual Studio
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
//
// Copyright (c) 2006 Alexander Chemeris
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. The name of the author may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef _MSC_VER // [
#error "Use this header only with Microsoft Visual C++ compilers!"
#endif // _MSC_VER ]
#ifndef _MSC_INTTYPES_H_ // [
#define _MSC_INTTYPES_H_
#if _MSC_VER > 1000
#pragma once
#endif
#include <stdint.h>
// 7.8 Format conversion of integer types
typedef struct {
intmax_t quot;
intmax_t rem;
} imaxdiv_t;
// 7.8.1 Macros for format specifiers
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
// The fprintf macros for signed integers are:
#define PRId8 "d"
#define PRIi8 "i"
#define PRIdLEAST8 "d"
#define PRIiLEAST8 "i"
#define PRIdFAST8 "d"
#define PRIiFAST8 "i"
#define PRId16 "hd"
#define PRIi16 "hi"
#define PRIdLEAST16 "hd"
#define PRIiLEAST16 "hi"
#define PRIdFAST16 "hd"
#define PRIiFAST16 "hi"
#define PRId32 "I32d"
#define PRIi32 "I32i"
#define PRIdLEAST32 "I32d"
#define PRIiLEAST32 "I32i"
#define PRIdFAST32 "I32d"
#define PRIiFAST32 "I32i"
#define PRId64 "I64d"
#define PRIi64 "I64i"
#define PRIdLEAST64 "I64d"
#define PRIiLEAST64 "I64i"
#define PRIdFAST64 "I64d"
#define PRIiFAST64 "I64i"
#define PRIdMAX "I64d"
#define PRIiMAX "I64i"
#define PRIdPTR "Id"
#define PRIiPTR "Ii"
// The fprintf macros for unsigned integers are:
#define PRIo8 "o"
#define PRIu8 "u"
#define PRIx8 "x"
#define PRIX8 "X"
#define PRIoLEAST8 "o"
#define PRIuLEAST8 "u"
#define PRIxLEAST8 "x"
#define PRIXLEAST8 "X"
#define PRIoFAST8 "o"
#define PRIuFAST8 "u"
#define PRIxFAST8 "x"
#define PRIXFAST8 "X"
#define PRIo16 "ho"
#define PRIu16 "hu"
#define PRIx16 "hx"
#define PRIX16 "hX"
#define PRIoLEAST16 "ho"
#define PRIuLEAST16 "hu"
#define PRIxLEAST16 "hx"
#define PRIXLEAST16 "hX"
#define PRIoFAST16 "ho"
#define PRIuFAST16 "hu"
#define PRIxFAST16 "hx"
#define PRIXFAST16 "hX"
#define PRIo32 "I32o"
#define PRIu32 "I32u"
#define PRIx32 "I32x"
#define PRIX32 "I32X"
#define PRIoLEAST32 "I32o"
#define PRIuLEAST32 "I32u"
#define PRIxLEAST32 "I32x"
#define PRIXLEAST32 "I32X"
#define PRIoFAST32 "I32o"
#define PRIuFAST32 "I32u"
#define PRIxFAST32 "I32x"
#define PRIXFAST32 "I32X"
#define PRIo64 "I64o"
#define PRIu64 "I64u"
#define PRIx64 "I64x"
#define PRIX64 "I64X"
#define PRIoLEAST64 "I64o"
#define PRIuLEAST64 "I64u"
#define PRIxLEAST64 "I64x"
#define PRIXLEAST64 "I64X"
#define PRIoFAST64 "I64o"
#define PRIuFAST64 "I64u"
#define PRIxFAST64 "I64x"
#define PRIXFAST64 "I64X"
#define PRIoMAX "I64o"
#define PRIuMAX "I64u"
#define PRIxMAX "I64x"
#define PRIXMAX "I64X"
#define PRIoPTR "Io"
#define PRIuPTR "Iu"
#define PRIxPTR "Ix"
#define PRIXPTR "IX"
// The fscanf macros for signed integers are:
#define SCNd8 "d"
#define SCNi8 "i"
#define SCNdLEAST8 "d"
#define SCNiLEAST8 "i"
#define SCNdFAST8 "d"
#define SCNiFAST8 "i"
#define SCNd16 "hd"
#define SCNi16 "hi"
#define SCNdLEAST16 "hd"
#define SCNiLEAST16 "hi"
#define SCNdFAST16 "hd"
#define SCNiFAST16 "hi"
#define SCNd32 "ld"
#define SCNi32 "li"
#define SCNdLEAST32 "ld"
#define SCNiLEAST32 "li"
#define SCNdFAST32 "ld"
#define SCNiFAST32 "li"
#define SCNd64 "I64d"
#define SCNi64 "I64i"
#define SCNdLEAST64 "I64d"
#define SCNiLEAST64 "I64i"
#define SCNdFAST64 "I64d"
#define SCNiFAST64 "I64i"
#define SCNdMAX "I64d"
#define SCNiMAX "I64i"
#ifdef _WIN64 // [
# define SCNdPTR "I64d"
# define SCNiPTR "I64i"
#else // _WIN64 ][
# define SCNdPTR "ld"
# define SCNiPTR "li"
#endif // _WIN64 ]
// The fscanf macros for unsigned integers are:
#define SCNo8 "o"
#define SCNu8 "u"
#define SCNx8 "x"
#define SCNX8 "X"
#define SCNoLEAST8 "o"
#define SCNuLEAST8 "u"
#define SCNxLEAST8 "x"
#define SCNXLEAST8 "X"
#define SCNoFAST8 "o"
#define SCNuFAST8 "u"
#define SCNxFAST8 "x"
#define SCNXFAST8 "X"
#define SCNo16 "ho"
#define SCNu16 "hu"
#define SCNx16 "hx"
#define SCNX16 "hX"
#define SCNoLEAST16 "ho"
#define SCNuLEAST16 "hu"
#define SCNxLEAST16 "hx"
#define SCNXLEAST16 "hX"
#define SCNoFAST16 "ho"
#define SCNuFAST16 "hu"
#define SCNxFAST16 "hx"
#define SCNXFAST16 "hX"
#define SCNo32 "lo"
#define SCNu32 "lu"
#define SCNx32 "lx"
#define SCNX32 "lX"
#define SCNoLEAST32 "lo"
#define SCNuLEAST32 "lu"
#define SCNxLEAST32 "lx"
#define SCNXLEAST32 "lX"
#define SCNoFAST32 "lo"
#define SCNuFAST32 "lu"
#define SCNxFAST32 "lx"
#define SCNXFAST32 "lX"
#define SCNo64 "I64o"
#define SCNu64 "I64u"
#define SCNx64 "I64x"
#define SCNX64 "I64X"
#define SCNoLEAST64 "I64o"
#define SCNuLEAST64 "I64u"
#define SCNxLEAST64 "I64x"
#define SCNXLEAST64 "I64X"
#define SCNoFAST64 "I64o"
#define SCNuFAST64 "I64u"
#define SCNxFAST64 "I64x"
#define SCNXFAST64 "I64X"
#define SCNoMAX "I64o"
#define SCNuMAX "I64u"
#define SCNxMAX "I64x"
#define SCNXMAX "I64X"
#ifdef _WIN64 // [
# define SCNoPTR "I64o"
# define SCNuPTR "I64u"
# define SCNxPTR "I64x"
# define SCNXPTR "I64X"
#else // _WIN64 ][
# define SCNoPTR "lo"
# define SCNuPTR "lu"
# define SCNxPTR "lx"
# define SCNXPTR "lX"
#endif // _WIN64 ]
#endif // __STDC_FORMAT_MACROS ]
// 7.8.2 Functions for greatest-width integer types
// 7.8.2.1 The imaxabs function
#define imaxabs _abs64
// 7.8.2.2 The imaxdiv function
// This is modified version of div() function from Microsoft's div.c found
// in %MSVC.NET%\crt\src\div.c
#ifdef STATIC_IMAXDIV // [
static
#else // STATIC_IMAXDIV ][
_inline
#endif // STATIC_IMAXDIV ]
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
{
imaxdiv_t result;
result.quot = numer / denom;
result.rem = numer % denom;
if (numer < 0 && result.rem > 0) {
// did division wrong; must fix up
++result.quot;
result.rem -= denom;
}
return result;
}
// 7.8.2.3 The strtoimax and strtoumax functions
#define strtoimax _strtoi64
#define strtoumax _strtoui64
// 7.8.2.4 The wcstoimax and wcstoumax functions
#define wcstoimax _wcstoi64
#define wcstoumax _wcstoui64
#endif // _MSC_INTTYPES_H_ ]

222
libass/win32/stdint.h Normal file
View File

@ -0,0 +1,222 @@
// ISO C9x compliant stdint.h for Microsoft Visual Studio
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
//
// Copyright (c) 2006 Alexander Chemeris
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. The name of the author may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef _MSC_VER // [
#error "Use this header only with Microsoft Visual C++ compilers!"
#endif // _MSC_VER ]
#ifndef _MSC_STDINT_H_ // [
#define _MSC_STDINT_H_
#if _MSC_VER > 1000
#pragma once
#endif
#include <limits.h>
// For Visual Studio 6 in C++ mode wrap <wchar.h> include with 'extern "C++" {}'
// or compiler give many errors like this:
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
#if (_MSC_VER < 1300) && defined(__cplusplus)
extern "C++" {
#endif
# include <wchar.h>
#if (_MSC_VER < 1300) && defined(__cplusplus)
}
#endif
// 7.18.1 Integer types
// 7.18.1.1 Exact-width integer types
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
// 7.18.1.2 Minimum-width integer types
typedef int8_t int_least8_t;
typedef int16_t int_least16_t;
typedef int32_t int_least32_t;
typedef int64_t int_least64_t;
typedef uint8_t uint_least8_t;
typedef uint16_t uint_least16_t;
typedef uint32_t uint_least32_t;
typedef uint64_t uint_least64_t;
// 7.18.1.3 Fastest minimum-width integer types
typedef int8_t int_fast8_t;
typedef int16_t int_fast16_t;
typedef int32_t int_fast32_t;
typedef int64_t int_fast64_t;
typedef uint8_t uint_fast8_t;
typedef uint16_t uint_fast16_t;
typedef uint32_t uint_fast32_t;
typedef uint64_t uint_fast64_t;
// 7.18.1.4 Integer types capable of holding object pointers
#ifdef _WIN64 // [
typedef __int64 intptr_t;
typedef unsigned __int64 uintptr_t;
#else // _WIN64 ][
typedef int intptr_t;
typedef unsigned int uintptr_t;
#endif // _WIN64 ]
// 7.18.1.5 Greatest-width integer types
typedef int64_t intmax_t;
typedef uint64_t uintmax_t;
// 7.18.2 Limits of specified-width integer types
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
// 7.18.2.1 Limits of exact-width integer types
#define INT8_MIN ((int8_t)_I8_MIN)
#define INT8_MAX _I8_MAX
#define INT16_MIN ((int16_t)_I16_MIN)
#define INT16_MAX _I16_MAX
#define INT32_MIN ((int32_t)_I32_MIN)
#define INT32_MAX _I32_MAX
#define INT64_MIN ((int64_t)_I64_MIN)
#define INT64_MAX _I64_MAX
#define UINT8_MAX _UI8_MAX
#define UINT16_MAX _UI16_MAX
#define UINT32_MAX _UI32_MAX
#define UINT64_MAX _UI64_MAX
// 7.18.2.2 Limits of minimum-width integer types
#define INT_LEAST8_MIN INT8_MIN
#define INT_LEAST8_MAX INT8_MAX
#define INT_LEAST16_MIN INT16_MIN
#define INT_LEAST16_MAX INT16_MAX
#define INT_LEAST32_MIN INT32_MIN
#define INT_LEAST32_MAX INT32_MAX
#define INT_LEAST64_MIN INT64_MIN
#define INT_LEAST64_MAX INT64_MAX
#define UINT_LEAST8_MAX UINT8_MAX
#define UINT_LEAST16_MAX UINT16_MAX
#define UINT_LEAST32_MAX UINT32_MAX
#define UINT_LEAST64_MAX UINT64_MAX
// 7.18.2.3 Limits of fastest minimum-width integer types
#define INT_FAST8_MIN INT8_MIN
#define INT_FAST8_MAX INT8_MAX
#define INT_FAST16_MIN INT16_MIN
#define INT_FAST16_MAX INT16_MAX
#define INT_FAST32_MIN INT32_MIN
#define INT_FAST32_MAX INT32_MAX
#define INT_FAST64_MIN INT64_MIN
#define INT_FAST64_MAX INT64_MAX
#define UINT_FAST8_MAX UINT8_MAX
#define UINT_FAST16_MAX UINT16_MAX
#define UINT_FAST32_MAX UINT32_MAX
#define UINT_FAST64_MAX UINT64_MAX
// 7.18.2.4 Limits of integer types capable of holding object pointers
#ifdef _WIN64 // [
# define INTPTR_MIN INT64_MIN
# define INTPTR_MAX INT64_MAX
# define UINTPTR_MAX UINT64_MAX
#else // _WIN64 ][
# define INTPTR_MIN INT32_MIN
# define INTPTR_MAX INT32_MAX
# define UINTPTR_MAX UINT32_MAX
#endif // _WIN64 ]
// 7.18.2.5 Limits of greatest-width integer types
#define INTMAX_MIN INT64_MIN
#define INTMAX_MAX INT64_MAX
#define UINTMAX_MAX UINT64_MAX
// 7.18.3 Limits of other integer types
#ifdef _WIN64 // [
# define PTRDIFF_MIN _I64_MIN
# define PTRDIFF_MAX _I64_MAX
#else // _WIN64 ][
# define PTRDIFF_MIN _I32_MIN
# define PTRDIFF_MAX _I32_MAX
#endif // _WIN64 ]
#define SIG_ATOMIC_MIN INT_MIN
#define SIG_ATOMIC_MAX INT_MAX
#ifndef SIZE_MAX // [
# ifdef _WIN64 // [
# define SIZE_MAX _UI64_MAX
# else // _WIN64 ][
# define SIZE_MAX _UI32_MAX
# endif // _WIN64 ]
#endif // SIZE_MAX ]
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
#ifndef WCHAR_MIN // [
# define WCHAR_MIN 0
#endif // WCHAR_MIN ]
#ifndef WCHAR_MAX // [
# define WCHAR_MAX _UI16_MAX
#endif // WCHAR_MAX ]
#define WINT_MIN 0
#define WINT_MAX _UI16_MAX
#endif // __STDC_LIMIT_MACROS ]
// 7.18.4 Limits of other integer types
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
// 7.18.4.1 Macros for minimum-width integer constants
#define INT8_C(val) val##i8
#define INT16_C(val) val##i16
#define INT32_C(val) val##i32
#define INT64_C(val) val##i64
#define UINT8_C(val) val##ui8
#define UINT16_C(val) val##ui16
#define UINT32_C(val) val##ui32
#define UINT64_C(val) val##ui64
// 7.18.4.2 Macros for greatest-width integer constants
#define INTMAX_C INT64_C
#define UINTMAX_C UINT64_C
#endif // __STDC_CONSTANT_MACROS ]
#endif // _MSC_STDINT_H_ ]