mirror of https://github.com/odrling/Aegisub
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:
parent
f4c2ffac54
commit
44da8de898
10
libass/ass.c
10
libass/ass.c
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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_ ]
|
|
@ -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_ ]
|
Loading…
Reference in New Issue