From 44da8de898a1e4d03c331ad314ded138583b71bb Mon Sep 17 00:00:00 2001 From: Rodrigo Braz Monteiro Date: Thu, 17 Jan 2008 16:50:19 +0000 Subject: [PATCH] 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. --- libass/ass.c | 10 +- libass/ass.h | 8 + libass/ass_bitmap.c | 2 +- libass/ass_bitmap.h | 2 +- libass/ass_cache.c | 352 +++++++++++++++++++++++++-------------- libass/ass_cache.h | 56 +++++-- libass/ass_font.c | 107 ++++++++---- libass/ass_font.h | 10 +- libass/ass_fontconfig.c | 56 +++---- libass/ass_render.c | 358 +++++++++++++++++++++++----------------- libass/ass_types.h | 2 +- libass/ass_utils.c | 4 - libass/ass_utils.h | 22 ++- libass/libass.vcproj | 6 +- libass/win32/inttypes.h | 305 ++++++++++++++++++++++++++++++++++ libass/win32/stdint.h | 222 +++++++++++++++++++++++++ 16 files changed, 1146 insertions(+), 376 deletions(-) create mode 100644 libass/win32/inttypes.h create mode 100644 libass/win32/stdint.h diff --git a/libass/ass.c b/libass/ass.c index 546e41797..30a305398 100644 --- a/libass/ass.c +++ b/libass/ass.c @@ -27,7 +27,7 @@ #include #include #include -#include +//#include #include #ifdef USE_ICONV @@ -347,7 +347,7 @@ void process_force_style(ass_track_t* track) { COLORVAL(SecondaryColour) COLORVAL(OutlineColour) COLORVAL(BackColour) - INTVAL(FontSize) + FPVAL(FontSize) INTVAL(Bold) INTVAL(Italic) 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 if (track->track_type == TRACK_TYPE_SSA) target->OutlineColour = target->BackColour; - INTVAL(FontSize) + FPVAL(FontSize) INTVAL(Bold) INTVAL(Italic) INTVAL(Underline) @@ -572,8 +572,10 @@ static int decode_font(ass_track_t* track) dsize = q - buf; 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); + buf = 0; + } error_decode_font: if (buf) free(buf); diff --git a/libass/ass.h b/libass/ass.h index 7cba671ff..2e1aa1ab9 100644 --- a/libass/ass.h +++ b/libass/ass.h @@ -37,6 +37,13 @@ typedef struct ass_image_s { struct ass_image_s* next; // linked list } 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 * \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_aspect_ratio(ass_renderer_t* priv, double ar); 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 diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c index 6a686673c..8aa1fe7a6 100644 --- a/libass/ass_bitmap.c +++ b/libass/ass_bitmap.c @@ -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)); } -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)); generate_tables(priv, blur_radius); diff --git a/libass/ass_bitmap.h b/libass/ass_bitmap.h index a4090636c..ba5867f7c 100644 --- a/libass/ass_bitmap.h +++ b/libass/ass_bitmap.h @@ -23,7 +23,7 @@ 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); typedef struct bitmap_s { diff --git a/libass/ass_cache.c b/libass/ass_cache.c index 463fdb50a..797c33887 100644 --- a/libass/ass_cache.c +++ b/libass/ass_cache.c @@ -34,12 +34,156 @@ #include "ass_bitmap.h" #include "ass_cache.h" -#define MAX_FONT_CACHE_SIZE 100 -static ass_font_t** font_cache; -static int font_cache_size; +typedef struct hashmap_item_s { + 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) return 0; 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; } -/** - * \brief Get a face struct from cache. - * \param desc required face description - * \return font struct -*/ +static void font_hash_dtor(void* key, size_t key_size, void* value, size_t value_size) +{ + ass_font_free(value); + free(key); +} + ass_font_t* ass_font_cache_find(ass_font_desc_t* desc) { - int i; - - for (i=0; idesc))) - return font_cache[i]; - - return 0; + return hashmap_find(font_cache, desc); } /** * \brief Add a face struct to cache. * \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) { - mp_msg(MSGT_ASS, MSGL_FATAL, MSGTR_LIBASS_TooManyFonts); - // FIXME: possible memory leak - return; - } - - font_cache[font_cache_size] = font; - font_cache_size++; + return hashmap_insert(font_cache, &(font->desc), font); } void ass_font_cache_init(void) { - font_cache = calloc(MAX_FONT_CACHE_SIZE, sizeof(ass_font_t*)); - font_cache_size = 0; + font_cache = hashmap_init(sizeof(ass_font_desc_t), + sizeof(ass_font_t), + 1000, + font_hash_dtor, font_compare, font_desc_hash); } void ass_font_cache_done(void) { - int i; - 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; + hashmap_done(font_cache); +} + +//--------------------------------- +// 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 -#define GLYPH_HASH_SIZE (0xFFFF + 13) +hashmap_t* glyph_cache; -typedef struct glyph_hash_item_s { - 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) +static void glyph_hash_dtor(void* key, size_t key_size, void* value, size_t value_size) { - unsigned hash = glyph_hash(key); - glyph_hash_item_t** next = glyph_hash_root + (hash % GLYPH_HASH_SIZE); - while (*next) { - if (glyph_compare(key, &((*next)->key))) - return; - 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_val_t* v = value; + if (v->glyph) FT_Done_Glyph(v->glyph); + if (v->outline_glyph) FT_Done_Glyph(v->outline_glyph); + free(key); + free(value); +} - glyph_hash_size ++; -/* 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)); - } */ +void* cache_add_glyph(glyph_hash_key_t* key, glyph_hash_val_t* val) +{ + 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) { - unsigned hash = glyph_hash(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; + return hashmap_find(glyph_cache, key); } void ass_glyph_cache_init(void) { - glyph_hash_root = calloc(GLYPH_HASH_SIZE, sizeof(glyph_hash_item_p)); - glyph_hash_size = 0; + glyph_cache = hashmap_init(sizeof(glyph_hash_key_t), + sizeof(glyph_hash_val_t), + 0xFFFF + 13, + glyph_hash_dtor, NULL, NULL); } void ass_glyph_cache_done(void) { - int i; - 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; + hashmap_done(glyph_cache); } void ass_glyph_cache_reset(void) @@ -217,4 +322,3 @@ void ass_glyph_cache_reset(void) ass_glyph_cache_done(); ass_glyph_cache_init(); } - diff --git a/libass/ass_cache.h b/libass/ass_cache.h index a4a5bf4ce..caa750a54 100644 --- a/libass/ass_cache.h +++ b/libass/ass_cache.h @@ -23,40 +23,76 @@ void ass_font_cache_init(void); 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); -// describes a glyph; glyphs with equivalents structs are considered identical -typedef struct glyph_hash_key_s { +// describes a bitmap; bitmaps with equivalents structs are considered identical +typedef struct bitmap_hash_key_s { char bitmap; // bool : true = bitmap, false = outline ass_font_t* font; - int size; // font size + double size; // font size uint32_t ch; // character code unsigned outline; // border width, 16.16 fixed point value int bold, italic; char be; // blur edges - // the following affects bitmap glyphs only unsigned scale_x, scale_y; // 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 +} 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; typedef struct glyph_hash_val_s { - bitmap_t* bm; // the actual glyph bitmaps - bitmap_t* bm_o; - bitmap_t* bm_s; + FT_Glyph glyph; + FT_Glyph outline_glyph; 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; 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); void ass_glyph_cache_reset(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 diff --git a/libass/ass_font.c b/libass/ass_font.c index 285ecde63..493a28317 100644 --- a/libass/ass_font.c +++ b/libass/ass_font.c @@ -25,6 +25,7 @@ #include FT_FREETYPE_H #include FT_SYNTHESIS_H #include FT_GLYPH_H +#include FT_TRUETYPE_TABLES_H #include "ass.h" #include "ass_library.h" @@ -32,6 +33,7 @@ #include "ass_bitmap.h" #include "ass_cache.h" #include "ass_fontconfig.h" +#include "ass_utils.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 */ @@ -83,12 +96,13 @@ ass_font_t* ass_font_new(ass_library_t* library, FT_Library ftlibrary, void* fc_ int index; FT_Face face; int error; - ass_font_t* font; + ass_font_t* fontp; + ass_font_t font; int mem_idx; - font = ass_font_cache_find(desc); - if (font) - return font; + fontp = ass_font_cache_find(desc); + if (fontp) + return fontp; 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); - font = calloc(1, sizeof(ass_font_t)); - font->ftlibrary = ftlibrary; - font->faces[0] = face; - font->n_faces = 1; - font->desc.family = strdup(desc->family); - font->desc.bold = desc->bold; - font->desc.italic = desc->italic; + font.ftlibrary = ftlibrary; + font.faces[0] = face; + font.n_faces = 1; + font.desc.family = strdup(desc->family); + font.desc.bold = desc->bold; + font.desc.italic = desc->italic; - font->m.xx = font->m.yy = (FT_Fixed)0x10000L; - font->m.xy = font->m.yy = 0; - font->v.x = font->v.y = 0; - font->size = 0; + font.scale_x = font.scale_y = 1.; + font.v.x = font.v.y = 0; + font.size = 0.; #ifdef HAVE_FONTCONFIG - font->charset = FcCharSetCreate(); + font.charset = FcCharSetCreate(); #endif - ass_font_cache_add(font); - - return font; + return ass_font_cache_add(&font); } /** * \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->m.xx = m->xx; - font->m.xy = m->xy; - font->m.yx = m->yx; - font->m.yy = m->yy; + font->scale_x = scale_x; + font->scale_y = scale_y; font->v.x = v->x; font->v.y = v->y; - for (i = 0; i < font->n_faces; ++i) - FT_Set_Transform(font->faces[i], &font->m, &font->v); + update_transform(font); +} + +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 **/ -void ass_font_set_size(ass_font_t* font, int size) +void ass_font_set_size(ass_font_t* font, double size) { int i; if (font->size != size) { font->size = size; 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; - - FT_Set_Transform(face, &font->m, &font->v); - FT_Set_Pixel_Sizes(face, 0, font->size); + update_transform(font); + FT_Set_Pixel_Sizes(face, 0, (int)font->size); } #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 * \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 index = 0; int i; FT_Glyph glyph; FT_Face face = 0; + int flags = 0; if (ch < 0x20) return 0; @@ -264,7 +296,14 @@ FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch } #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) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph); return 0; diff --git a/libass/ass_font.h b/libass/ass_font.h index 5d986e9f0..85c0218bd 100644 --- a/libass/ass_font.h +++ b/libass/ass_font.h @@ -38,19 +38,19 @@ typedef struct ass_font_s { FT_Library ftlibrary; FT_Face faces[ASS_FONT_MAX_FACES]; int n_faces; - FT_Matrix m; // current transformation + double scale_x, scale_y; // current transform FT_Vector v; // current shift - int size; + double size; #ifdef HAVE_FONTCONFIG FcCharSet* charset; #endif } ass_font_t; 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_size(ass_font_t* font, int size); +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, double size); void ass_font_get_asc_desc(ass_font_t* font, uint32_t ch, int* asc, int* desc); -FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch); +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); void ass_font_free(ass_font_t* font); diff --git a/libass/ass_fontconfig.c b/libass/ass_fontconfig.c index 9dd832501..e1579de4c 100644 --- a/libass/ass_fontconfig.c +++ b/libass/ass_fontconfig.c @@ -65,19 +65,20 @@ static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold { FcBool rc; FcResult result; - FcPattern *pat, *rpat; + FcPattern *pat = 0, *rpat; int val_i; FcChar8* val_s; FcBool val_b; FcCharSet* val_cs; - FcFontSet* fset; + FcFontSet* fset = 0; int curf, bestf, bestdiff = 0; + char* retval = 0; *index = 0; pat = FcPatternCreate(); if (!pat) - return 0; + goto error; FcPatternAddString(pat, FC_FAMILY, (const FcChar8*)family); 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); if (!rc) - return 0; + goto error; 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) - return 0; + goto error; rpat = fset->fonts[bestf]; result = FcPatternGetInteger(rpat, FC_INDEX, 0, &val_i); if (result != FcResultMatch) - return 0; + goto error; *index = val_i; result = FcPatternGetString(rpat, FC_FAMILY, 0, &val_s); if (result != FcResultMatch) - return 0; + goto error; if (strcasecmp((const char*)val_s, family) != 0) 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); 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); } +#if (FC_VERSION < 20402) static char* validate_fname(char* name) { char* fname; @@ -227,6 +233,7 @@ static char* validate_fname(char* name) *q = 0; return fname; } +#endif /** * \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) { - char buf[1000]; - FILE* fp = 0; int rc; - struct stat st; - char* fname; const char* name = library->fontdata[idx].name; const char* data = library->fontdata[idx].data; 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) + struct stat st; + char* fname; + const char* fonts_dir = library->fonts_dir; + char buf[1000]; + FILE* fp = 0; + if (!fonts_dir) return; 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); #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); 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) { int rc; - struct stat st; fc_instance_t* priv = calloc(1, sizeof(fc_instance_t)); const char* dir = library->fonts_dir; 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->path_default = path ? strdup(path) : 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; - else - priv->path_default = 0; -#endif return priv; } diff --git a/libass/ass_render.c b/libass/ass_render.c index 307bc2af1..a592dccf4 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -56,6 +56,7 @@ typedef struct ass_settings_s { int use_margins; // 0 - place all subtitles inside original frame // 1 - use margins for placing toptitles and subtitles double aspect; // frame aspect ratio, d_width / d_height. + ass_hinting_t hinting; char* default_font; char* default_family; @@ -112,7 +113,7 @@ typedef struct glyph_info_s { int shadow; double frx, fry, frz; // rotation - glyph_hash_key_t hash_key; + bitmap_hash_key_t hash_key; } glyph_info_t; typedef struct line_info_s { @@ -136,7 +137,7 @@ typedef struct render_context_s { ass_font_t* font; char* font_path; - int font_size; + double font_size; FT_Stroker stroker; 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 ass_font_cache_init(); + ass_bitmap_cache_init(); ass_glyph_cache_init(); 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) { ass_font_cache_done(); + ass_bitmap_cache_done(); ass_glyph_cache_done(); if (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 - * Rasterize glyphs and put them in glyph cache. + * \brief Convert text_info_t struct to ass_image_t list + * 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) { int pen_x, pen_y; - int i, error; + int i; bitmap_t* bm; - glyph_hash_val_t hash_val; ass_image_t* 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) { glyph_info_t* info = text_info->glyphs + i; 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. */ -static inline int mystrcmp(char** p, const char* sample) { +static int mystrcmp(char** p, const char* sample) { int len = strlen(sample); if (strncmp(*p, sample, len) == 0) { (*p) += len; @@ -530,9 +506,7 @@ static inline int mystrcmp(char** p, const char* sample) { return 0; } -double ass_internal_font_size_coeff = 0.8; - -static void change_font_size(int sz) +static void change_font_size(double sz) { double size = sz * frame_context.font_scale; @@ -568,6 +542,7 @@ static void update_font(void) desc.italic = val; render_context.font = ass_font_new(priv->library, priv->ftlibrary, priv->fontconfig_priv, &desc); + free(desc.family); if (render_context.font) change_font_size(render_context.font_size); @@ -680,7 +655,7 @@ static unsigned interpolate_alpha(long long now, return a; } -static void reset_render_context(); +static void reset_render_context(void); /** * \brief Parse style override tag. @@ -719,8 +694,8 @@ static char* parse_tag(char* p, double pwr) { else render_context.hspacing = render_context.style->Spacing; } else if (mystrcmp(&p, "fs")) { - int val; - if (mystrtoi(&p, 10, &val)) + double val; + if (mystrtod(&p, &val)) val = render_context.font_size * ( 1 - pwr ) + val * pwr; else val = render_context.style->FontSize; @@ -834,7 +809,7 @@ static char* parse_tag(char* p, double pwr) { } else render_context.alignment = render_context.style->Alignment; } else if (mystrcmp(&p, "a")) { - int val = strtol(p, &p, 10); + int val; if (mystrtoi(&p, 10, &val) && val) render_context.alignment = val; else @@ -927,11 +902,14 @@ static char* parse_tag(char* p, double pwr) { if (v3 < 0.) v3 = 0.; t = frame_context.time - render_context.event->Start; // FIXME: move to render_context - if (t < t1) + if (t <= t1) k = 0.; - else if (t > t2) + else if (t >= t2) 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 == '\\') 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 @@ -1219,70 +1197,121 @@ static void free_render_context(void) } /** - * \brief Get normal and outline glyphs from cache (if possible) or font face - * \param index face glyph index + * \brief Get normal and outline (border) glyphs * \param symbol ucs4 char * \param info out: struct filled with extracted data - * \param advance advance vector of the extracted glyph - * \return 0 on success + * \param advance subpixel shift vector used for cache lookup + * 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; glyph_hash_val_t* val; - glyph_hash_key_t* key = &(info->hash_key); - - 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; + 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; - val = cache_find_glyph(key); -// val = 0; - + info->glyph = info->outline_glyph = 0; + + val = cache_find_glyph(&key); if (val) { - info->glyph = info->outline_glyph = 0; - info->bm = val->bm; - info->bm_o = val->bm_o; - info->bm_s = val->bm_s; + 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->advance.x = val->advance.x; info->advance.y = val->advance.y; + } else { + glyph_hash_val_t v; + info->glyph = ass_font_get_glyph(frame_context.ass_priv->fontconfig_priv, render_context.font, symbol, global_settings->hinting); + if (!info->glyph) + return; + info->advance.x = d16_to_d6(info->glyph->advance.x); + info->advance.y = d16_to_d6(info->glyph->advance.y); + FT_Glyph_Get_CBox( info->glyph, FT_GLYPH_BBOX_PIXELS, &info->bbox); - return 0; + if (render_context.stroker) { + info->outline_glyph = info->glyph; + error = FT_Glyph_StrokeBorder( &(info->outline_glyph), render_context.stroker, 0 , 0 ); // don't destroy original + if (error) { + mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FT_Glyph_Stroke_Error, error); + } + } + + 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); } +} - // 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); +static void transform_3d(FT_Vector shift, FT_Glyph* glyph, FT_Glyph* glyph2, double frx, double fry, double frz); - info->outline_glyph = 0; - info->bm = info->bm_o = info->bm_s = 0; +/** + * \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; - info->glyph = ass_font_get_glyph(frame_context.ass_priv->fontconfig_priv, render_context.font, symbol); - if (!info->glyph) - return 0; + 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); - info->advance.x = d16_to_d6(info->glyph->advance.x); - info->advance.y = d16_to_d6(info->glyph->advance.y); + // 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; - if (render_context.stroker) { - info->outline_glyph = info->glyph; - error = FT_Glyph_Stroke( &(info->outline_glyph), render_context.stroker, 0 ); // don't destroy original - if (error) { - mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FT_Glyph_Stroke_Error, error); + // 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); } } - - return 0; + // 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[].desc */ -static void measure_text() +static void measure_text(void) { int cur_line = 0, max_asc = 0, max_desc = 0; int i; @@ -1386,6 +1415,11 @@ static void wrap_lines_smart(int max_text_width) if (cur->symbol == ' ') 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)) 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 * 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[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 * 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]; a[0] = d6_to_double(v->x); a[1] = d6_to_double(v->y); a[2] = 0.; a[3] = 1.; 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) b[3] = b[3] < 0. ? -0.001 : 0.001; 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 * 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; FT_Outline* outline = &((FT_OutlineGlyph)glyph)->outline; + FT_Vector* p = outline->points; - for (i=0; in_points; i++) - transform_vector_3d(outline->points + i, m); + for (i=0; in_points; i++) { + 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 - * \param vec FreeType vector + * \param shift FreeType vector * \param glyph FreeType glyph * \param glyph2 FreeType glyph * \param frx x-axis rotation angle * \param fry y-axis rotation angle * \param frz z-axis rotation angle - * Rotates 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.) { double m[16]; 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 cy = cos(fry); 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[4] = -sz*cy; m[5] = cz*cx - sz*sy*sx; m[6] = sz*sy*cx + cz*sx; m[7] = 0.0; - m[8] = sy; m[9] = -sx*cy; 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[0] = cy * cz; m[1] = cy*sz; m[2] = -sy; m[3] = 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] = 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; if (glyph && *glyph) - transform_glyph_3d(*glyph, m); + transform_glyph_3d(*glyph, m, shift); if (glyph2 && *glyph2) - transform_glyph_3d(*glyph2, m); - - if (vec) - transform_vector_3d(vec, m); + transform_glyph_3d(*glyph2, m, shift); } } @@ -1650,7 +1701,6 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images) FT_UInt previous; FT_UInt num_glyphs; FT_Vector pen; - int error; unsigned code; FT_BBox bbox; 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.y = pen.y & 63; - { - FT_Matrix matrix; - matrix.xx = (FT_Fixed)( render_context.scale_x * frame_context.font_scale_x * 0x10000L ); - matrix.xy = (FT_Fixed)( 0 * 0x10000L ); - matrix.yx = (FT_Fixed)( 0 * 0x10000L ); - matrix.yy = (FT_Fixed)( render_context.scale_y * 0x10000L ); + ass_font_set_transform(render_context.font, + render_context.scale_x * frame_context.font_scale_x, + render_context.scale_y, + &shift ); - 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); - - 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); + text_info.glyphs[text_info.length].pos.x = pen.x >> 6; + text_info.glyphs[text_info.length].pos.y = pen.y >> 6; pen.x += text_info.glyphs[text_info.length].advance.x; pen.x += double_to_d6(render_context.hspacing); 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; 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].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++; 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; 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) { - int width, shift; + int width, shift = 0; glyph_info_t* first_glyph = text_info.glyphs + last_break + 1; glyph_info_t* last_glyph = text_info.glyphs + i - 1; while ((last_glyph > first_glyph) && ((last_glyph->symbol == '\n') || (last_glyph->symbol == 0))) last_glyph --; - width = last_glyph->pos.x + last_glyph->bbox.xMax - first_glyph->pos.x - first_glyph->bbox.xMin; - shift = - first_glyph->bbox.xMin; // now text line starts exactly at 0 (left margin) + width = last_glyph->pos.x + d6_to_int(last_glyph->advance.x) - first_glyph->pos.x; if (halign == HALIGN_LEFT) { // left aligned, no action + shift = 0; } else if (halign == HALIGN_RIGHT) { // right aligned shift = max_text_width - width; } 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); } - // rotate glyphs if needed + // calculate rotation parameters { FT_Vector center; if (render_context.have_origin) { - center.x = render_context.org_x; - center.y = render_context.org_y; + center.x = x2scr(render_context.org_x); + center.y = y2scr(render_context.org_y); } else { int bx, by; get_base_point(bbox, alignment, &bx, &by); @@ -1908,28 +1959,22 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images) } for (i = 0; i < text_info.length; ++i) { - FT_Vector start; - FT_Vector start_old; glyph_info_t* info = text_info.glyphs + i; - // calculating shift vector - // shift = (position - center)*M - (position - center) - start.x = int_to_d6(info->pos.x + device_x - center.x); - start.y = - int_to_d6(info->pos.y + device_y - center.y); - start_old.x = start.x; - start_old.y = start.y; - - 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); - + if (info->hash_key.frx || info->hash_key.fry || info->hash_key.frz) { + info->hash_key.shift_x = info->pos.x + device_x - center.x; + info->hash_key.shift_y = - (info->pos.y + device_y - center.y); + } else { + info->hash_key.shift_x = 0; + info->hash_key.shift_y = 0; + } } } + // 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->height = d6_to_int(text_info.height); event_images->detect_collisions = render_context.detect_collisions; @@ -1959,6 +2004,7 @@ static void ass_reconfigure(ass_renderer_t* priv) { priv->render_id = ++last_render_id; ass_glyph_cache_reset(); + ass_bitmap_cache_reset(); ass_free_images(priv->prev_images_root); 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) { 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(); - 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.border_scale = ((double)frame_context.orig_height) / frame_context.track->PlayResY; diff --git a/libass/ass_types.h b/libass/ass_types.h index e39a24553..0795d5637 100644 --- a/libass/ass_types.h +++ b/libass/ass_types.h @@ -32,7 +32,7 @@ typedef struct ass_style_s { char* Name; char* FontName; - int FontSize; + double FontSize; uint32_t PrimaryColour; uint32_t SecondaryColour; uint32_t OutlineColour; diff --git a/libass/ass_utils.c b/libass/ass_utils.c index cfa8ba4e0..3be71b8f3 100644 --- a/libass/ass_utils.c +++ b/libass/ass_utils.c @@ -22,10 +22,6 @@ #include #include -#ifndef __VISUALC__ -#include -#endif -#include #include "mputils.h" #include "ass_utils.h" diff --git a/libass/ass_utils.h b/libass/ass_utils.h index 6c4eccecd..252e5a8ee 100644 --- a/libass/ass_utils.h +++ b/libass/ass_utils.h @@ -26,30 +26,36 @@ int mystrtou32(char** p, int base, uint32_t* res); int mystrtod(char** p, double* 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; } -static inline int d16_to_int(int x) { +static int d16_to_int(int x) { return (x + 32768) >> 16; } -static inline int int_to_d6(int x) { +static int int_to_d6(int x) { return x << 6; } -static inline int int_to_d16(int x) { +static int int_to_d16(int x) { return x << 16; } -static inline int d16_to_d6(int x) { +static int d16_to_d6(int x) { return (x + 512) >> 10; } -static inline int d6_to_d16(int x) { +static int d6_to_d16(int x) { return x << 10; } -static inline double d6_to_double(int x) { +static double d6_to_double(int x) { return x / 64.; } -static inline int double_to_d6(double x) { +static int double_to_d6(double x) { 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 diff --git a/libass/libass.vcproj b/libass/libass.vcproj index 8f9d74c5f..a1ed2bd5f 100644 --- a/libass/libass.vcproj +++ b/libass/libass.vcproj @@ -1,7 +1,7 @@ 1000 +#pragma once +#endif + +#include + +// 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_ ] diff --git a/libass/win32/stdint.h b/libass/win32/stdint.h new file mode 100644 index 000000000..7e200dc6f --- /dev/null +++ b/libass/win32/stdint.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 + +// For Visual Studio 6 in C++ mode wrap 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 +#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 +#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_ ]