diff options
author | Sébastien Brochet <blinkseb@xbmc.org> | 2013-10-12 14:21:47 +0200 |
---|---|---|
committer | Sébastien Brochet <blinkseb@xbmc.org> | 2013-11-02 10:06:53 +0100 |
commit | cbc97145fb8f5ca75c6fca78997330ff03d1f7f2 (patch) | |
tree | 6958d12671206d9b6229e4c7faceedcc7bacdb5c /lib | |
parent | 9b3ff6654e94394a4a5ddef356e6ffbdb63548d6 (diff) |
Remove libass from repository
Diffstat (limited to 'lib')
44 files changed, 0 insertions, 12369 deletions
diff --git a/lib/libass/COPYING b/lib/libass/COPYING deleted file mode 100644 index 8351a30e3a..0000000000 --- a/lib/libass/COPYING +++ /dev/null @@ -1,11 +0,0 @@ -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/lib/libass/Changelog b/lib/libass/Changelog deleted file mode 100644 index ef31e60586..0000000000 --- a/lib/libass/Changelog +++ /dev/null @@ -1,109 +0,0 @@ -libass (0.10.0) - * Bidirectional layout and Arabic shaping via FriBidi (GC #13) - * OpenType shaping via HarfBuzz-ng (GC #13) - * Add API for shaper configuration - * Add support for `Language' Script Info property, this can be used for - hinting the text language - * Vertical layout improvements - * Use `vert' and `vkna' OpenType features for vertical glyph variants - * Position rotated glyphs onto baseline - * Parse font encoding property for base text direction hinting - * Refactor cache system - * Use generic outlines in place of FreeType glyphs - * Direct outline bitmap rendering - * Fix whitespace trimming (GC #35) - * Do not render border if there's no shadow or glyph (GC #29) - * Adjust spacing after a italic to non-italic style change (GC #37) - * Fix fade timing - * Fix x positioning with borders (GC #27) - * Build system tweaks - -libass (0.9.12) - * Switch to permissive (ISC) license - * Support \fs+ and \fs- syntax for modifying font size - * Fix word-wrapping - * Improved charmap fallback matching - * Handle a few more VSFilter quirks correctly - * Add a sensible default style - * Fix compilation against libpng 1.5 - -libass (0.9.11) - * Fix serious memory leaks - * Reduce frame/drawing initialization overhead - -libass (0.9.10) - * Basic (incorrect, but working) support for @font vertical text layout - * Fix multiple faces per font attachment - * charmap selection fixes - * Add ass_flush_events API function - * Improve fullname font matching - * Better PAR correction if text transforms are used - * Calculate drawing bounding box like VSFilter - * Performance improvements - * Cache vector clip masks - * Avoid unnecessary glyph copies - * Various rendering fixes - -libass (0.9.9) - * Parse numbers in a locale-independent way - * Remove support for freetype < 2.2.1, fontconfig < 2.4.1; this especially - means libass will not extract fonts into the file system anymore - * Disable script file size limit - * Match fonts against the full name ("name for humans") - * Reset clip mode after \iclip - * Improve VSFilter compatibility - * Update API documentation - * A couple of smaller fixes and cleanups - -libass (0.9.8) - * Support \q override tag - * Support wrap style 1 (i.e. wrap, but do not equalize line lengths) - * Support border style 3 (opaque box) - * Use the event bounding box (instead of vertical position and height) for - collision detection - * Embold glyphs if no bold variant is available, but was requested - * Modify \fax to be similar to VSFilter - * Trim spaces after line wrapping - * Fix border/shadow overlap combining in some cases - * Disable kerning by default. Use "Kerning=yes" style override or - "Kerning: yes" in [Script Info] to enable it - * Slight bitmap handling optimizations - * Various bugfixes - -libass (0.9.7) - * Build system fixes - * Fixed cache lookup and overload problems - * All globals have been eliminated, libass is reentrant - * Dynamically allocate glyph and line buffers - * Fix up stroking of big borders - * Support empty lines (\N\N) - * Support for the following override tags: - \fax, \fay, \xshad, \yshad, \ybord, \xbord, \iclip, \u, \s, \p, \pbo - * Full subpixel accuracy for positioning - * PAR and rotation correction for EOSD rendering - * Drawing mode (including vector \clip and \iclip) - * Fixed a few memory leaks - * Removed MPlayer compatibility code - * Introduced message handling callback - * Various fixes to match VSFilter quirks and Windows font metrics - * Lots of bugfixes - -LibASS (0.9.6) - * Various fixes and updates to match VSFilter renderer. - * Support \blur tag and ScaledBordersAndShadow property. - * Fractional arguments and subpixel accuracy. - * Keep positions when pan-and-scan is used. - * Lots of bugfixes and other changes. - -LibASS (0.9.5) - * Support '=' and '.' in style name in arguments to ass_set_style_overrides(). - * Allow overriding [Script Info] parameters with ass_set_style_overrides(). - * Add workarounds for some buggy fonts. - * Remove buggy workarounds for some other fonts. - * Fixed ass_set_line_spacing() (was broken before). - * Negative margin sizes are now used for image cropping. - * Better handling of behind-the-camera objects. - * Case insensitive parsing of SSA/ASS section headers. - * Improved font matching. - * When 2 styles have the same name, the later one is used. - * Fixed several other bugs. diff --git a/lib/libass/Makefile.am b/lib/libass/Makefile.am deleted file mode 100644 index 5a17a08309..0000000000 --- a/lib/libass/Makefile.am +++ /dev/null @@ -1,13 +0,0 @@ -ACLOCAL_AMFLAGS = -I m4 -AUTOMAKE_OPTIONS = foreign -EXTRA_DIST = libass.pc.in Changelog - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libass.pc - -if HAVE_LIBPNG - test = test -endif - -SUBDIRS = libass $(test) - diff --git a/lib/libass/configure.ac b/lib/libass/configure.ac deleted file mode 100644 index 35548c6291..0000000000 --- a/lib/libass/configure.ac +++ /dev/null @@ -1,118 +0,0 @@ -AC_INIT(libass, 0.10.0) -AM_INIT_AUTOMAKE -AC_CONFIG_MACRO_DIR([m4]) -# Disable C++/Fortran checks -define([AC_LIBTOOL_LANG_CXX_CONFIG], [:]) -define([AC_LIBTOOL_LANG_F77_CONFIG], [:]) -AC_PROG_LIBTOOL -AC_CONFIG_SRCDIR([libass/ass.c]) -AC_CONFIG_HEADER([config.h]) - -# Checks for programs. -AC_PROG_CC -AC_PROG_CPP -AM_PROG_CC_C_O - -# Checks for header files. -AC_HEADER_STDC -AC_HEADER_STDBOOL -AC_CHECK_HEADERS([inttypes.h stdint.h stdlib.h string.h sys/time.h unistd.h iconv.h]) - -# Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST -AC_C_INLINE -AC_TYPE_INT64_T -AC_TYPE_SIZE_T -AC_TYPE_UINT32_T -AC_TYPE_UINT8_T - -# Checks for library functions. -AC_CHECK_FUNCS([mkdir strcasecmp strdup strtol]) - -# Checks for libraries. -AC_SEARCH_LIBS([iconv_open], [iconv], AC_DEFINE(CONFIG_ICONV, 1, [use iconv])) -AC_CHECK_LIB([m], [fabs]) - -# Check for libraries via pkg-config -AC_ARG_ENABLE([test], AS_HELP_STRING([--enable-test], - [enable test program (requires libpng) @<:@default=no@:>@])) -AC_ARG_ENABLE([enca], AS_HELP_STRING([--disable-enca], - [disable enca (charset autodetect) support @<:@default=check@:>@])) -AC_ARG_ENABLE([fontconfig], AS_HELP_STRING([--disable-fontconfig], - [disable fontconfig support @<:@default=enabled@:>@])) -AC_ARG_ENABLE([harfbuzz], AS_HELP_STRING([--disable-harfbuzz], - [disable HarfBuzz support @<:@default=check@:>@])) - -PKG_CHECK_MODULES([FREETYPE], freetype2 >= 9.10.3, [ - CFLAGS="$CFLAGS $FREETYPE_CFLAGS" - LIBS="$LIBS $FREETYPE_LIBS" - AC_DEFINE(CONFIG_FREETYPE, 1, [found freetype2 via pkg-config]) - ]) - -PKG_CHECK_MODULES([FRIBIDI], fribidi >= 0.19.0, [ - CFLAGS="$CFLAGS $FRIBIDI_CFLAGS" - LIBS="$LIBS $FRIBIDI_LIBS" - AC_DEFINE(CONFIG_FRIBIDI, 1, [found fribidi via pkg-config]) - ]) - -if test x$enable_fontconfig != xno; then -PKG_CHECK_MODULES([FONTCONFIG], fontconfig >= 2.4.2, [ - CFLAGS="$CFLAGS $FONTCONFIG_CFLAGS" - LIBS="$LIBS $FONTCONFIG_LIBS" - AC_DEFINE(CONFIG_FONTCONFIG, 1, [found fontconfig via pkg-config]) - fontconfig=true - ]) -fi - -if test x$enable_harfbuzz != xno; then -PKG_CHECK_MODULES([HARFBUZZ], harfbuzz >= 0.7.0, [ - CFLAGS="$CFLAGS $HARFBUZZ_CFLAGS" - LIBS="$LIBS $HARFBUZZ_LIBS" - AC_DEFINE(CONFIG_HARFBUZZ, 1, [found harfbuzz-ng via pkg-config]) - harfbuzz=true - ], [harfbuzz=false]) -fi - -if test x$enable_enca != xno; then -PKG_CHECK_MODULES([ENCA], enca, [ - CFLAGS="$CFLAGS $ENCA_CFLAGS" - LIBS="$LIBS $ENCA_LIBS" - AC_DEFINE(CONFIG_ENCA, 1, [found enca via pkg-config]) - enca=true - ], [enca=false]) -fi - -libpng=false -if test x$enable_test = xyes; then -PKG_CHECK_MODULES([LIBPNG], libpng >= 1.2.0, [ - CFLAGS="$CFLAGS $LIBPNG_CFLAGS" - AC_DEFINE(CONFIG_LIBPNG, 1, [found libpng via pkg-config]) - libpng=true]) -fi - -AM_CONDITIONAL([HAVE_LIBPNG], [test x$libpng = xtrue]) - -# add libraries/packages to pkg-config for static linking -pkg_libs="-lm" -pkg_requires="freetype2 >= 9.6.3" -pkg_requires="fribidi >= 0.19.0, ${pkg_requires}" -if test x$enca = xtrue; then - pkg_requires="enca, ${pkg_requires}" -fi -if test x$fontconfig = xtrue; then - pkg_requires="fontconfig >= 2.2.0, ${pkg_requires}" -fi -if test x$harfbuzz = xtrue; then - pkg_requires="harfbuzz >= 0.7.0, ${pkg_requires}" -fi - -AC_SUBST([PKG_LIBS_DEFAULT], [$(test x$enable_shared = xno && echo ${pkg_libs})]) -AC_SUBST([PKG_REQUIRES_DEFAULT], [$(test x$enable_shared = xno && echo ${pkg_requires})]) -AC_SUBST([PKG_LIBS_PRIVATE], [$(test x$enable_shared = xno || echo ${pkg_libs})]) -AC_SUBST([PKG_REQUIRES_PRIVATE], [$(test x$enable_shared = xno || echo ${pkg_requires})]) - -# Setup output beautifier. -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) - -AC_CONFIG_FILES([Makefile libass/Makefile test/Makefile libass.pc]) -AC_OUTPUT diff --git a/lib/libass/libass.pc.in b/lib/libass/libass.pc.in deleted file mode 100644 index e08783516b..0000000000 --- a/lib/libass/libass.pc.in +++ /dev/null @@ -1,13 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libass -Description: LibASS is an SSA/ASS subtitles rendering library -Version: @PACKAGE_VERSION@ -Requires: @PKG_REQUIRES_DEFAULT@ -Requires.private: @PKG_REQUIRES_PRIVATE@ -Libs: -L${libdir} -lass @PKG_LIBS_DEFAULT@ -Libs.private: @PKG_LIBS_PRIVATE@ -Cflags: -I${includedir} diff --git a/lib/libass/libass/Makefile.am b/lib/libass/libass/Makefile.am deleted file mode 100644 index 142de68fbb..0000000000 --- a/lib/libass/libass/Makefile.am +++ /dev/null @@ -1,21 +0,0 @@ -AM_CFLAGS = -Wall - -LIBASS_LT_CURRENT = 5 -LIBASS_LT_REVISION = 0 -LIBASS_LT_AGE = 1 - -lib_LTLIBRARIES = libass.la -libass_la_SOURCES = ass.c ass_cache.c ass_font.c ass_fontconfig.c ass_render.c \ - ass_utils.c ass_bitmap.c ass_library.c ass_bitmap.h \ - ass_cache.h ass_fontconfig.h ass_font.h ass.h \ - ass_library.h ass_types.h ass_utils.h ass_drawing.c \ - ass_drawing.h ass_cache_template.h ass_render.h \ - ass_parse.c ass_parse.h ass_render_api.c ass_shaper.c \ - ass_shaper.h ass_strtod.c -libass_la_LDFLAGS = -version-info $(LIBASS_LT_CURRENT):$(LIBASS_LT_REVISION):$(LIBASS_LT_AGE) -libass_la_LDFLAGS += -export-symbols $(srcdir)/libass.sym - -assheadersdir = $(includedir)/ass -dist_assheaders_HEADERS = ass.h ass_types.h - -EXTRA_DIST = libass.sym diff --git a/lib/libass/libass/ass.c b/lib/libass/libass/ass.c deleted file mode 100644 index 66868f27f5..0000000000 --- a/lib/libass/libass/ass.c +++ /dev/null @@ -1,1320 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "config.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#ifndef _WIN32 -#include <strings.h> -#endif -#include <assert.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <inttypes.h> -#include <ctype.h> - -#ifdef CONFIG_ICONV -#include <iconv.h> -#endif - -#include "ass.h" -#include "ass_utils.h" -#include "ass_library.h" - -#ifdef _WIN32 -#pragma comment(lib, "libiconv.lib") -#pragma comment(lib, "freetype246MT.lib") -#pragma comment(lib, "libfribidi.lib") -#endif - -#define ass_atof(STR) (ass_strtod((STR),NULL)) - -typedef enum { - PST_UNKNOWN = 0, - PST_INFO, - PST_STYLES, - PST_EVENTS, - PST_FONTS -} ParserState; - -struct parser_priv { - ParserState state; - char *fontname; - char *fontdata; - int fontdata_size; - int fontdata_used; -}; - -#define ASS_STYLES_ALLOC 20 -#define ASS_EVENTS_ALLOC 200 - -void ass_free_track(ASS_Track *track) -{ - int i; - - if (track->parser_priv) { - free(track->parser_priv->fontname); - free(track->parser_priv->fontdata); - free(track->parser_priv); - } - free(track->style_format); - free(track->event_format); - free(track->Language); - if (track->styles) { - for (i = 0; i < track->n_styles; ++i) - ass_free_style(track, i); - } - free(track->styles); - if (track->events) { - for (i = 0; i < track->n_events; ++i) - ass_free_event(track, i); - } - free(track->events); - free(track->name); - free(track); -} - -/// \brief Allocate a new style struct -/// \param track track -/// \return style id -int ass_alloc_style(ASS_Track *track) -{ - int sid; - - assert(track->n_styles <= track->max_styles); - - if (track->n_styles == track->max_styles) { - track->max_styles += ASS_STYLES_ALLOC; - track->styles = - (ASS_Style *) realloc(track->styles, - sizeof(ASS_Style) * - track->max_styles); - } - - sid = track->n_styles++; - memset(track->styles + sid, 0, sizeof(ASS_Style)); - return sid; -} - -/// \brief Allocate a new event struct -/// \param track track -/// \return event id -int ass_alloc_event(ASS_Track *track) -{ - int eid; - - assert(track->n_events <= track->max_events); - - if (track->n_events == track->max_events) { - track->max_events += ASS_EVENTS_ALLOC; - track->events = - (ASS_Event *) realloc(track->events, - sizeof(ASS_Event) * - track->max_events); - } - - eid = track->n_events++; - memset(track->events + eid, 0, sizeof(ASS_Event)); - return eid; -} - -void ass_free_event(ASS_Track *track, int eid) -{ - ASS_Event *event = track->events + eid; - - free(event->Name); - free(event->Effect); - free(event->Text); - free(event->render_priv); -} - -void ass_free_style(ASS_Track *track, int sid) -{ - ASS_Style *style = track->styles + sid; - - free(style->Name); - free(style->FontName); -} - -// ============================================================================================== - -static void skip_spaces(char **str) -{ - char *p = *str; - while ((*p == ' ') || (*p == '\t')) - ++p; - *str = p; -} - -static void rskip_spaces(char **str, char *limit) -{ - char *p = *str; - while ((p >= limit) && ((*p == ' ') || (*p == '\t'))) - --p; - *str = p; -} - -/** - * \brief Set up default style - * \param style style to edit to defaults - * The parameters are mostly taken directly from VSFilter source for - * best compatibility. - */ -static void set_default_style(ASS_Style *style) -{ - style->Name = strdup("Default"); - style->FontName = strdup("Arial"); - style->FontSize = 18; - style->PrimaryColour = 0xffffff00; - style->SecondaryColour = 0x00ffff00; - style->OutlineColour = 0x00000000; - style->BackColour = 0x00000080; - style->Bold = 200; - style->ScaleX = 1.0; - style->ScaleY = 1.0; - style->Spacing = 0; - style->BorderStyle = 1; - style->Outline = 2; - style->Shadow = 3; - style->Alignment = 2; - style->MarginL = style->MarginR = style->MarginV = 20; -} - -/** - * \brief find style by name - * \param track track - * \param name style name - * \return index in track->styles - * Returnes 0 if no styles found => expects at least 1 style. - * Parsing code always adds "Default" style in the end. - */ -static int lookup_style(ASS_Track *track, char *name) -{ - int i; - if (*name == '*') - ++name; // FIXME: what does '*' really mean ? - for (i = track->n_styles - 1; i >= 0; --i) { - if (strcmp(track->styles[i].Name, name) == 0) - return i; - } - i = track->default_style; - ass_msg(track->library, MSGL_WARN, - "[%p]: Warning: no style named '%s' found, using '%s'", - track, name, track->styles[i].Name); - return i; // use the first style -} - -static uint32_t string2color(ASS_Library *library, char *p) -{ - uint32_t tmp; - (void) strtocolor(library, &p, &tmp, 0); - return tmp; -} - -static long long string2timecode(ASS_Library *library, char *p) -{ - unsigned h, m, s, ms; - long long tm; - int res = sscanf(p, "%1d:%2d:%2d.%2d", &h, &m, &s, &ms); - if (res < 4) { - ass_msg(library, MSGL_WARN, "Bad timestamp"); - return 0; - } - tm = ((h * 60 + m) * 60 + s) * 1000 + ms * 10; - return tm; -} - -/** - * \brief converts numpad-style align to align. - */ -static int numpad2align(int val) -{ - int res, v; - v = (val - 1) / 3; // 0, 1 or 2 for vertical alignment - if (v != 0) - v = 3 - v; - res = ((val - 1) % 3) + 1; // horizontal alignment - res += v * 4; - return res; -} - -#define NEXT(str,token) \ - token = next_token(&str); \ - if (!token) break; - -#define ANYVAL(name,func) \ - } else if (strcasecmp(tname, #name) == 0) { \ - target->name = func(token); \ - ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); - -#define STRVAL(name) \ - } else if (strcasecmp(tname, #name) == 0) { \ - if (target->name != NULL) free(target->name); \ - target->name = strdup(token); \ - ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); - -#define COLORVAL(name) \ - } else if (strcasecmp(tname, #name) == 0) { \ - target->name = string2color(track->library, token); \ - ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); - -#define INTVAL(name) ANYVAL(name,atoi) -#define FPVAL(name) ANYVAL(name,ass_atof) -#define TIMEVAL(name) \ - } else if (strcasecmp(tname, #name) == 0) { \ - target->name = string2timecode(track->library, token); \ - ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); - -#define STYLEVAL(name) \ - } else if (strcasecmp(tname, #name) == 0) { \ - target->name = lookup_style(track, token); \ - ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); - -#define ALIAS(alias,name) \ - if (strcasecmp(tname, #alias) == 0) {tname = #name;} - -static char *next_token(char **str) -{ - char *p = *str; - char *start; - skip_spaces(&p); - if (*p == '\0') { - *str = p; - return 0; - } - start = p; // start of the token - for (; (*p != '\0') && (*p != ','); ++p) { - } - if (*p == '\0') { - *str = p; // eos found, str will point to '\0' at exit - } else { - *p = '\0'; - *str = p + 1; // ',' found, str will point to the next char (beginning of the next token) - } - --p; // end of current token - rskip_spaces(&p, start); - if (p < start) - p = start; // empty token - else - ++p; // the first space character, or '\0' - *p = '\0'; - return start; -} - -/** - * \brief Parse the tail of Dialogue line - * \param track track - * \param event parsed data goes here - * \param str string to parse, zero-terminated - * \param n_ignored number of format options to skip at the beginning -*/ -static int process_event_tail(ASS_Track *track, ASS_Event *event, - char *str, int n_ignored) -{ - char *token; - char *tname; - char *p = str; - int i; - ASS_Event *target = event; - - char *format = strdup(track->event_format); - char *q = format; // format scanning pointer - - if (track->n_styles == 0) { - // add "Default" style to the end - // will be used if track does not contain a default style (or even does not contain styles at all) - int sid = ass_alloc_style(track); - set_default_style(&track->styles[sid]); - track->default_style = sid; - } - - for (i = 0; i < n_ignored; ++i) { - NEXT(q, tname); - } - - while (1) { - NEXT(q, tname); - if (strcasecmp(tname, "Text") == 0) { - char *last; - event->Text = strdup(p); - if (*event->Text != 0) { - last = event->Text + strlen(event->Text) - 1; - if (last >= event->Text && *last == '\r') - *last = 0; - } - ass_msg(track->library, MSGL_DBG2, "Text = %s", event->Text); - event->Duration -= event->Start; - free(format); - return 0; // "Text" is always the last - } - NEXT(p, token); - - ALIAS(End, Duration) // temporarily store end timecode in event->Duration - if (0) { // cool ;) - INTVAL(Layer) - STYLEVAL(Style) - STRVAL(Name) - STRVAL(Effect) - INTVAL(MarginL) - INTVAL(MarginR) - INTVAL(MarginV) - TIMEVAL(Start) - TIMEVAL(Duration) - } - } - free(format); - return 1; -} - -/** - * \brief Parse command line style overrides (--ass-force-style option) - * \param track track to apply overrides to - * The format for overrides is [StyleName.]Field=Value - */ -void ass_process_force_style(ASS_Track *track) -{ - char **fs, *eq, *dt, *style, *tname, *token; - ASS_Style *target; - int sid; - char **list = track->library->style_overrides; - - if (!list) - return; - - for (fs = list; *fs; ++fs) { - eq = strrchr(*fs, '='); - if (!eq) - continue; - *eq = '\0'; - token = eq + 1; - - if (!strcasecmp(*fs, "PlayResX")) - track->PlayResX = atoi(token); - else if (!strcasecmp(*fs, "PlayResY")) - track->PlayResY = atoi(token); - else if (!strcasecmp(*fs, "Timer")) - track->Timer = ass_atof(token); - else if (!strcasecmp(*fs, "WrapStyle")) - track->WrapStyle = atoi(token); - else if (!strcasecmp(*fs, "ScaledBorderAndShadow")) - track->ScaledBorderAndShadow = parse_bool(token); - else if (!strcasecmp(*fs, "Kerning")) - track->Kerning = parse_bool(token); - - dt = strrchr(*fs, '.'); - if (dt) { - *dt = '\0'; - style = *fs; - tname = dt + 1; - } else { - style = NULL; - tname = *fs; - } - for (sid = 0; sid < track->n_styles; ++sid) { - if (style == NULL - || strcasecmp(track->styles[sid].Name, style) == 0) { - target = track->styles + sid; - if (0) { - STRVAL(FontName) - COLORVAL(PrimaryColour) - COLORVAL(SecondaryColour) - COLORVAL(OutlineColour) - COLORVAL(BackColour) - FPVAL(FontSize) - INTVAL(Bold) - INTVAL(Italic) - INTVAL(Underline) - INTVAL(StrikeOut) - FPVAL(Spacing) - INTVAL(Angle) - INTVAL(BorderStyle) - INTVAL(Alignment) - INTVAL(MarginL) - INTVAL(MarginR) - INTVAL(MarginV) - INTVAL(Encoding) - FPVAL(ScaleX) - FPVAL(ScaleY) - FPVAL(Outline) - FPVAL(Shadow) - } - } - } - *eq = '='; - if (dt) - *dt = '.'; - } -} - -/** - * \brief Parse the Style line - * \param track track - * \param str string to parse, zero-terminated - * Allocates a new style struct. -*/ -static int process_style(ASS_Track *track, char *str) -{ - - char *token; - char *tname; - char *p = str; - char *format; - char *q; // format scanning pointer - int sid; - ASS_Style *style; - ASS_Style *target; - - if (!track->style_format) { - // no style format header - // probably an ancient script version - if (track->track_type == TRACK_TYPE_SSA) - track->style_format = - strdup - ("Name, Fontname, Fontsize, PrimaryColour, SecondaryColour," - "TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline," - "Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding"); - else - track->style_format = - strdup - ("Name, Fontname, Fontsize, PrimaryColour, SecondaryColour," - "OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut," - "ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow," - "Alignment, MarginL, MarginR, MarginV, Encoding"); - } - - q = format = strdup(track->style_format); - - // Add default style first - if (track->n_styles == 0) { - // will be used if track does not contain a default style (or even does not contain styles at all) - int sid = ass_alloc_style(track); - set_default_style(&track->styles[sid]); - track->default_style = sid; - } - - ass_msg(track->library, MSGL_V, "[%p] Style: %s", track, str); - - sid = ass_alloc_style(track); - - style = track->styles + sid; - target = style; - - // fill style with some default values - style->ScaleX = 100.; - style->ScaleY = 100.; - - while (1) { - NEXT(q, tname); - NEXT(p, token); - - if (0) { // cool ;) - STRVAL(Name) - if ((strcmp(target->Name, "Default") == 0) - || (strcmp(target->Name, "*Default") == 0)) - track->default_style = sid; - STRVAL(FontName) - COLORVAL(PrimaryColour) - COLORVAL(SecondaryColour) - COLORVAL(OutlineColour) // TertiaryColor - COLORVAL(BackColour) - // SSA uses BackColour for both outline and shadow - // 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; - FPVAL(FontSize) - INTVAL(Bold) - INTVAL(Italic) - INTVAL(Underline) - INTVAL(StrikeOut) - FPVAL(Spacing) - INTVAL(Angle) - INTVAL(BorderStyle) - INTVAL(Alignment) - if (track->track_type == TRACK_TYPE_ASS) - target->Alignment = numpad2align(target->Alignment); - INTVAL(MarginL) - INTVAL(MarginR) - INTVAL(MarginV) - INTVAL(Encoding) - FPVAL(ScaleX) - FPVAL(ScaleY) - FPVAL(Outline) - FPVAL(Shadow) - } - } - style->ScaleX /= 100.; - style->ScaleY /= 100.; - style->Bold = !!style->Bold; - style->Italic = !!style->Italic; - style->Underline = !!style->Underline; - if (!style->Name) - style->Name = strdup("Default"); - if (!style->FontName) - style->FontName = strdup("Arial"); - free(format); - return 0; - -} - -static int process_styles_line(ASS_Track *track, char *str) -{ - if (!strncmp(str, "Format:", 7)) { - char *p = str + 7; - skip_spaces(&p); - track->style_format = strdup(p); - ass_msg(track->library, MSGL_DBG2, "Style format: %s", - track->style_format); - } else if (!strncmp(str, "Style:", 6)) { - char *p = str + 6; - skip_spaces(&p); - process_style(track, p); - } - return 0; -} - -static int process_info_line(ASS_Track *track, char *str) -{ - if (!strncmp(str, "PlayResX:", 9)) { - track->PlayResX = atoi(str + 9); - } else if (!strncmp(str, "PlayResY:", 9)) { - track->PlayResY = atoi(str + 9); - } else if (!strncmp(str, "Timer:", 6)) { - track->Timer = ass_atof(str + 6); - } else if (!strncmp(str, "WrapStyle:", 10)) { - track->WrapStyle = atoi(str + 10); - } else if (!strncmp(str, "ScaledBorderAndShadow:", 22)) { - track->ScaledBorderAndShadow = parse_bool(str + 22); - } else if (!strncmp(str, "Kerning:", 8)) { - track->Kerning = parse_bool(str + 8); - } else if (!strncmp(str, "Language:", 9)) { - char *p = str + 9; - while (*p && isspace(*p)) p++; - track->Language = malloc(3); - strncpy(track->Language, p, 2); - track->Language[2] = 0; - } - return 0; -} - -static void event_format_fallback(ASS_Track *track) -{ - track->parser_priv->state = PST_EVENTS; - if (track->track_type == TRACK_TYPE_SSA) - track->event_format = strdup("Format: Marked, Start, End, Style, " - "Name, MarginL, MarginR, MarginV, Effect, Text"); - else - track->event_format = strdup("Format: Layer, Start, End, Style, " - "Actor, MarginL, MarginR, MarginV, Effect, Text"); - ass_msg(track->library, MSGL_V, - "No event format found, using fallback"); -} - -static int process_events_line(ASS_Track *track, char *str) -{ - if (!strncmp(str, "Format:", 7)) { - char *p = str + 7; - skip_spaces(&p); - free(track->event_format); - track->event_format = strdup(p); - ass_msg(track->library, MSGL_DBG2, "Event format: %s", track->event_format); - } else if (!strncmp(str, "Dialogue:", 9)) { - // This should never be reached for embedded subtitles. - // They have slightly different format and are parsed in ass_process_chunk, - // called directly from demuxer - int eid; - ASS_Event *event; - - str += 9; - skip_spaces(&str); - - eid = ass_alloc_event(track); - event = track->events + eid; - - // We can't parse events with event_format - if (!track->event_format) - event_format_fallback(track); - - process_event_tail(track, event, str, 0); - } else { - ass_msg(track->library, MSGL_V, "Not understood: '%.30s'", str); - } - return 0; -} - -// Copied from mkvtoolnix -static unsigned char *decode_chars(unsigned char c1, unsigned char c2, - unsigned char c3, unsigned char c4, - unsigned char *dst, int cnt) -{ - uint32_t value; - unsigned char bytes[3]; - int i; - - value = - ((c1 - 33) << 18) + ((c2 - 33) << 12) + ((c3 - 33) << 6) + (c4 - - 33); - bytes[2] = value & 0xff; - bytes[1] = (value & 0xff00) >> 8; - bytes[0] = (value & 0xff0000) >> 16; - - for (i = 0; i < cnt; ++i) - *dst++ = bytes[i]; - return dst; -} - -static int decode_font(ASS_Track *track) -{ - unsigned char *p; - unsigned char *q; - int i; - int size; // original size - int dsize; // decoded size - unsigned char *buf = 0; - - ass_msg(track->library, MSGL_V, "Font: %d bytes encoded data", - track->parser_priv->fontdata_used); - size = track->parser_priv->fontdata_used; - if (size % 4 == 1) { - ass_msg(track->library, MSGL_ERR, "Bad encoded data size"); - goto error_decode_font; - } - buf = malloc(size / 4 * 3 + 2); - q = buf; - for (i = 0, p = (unsigned char *) track->parser_priv->fontdata; - i < size / 4; i++, p += 4) { - q = decode_chars(p[0], p[1], p[2], p[3], q, 3); - } - if (size % 4 == 2) { - q = decode_chars(p[0], p[1], 0, 0, q, 1); - } else if (size % 4 == 3) { - q = decode_chars(p[0], p[1], p[2], 0, q, 2); - } - dsize = q - buf; - assert(dsize <= size / 4 * 3 + 2); - - if (track->library->extract_fonts) { - ass_add_font(track->library, track->parser_priv->fontname, - (char *) buf, dsize); - } - -error_decode_font: - free(buf); - free(track->parser_priv->fontname); - free(track->parser_priv->fontdata); - track->parser_priv->fontname = 0; - track->parser_priv->fontdata = 0; - track->parser_priv->fontdata_size = 0; - track->parser_priv->fontdata_used = 0; - return 0; -} - -static int process_fonts_line(ASS_Track *track, char *str) -{ - int len; - - if (!strncmp(str, "fontname:", 9)) { - char *p = str + 9; - skip_spaces(&p); - if (track->parser_priv->fontname) { - decode_font(track); - } - track->parser_priv->fontname = strdup(p); - ass_msg(track->library, MSGL_V, "Fontname: %s", - track->parser_priv->fontname); - return 0; - } - - if (!track->parser_priv->fontname) { - ass_msg(track->library, MSGL_V, "Not understood: '%s'", str); - return 0; - } - - len = strlen(str); - if (len > 80) { - ass_msg(track->library, MSGL_WARN, "Font line too long: %d, %s", - len, str); - return 0; - } - if (track->parser_priv->fontdata_used + len > - track->parser_priv->fontdata_size) { - track->parser_priv->fontdata_size += 100 * 1024; - track->parser_priv->fontdata = - realloc(track->parser_priv->fontdata, - track->parser_priv->fontdata_size); - } - memcpy(track->parser_priv->fontdata + track->parser_priv->fontdata_used, - str, len); - track->parser_priv->fontdata_used += len; - - return 0; -} - -/** - * \brief Parse a header line - * \param track track - * \param str string to parse, zero-terminated -*/ -static int process_line(ASS_Track *track, char *str) -{ - if (!strncasecmp(str, "[Script Info]", 13)) { - track->parser_priv->state = PST_INFO; - } else if (!strncasecmp(str, "[V4 Styles]", 11)) { - track->parser_priv->state = PST_STYLES; - track->track_type = TRACK_TYPE_SSA; - } else if (!strncasecmp(str, "[V4+ Styles]", 12)) { - track->parser_priv->state = PST_STYLES; - track->track_type = TRACK_TYPE_ASS; - } else if (!strncasecmp(str, "[Events]", 8)) { - track->parser_priv->state = PST_EVENTS; - } else if (!strncasecmp(str, "[Fonts]", 7)) { - track->parser_priv->state = PST_FONTS; - } else { - switch (track->parser_priv->state) { - case PST_INFO: - process_info_line(track, str); - break; - case PST_STYLES: - process_styles_line(track, str); - break; - case PST_EVENTS: - process_events_line(track, str); - break; - case PST_FONTS: - process_fonts_line(track, str); - break; - default: - break; - } - } - - // there is no explicit end-of-font marker in ssa/ass - if ((track->parser_priv->state != PST_FONTS) - && (track->parser_priv->fontname)) - decode_font(track); - - return 0; -} - -static int process_text(ASS_Track *track, char *str) -{ - char *p = str; - while (1) { - char *q; - while (1) { - if ((*p == '\r') || (*p == '\n')) - ++p; - else if (p[0] == '\xef' && p[1] == '\xbb' && p[2] == '\xbf') - p += 3; // U+FFFE (BOM) - else - break; - } - for (q = p; ((*q != '\0') && (*q != '\r') && (*q != '\n')); ++q) { - }; - if (q == p) - break; - if (*q != '\0') - *(q++) = '\0'; - process_line(track, p); - if (*q == '\0') - break; - p = q; - } - return 0; -} - -/** - * \brief Process a chunk of subtitle stream data. - * \param track track - * \param data string to parse - * \param size length of data -*/ -void ass_process_data(ASS_Track *track, char *data, int size) -{ - char *str = malloc(size + 1); - - memcpy(str, data, size); - str[size] = '\0'; - - ass_msg(track->library, MSGL_V, "Event: %s", str); - process_text(track, str); - free(str); -} - -/** - * \brief Process CodecPrivate section of subtitle stream - * \param track track - * \param data string to parse - * \param size length of data - CodecPrivate section contains [Stream Info] and [V4+ Styles] ([V4 Styles] for SSA) sections -*/ -void ass_process_codec_private(ASS_Track *track, char *data, int size) -{ - ass_process_data(track, data, size); - - // probably an mkv produced by ancient mkvtoolnix - // such files don't have [Events] and Format: headers - if (!track->event_format) - event_format_fallback(track); - - ass_process_force_style(track); -} - -static int check_duplicate_event(ASS_Track *track, int ReadOrder) -{ - int i; - for (i = 0; i < track->n_events - 1; ++i) // ignoring last event, it is the one we are comparing with - if (track->events[i].ReadOrder == ReadOrder) - return 1; - return 0; -} - -/** - * \brief Process a chunk of subtitle stream data. In Matroska, this contains exactly 1 event (or a commentary). - * \param track track - * \param data string to parse - * \param size length of data - * \param timecode starting time of the event (milliseconds) - * \param duration duration of the event (milliseconds) -*/ -void ass_process_chunk(ASS_Track *track, char *data, int size, - long long timecode, long long duration) -{ - char *str; - int eid; - char *p; - char *token; - ASS_Event *event; - - if (!track->event_format) { - ass_msg(track->library, MSGL_WARN, "Event format header missing"); - return; - } - - str = malloc(size + 1); - memcpy(str, data, size); - str[size] = '\0'; - ass_msg(track->library, MSGL_V, "Event at %" PRId64 ", +%" PRId64 ": %s", - (int64_t) timecode, (int64_t) duration, str); - - eid = ass_alloc_event(track); - event = track->events + eid; - - p = str; - - do { - NEXT(p, token); - event->ReadOrder = atoi(token); - if (check_duplicate_event(track, event->ReadOrder)) - break; - - NEXT(p, token); - event->Layer = atoi(token); - - process_event_tail(track, event, p, 3); - - event->Start = timecode; - event->Duration = duration; - - free(str); - return; -// dump_events(tid); - } while (0); - // some error - ass_free_event(track, eid); - track->n_events--; - free(str); -} - -/** - * \brief Flush buffered events. - * \param track track -*/ -void ass_flush_events(ASS_Track *track) -{ - if (track->events) { - int eid; - for (eid = 0; eid < track->n_events; eid++) - ass_free_event(track, eid); - track->n_events = 0; - } -} - -#ifdef CONFIG_ICONV -/** \brief recode buffer to utf-8 - * constraint: codepage != 0 - * \param data pointer to text buffer - * \param size buffer size - * \return a pointer to recoded buffer, caller is responsible for freeing it -**/ -static char *sub_recode(ASS_Library *library, char *data, size_t size, - char *codepage) -{ - iconv_t icdsc; - char *tocp = "UTF-8"; - char *outbuf; - assert(codepage); - - { - const char *cp_tmp = codepage; -#ifdef CONFIG_ENCA - char enca_lang[3], enca_fallback[100]; - if (sscanf(codepage, "enca:%2s:%99s", enca_lang, enca_fallback) == 2 - || sscanf(codepage, "ENCA:%2s:%99s", enca_lang, - enca_fallback) == 2) { - cp_tmp = - ass_guess_buffer_cp(library, (unsigned char *) data, size, - enca_lang, enca_fallback); - } -#endif - if ((icdsc = iconv_open(tocp, cp_tmp)) != (iconv_t) (-1)) { - ass_msg(library, MSGL_V, "Opened iconv descriptor"); - } else - ass_msg(library, MSGL_ERR, "Error opening iconv descriptor"); - } - - { - size_t osize = size; - size_t ileft = size; - size_t oleft = size - 1; - char *ip; - char *op; - size_t rc; - int clear = 0; - - outbuf = malloc(osize); - ip = data; - op = outbuf; - - while (1) { - if (ileft) - rc = iconv(icdsc, &ip, &ileft, &op, &oleft); - else { // clear the conversion state and leave - clear = 1; - rc = iconv(icdsc, NULL, NULL, &op, &oleft); - } - if (rc == (size_t) (-1)) { - if (errno == E2BIG) { - size_t offset = op - outbuf; - outbuf = (char *) realloc(outbuf, osize + size); - op = outbuf + offset; - osize += size; - oleft += size; - } else { - ass_msg(library, MSGL_WARN, "Error recoding file"); - return NULL; - } - } else if (clear) - break; - } - outbuf[osize - oleft - 1] = 0; - } - - if (icdsc != (iconv_t) (-1)) { - (void) iconv_close(icdsc); - icdsc = (iconv_t) (-1); - ass_msg(library, MSGL_V, "Closed iconv descriptor"); - } - - return outbuf; -} -#endif // ICONV - -/** - * \brief read file contents into newly allocated buffer - * \param fname file name - * \param bufsize out: file size - * \return pointer to file contents. Caller is responsible for its deallocation. - */ -static char *read_file(ASS_Library *library, char *fname, size_t *bufsize) -{ - int res; - long sz; - long bytes_read; - char *buf; - - FILE *fp = fopen(fname, "rb"); - if (!fp) { - ass_msg(library, MSGL_WARN, - "ass_read_file(%s): fopen failed", fname); - return 0; - } - res = fseek(fp, 0, SEEK_END); - if (res == -1) { - ass_msg(library, MSGL_WARN, - "ass_read_file(%s): fseek failed", fname); - fclose(fp); - return 0; - } - - sz = ftell(fp); - rewind(fp); - - ass_msg(library, MSGL_V, "File size: %ld", sz); - - buf = malloc(sz + 1); - assert(buf); - bytes_read = 0; - do { - res = fread(buf + bytes_read, 1, sz - bytes_read, fp); - if (res <= 0) { - ass_msg(library, MSGL_INFO, "Read failed, %d: %s", errno, - strerror(errno)); - fclose(fp); - free(buf); - return 0; - } - bytes_read += res; - } while (sz - bytes_read > 0); - buf[sz] = '\0'; - fclose(fp); - - if (bufsize) - *bufsize = sz; - return buf; -} - -/* - * \param buf pointer to subtitle text in utf-8 - */ -static ASS_Track *parse_memory(ASS_Library *library, char *buf) -{ - ASS_Track *track; - int i; - - track = ass_new_track(library); - - // process header - process_text(track, buf); - - // external SSA/ASS subs does not have ReadOrder field - for (i = 0; i < track->n_events; ++i) - track->events[i].ReadOrder = i; - - // there is no explicit end-of-font marker in ssa/ass - if (track->parser_priv->fontname) - decode_font(track); - - if (track->track_type == TRACK_TYPE_UNKNOWN) { - ass_free_track(track); - return 0; - } - - ass_process_force_style(track); - - return track; -} - -/** - * \brief Read subtitles from memory. - * \param library libass library object - * \param buf pointer to subtitles text - * \param bufsize size of buffer - * \param codepage recode buffer contents from given codepage - * \return newly allocated track -*/ -ASS_Track *ass_read_memory(ASS_Library *library, char *buf, - size_t bufsize, char *codepage) -{ - ASS_Track *track; - int need_free = 0; - - if (!buf) - return 0; - -#ifdef CONFIG_ICONV - if (codepage) { - buf = sub_recode(library, buf, bufsize, codepage); - if (!buf) - return 0; - else - need_free = 1; - } -#endif - track = parse_memory(library, buf); - if (need_free) - free(buf); - if (!track) - return 0; - - ass_msg(library, MSGL_INFO, "Added subtitle file: " - "<memory> (%d styles, %d events)", - track->n_styles, track->n_events); - return track; -} - -static char *read_file_recode(ASS_Library *library, char *fname, - char *codepage, size_t *size) -{ - char *buf; - size_t bufsize; - - buf = read_file(library, fname, &bufsize); - if (!buf) - return 0; -#ifdef CONFIG_ICONV - if (codepage) { - char *tmpbuf = sub_recode(library, buf, bufsize, codepage); - free(buf); - buf = tmpbuf; - } - if (!buf) - return 0; -#endif - *size = bufsize; - return buf; -} - -/** - * \brief Read subtitles from file. - * \param library libass library object - * \param fname file name - * \param codepage recode buffer contents from given codepage - * \return newly allocated track -*/ -ASS_Track *ass_read_file(ASS_Library *library, char *fname, - char *codepage) -{ - char *buf; - ASS_Track *track; - size_t bufsize; - - buf = read_file_recode(library, fname, codepage, &bufsize); - if (!buf) - return 0; - track = parse_memory(library, buf); - free(buf); - if (!track) - return 0; - - track->name = strdup(fname); - - ass_msg(library, MSGL_INFO, - "Added subtitle file: '%s' (%d styles, %d events)", - fname, track->n_styles, track->n_events); - - return track; -} - -/** - * \brief read styles from file into already initialized track - */ -int ass_read_styles(ASS_Track *track, char *fname, char *codepage) -{ - char *buf; - ParserState old_state; - size_t sz; - - buf = read_file(track->library, fname, &sz); - if (!buf) - return 1; -#ifdef CONFIG_ICONV - if (codepage) { - char *tmpbuf; - tmpbuf = sub_recode(track->library, buf, sz, codepage); - free(buf); - buf = tmpbuf; - } - if (!buf) - return 0; -#endif - - old_state = track->parser_priv->state; - track->parser_priv->state = PST_STYLES; - process_text(track, buf); - track->parser_priv->state = old_state; - - return 0; -} - -long long ass_step_sub(ASS_Track *track, long long now, int movement) -{ - int i; - - if (movement == 0) - return 0; - if (track->n_events == 0) - return 0; - - if (movement < 0) - for (i = 0; - (i < track->n_events) - && - ((long long) (track->events[i].Start + - track->events[i].Duration) <= now); ++i) { - } else - for (i = track->n_events - 1; - (i >= 0) && ((long long) (track->events[i].Start) > now); - --i) { - } - - // -1 and n_events are ok - assert(i >= -1); - assert(i <= track->n_events); - i += movement; - if (i < 0) - i = 0; - if (i >= track->n_events) - i = track->n_events - 1; - return ((long long) track->events[i].Start) - now; -} - -ASS_Track *ass_new_track(ASS_Library *library) -{ - ASS_Track *track = calloc(1, sizeof(ASS_Track)); - track->library = library; - track->ScaledBorderAndShadow = 1; - track->parser_priv = calloc(1, sizeof(ASS_ParserPriv)); - return track; -} - -/** - * \brief Prepare track for rendering - */ -void ass_lazy_track_init(ASS_Library *lib, ASS_Track *track) -{ - if (track->PlayResX && track->PlayResY) - return; - if (!track->PlayResX && !track->PlayResY) { - ass_msg(lib, MSGL_WARN, - "Neither PlayResX nor PlayResY defined. Assuming 384x288"); - track->PlayResX = 384; - track->PlayResY = 288; - } else { - if (!track->PlayResY && track->PlayResX == 1280) { - track->PlayResY = 1024; - ass_msg(lib, MSGL_WARN, - "PlayResY undefined, setting to %d", track->PlayResY); - } else if (!track->PlayResY) { - track->PlayResY = track->PlayResX * 3 / 4; - ass_msg(lib, MSGL_WARN, - "PlayResY undefined, setting to %d", track->PlayResY); - } else if (!track->PlayResX && track->PlayResY == 1024) { - track->PlayResX = 1280; - ass_msg(lib, MSGL_WARN, - "PlayResX undefined, setting to %d", track->PlayResX); - } else if (!track->PlayResX) { - track->PlayResX = track->PlayResY * 4 / 3; - ass_msg(lib, MSGL_WARN, - "PlayResX undefined, setting to %d", track->PlayResX); - } - } -} diff --git a/lib/libass/libass/ass.h b/lib/libass/libass/ass.h deleted file mode 100644 index 5aef92e3e5..0000000000 --- a/lib/libass/libass/ass.h +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef LIBASS_ASS_H -#define LIBASS_ASS_H - -#include <stdio.h> -#include <stdarg.h> -#include "ass_types.h" - -#define LIBASS_VERSION 0x01000000 - -/* - * A linked list of images produced by an ass renderer. - * - * These images have to be rendered in-order for the correct screen - * composition. The libass renderer clips these bitmaps to the frame size. - * w/h can be zero, in this case the bitmap should not be rendered at all. - * The last bitmap row is not guaranteed to be padded up to stride size, - * e.g. in the worst case a bitmap has the size stride * (h - 1) + w. - */ -typedef struct ass_image { - int w, h; // Bitmap width/height - int stride; // Bitmap stride - unsigned char *bitmap; // 1bpp stride*h alpha buffer - // Note: the last row may not be padded to - // bitmap stride! - uint32_t color; // Bitmap color and alpha, RGBA - int dst_x, dst_y; // Bitmap placement inside the video frame - - struct ass_image *next; // Next image, or NULL -} ASS_Image; - -/* - * Hinting type. (see ass_set_hinting below) - * - * FreeType's native hinter is still buggy sometimes and it is recommended - * to use the light autohinter, ASS_HINTING_LIGHT, instead. For best - * compatibility with problematic fonts, disable hinting. - */ -typedef enum { - ASS_HINTING_NONE = 0, - ASS_HINTING_LIGHT, - ASS_HINTING_NORMAL, - ASS_HINTING_NATIVE -} ASS_Hinting; - -/** - * \brief Text shaping levels. - * - * SIMPLE is a fast, font-agnostic shaper that can do only substitutions. - * COMPLEX is a slower shaper using OpenType for substitutions and positioning. - * - * libass uses the best shaper available by default. - */ -typedef enum { - ASS_SHAPING_SIMPLE = 0, - ASS_SHAPING_COMPLEX -} ASS_ShapingLevel; - -/** - * \brief Initialize the library. - * \return library handle or NULL if failed - */ -ASS_Library *ass_library_init(void); - -/** - * \brief Finalize the library - * \param priv library handle - */ -void ass_library_done(ASS_Library *priv); - -/** - * \brief Set additional fonts directory. - * Optional directory that will be scanned for fonts recursively. The fonts - * found are used for font lookup. - * NOTE: A valid font directory is not needed to support embedded fonts. - * - * \param priv library handle - * \param fonts_dir directory with additional fonts - */ -void ass_set_fonts_dir(ASS_Library *priv, const char *fonts_dir); - -/** - * \brief Whether fonts should be extracted from track data. - * \param priv library handle - * \param extract whether to extract fonts - */ -void ass_set_extract_fonts(ASS_Library *priv, int extract); - -/** - * \brief Register style overrides with a library instance. - * The overrides should have the form [Style.]Param=Value, e.g. - * SomeStyle.Font=Arial - * ScaledBorderAndShadow=yes - * - * \param priv library handle - * \param list NULL-terminated list of strings - */ -void ass_set_style_overrides(ASS_Library *priv, char **list); - -/** - * \brief Explicitly process style overrides for a track. - * \param track track handle - */ -void ass_process_force_style(ASS_Track *track); - -/** - * \brief Register a callback for debug/info messages. - * If a callback is registered, it is called for every message emitted by - * libass. The callback receives a format string and a list of arguments, - * to be used for the printf family of functions. Additionally, a log level - * from 0 (FATAL errors) to 7 (verbose DEBUG) is passed. Usually, level 5 - * should be used by applications. - * If no callback is set, all messages level < 5 are printed to stderr, - * prefixed with [ass]. - * - * \param priv library handle - * \param msg_cb pointer to callback function - * \param data additional data, will be passed to callback - */ -void ass_set_message_cb(ASS_Library *priv, void (*msg_cb) - (int level, const char *fmt, va_list args, void *data), - void *data); - -/** - * \brief Initialize the renderer. - * \param priv library handle - * \return renderer handle or NULL if failed - */ -ASS_Renderer *ass_renderer_init(ASS_Library *); - -/** - * \brief Finalize the renderer. - * \param priv renderer handle - */ -void ass_renderer_done(ASS_Renderer *priv); - -/** - * \brief Set the frame size in pixels, including margins. - * \param priv renderer handle - * \param w width - * \param h height - */ -void ass_set_frame_size(ASS_Renderer *priv, int w, int h); - -/** - * \brief Set shaping level. This is merely a hint, the renderer will use - * whatever is available if the request cannot be fulfilled. - * \param level shaping level - */ -void ass_set_shaper(ASS_Renderer *priv, ASS_ShapingLevel level); - -/** - * \brief Set frame margins. These values may be negative if pan-and-scan - * is used. - * \param priv renderer handle - * \param t top margin - * \param b bottom margin - * \param l left margin - * \param r right margin - */ -void ass_set_margins(ASS_Renderer *priv, int t, int b, int l, int r); - -/** - * \brief Whether margins should be used for placing regular events. - * \param priv renderer handle - * \param use whether to use the margins - */ -void ass_set_use_margins(ASS_Renderer *priv, int use); - -/** - * \brief Set aspect ratio parameters. - * \param priv renderer handle - * \param dar display aspect ratio (DAR), prescaled for output PAR - * \param sar storage aspect ratio (SAR) - */ -void ass_set_aspect_ratio(ASS_Renderer *priv, double dar, double sar); - -/** - * \brief Set a fixed font scaling factor. - * \param priv renderer handle - * \param font_scale scaling factor, default is 1.0 - */ -void ass_set_font_scale(ASS_Renderer *priv, double font_scale); - -/** - * \brief Set font hinting method. - * \param priv renderer handle - * \param ht hinting method - */ -void ass_set_hinting(ASS_Renderer *priv, ASS_Hinting ht); - -/** - * \brief Set line spacing. Will not be scaled with frame size. - * \param priv renderer handle - * \param line_spacing line spacing in pixels - */ -void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing); - -/** - * \brief Set font lookup defaults. - * \param default_font path to default font to use. Must be supplied if - * fontconfig is disabled or unavailable. - * \param default_family fallback font family for fontconfig, or NULL - * \param fc whether to use fontconfig - * \param config path to fontconfig configuration file, or NULL. Only relevant - * if fontconfig is used. - * \param update whether fontconfig cache should be built/updated now. Only - * relevant if fontconfig is used. - * - * NOTE: font lookup must be configured before an ASS_Renderer can be used. - */ -void ass_set_fonts(ASS_Renderer *priv, const char *default_font, - const char *default_family, int fc, const char *config, - int update); - -/** - * \brief Update/build font cache. This needs to be called if it was - * disabled when ass_set_fonts was set. - * - * \param priv renderer handle - * \return success - */ -int ass_fonts_update(ASS_Renderer *priv); - -/** - * \brief Set hard cache limits. Do not set, or set to zero, for reasonable - * defaults. - * - * \param priv renderer handle - * \param glyph_max maximum number of cached glyphs - * \param bitmap_max_size maximum bitmap cache size (in MB) - */ -void ass_set_cache_limits(ASS_Renderer *priv, int glyph_max, - int bitmap_max_size); - -/** - * \brief Render a frame, producing a list of ASS_Image. - * \param priv renderer handle - * \param track subtitle track - * \param now video timestamp in milliseconds - * \param detect_change will be set to 1 if a change occured compared - * to the last invocation - */ -ASS_Image *ass_render_frame(ASS_Renderer *priv, ASS_Track *track, - long long now, int *detect_change); - - -/* - * The following functions operate on track objects and do not need - * an ass_renderer - */ - -/** - * \brief Allocate a new empty track object. - * \param library handle - * \return pointer to empty track - */ -ASS_Track *ass_new_track(ASS_Library *); - -/** - * \brief Deallocate track and all its child objects (styles and events). - * \param track track to deallocate - */ -void ass_free_track(ASS_Track *track); - -/** - * \brief Allocate new style. - * \param track track - * \return newly allocated style id - */ -int ass_alloc_style(ASS_Track *track); - -/** - * \brief Allocate new event. - * \param track track - * \return newly allocated event id - */ -int ass_alloc_event(ASS_Track *track); - -/** - * \brief Delete a style. - * \param track track - * \param sid style id - * Deallocates style data. Does not modify track->n_styles. - */ -void ass_free_style(ASS_Track *track, int sid); - -/** - * \brief Delete an event. - * \param track track - * \param eid event id - * Deallocates event data. Does not modify track->n_events. - */ -void ass_free_event(ASS_Track *track, int eid); - -/** - * \brief Parse a chunk of subtitle stream data. - * \param track track - * \param data string to parse - * \param size length of data - */ -void ass_process_data(ASS_Track *track, char *data, int size); - -/** - * \brief Parse Codec Private section of the subtitle stream, in Matroska - * format. See the Matroska specification for details. - * \param track target track - * \param data string to parse - * \param size length of data - */ -void ass_process_codec_private(ASS_Track *track, char *data, int size); - -/** - * \brief Parse a chunk of subtitle stream data. A chunk contains exactly one - * event in Matroska format. See the Matroska specification for details. - * \param track track - * \param data string to parse - * \param size length of data - * \param timecode starting time of the event (milliseconds) - * \param duration duration of the event (milliseconds) - */ -void ass_process_chunk(ASS_Track *track, char *data, int size, - long long timecode, long long duration); - -/** - * \brief Flush buffered events. - * \param track track -*/ -void ass_flush_events(ASS_Track *track); - -/** - * \brief Read subtitles from file. - * \param library library handle - * \param fname file name - * \param codepage encoding (iconv format) - * \return newly allocated track -*/ -ASS_Track *ass_read_file(ASS_Library *library, char *fname, - char *codepage); - -/** - * \brief Read subtitles from memory. - * \param library library handle - * \param buf pointer to subtitles text - * \param bufsize size of buffer - * \param codepage encoding (iconv format) - * \return newly allocated track -*/ -ASS_Track *ass_read_memory(ASS_Library *library, char *buf, - size_t bufsize, char *codepage); -/** - * \brief Read styles from file into already initialized track. - * \param fname file name - * \param codepage encoding (iconv format) - * \return 0 on success - */ -int ass_read_styles(ASS_Track *track, char *fname, char *codepage); - -/** - * \brief Add a memory font. - * \param library library handle - * \param name attachment name - * \param data binary font data - * \param data_size data size -*/ -void ass_add_font(ASS_Library *library, char *name, char *data, - int data_size); - -/** - * \brief Remove all fonts stored in an ass_library object. - * \param library library handle - */ -void ass_clear_fonts(ASS_Library *library); - -/** - * \brief Calculates timeshift from now to the start of some other subtitle - * event, depending on movement parameter. - * \param track subtitle track - * \param now current time in milliseconds - * \param movement how many events to skip from the one currently displayed - * +2 means "the one after the next", -1 means "previous" - * \return timeshift in milliseconds - */ -long long ass_step_sub(ASS_Track *track, long long now, int movement); - -#endif /* LIBASS_ASS_H */ diff --git a/lib/libass/libass/ass_bitmap.c b/lib/libass/libass/ass_bitmap.c deleted file mode 100644 index 6afe05d2f0..0000000000 --- a/lib/libass/libass/ass_bitmap.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <stdlib.h> -#include <string.h> -#include <math.h> -#include <assert.h> -#include <ft2build.h> -#include FT_GLYPH_H -#include FT_OUTLINE_H - -#include "ass_utils.h" -#include "ass_bitmap.h" - -struct ass_synth_priv { - int tmp_w, tmp_h; - unsigned short *tmp; - - int g_r; - int g_w; - - unsigned *g; - unsigned *gt2; - - double radius; -}; - -static const unsigned int maxcolor = 255; -static const unsigned base = 256; - -static int generate_tables(ASS_SynthPriv *priv, double radius) -{ - double A = log(1.0 / base) / (radius * radius * 2); - int mx, i; - double volume_diff, volume_factor = 0; - unsigned volume; - - if (priv->radius == radius) - return 0; - else - priv->radius = radius; - - priv->g_r = ceil(radius); - priv->g_w = 2 * priv->g_r + 1; - - if (priv->g_r) { - priv->g = realloc(priv->g, priv->g_w * sizeof(unsigned)); - priv->gt2 = realloc(priv->gt2, 256 * priv->g_w * sizeof(unsigned)); - if (priv->g == NULL || priv->gt2 == NULL) { - return -1; - } - } - - if (priv->g_r) { - // gaussian curve with volume = 256 - for (volume_diff = 10000000; volume_diff > 0.0000001; - volume_diff *= 0.5) { - volume_factor += volume_diff; - volume = 0; - for (i = 0; i < priv->g_w; ++i) { - priv->g[i] = - (unsigned) (exp(A * (i - priv->g_r) * (i - priv->g_r)) * - volume_factor + .5); - volume += priv->g[i]; - } - if (volume > 256) - volume_factor -= volume_diff; - } - volume = 0; - for (i = 0; i < priv->g_w; ++i) { - priv->g[i] = - (unsigned) (exp(A * (i - priv->g_r) * (i - priv->g_r)) * - volume_factor + .5); - volume += priv->g[i]; - } - - // gauss table: - for (mx = 0; mx < priv->g_w; mx++) { - for (i = 0; i < 256; i++) { - priv->gt2[mx + i * priv->g_w] = i * priv->g[mx]; - } - } - } - - return 0; -} - -static void resize_tmp(ASS_SynthPriv *priv, int w, int h) -{ - if (priv->tmp_w >= w && priv->tmp_h >= h) - return; - if (priv->tmp_w == 0) - priv->tmp_w = 64; - if (priv->tmp_h == 0) - priv->tmp_h = 64; - while (priv->tmp_w < w) - priv->tmp_w *= 2; - while (priv->tmp_h < h) - priv->tmp_h *= 2; - free(priv->tmp); - priv->tmp = malloc((priv->tmp_w + 1) * priv->tmp_h * sizeof(short)); -} - -ASS_SynthPriv *ass_synth_init(double radius) -{ - ASS_SynthPriv *priv = calloc(1, sizeof(ASS_SynthPriv)); - generate_tables(priv, radius); - return priv; -} - -void ass_synth_done(ASS_SynthPriv *priv) -{ - free(priv->tmp); - free(priv->g); - free(priv->gt2); - free(priv); -} - -static Bitmap *alloc_bitmap(int w, int h) -{ - Bitmap *bm; - unsigned s = w; // XXX: alignment - bm = malloc(sizeof(Bitmap)); - bm->buffer = calloc(s, h); - bm->w = w; - bm->h = h; - bm->stride = s; - bm->left = bm->top = 0; - return bm; -} - -void ass_free_bitmap(Bitmap *bm) -{ - if (bm) - free(bm->buffer); - free(bm); -} - -static Bitmap *copy_bitmap(const Bitmap *src) -{ - Bitmap *dst = alloc_bitmap(src->w, src->h); - dst->left = src->left; - dst->top = src->top; - memcpy(dst->buffer, src->buffer, src->stride * src->h); - return dst; -} - -Bitmap *outline_to_bitmap(ASS_Library *library, FT_Library ftlib, - FT_Outline *outline, int bord) -{ - Bitmap *bm; - int w, h; - int error; - FT_BBox bbox; - FT_Bitmap bitmap; - - FT_Outline_Get_CBox(outline, &bbox); - // move glyph to origin (0, 0) - bbox.xMin &= ~63; - bbox.yMin &= ~63; - FT_Outline_Translate(outline, -bbox.xMin, -bbox.yMin); - // bitmap size - bbox.xMax = (bbox.xMax + 63) & ~63; - bbox.yMax = (bbox.yMax + 63) & ~63; - w = (bbox.xMax - bbox.xMin) >> 6; - h = (bbox.yMax - bbox.yMin) >> 6; - // pen offset - bbox.xMin >>= 6; - bbox.yMax >>= 6; - - if (w * h > 8000000) { - ass_msg(library, MSGL_WARN, "Glyph bounding box too large: %dx%dpx", - w, h); - return NULL; - } - - // allocate and set up bitmap - bm = alloc_bitmap(w + 2 * bord, h + 2 * bord); - bm->left = bbox.xMin - bord; - bm->top = -bbox.yMax - bord; - bitmap.width = w; - bitmap.rows = h; - bitmap.pitch = bm->stride; - bitmap.buffer = bm->buffer + bord + bm->stride * bord; - bitmap.num_grays = 256; - bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; - - // render into target bitmap - if ((error = FT_Outline_Get_Bitmap(ftlib, outline, &bitmap))) { - ass_msg(library, MSGL_WARN, "Failed to rasterize glyph: %d\n", error); - ass_free_bitmap(bm); - return NULL; - } - - return bm; -} - -/** - * \brief fix outline bitmap - * - * The glyph bitmap is subtracted from outline bitmap. This way looks much - * better in some cases. - */ -static void fix_outline(Bitmap *bm_g, Bitmap *bm_o) -{ - int x, y; - const int l = bm_o->left > bm_g->left ? bm_o->left : bm_g->left; - const int t = bm_o->top > bm_g->top ? bm_o->top : bm_g->top; - const int r = - bm_o->left + bm_o->stride < - bm_g->left + bm_g->stride ? bm_o->left + bm_o->stride : bm_g->left + bm_g->stride; - const int b = - bm_o->top + bm_o->h < - bm_g->top + bm_g->h ? bm_o->top + bm_o->h : bm_g->top + bm_g->h; - - unsigned char *g = - bm_g->buffer + (t - bm_g->top) * bm_g->stride + (l - bm_g->left); - unsigned char *o = - bm_o->buffer + (t - bm_o->top) * bm_o->stride + (l - bm_o->left); - - for (y = 0; y < b - t; ++y) { - for (x = 0; x < r - l; ++x) { - unsigned char c_g, c_o; - c_g = g[x]; - c_o = o[x]; - o[x] = (c_o > c_g) ? c_o - (c_g / 2) : 0; - } - g += bm_g->stride; - o += bm_o->stride; - } -} - -/** - * \brief Shift a bitmap by the fraction of a pixel in x and y direction - * expressed in 26.6 fixed point - */ -static void shift_bitmap(Bitmap *bm, int shift_x, int shift_y) -{ - int x, y, b; - int w = bm->w; - int h = bm->h; - int s = bm->stride; - unsigned char *buf = bm->buffer; - - // Shift in x direction - if (shift_x > 0) { - for (y = 0; y < h; y++) { - for (x = w - 1; x > 0; x--) { - b = (buf[x + y * s - 1] * shift_x) >> 6; - buf[x + y * s - 1] -= b; - buf[x + y * s] += b; - } - } - } else if (shift_x < 0) { - shift_x = -shift_x; - for (y = 0; y < h; y++) { - for (x = 0; x < w - 1; x++) { - b = (buf[x + y * s + 1] * shift_x) >> 6; - buf[x + y * s + 1] -= b; - buf[x + y * s] += b; - } - } - } - - // Shift in y direction - if (shift_y > 0) { - for (x = 0; x < w; x++) { - for (y = h - 1; y > 0; y--) { - b = (buf[x + (y - 1) * s] * shift_y) >> 6; - buf[x + (y - 1) * s] -= b; - buf[x + y * s] += b; - } - } - } else if (shift_y < 0) { - shift_y = -shift_y; - for (x = 0; x < w; x++) { - for (y = 0; y < h - 1; y++) { - b = (buf[x + (y + 1) * s] * shift_y) >> 6; - buf[x + (y + 1) * s] -= b; - buf[x + y * s] += b; - } - } - } -} - -/* - * Gaussian blur. An fast pure C implementation from MPlayer. - */ -static void ass_gauss_blur(unsigned char *buffer, unsigned short *tmp2, - int width, int height, int stride, int *m2, - int r, int mwidth) -{ - - int x, y; - - unsigned char *s = buffer; - unsigned short *t = tmp2 + 1; - for (y = 0; y < height; y++) { - memset(t - 1, 0, (width + 1) * sizeof(short)); - - for (x = 0; x < r; x++) { - const int src = s[x]; - if (src) { - register unsigned short *dstp = t + x - r; - int mx; - unsigned *m3 = (unsigned *) (m2 + src * mwidth); - for (mx = r - x; mx < mwidth; mx++) { - dstp[mx] += m3[mx]; - } - } - } - - for (; x < width - r; x++) { - const int src = s[x]; - if (src) { - register unsigned short *dstp = t + x - r; - int mx; - unsigned *m3 = (unsigned *) (m2 + src * mwidth); - for (mx = 0; mx < mwidth; mx++) { - dstp[mx] += m3[mx]; - } - } - } - - for (; x < width; x++) { - const int src = s[x]; - if (src) { - register unsigned short *dstp = t + x - r; - int mx; - const int x2 = r + width - x; - unsigned *m3 = (unsigned *) (m2 + src * mwidth); - for (mx = 0; mx < x2; mx++) { - dstp[mx] += m3[mx]; - } - } - } - - s += stride; - t += width + 1; - } - - t = tmp2; - for (x = 0; x < width; x++) { - for (y = 0; y < r; y++) { - unsigned short *srcp = t + y * (width + 1) + 1; - int src = *srcp; - if (src) { - register unsigned short *dstp = srcp - 1 + width + 1; - const int src2 = (src + 128) >> 8; - unsigned *m3 = (unsigned *) (m2 + src2 * mwidth); - - int mx; - *srcp = 128; - for (mx = r - 1; mx < mwidth; mx++) { - *dstp += m3[mx]; - dstp += width + 1; - } - } - } - for (; y < height - r; y++) { - unsigned short *srcp = t + y * (width + 1) + 1; - int src = *srcp; - if (src) { - register unsigned short *dstp = srcp - 1 - r * (width + 1); - const int src2 = (src + 128) >> 8; - unsigned *m3 = (unsigned *) (m2 + src2 * mwidth); - - int mx; - *srcp = 128; - for (mx = 0; mx < mwidth; mx++) { - *dstp += m3[mx]; - dstp += width + 1; - } - } - } - for (; y < height; y++) { - unsigned short *srcp = t + y * (width + 1) + 1; - int src = *srcp; - if (src) { - const int y2 = r + height - y; - register unsigned short *dstp = srcp - 1 - r * (width + 1); - const int src2 = (src + 128) >> 8; - unsigned *m3 = (unsigned *) (m2 + src2 * mwidth); - - int mx; - *srcp = 128; - for (mx = 0; mx < y2; mx++) { - *dstp += m3[mx]; - dstp += width + 1; - } - } - } - t++; - } - - t = tmp2; - s = buffer; - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - s[x] = t[x] >> 8; - } - s += stride; - t += width + 1; - } -} - -/** - * \brief Blur with [[1,2,1]. [2,4,2], [1,2,1]] kernel - * This blur is the same as the one employed by vsfilter. - */ -static void be_blur(Bitmap *bm) -{ - int w = bm->w; - int h = bm->h; - int s = bm->stride; - unsigned char *buf = bm->buffer; - unsigned int x, y; - unsigned int old_sum, new_sum; - - for (y = 0; y < h; y++) { - old_sum = 2 * buf[y * s]; - for (x = 0; x < w - 1; x++) { - new_sum = buf[y * s + x] + buf[y * s + x + 1]; - buf[y * s + x] = (old_sum + new_sum) >> 2; - old_sum = new_sum; - } - } - - for (x = 0; x < w; x++) { - old_sum = 2 * buf[x]; - for (y = 0; y < h - 1; y++) { - new_sum = buf[y * s + x] + buf[(y + 1) * s + x]; - buf[y * s + x] = (old_sum + new_sum) >> 2; - old_sum = new_sum; - } - } -} - -int outline_to_bitmap3(ASS_Library *library, ASS_SynthPriv *priv_blur, - FT_Library ftlib, FT_Outline *outline, FT_Outline *border, - Bitmap **bm_g, Bitmap **bm_o, Bitmap **bm_s, - int be, double blur_radius, FT_Vector shadow_offset, - int border_style) -{ - int bord, bbord, gbord; - blur_radius *= 2; - bbord = be > 0 ? sqrt(2 * be) : 0; - gbord = blur_radius > 0.0 ? blur_radius + 1 : 0; - bord = FFMAX(bbord, gbord); - if (bord == 0 && (shadow_offset.x || shadow_offset.y)) - bord = 1; - - assert(bm_g && bm_o && bm_s); - - *bm_g = *bm_o = *bm_s = 0; - - if (outline) - *bm_g = outline_to_bitmap(library, ftlib, outline, bord); - if (!*bm_g) - return 1; - - if (border) { - *bm_o = outline_to_bitmap(library, ftlib, border, bord); - if (!*bm_o) { - return 1; - } - } - - // Apply box blur (multiple passes, if requested) - while (be--) { - if (*bm_o) - be_blur(*bm_o); - else - be_blur(*bm_g); - } - - // Apply gaussian blur - if (blur_radius > 0.0) { - if (*bm_o) - resize_tmp(priv_blur, (*bm_o)->w, (*bm_o)->h); - else - resize_tmp(priv_blur, (*bm_g)->w, (*bm_g)->h); - generate_tables(priv_blur, blur_radius); - if (*bm_o) - ass_gauss_blur((*bm_o)->buffer, priv_blur->tmp, - (*bm_o)->w, (*bm_o)->h, (*bm_o)->stride, - (int *) priv_blur->gt2, priv_blur->g_r, - priv_blur->g_w); - else - ass_gauss_blur((*bm_g)->buffer, priv_blur->tmp, - (*bm_g)->w, (*bm_g)->h, (*bm_g)->stride, - (int *) priv_blur->gt2, priv_blur->g_r, - priv_blur->g_w); - } - - // Create shadow and fix outline as needed - if (*bm_o && border_style != 3) { - *bm_s = copy_bitmap(*bm_o); - fix_outline(*bm_g, *bm_o); - } else if (*bm_o) { - *bm_s = copy_bitmap(*bm_o); - } else - *bm_s = copy_bitmap(*bm_g); - - assert(bm_s); - - shift_bitmap(*bm_s, shadow_offset.x, shadow_offset.y); - - return 0; -} diff --git a/lib/libass/libass/ass_bitmap.h b/lib/libass/libass/ass_bitmap.h deleted file mode 100644 index 2a46aec447..0000000000 --- a/lib/libass/libass/ass_bitmap.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef LIBASS_BITMAP_H -#define LIBASS_BITMAP_H - -#include <ft2build.h> -#include FT_GLYPH_H - -#include "ass.h" - -typedef struct ass_synth_priv ASS_SynthPriv; - -ASS_SynthPriv *ass_synth_init(double); -void ass_synth_done(ASS_SynthPriv *priv); - -typedef struct { - int left, top; - int w, h; // width, height - int stride; - unsigned char *buffer; // w x h buffer -} Bitmap; - -Bitmap *outline_to_bitmap(ASS_Library *library, FT_Library ftlib, - FT_Outline *outline, int bord); -/** - * \brief perform glyph rendering - * \param glyph original glyph - * \param outline_glyph "border" glyph, produced from original by FreeType's glyph stroker - * \param bm_g out: pointer to the bitmap of original glyph is returned here - * \param bm_o out: pointer to the bitmap of outline (border) glyph is returned here - * \param bm_g out: pointer to the bitmap of glyph shadow is returned here - * \param be 1 = produces blurred bitmaps, 0 = normal bitmaps - */ -int outline_to_bitmap3(ASS_Library *library, ASS_SynthPriv *priv_blur, - FT_Library ftlib, FT_Outline *outline, FT_Outline *border, - Bitmap **bm_g, Bitmap **bm_o, Bitmap **bm_s, - int be, double blur_radius, FT_Vector shadow_offset, - int border_style); - -void ass_free_bitmap(Bitmap *bm); - -#endif /* LIBASS_BITMAP_H */ diff --git a/lib/libass/libass/ass_cache.c b/lib/libass/libass/ass_cache.c deleted file mode 100644 index 91801a0abc..0000000000 --- a/lib/libass/libass/ass_cache.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "config.h" - -#include <inttypes.h> -#include <ft2build.h> -#include FT_OUTLINE_H -#include <assert.h> - -#include "ass_utils.h" -#include "ass_font.h" -#include "ass_cache.h" - -// type-specific functions -// create hash/compare functions for bitmap, outline and composite cache -#define CREATE_HASH_FUNCTIONS -#include "ass_cache_template.h" -#define CREATE_COMPARISON_FUNCTIONS -#include "ass_cache_template.h" - -// font cache -static unsigned font_hash(void *buf, size_t len) -{ - ASS_FontDesc *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); - hval = fnv_32a_buf(&desc->treat_family_as_pattern, - sizeof(desc->treat_family_as_pattern), hval); - hval = fnv_32a_buf(&desc->vertical, sizeof(desc->vertical), hval); - return hval; -} - -static unsigned font_compare(void *key1, void *key2, size_t key_size) -{ - ASS_FontDesc *a = key1; - ASS_FontDesc *b = key2; - if (strcmp(a->family, b->family) != 0) - return 0; - if (a->bold != b->bold) - return 0; - if (a->italic != b->italic) - return 0; - if (a->treat_family_as_pattern != b->treat_family_as_pattern) - return 0; - if (a->vertical != b->vertical) - return 0; - return 1; -} - -static void font_destruct(void *key, void *value) -{ - ass_font_free(value); - free(key); -} - -// bitmap cache -static void bitmap_destruct(void *key, void *value) -{ - BitmapHashValue *v = value; - BitmapHashKey *k = key; - 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); - if (k->type == BITMAP_CLIP) - free(k->u.clip.text); - free(key); - free(value); -} - -static size_t bitmap_size(void *value, size_t value_size) -{ - BitmapHashValue *val = value; - if (val->bm_o) - return val->bm_o->w * val->bm_o->h * 3; - else if (val->bm) - return val->bm->w * val->bm->h * 3; - return 0; -} - -static unsigned bitmap_hash(void *key, size_t key_size) -{ - BitmapHashKey *k = key; - switch (k->type) { - case BITMAP_OUTLINE: return outline_bitmap_hash(&k->u, key_size); - case BITMAP_CLIP: return clip_bitmap_hash(&k->u, key_size); - default: return 0; - } -} - -static unsigned bitmap_compare (void *a, void *b, size_t key_size) -{ - BitmapHashKey *ak = a; - BitmapHashKey *bk = b; - if (ak->type != bk->type) return 0; - switch (ak->type) { - case BITMAP_OUTLINE: return outline_bitmap_compare(&ak->u, &bk->u, key_size); - case BITMAP_CLIP: return clip_bitmap_compare(&ak->u, &bk->u, key_size); - default: return 0; - } -} - -// composite cache -static void composite_destruct(void *key, void *value) -{ - CompositeHashValue *v = value; - free(v->a); - free(v->b); - free(key); - free(value); -} - -// outline cache - -static unsigned outline_hash(void *key, size_t key_size) -{ - OutlineHashKey *k = key; - switch (k->type) { - case OUTLINE_GLYPH: return glyph_hash(&k->u, key_size); - case OUTLINE_DRAWING: return drawing_hash(&k->u, key_size); - default: return 0; - } -} - -static unsigned outline_compare(void *a, void *b, size_t key_size) -{ - OutlineHashKey *ak = a; - OutlineHashKey *bk = b; - if (ak->type != bk->type) return 0; - switch (ak->type) { - case OUTLINE_GLYPH: return glyph_compare(&ak->u, &bk->u, key_size); - case OUTLINE_DRAWING: return drawing_compare(&ak->u, &bk->u, key_size); - default: return 0; - } -} - -static void outline_destruct(void *key, void *value) -{ - OutlineHashValue *v = value; - OutlineHashKey *k = key; - if (v->outline) - outline_free(v->lib, v->outline); - if (v->border) - outline_free(v->lib, v->border); - if (k->type == OUTLINE_DRAWING) - free(k->u.drawing.text); - free(key); - free(value); -} - - - -// Cache data -typedef struct cache_item { - void *key; - void *value; - struct cache_item *next; -} CacheItem; - -struct cache { - unsigned buckets; - CacheItem **map; - - HashFunction hash_func; - ItemSize size_func; - HashCompare compare_func; - CacheItemDestructor destruct_func; - size_t key_size; - size_t value_size; - - size_t cache_size; - unsigned hits; - unsigned misses; - unsigned items; -}; - -// Hash for a simple (single value or array) type -static unsigned hash_simple(void *key, size_t key_size) -{ - return fnv_32a_buf(key, key_size, FNV1_32A_INIT); -} - -// Comparison of a simple type -static unsigned compare_simple(void *a, void *b, size_t key_size) -{ - return memcmp(a, b, key_size) == 0; -} - -// Default destructor -static void destruct_simple(void *key, void *value) -{ - free(key); - free(value); -} - - -// Create a cache with type-specific hash/compare/destruct/size functions -Cache *ass_cache_create(HashFunction hash_func, HashCompare compare_func, - CacheItemDestructor destruct_func, ItemSize size_func, - size_t key_size, size_t value_size) -{ - Cache *cache = calloc(1, sizeof(*cache)); - cache->buckets = 0xFFFF; - cache->hash_func = hash_simple; - cache->compare_func = compare_simple; - cache->destruct_func = destruct_simple; - cache->size_func = size_func; - if (hash_func) - cache->hash_func = hash_func; - if (compare_func) - cache->compare_func = compare_func; - if (destruct_func) - cache->destruct_func = destruct_func; - cache->key_size = key_size; - cache->value_size = value_size; - cache->map = calloc(cache->buckets, sizeof(CacheItem *)); - - return cache; -} - -void *ass_cache_put(Cache *cache, void *key, void *value) -{ - unsigned bucket = cache->hash_func(key, cache->key_size) % cache->buckets; - CacheItem **item = &cache->map[bucket]; - while (*item) - item = &(*item)->next; - (*item) = calloc(1, sizeof(CacheItem)); - (*item)->key = malloc(cache->key_size); - (*item)->value = malloc(cache->value_size); - memcpy((*item)->key, key, cache->key_size); - memcpy((*item)->value, value, cache->value_size); - - cache->items++; - if (cache->size_func) - cache->cache_size += cache->size_func(value, cache->value_size); - else - cache->cache_size++; - - return (*item)->value; -} - -void *ass_cache_get(Cache *cache, void *key) -{ - unsigned bucket = cache->hash_func(key, cache->key_size) % cache->buckets; - CacheItem *item = cache->map[bucket]; - while (item) { - if (cache->compare_func(key, item->key, cache->key_size)) { - cache->hits++; - return item->value; - } - item = item->next; - } - cache->misses++; - return NULL; -} - -int ass_cache_empty(Cache *cache, size_t max_size) -{ - int i; - - if (cache->cache_size < max_size) - return 0; - - for (i = 0; i < cache->buckets; i++) { - CacheItem *item = cache->map[i]; - while (item) { - CacheItem *next = item->next; - cache->destruct_func(item->key, item->value); - free(item); - item = next; - } - cache->map[i] = NULL; - } - - cache->items = cache->hits = cache->misses = cache->cache_size = 0; - - return 1; -} - -void ass_cache_stats(Cache *cache, size_t *size, unsigned *hits, - unsigned *misses, unsigned *count) -{ - if (size) - *size = cache->cache_size; - if (hits) - *hits = cache->hits; - if (misses) - *misses = cache->misses; - if (count) - *count = cache->items; -} - -void ass_cache_done(Cache *cache) -{ - ass_cache_empty(cache, 0); - free(cache->map); - free(cache); -} - -// Type-specific creation function -Cache *ass_font_cache_create(void) -{ - return ass_cache_create(font_hash, font_compare, font_destruct, - (ItemSize)NULL, sizeof(ASS_FontDesc), sizeof(ASS_Font)); -} - -Cache *ass_outline_cache_create(void) -{ - return ass_cache_create(outline_hash, outline_compare, outline_destruct, - NULL, sizeof(OutlineHashKey), sizeof(OutlineHashValue)); -} - -Cache *ass_glyph_metrics_cache_create(void) -{ - return ass_cache_create(glyph_metrics_hash, glyph_metrics_compare, NULL, - (ItemSize) NULL, sizeof(GlyphMetricsHashKey), - sizeof(GlyphMetricsHashValue)); -} - -Cache *ass_bitmap_cache_create(void) -{ - return ass_cache_create(bitmap_hash, bitmap_compare, bitmap_destruct, - bitmap_size, sizeof(BitmapHashKey), sizeof(BitmapHashValue)); -} - -Cache *ass_composite_cache_create(void) -{ - return ass_cache_create(composite_hash, composite_compare, - composite_destruct, (ItemSize)NULL, sizeof(CompositeHashKey), - sizeof(CompositeHashValue)); -} diff --git a/lib/libass/libass/ass_cache.h b/lib/libass/libass/ass_cache.h deleted file mode 100644 index 7375f04343..0000000000 --- a/lib/libass/libass/ass_cache.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef LIBASS_CACHE_H -#define LIBASS_CACHE_H - -#include "ass.h" -#include "ass_font.h" -#include "ass_bitmap.h" - -typedef struct cache Cache; - -// cache values - -typedef struct { - Bitmap *bm; // the actual bitmaps - Bitmap *bm_o; - Bitmap *bm_s; -} BitmapHashValue; - -typedef struct { - unsigned char *a; - unsigned char *b; -} CompositeHashValue; - -typedef struct { - FT_Library lib; - FT_Outline *outline; - FT_Outline *border; - FT_BBox bbox_scaled; // bbox after scaling, but before rotation - FT_Vector advance; // 26.6, advance distance to the next outline in line - int asc, desc; // ascender/descender -} OutlineHashValue; - -typedef struct { - FT_Glyph_Metrics metrics; -} GlyphMetricsHashValue; - -// Create definitions for bitmap, outline and composite hash keys -#define CREATE_STRUCT_DEFINITIONS -#include "ass_cache_template.h" - -// Type-specific function pointers -typedef unsigned(*HashFunction)(void *key, size_t key_size); -typedef size_t(*ItemSize)(void *value, size_t value_size); -typedef unsigned(*HashCompare)(void *a, void *b, size_t key_size); -typedef void(*CacheItemDestructor)(void *key, void *value); - -// cache hash keys - -typedef struct outline_hash_key { - enum { - OUTLINE_GLYPH, - OUTLINE_DRAWING, - } type; - union { - GlyphHashKey glyph; - DrawingHashKey drawing; - } u; -} OutlineHashKey; - -typedef struct bitmap_hash_key { - enum { - BITMAP_OUTLINE, - BITMAP_CLIP, - } type; - union { - OutlineBitmapHashKey outline; - ClipMaskHashKey clip; - } u; -} BitmapHashKey; - -Cache *ass_cache_create(HashFunction hash_func, HashCompare compare_func, - CacheItemDestructor destruct_func, ItemSize size_func, - size_t key_size, size_t value_size); -void *ass_cache_put(Cache *cache, void *key, void *value); -void *ass_cache_get(Cache *cache, void *key); -int ass_cache_empty(Cache *cache, size_t max_size); -void ass_cache_stats(Cache *cache, size_t *size, unsigned *hits, - unsigned *misses, unsigned *count); -void ass_cache_done(Cache *cache); -Cache *ass_font_cache_create(void); -Cache *ass_outline_cache_create(void); -Cache *ass_glyph_metrics_cache_create(void); -Cache *ass_bitmap_cache_create(void); -Cache *ass_composite_cache_create(void); - -#endif /* LIBASS_CACHE_H */ diff --git a/lib/libass/libass/ass_cache_template.h b/lib/libass/libass/ass_cache_template.h deleted file mode 100644 index f9aab77919..0000000000 --- a/lib/libass/libass/ass_cache_template.h +++ /dev/null @@ -1,144 +0,0 @@ -#ifdef CREATE_STRUCT_DEFINITIONS -#undef CREATE_STRUCT_DEFINITIONS -#define START(funcname, structname) \ - typedef struct structname { -#define GENERIC(type, member) \ - type member; -#define STRING(member) \ - char *member; -#define FTVECTOR(member) \ - FT_Vector member; -#define BITMAPHASHKEY(member) \ - BitmapHashKey member; -#define END(typedefnamename) \ - } typedefnamename; - -#elif defined(CREATE_COMPARISON_FUNCTIONS) -#undef CREATE_COMPARISON_FUNCTIONS -#define START(funcname, structname) \ - static unsigned funcname##_compare(void *key1, void *key2, size_t key_size) \ - { \ - struct structname *a = key1; \ - struct structname *b = key2; \ - return // conditions follow -#define GENERIC(type, member) \ - a->member == b->member && -#define STRING(member) \ - strcmp(a->member, b->member) == 0 && -#define FTVECTOR(member) \ - a->member.x == b->member.x && a->member.y == b->member.y && -#define BITMAPHASHKEY(member) \ - bitmap_compare(&a->member, &b->member, sizeof(a->member)) && -#define END(typedefname) \ - 1; \ - } - -#elif defined(CREATE_HASH_FUNCTIONS) -#undef CREATE_HASH_FUNCTIONS -#define START(funcname, structname) \ - static unsigned funcname##_hash(void *buf, size_t len) \ - { \ - struct structname *p = buf; \ - unsigned hval = FNV1_32A_INIT; -#define GENERIC(type, member) \ - hval = fnv_32a_buf(&p->member, sizeof(p->member), hval); -#define STRING(member) \ - hval = fnv_32a_str(p->member, hval); -#define FTVECTOR(member) GENERIC(, member.x); GENERIC(, member.y); -#define BITMAPHASHKEY(member) { \ - unsigned temp = bitmap_hash(&p->member, sizeof(p->member)); \ - hval = fnv_32a_buf(&temp, sizeof(temp), hval); \ - } -#define END(typedefname) \ - return hval; \ - } - -#else -#error missing defines -#endif - - - -// describes an outline bitmap -START(outline_bitmap, outline_bitmap_hash_key) - GENERIC(OutlineHashValue *, outline) - GENERIC(char, be) // blur edges - GENERIC(double, blur) // gaussian blur - GENERIC(int, frx) // signed 16.16 - GENERIC(int, fry) // signed 16.16 - GENERIC(int, frz) // signed 16.16 - GENERIC(int, fax) // signed 16.16 - GENERIC(int, fay) // signed 16.16 - // shift vector that was added to glyph before applying rotation - // = 0, if frx = fry = frx = 0 - // = (glyph base point) - (rotation origin), otherwise - GENERIC(int, shift_x) - GENERIC(int, shift_y) - FTVECTOR(advance) // subpixel shift vector - FTVECTOR(shadow_offset) // shadow subpixel shift -END(OutlineBitmapHashKey) - -// describe a clip mask bitmap -START(clip_bitmap, clip_bitmap_hash_key) - STRING(text) -END(ClipMaskHashKey) - -// describes an outline glyph -START(glyph, glyph_hash_key) - GENERIC(ASS_Font *, font) - GENERIC(double, size) // font size - GENERIC(int, face_index) - GENERIC(int, glyph_index) - GENERIC(int, bold) - GENERIC(int, italic) - GENERIC(unsigned, scale_x) // 16.16 - GENERIC(unsigned, scale_y) // 16.16 - FTVECTOR(outline) // border width, 16.16 - GENERIC(unsigned, flags) // glyph decoration flags - GENERIC(unsigned, border_style) -END(GlyphHashKey) - -START(glyph_metrics, glyph_metrics_hash_key) - GENERIC(ASS_Font *, font) - GENERIC(double, size) - GENERIC(int, face_index) - GENERIC(int, glyph_index) - GENERIC(unsigned, scale_x) - GENERIC(unsigned, scale_y) -END(GlyphMetricsHashKey) - -// describes an outline drawing -START(drawing, drawing_hash_key) - GENERIC(unsigned, scale_x) - GENERIC(unsigned, scale_y) - GENERIC(int, pbo) - FTVECTOR(outline) - GENERIC(unsigned, border_style) - GENERIC(int, scale) - GENERIC(unsigned, hash) - STRING(text) -END(DrawingHashKey) - -// Cache for composited bitmaps -START(composite, composite_hash_key) - GENERIC(int, aw) - GENERIC(int, ah) - GENERIC(int, bw) - GENERIC(int, bh) - GENERIC(int, ax) - GENERIC(int, ay) - GENERIC(int, bx) - GENERIC(int, by) - GENERIC(int, as) - GENERIC(int, bs) - GENERIC(unsigned char *, a) - GENERIC(unsigned char *, b) -END(CompositeHashKey) - - -#undef START -#undef GENERIC -#undef STRING -#undef FTVECTOR -#undef BITMAPHASHKEY -#undef END diff --git a/lib/libass/libass/ass_drawing.c b/lib/libass/libass/ass_drawing.c deleted file mode 100644 index 764e6f66b0..0000000000 --- a/lib/libass/libass/ass_drawing.c +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <ft2build.h> -#include FT_OUTLINE_H -#include FT_BBOX_H -#include <math.h> - -#include "ass_utils.h" -#include "ass_drawing.h" - -#define CURVE_ACCURACY 64.0 -#define GLYPH_INITIAL_POINTS 100 -#define GLYPH_INITIAL_CONTOURS 5 - -/* - * \brief Add a single point to a contour. - */ -static inline void drawing_add_point(ASS_Drawing *drawing, - FT_Vector *point) -{ - FT_Outline *ol = &drawing->outline; - - if (ol->n_points >= drawing->max_points) { - drawing->max_points *= 2; - ol->points = realloc(ol->points, sizeof(FT_Vector) * - drawing->max_points); - ol->tags = realloc(ol->tags, drawing->max_points); - } - - ol->points[ol->n_points].x = point->x; - ol->points[ol->n_points].y = point->y; - ol->tags[ol->n_points] = 1; - ol->n_points++; -} - -/* - * \brief Close a contour and check outline size overflow. - */ -static inline void drawing_close_shape(ASS_Drawing *drawing) -{ - FT_Outline *ol = &drawing->outline; - - if (ol->n_contours >= drawing->max_contours) { - drawing->max_contours *= 2; - ol->contours = realloc(ol->contours, sizeof(short) * - drawing->max_contours); - } - - if (ol->n_points) { - ol->contours[ol->n_contours] = ol->n_points - 1; - ol->n_contours++; - } -} - -/* - * \brief Prepare drawing for parsing. This just sets a few parameters. - */ -static void drawing_prepare(ASS_Drawing *drawing) -{ - // Scaling parameters - drawing->point_scale_x = drawing->scale_x * - 64.0 / (1 << (drawing->scale - 1)); - drawing->point_scale_y = drawing->scale_y * - 64.0 / (1 << (drawing->scale - 1)); -} - -/* - * \brief Finish a drawing. This only sets the horizontal advance according - * to the outline's bbox at the moment. - */ -static void drawing_finish(ASS_Drawing *drawing, int raw_mode) -{ - int i, offset; - FT_BBox bbox = drawing->cbox; - FT_Outline *ol = &drawing->outline; - - // Close the last contour - drawing_close_shape(drawing); - - if (drawing->library) - ass_msg(drawing->library, MSGL_V, - "Parsed drawing with %d points and %d contours", ol->n_points, - ol->n_contours); - - if (raw_mode) - return; - - drawing->advance.x = bbox.xMax - bbox.xMin; - - drawing->desc = double_to_d6(-drawing->pbo * drawing->scale_y); - drawing->asc = bbox.yMax - bbox.yMin + drawing->desc; - - // Place it onto the baseline - offset = (bbox.yMax - bbox.yMin) + double_to_d6(-drawing->pbo * - drawing->scale_y); - for (i = 0; i < ol->n_points; i++) - ol->points[i].y += offset; -} - -/* - * \brief Check whether a number of items on the list is available - */ -static int token_check_values(ASS_DrawingToken *token, int i, int type) -{ - int j; - for (j = 0; j < i; j++) { - if (!token || token->type != type) return 0; - token = token->next; - } - - return 1; -} - -/* - * \brief Tokenize a drawing string into a list of ASS_DrawingToken - * This also expands points for closing b-splines - */ -static ASS_DrawingToken *drawing_tokenize(char *str) -{ - char *p = str; - int i, val, type = -1, is_set = 0; - FT_Vector point = {0, 0}; - - ASS_DrawingToken *root = NULL, *tail = NULL, *spline_start = NULL; - - while (*p) { - if (*p == 'c' && spline_start) { - // Close b-splines: add the first three points of the b-spline - // back to the end - if (token_check_values(spline_start->next, 2, TOKEN_B_SPLINE)) { - for (i = 0; i < 3; i++) { - tail->next = calloc(1, sizeof(ASS_DrawingToken)); - tail->next->prev = tail; - tail = tail->next; - tail->type = TOKEN_B_SPLINE; - tail->point = spline_start->point; - spline_start = spline_start->next; - } - spline_start = NULL; - } - } else if (!is_set && mystrtoi(&p, &val)) { - point.x = val; - is_set = 1; - p--; - } else if (is_set == 1 && mystrtoi(&p, &val)) { - point.y = val; - is_set = 2; - p--; - } else if (*p == 'm') - type = TOKEN_MOVE; - else if (*p == 'n') - type = TOKEN_MOVE_NC; - else if (*p == 'l') - type = TOKEN_LINE; - else if (*p == 'b') - type = TOKEN_CUBIC_BEZIER; - else if (*p == 'q') - type = TOKEN_CONIC_BEZIER; - else if (*p == 's') - type = TOKEN_B_SPLINE; - // We're simply ignoring TOKEN_EXTEND_B_SPLINE here. - // This is not harmful at all, since it can be ommitted with - // similar result (the spline is extended anyway). - - if (type != -1 && is_set == 2) { - if (root) { - tail->next = calloc(1, sizeof(ASS_DrawingToken)); - tail->next->prev = tail; - tail = tail->next; - } else - root = tail = calloc(1, sizeof(ASS_DrawingToken)); - tail->type = type; - tail->point = point; - is_set = 0; - if (type == TOKEN_B_SPLINE && !spline_start) - spline_start = tail->prev; - } - p++; - } - - return root; -} - -/* - * \brief Free a list of tokens - */ -static void drawing_free_tokens(ASS_DrawingToken *token) -{ - while (token) { - ASS_DrawingToken *at = token; - token = token->next; - free(at); - } -} - -/* - * \brief Update drawing cbox - */ -static inline void update_cbox(ASS_Drawing *drawing, FT_Vector *point) -{ - FT_BBox *box = &drawing->cbox; - - box->xMin = FFMIN(box->xMin, point->x); - box->xMax = FFMAX(box->xMax, point->x); - box->yMin = FFMIN(box->yMin, point->y); - box->yMax = FFMAX(box->yMax, point->y); -} - -/* - * \brief Translate and scale a point coordinate according to baseline - * offset and scale. - */ -static inline void translate_point(ASS_Drawing *drawing, FT_Vector *point) -{ - point->x = drawing->point_scale_x * point->x; - point->y = drawing->point_scale_y * -point->y; - - update_cbox(drawing, point); -} - -/* - * \brief Evaluate a curve into lines - * This curve evaluator is also used in VSFilter (RTS.cpp); it's a simple - * implementation of the De Casteljau algorithm. - */ -static void drawing_evaluate_curve(ASS_Drawing *drawing, - ASS_DrawingToken *token, char spline, - int started) -{ - double cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0; - double t, h, max_accel, max_accel1, max_accel2; - int x0, y0, x1, y1, x2, y2, x3, y3; - FT_Vector cur = {0, 0}; - - cur = token->point; - translate_point(drawing, &cur); - x0 = cur.x; - y0 = cur.y; - token = token->next; - cur = token->point; - translate_point(drawing, &cur); - x1 = cur.x; - y1 = cur.y; - token = token->next; - cur = token->point; - translate_point(drawing, &cur); - x2 = cur.x; - y2 = cur.y; - token = token->next; - cur = token->point; - translate_point(drawing, &cur); - x3 = cur.x; - y3 = cur.y; - - if (spline) { - // 1 [-1 +3 -3 +1] - // - * [+3 -6 +3 0] - // 6 [-3 0 +3 0] - // [+1 +4 +1 0] - - double div6 = 1.0/6.0; - - cx3 = div6*(- x0+3*x1-3*x2+x3); - cx2 = div6*( 3*x0-6*x1+3*x2); - cx1 = div6*(-3*x0 +3*x2); - cx0 = div6*( x0+4*x1+1*x2); - - cy3 = div6*(- y0+3*y1-3*y2+y3); - cy2 = div6*( 3*y0-6*y1+3*y2); - cy1 = div6*(-3*y0 +3*y2); - cy0 = div6*( y0+4*y1+1*y2); - } else { - // [-1 +3 -3 +1] - // [+3 -6 +3 0] - // [-3 +3 0 0] - // [+1 0 0 0] - - cx3 = - x0+3*x1-3*x2+x3; - cx2 = 3*x0-6*x1+3*x2; - cx1 = -3*x0+3*x1; - cx0 = x0; - - cy3 = - y0+3*y1-3*y2+y3; - cy2 = 3*y0-6*y1+3*y2; - cy1 = -3*y0+3*y1; - cy0 = y0; - } - - max_accel1 = fabs(2 * cy2) + fabs(6 * cy3); - max_accel2 = fabs(2 * cx2) + fabs(6 * cx3); - - max_accel = FFMAX(max_accel1, max_accel2); - h = 1.0; - - if (max_accel > CURVE_ACCURACY) - h = sqrt(CURVE_ACCURACY / max_accel); - - if (!started) { - cur.x = cx0; - cur.y = cy0; - drawing_add_point(drawing, &cur); - } - - for (t = 0; t < 1.0; t += h) { - cur.x = cx0 + t * (cx1 + t * (cx2 + t * cx3)); - cur.y = cy0 + t * (cy1 + t * (cy2 + t * cy3)); - drawing_add_point(drawing, &cur); - } - - cur.x = cx0 + cx1 + cx2 + cx3; - cur.y = cy0 + cy1 + cy2 + cy3; - drawing_add_point(drawing, &cur); -} - -/* - * \brief Create and initialize a new drawing and return it - */ -ASS_Drawing *ass_drawing_new(ASS_Library *lib, FT_Library ftlib) -{ - ASS_Drawing *drawing; - - drawing = calloc(1, sizeof(*drawing)); - drawing->text = calloc(1, DRAWING_INITIAL_SIZE); - drawing->size = DRAWING_INITIAL_SIZE; - drawing->cbox.xMin = drawing->cbox.yMin = INT_MAX; - drawing->cbox.xMax = drawing->cbox.yMax = INT_MIN; - drawing->ftlibrary = ftlib; - drawing->library = lib; - drawing->scale_x = 1.; - drawing->scale_y = 1.; - drawing->max_contours = GLYPH_INITIAL_CONTOURS; - drawing->max_points = GLYPH_INITIAL_POINTS; - - FT_Outline_New(drawing->ftlibrary, GLYPH_INITIAL_POINTS, - GLYPH_INITIAL_CONTOURS, &drawing->outline); - drawing->outline.n_contours = 0; - drawing->outline.n_points = 0; - - return drawing; -} - -/* - * \brief Free a drawing - */ -void ass_drawing_free(ASS_Drawing* drawing) -{ - if (drawing) { - free(drawing->text); - FT_Outline_Done(drawing->ftlibrary, &drawing->outline); - } - free(drawing); -} - -/* - * \brief Add one ASCII character to the drawing text buffer - */ -void ass_drawing_add_char(ASS_Drawing* drawing, char symbol) -{ - drawing->text[drawing->i++] = symbol; - drawing->text[drawing->i] = 0; - - if (drawing->i + 1 >= drawing->size) { - drawing->size *= 2; - drawing->text = realloc(drawing->text, drawing->size); - } -} - -/* - * \brief Create a hashcode for the drawing - * XXX: To avoid collisions a better hash algorithm might be useful. - */ -void ass_drawing_hash(ASS_Drawing* drawing) -{ - drawing->hash = fnv_32a_str(drawing->text, FNV1_32A_INIT); -} - -/* - * \brief Convert token list to outline. Calls the line and curve evaluators. - */ -FT_Outline *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode) -{ - int started = 0; - ASS_DrawingToken *token; - FT_Vector pen = {0, 0}; - - drawing->tokens = drawing_tokenize(drawing->text); - drawing_prepare(drawing); - - token = drawing->tokens; - while (token) { - // Draw something according to current command - switch (token->type) { - case TOKEN_MOVE_NC: - pen = token->point; - translate_point(drawing, &pen); - token = token->next; - break; - case TOKEN_MOVE: - pen = token->point; - translate_point(drawing, &pen); - if (started) { - drawing_close_shape(drawing); - started = 0; - } - token = token->next; - break; - case TOKEN_LINE: { - FT_Vector to; - to = token->point; - translate_point(drawing, &to); - if (!started) drawing_add_point(drawing, &pen); - drawing_add_point(drawing, &to); - started = 1; - token = token->next; - break; - } - case TOKEN_CUBIC_BEZIER: - if (token_check_values(token, 3, TOKEN_CUBIC_BEZIER) && - token->prev) { - drawing_evaluate_curve(drawing, token->prev, 0, started); - token = token->next; - token = token->next; - token = token->next; - started = 1; - } else - token = token->next; - break; - case TOKEN_B_SPLINE: - if (token_check_values(token, 3, TOKEN_B_SPLINE) && - token->prev) { - drawing_evaluate_curve(drawing, token->prev, 1, started); - token = token->next; - started = 1; - } else - token = token->next; - break; - default: - token = token->next; - break; - } - } - - drawing_finish(drawing, raw_mode); - drawing_free_tokens(drawing->tokens); - return &drawing->outline; -} diff --git a/lib/libass/libass/ass_drawing.h b/lib/libass/libass/ass_drawing.h deleted file mode 100644 index b17d7e3bea..0000000000 --- a/lib/libass/libass/ass_drawing.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef LIBASS_DRAWING_H -#define LIBASS_DRAWING_H - -#include <ft2build.h> -#include FT_OUTLINE_H - -#include "ass.h" - -#define DRAWING_INITIAL_SIZE 256 - -typedef enum { - TOKEN_MOVE, - TOKEN_MOVE_NC, - TOKEN_LINE, - TOKEN_CUBIC_BEZIER, - TOKEN_CONIC_BEZIER, - TOKEN_B_SPLINE, - TOKEN_EXTEND_SPLINE, - TOKEN_CLOSE -} ASS_TokenType; - -typedef struct ass_drawing_token { - ASS_TokenType type; - FT_Vector point; - struct ass_drawing_token *next; - struct ass_drawing_token *prev; -} ASS_DrawingToken; - -typedef struct { - char *text; // drawing string - int i; // text index - int scale; // scale (1-64) for subpixel accuracy - double pbo; // drawing will be shifted in y direction by this amount - double scale_x; // FontScaleX - double scale_y; // FontScaleY - int asc; // ascender - int desc; // descender - FT_Outline outline; // target outline - FT_Vector advance; // advance (from cbox) - int hash; // hash value (for caching) - - // private - FT_Library ftlibrary; // needed for font ops - ASS_Library *library; - int size; // current buffer size - ASS_DrawingToken *tokens; // tokenized drawing - int max_points; // current maximum size - int max_contours; - double point_scale_x; - double point_scale_y; - FT_BBox cbox; // bounding box, or let's say... VSFilter's idea of it -} ASS_Drawing; - -ASS_Drawing *ass_drawing_new(ASS_Library *lib, FT_Library ftlib); -void ass_drawing_free(ASS_Drawing* drawing); -void ass_drawing_add_char(ASS_Drawing* drawing, char symbol); -void ass_drawing_hash(ASS_Drawing* drawing); -FT_Outline *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode); - -#endif /* LIBASS_DRAWING_H */ diff --git a/lib/libass/libass/ass_font.c b/lib/libass/libass/ass_font.c deleted file mode 100644 index 4b6a71b6d5..0000000000 --- a/lib/libass/libass/ass_font.c +++ /dev/null @@ -1,776 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "config.h" - -#include <inttypes.h> -#include <ft2build.h> -#include FT_FREETYPE_H -#include FT_SYNTHESIS_H -#include FT_GLYPH_H -#include FT_TRUETYPE_TABLES_H -#include FT_OUTLINE_H -#ifndef _WIN32 -#include <strings.h> -#endif - -#include "ass.h" -#include "ass_library.h" -#include "ass_font.h" -#include "ass_fontconfig.h" -#include "ass_utils.h" -#include "ass_shaper.h" - -/** - * Select a good charmap, prefer Microsoft Unicode charmaps. - * Otherwise, let FreeType decide. - */ -static void charmap_magic(ASS_Library *library, FT_Face face) -{ - int i; - int ms_cmap = -1; - - // Search for a Microsoft Unicode cmap - for (i = 0; i < face->num_charmaps; ++i) { - FT_CharMap cmap = face->charmaps[i]; - unsigned pid = cmap->platform_id; - unsigned eid = cmap->encoding_id; - if (pid == 3 /*microsoft */ - && (eid == 1 /*unicode bmp */ - || eid == 10 /*full unicode */ )) { - FT_Set_Charmap(face, cmap); - return; - } else if (pid == 3 && ms_cmap < 0) - ms_cmap = i; - } - - // Try the first Microsoft cmap if no Microsoft Unicode cmap was found - if (ms_cmap >= 0) { - FT_CharMap cmap = face->charmaps[ms_cmap]; - FT_Set_Charmap(face, cmap); - return; - } - - if (!face->charmap) { - if (face->num_charmaps == 0) { - ass_msg(library, MSGL_WARN, "Font face with no charmaps"); - return; - } - ass_msg(library, MSGL_WARN, - "No charmap autodetected, trying the first one"); - FT_Set_Charmap(face, face->charmaps[0]); - return; - } -} - -/** - * \brief find a memory font by name - */ -static int find_font(ASS_Library *library, char *name) -{ - int i; - for (i = 0; i < library->num_fontdata; ++i) - if (strcasecmp(name, library->fontdata[i].name) == 0) - return i; - return -1; -} - -static void buggy_font_workaround(FT_Face face) -{ - // Some fonts have zero Ascender/Descender fields in 'hhea' table. - // In this case, get the information from 'os2' table or, as - // a last resort, from face.bbox. - if (face->ascender + face->descender == 0 || face->height == 0) { - TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); - if (os2) { - face->ascender = os2->sTypoAscender; - face->descender = os2->sTypoDescender; - face->height = face->ascender - face->descender; - } else { - face->ascender = face->bbox.yMax; - face->descender = face->bbox.yMin; - face->height = face->ascender - face->descender; - } - } -} - -/** - * \brief Select a face with the given charcode and add it to ASS_Font - * \return index of the new face in font->faces, -1 if failed - */ -static int add_face(void *fc_priv, ASS_Font *font, uint32_t ch) -{ - char *path; - int index; - FT_Face face; - int error; - int mem_idx; - - if (font->n_faces == ASS_FONT_MAX_FACES) - return -1; - - path = - fontconfig_select(font->library, fc_priv, font->desc.family, - font->desc.treat_family_as_pattern, - font->desc.bold, font->desc.italic, &index, ch); - if (!path) - return -1; - - mem_idx = find_font(font->library, path); - if (mem_idx >= 0) { - error = - FT_New_Memory_Face(font->ftlibrary, - (unsigned char *) font->library-> - fontdata[mem_idx].data, - font->library->fontdata[mem_idx].size, index, - &face); - if (error) { - ass_msg(font->library, MSGL_WARN, - "Error opening memory font: '%s'", path); - free(path); - return -1; - } - } else { - error = FT_New_Face(font->ftlibrary, path, index, &face); - if (error) { - ass_msg(font->library, MSGL_WARN, - "Error opening font: '%s', %d", path, index); - free(path); - return -1; - } - } - charmap_magic(font->library, face); - buggy_font_workaround(face); - - font->faces[font->n_faces++] = face; - ass_face_set_size(face, font->size); - free(path); - return font->n_faces - 1; -} - -/** - * \brief Create a new ASS_Font according to "desc" argument - */ -ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library, - FT_Library ftlibrary, void *fc_priv, - ASS_FontDesc *desc) -{ - int error; - ASS_Font *fontp; - ASS_Font font; - - fontp = ass_cache_get(font_cache, desc); - if (fontp) - return fontp; - - font.library = library; - font.ftlibrary = ftlibrary; - font.shaper_priv = NULL; - font.n_faces = 0; - font.desc.family = strdup(desc->family); - font.desc.treat_family_as_pattern = desc->treat_family_as_pattern; - font.desc.bold = desc->bold; - font.desc.italic = desc->italic; - font.desc.vertical = desc->vertical; - - font.scale_x = font.scale_y = 1.; - font.v.x = font.v.y = 0; - font.size = 0.; - - error = add_face(fc_priv, &font, 0); - if (error == -1) { - free(font.desc.family); - return 0; - } else - return ass_cache_put(font_cache, &font.desc, &font); -} - -/** - * \brief Set font transformation matrix and shift vector - **/ -void ass_font_set_transform(ASS_Font *font, double scale_x, - double scale_y, FT_Vector *v) -{ - font->scale_x = scale_x; - font->scale_y = scale_y; - if (v) { - font->v.x = v->x; - font->v.y = v->y; - } -} - -void ass_face_set_size(FT_Face face, double size) -{ - 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) { - int hori_height = hori->Ascender - hori->Descender; - int os2_height = os2->usWinAscent + os2->usWinDescent; - if (hori_height && os2_height) - mscale = (double) hori_height / os2_height; - } - 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; -} - -/** - * \brief Set font size - **/ -void ass_font_set_size(ASS_Font *font, double size) -{ - int i; - if (font->size != size) { - font->size = size; - for (i = 0; i < font->n_faces; ++i) - ass_face_set_size(font->faces[i], size); - } -} - -/** - * \brief Get maximal font ascender and descender. - * \param ch character code - * The values are extracted from the font face that provides glyphs for the given character - **/ -void ass_font_get_asc_desc(ASS_Font *font, uint32_t ch, int *asc, - int *desc) -{ - int i; - for (i = 0; i < font->n_faces; ++i) { - FT_Face face = font->faces[i]; - TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); - if (FT_Get_Char_Index(face, ch)) { - int y_scale = face->size->metrics.y_scale; - if (os2) { - *asc = FT_MulFix(os2->usWinAscent, y_scale); - *desc = FT_MulFix(os2->usWinDescent, y_scale); - } else { - *asc = FT_MulFix(face->ascender, y_scale); - *desc = FT_MulFix(-face->descender, y_scale); - } - return; - } - } - - *asc = *desc = 0; -} - -/* - * Strike a glyph with a horizontal line; it's possible to underline it - * and/or strike through it. For the line's position and size, truetype - * tables are consulted. Obviously this relies on the data in the tables - * being accurate. - * - */ -static int ass_strike_outline_glyph(FT_Face face, ASS_Font *font, - FT_Glyph glyph, int under, int through) -{ - TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); - TT_Postscript *ps = FT_Get_Sfnt_Table(face, ft_sfnt_post); - FT_Outline *ol = &((FT_OutlineGlyph) glyph)->outline; - FT_Vector points[4]; - int bear, advance, y_scale, i, dir; - - if (!under && !through) - return 0; - - // Grow outline - i = (under ? 4 : 0) + (through ? 4 : 0); - ol->points = (FT_Vector *) realloc(ol->points, sizeof(FT_Vector) * - (ol->n_points + i)); - ol->tags = (char *) realloc(ol->tags, ol->n_points + i); - i = !!under + !!through; - ol->contours = (short *) realloc(ol->contours, sizeof(short) * - (ol->n_contours + i)); - - // If the bearing is negative, the glyph starts left of the current - // pen position - bear = FFMIN(face->glyph->metrics.horiBearingX, 0); - // We're adding half a pixel to avoid small gaps - advance = d16_to_d6(glyph->advance.x) + 32; - y_scale = face->size->metrics.y_scale; - - // Reverse drawing direction for non-truetype fonts - dir = FT_Outline_Get_Orientation(ol); - - // Add points to the outline - if (under && ps) { - int pos, size; - pos = FT_MulFix(ps->underlinePosition, y_scale * font->scale_y); - size = FT_MulFix(ps->underlineThickness, - y_scale * font->scale_y / 2); - - if (pos > 0 || size <= 0) - return 1; - - points[0].x = bear; - points[0].y = pos + size; - points[1].x = advance; - points[1].y = pos + size; - points[2].x = advance; - points[2].y = pos - size; - points[3].x = bear; - points[3].y = pos - size; - - if (dir == FT_ORIENTATION_TRUETYPE) { - for (i = 0; i < 4; i++) { - ol->points[ol->n_points] = points[i]; - ol->tags[ol->n_points++] = 1; - } - } else { - for (i = 3; i >= 0; i--) { - ol->points[ol->n_points] = points[i]; - ol->tags[ol->n_points++] = 1; - } - } - - ol->contours[ol->n_contours++] = ol->n_points - 1; - } - - if (through && os2) { - int pos, size; - pos = FT_MulFix(os2->yStrikeoutPosition, y_scale * font->scale_y); - size = FT_MulFix(os2->yStrikeoutSize, y_scale * font->scale_y / 2); - - if (pos < 0 || size <= 0) - return 1; - - points[0].x = bear; - points[0].y = pos + size; - points[1].x = advance; - points[1].y = pos + size; - points[2].x = advance; - points[2].y = pos - size; - points[3].x = bear; - points[3].y = pos - size; - - if (dir == FT_ORIENTATION_TRUETYPE) { - for (i = 0; i < 4; i++) { - ol->points[ol->n_points] = points[i]; - ol->tags[ol->n_points++] = 1; - } - } else { - for (i = 3; i >= 0; i--) { - ol->points[ol->n_points] = points[i]; - ol->tags[ol->n_points++] = 1; - } - } - - ol->contours[ol->n_contours++] = ol->n_points - 1; - } - - return 0; -} - -void outline_copy(FT_Library lib, FT_Outline *source, FT_Outline **dest) -{ - if (source == NULL) { - *dest = NULL; - return; - } - *dest = calloc(1, sizeof(**dest)); - - FT_Outline_New(lib, source->n_points, source->n_contours, *dest); - FT_Outline_Copy(source, *dest); -} - -void outline_free(FT_Library lib, FT_Outline *outline) -{ - if (outline) - FT_Outline_Done(lib, outline); - free(outline); -} - -/** - * Slightly embold a glyph without touching its metrics - */ -static void ass_glyph_embolden(FT_GlyphSlot slot) -{ - int str; - - if (slot->format != FT_GLYPH_FORMAT_OUTLINE) - return; - - str = FT_MulFix(slot->face->units_per_EM, - slot->face->size->metrics.y_scale) / 64; - - FT_Outline_Embolden(&slot->outline, str); -} - -/** - * \brief Get glyph and face index - * Finds a face that has the requested codepoint and returns both face - * and glyph index. - */ -int ass_font_get_index(void *fcpriv, ASS_Font *font, uint32_t symbol, - int *face_index, int *glyph_index) -{ - int index = 0; - int i; - FT_Face face = 0; - - *glyph_index = 0; - - if (symbol < 0x20) { - *face_index = 0; - return 0; - } - // Handle NBSP like a regular space when rendering the glyph - if (symbol == 0xa0) - symbol = ' '; - if (font->n_faces == 0) { - *face_index = 0; - return 0; - } - - // try with the requested face - if (*face_index < font->n_faces) { - face = font->faces[*face_index]; - index = FT_Get_Char_Index(face, symbol); - } - - // not found in requested face, try all others - for (i = 0; i < font->n_faces && index == 0; ++i) { - face = font->faces[i]; - index = FT_Get_Char_Index(face, symbol); - if (index) - *face_index = i; - } - -#ifdef CONFIG_FONTCONFIG - if (index == 0) { - int face_idx; - ass_msg(font->library, MSGL_INFO, - "Glyph 0x%X not found, selecting one more " - "font for (%s, %d, %d)", symbol, font->desc.family, - font->desc.bold, font->desc.italic); - face_idx = *face_index = add_face(fcpriv, font, symbol); - if (face_idx >= 0) { - face = font->faces[face_idx]; - index = FT_Get_Char_Index(face, symbol); - if (index == 0 && face->num_charmaps > 0) { - int i; - ass_msg(font->library, MSGL_WARN, - "Glyph 0x%X not found, broken font? Trying all charmaps", symbol); - for (i = 0; i < face->num_charmaps; i++) { - FT_Set_Charmap(face, face->charmaps[i]); - if ((index = FT_Get_Char_Index(face, symbol)) != 0) break; - } - } - if (index == 0) { - ass_msg(font->library, MSGL_ERR, - "Glyph 0x%X not found in font for (%s, %d, %d)", - symbol, font->desc.family, font->desc.bold, - font->desc.italic); - } - } - } -#endif - // FIXME: make sure we have a valid face_index. this is a HACK. - *face_index = FFMAX(*face_index, 0); - *glyph_index = index; - - return 1; -} - -/** - * \brief Get a glyph - * \param ch character code - **/ -FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font, - uint32_t ch, int face_index, int index, - ASS_Hinting hinting, int deco) -{ - int error; - FT_Glyph glyph; - FT_Matrix scale; - FT_Outline *outl = NULL; - FT_Face face = font->faces[face_index]; - int flags = 0; - int vertical = font->desc.vertical; - - flags = FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH - | FT_LOAD_IGNORE_TRANSFORM; - switch (hinting) { - case ASS_HINTING_NONE: - flags |= FT_LOAD_NO_HINTING; - 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: - break; - } - - error = FT_Load_Glyph(face, index, flags); - if (error) { - ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d", - index); - return 0; - } - if (!(face->style_flags & FT_STYLE_FLAG_ITALIC) && - (font->desc.italic > 55)) { - FT_GlyphSlot_Oblique(face->glyph); - } - - if (!(face->style_flags & FT_STYLE_FLAG_BOLD) && - (font->desc.bold > 80)) { - ass_glyph_embolden(face->glyph); - } - error = FT_Get_Glyph(face->glyph, &glyph); - if (error) { - ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d", - index); - return 0; - } - - // Rotate glyph, if needed - if (vertical && ch >= VERTICAL_LOWER_BOUND) { - FT_Matrix m = { 0, double_to_d16(-1.0), double_to_d16(1.0), 0 }; - TT_OS2 *os2 = (TT_OS2*) FT_Get_Sfnt_Table(face, ft_sfnt_os2); - int desc = 0; - - if (os2) - desc = FT_MulFix(os2->sTypoDescender, face->size->metrics.y_scale); - - FT_Outline_Translate(&((FT_OutlineGlyph) glyph)->outline, 0, -desc); - FT_Outline_Transform(&((FT_OutlineGlyph) glyph)->outline, &m); - FT_Outline_Translate(&((FT_OutlineGlyph) glyph)->outline, - face->glyph->metrics.vertAdvance, desc); - glyph->advance.x = face->glyph->linearVertAdvance; - } - - // Apply scaling and shift - scale.xx = double_to_d16(font->scale_x); - scale.xy = 0; - scale.yx = 0; - scale.yy = double_to_d16(font->scale_y); - - outl = &((FT_OutlineGlyph) glyph)->outline; - FT_Outline_Transform(outl, &scale); - FT_Outline_Translate(outl, font->v.x, font->v.y); - glyph->advance.x *= font->scale_x; - - ass_strike_outline_glyph(face, font, glyph, deco & DECO_UNDERLINE, - deco & DECO_STRIKETHROUGH); - - return glyph; -} - -/** - * \brief Get kerning for the pair of glyphs. - **/ -FT_Vector ass_font_get_kerning(ASS_Font *font, uint32_t c1, uint32_t c2) -{ - FT_Vector v = { 0, 0 }; - int i; - - if (font->desc.vertical) - return v; - - for (i = 0; i < font->n_faces; ++i) { - FT_Face face = font->faces[i]; - int i1 = FT_Get_Char_Index(face, c1); - int i2 = FT_Get_Char_Index(face, c2); - if (i1 && i2) { - if (FT_HAS_KERNING(face)) - FT_Get_Kerning(face, i1, i2, FT_KERNING_DEFAULT, &v); - return v; - } - if (i1 || i2) // these glyphs are from different font faces, no kerning information - return v; - } - return v; -} - -/** - * \brief Deallocate ASS_Font - **/ -void ass_font_free(ASS_Font *font) -{ - int i; - for (i = 0; i < font->n_faces; ++i) - if (font->faces[i]) - FT_Done_Face(font->faces[i]); - if (font->shaper_priv) - ass_shaper_font_data_free(font->shaper_priv); - free(font->desc.family); - free(font); -} - -/** - * \brief Calculate the cbox of a series of points - */ -static void -get_contour_cbox(FT_BBox *box, FT_Vector *points, int start, int end) -{ - int i; - box->xMin = box->yMin = INT_MAX; - box->xMax = box->yMax = INT_MIN; - - for (i = start; i <= end; i++) { - box->xMin = (points[i].x < box->xMin) ? points[i].x : box->xMin; - box->xMax = (points[i].x > box->xMax) ? points[i].x : box->xMax; - box->yMin = (points[i].y < box->yMin) ? points[i].y : box->yMin; - box->yMax = (points[i].y > box->yMax) ? points[i].y : box->yMax; - } -} - -/** - * \brief Determine winding direction of a contour - * \return direction; 0 = clockwise - */ -static int get_contour_direction(FT_Vector *points, int start, int end) -{ - int i; - long long sum = 0; - int x = points[start].x; - int y = points[start].y; - for (i = start + 1; i <= end; i++) { - sum += x * (points[i].y - y) - y * (points[i].x - x); - x = points[i].x; - y = points[i].y; - } - sum += x * (points[start].y - y) - y * (points[start].x - x); - return sum > 0; -} - -/** - * \brief Apply fixups to please the FreeType stroker and improve the - * rendering result, especially in case the outline has some anomalies. - * At the moment, the following fixes are done: - * - * 1. Reverse contours that have "inside" winding direction but are not - * contained in any other contours' cbox. - * 2. Remove "inside" contours depending on border size, so that large - * borders do not reverse the winding direction, which leads to "holes" - * inside the border. The inside will be filled by the border of the - * outside contour anyway in this case. - * - * \param outline FreeType outline, modified in-place - * \param border_x border size, x direction, d6 format - * \param border_x border size, y direction, d6 format - */ -void fix_freetype_stroker(FT_Outline *outline, int border_x, int border_y) -{ - int nc = outline->n_contours; - int begin, stop; - char modified = 0; - char *valid_cont = malloc(nc); - int start = 0; - int end = -1; - FT_BBox *boxes = malloc(nc * sizeof(FT_BBox)); - int i, j; - int inside_direction; - - inside_direction = FT_Outline_Get_Orientation(outline) == - FT_ORIENTATION_TRUETYPE; - - // create a list of cboxes of the contours - for (i = 0; i < nc; i++) { - start = end + 1; - end = outline->contours[i]; - get_contour_cbox(&boxes[i], outline->points, start, end); - } - - // for each contour, check direction and whether it's "outside" - // or contained in another contour - end = -1; - for (i = 0; i < nc; i++) { - int dir; - start = end + 1; - end = outline->contours[i]; - dir = get_contour_direction(outline->points, start, end); - valid_cont[i] = 1; - if (dir == inside_direction) { - for (j = 0; j < nc; j++) { - if (i == j) - continue; - if (boxes[i].xMin >= boxes[j].xMin && - boxes[i].xMax <= boxes[j].xMax && - boxes[i].yMin >= boxes[j].yMin && - boxes[i].yMax <= boxes[j].yMax) - goto check_inside; - } - /* "inside" contour but we can't find anything it could be - * inside of - assume the font is buggy and it should be - * an "outside" contour, and reverse it */ - for (j = 0; j < (end + 1 - start) / 2; j++) { - FT_Vector temp = outline->points[start + j]; - char temp2 = outline->tags[start + j]; - outline->points[start + j] = outline->points[end - j]; - outline->points[end - j] = temp; - outline->tags[start + j] = outline->tags[end - j]; - outline->tags[end - j] = temp2; - } - dir ^= 1; - } - check_inside: - if (dir == inside_direction) { - FT_BBox box; - int width, height; - get_contour_cbox(&box, outline->points, start, end); - width = box.xMax - box.xMin; - height = box.yMax - box.yMin; - if (width < border_x * 2 || height < border_y * 2) { - valid_cont[i] = 0; - modified = 1; - } - } - } - - // if we need to modify the outline, rewrite it and skip - // the contours that we determined should be removed. - if (modified) { - int p = 0, c = 0; - for (i = 0; i < nc; i++) { - if (!valid_cont[i]) - continue; - begin = (i == 0) ? 0 : outline->contours[i - 1] + 1; - stop = outline->contours[i]; - for (j = begin; j <= stop; j++) { - outline->points[p].x = outline->points[j].x; - outline->points[p].y = outline->points[j].y; - outline->tags[p] = outline->tags[j]; - p++; - } - outline->contours[c] = p - 1; - c++; - } - outline->n_points = p; - outline->n_contours = c; - } - - free(boxes); - free(valid_cont); -} - diff --git a/lib/libass/libass/ass_font.h b/lib/libass/libass/ass_font.h deleted file mode 100644 index 481a63015f..0000000000 --- a/lib/libass/libass/ass_font.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef LIBASS_FONT_H -#define LIBASS_FONT_H - -#include <stdint.h> -#include <ft2build.h> -#include FT_GLYPH_H -#include FT_OUTLINE_H - -#include "ass.h" -#include "ass_types.h" - -#define VERTICAL_LOWER_BOUND 0x02f1 - -#define ASS_FONT_MAX_FACES 10 -#define DECO_UNDERLINE 1 -#define DECO_STRIKETHROUGH 2 - -typedef struct ass_shaper_font_data ASS_ShaperFontData; - -typedef struct { - char *family; - unsigned bold; - unsigned italic; - int treat_family_as_pattern; - int vertical; // @font vertical layout -} ASS_FontDesc; - -typedef struct { - ASS_FontDesc desc; - ASS_Library *library; - FT_Library ftlibrary; - FT_Face faces[ASS_FONT_MAX_FACES]; - ASS_ShaperFontData *shaper_priv; - int n_faces; - double scale_x, scale_y; // current transform - FT_Vector v; // current shift - double size; -} ASS_Font; - -#include "ass_cache.h" - -ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library, - FT_Library ftlibrary, void *fc_priv, - ASS_FontDesc *desc); -void ass_font_set_transform(ASS_Font *font, double scale_x, - double scale_y, FT_Vector *v); -void ass_face_set_size(FT_Face face, double size); -void ass_font_set_size(ASS_Font *font, double size); -void ass_font_get_asc_desc(ASS_Font *font, uint32_t ch, int *asc, - int *desc); -int ass_font_get_index(void *fcpriv, ASS_Font *font, uint32_t symbol, - int *face_index, int *glyph_index); -FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font, - uint32_t ch, int face_index, int index, - ASS_Hinting hinting, int deco); -FT_Vector ass_font_get_kerning(ASS_Font *font, uint32_t c1, uint32_t c2); -void ass_font_free(ASS_Font *font); -void fix_freetype_stroker(FT_Outline *outline, int border_x, int border_y); -void outline_copy(FT_Library lib, FT_Outline *source, FT_Outline **dest); -void outline_free(FT_Library lib, FT_Outline *outline); - -#endif /* LIBASS_FONT_H */ diff --git a/lib/libass/libass/ass_fontconfig.c b/lib/libass/libass/ass_fontconfig.c deleted file mode 100644 index 76ca045940..0000000000 --- a/lib/libass/libass/ass_fontconfig.c +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "config.h" - -#include <stdlib.h> -#include <stdio.h> -#include <assert.h> -#include <string.h> -#ifndef _WIN32 -#include <strings.h> -#endif -#include <sys/types.h> -#include <sys/stat.h> -#include <inttypes.h> -#include <ft2build.h> -#include FT_FREETYPE_H - -#include "ass_utils.h" -#include "ass.h" -#include "ass_library.h" -#include "ass_fontconfig.h" - -#ifdef CONFIG_FONTCONFIG -#include <fontconfig/fontconfig.h> -#include <fontconfig/fcfreetype.h> -#endif - -struct fc_instance { -#ifdef CONFIG_FONTCONFIG - FcConfig *config; -#endif - char *family_default; - char *path_default; - int index_default; -}; - -#ifdef CONFIG_FONTCONFIG - -/** - * \brief Case-insensitive match ASS/SSA font family against full name. (also - * known as "name for humans") - * - * \param lib library instance - * \param priv fontconfig instance - * \param family font fullname - * \param bold weight attribute - * \param italic italic attribute - * \return font set - */ -static FcFontSet * -match_fullname(ASS_Library *lib, FCInstance *priv, const char *family, - unsigned bold, unsigned italic) -{ - FcFontSet *sets[2]; - FcFontSet *result = FcFontSetCreate(); - int nsets = 0; - int i, fi; - - if ((sets[nsets] = FcConfigGetFonts(priv->config, FcSetSystem))) - nsets++; - if ((sets[nsets] = FcConfigGetFonts(priv->config, FcSetApplication))) - nsets++; - - // Run over font sets and patterns and try to match against full name - for (i = 0; i < nsets; i++) { - FcFontSet *set = sets[i]; - for (fi = 0; fi < set->nfont; fi++) { - FcPattern *pat = set->fonts[fi]; - char *fullname; - int pi = 0, at; - FcBool ol; - while (FcPatternGetString(pat, FC_FULLNAME, pi++, - (FcChar8 **) &fullname) == FcResultMatch) { - if (FcPatternGetBool(pat, FC_OUTLINE, 0, &ol) != FcResultMatch - || ol != FcTrue) - continue; - if (FcPatternGetInteger(pat, FC_SLANT, 0, &at) != FcResultMatch - || at < italic) - continue; - if (FcPatternGetInteger(pat, FC_WEIGHT, 0, &at) != FcResultMatch - || at < bold) - continue; - if (strcasecmp(fullname, family) == 0) { - FcFontSetAdd(result, FcPatternDuplicate(pat)); - break; - } - } - } - } - - return result; -} - -/** - * \brief Low-level font selection. - * \param priv private data - * \param family font family - * \param treat_family_as_pattern treat family as fontconfig pattern - * \param bold font weight value - * \param italic font slant value - * \param index out: font index inside a file - * \param code: the character that should be present in the font, can be 0 - * \return font file path -*/ -static char *select_font(ASS_Library *library, FCInstance *priv, - const char *family, int treat_family_as_pattern, - unsigned bold, unsigned italic, int *index, - uint32_t code) -{ - FcBool rc; - FcResult result; - FcPattern *pat = NULL, *rpat = NULL; - int r_index, r_slant, r_weight; - FcChar8 *r_family, *r_style, *r_file, *r_fullname; - FcBool r_outline, r_embolden; - FcCharSet *r_charset; - FcFontSet *ffullname = NULL, *fsorted = NULL, *fset = NULL; - int curf; - char *retval = NULL; - int family_cnt = 0; - - *index = 0; - - if (treat_family_as_pattern) - pat = FcNameParse((const FcChar8 *) family); - else - pat = FcPatternCreate(); - - if (!pat) - goto error; - - if (!treat_family_as_pattern) { - FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *) family); - - // In SSA/ASS fonts are sometimes referenced by their "full name", - // which is usually a concatenation of family name and font - // style (ex. Ottawa Bold). Full name is available from - // FontConfig pattern element FC_FULLNAME, but it is never - // used for font matching. - // Therefore, I'm removing words from the end of the name one - // by one, and adding shortened names to the pattern. It seems - // that the first value (full name in this case) has - // precedence in matching. - // An alternative approach could be to reimplement FcFontSort - // using FC_FULLNAME instead of FC_FAMILY. - family_cnt = 1; - { - char *s = strdup(family); - char *p = s + strlen(s); - while (--p > s) - if (*p == ' ' || *p == '-') { - *p = '\0'; - FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *) s); - ++family_cnt; - } - free(s); - } - } - FcPatternAddBool(pat, FC_OUTLINE, FcTrue); - FcPatternAddInteger(pat, FC_SLANT, italic); - FcPatternAddInteger(pat, FC_WEIGHT, bold); - - FcDefaultSubstitute(pat); - - rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern); - if (!rc) - goto error; - - fsorted = FcFontSort(priv->config, pat, FcTrue, NULL, &result); - ffullname = match_fullname(library, priv, family, bold, italic); - if (!fsorted || !ffullname) - goto error; - - fset = FcFontSetCreate(); - for (curf = 0; curf < ffullname->nfont; ++curf) { - FcPattern *curp = ffullname->fonts[curf]; - FcPatternReference(curp); - FcFontSetAdd(fset, curp); - } - for (curf = 0; curf < fsorted->nfont; ++curf) { - FcPattern *curp = fsorted->fonts[curf]; - FcPatternReference(curp); - FcFontSetAdd(fset, curp); - } - - for (curf = 0; curf < fset->nfont; ++curf) { - FcPattern *curp = fset->fonts[curf]; - - result = FcPatternGetBool(curp, FC_OUTLINE, 0, &r_outline); - if (result != FcResultMatch) - continue; - if (r_outline != FcTrue) - continue; - if (!code) - break; - result = FcPatternGetCharSet(curp, FC_CHARSET, 0, &r_charset); - if (result != FcResultMatch) - continue; - if (FcCharSetHasChar(r_charset, code)) - break; - } - - if (curf >= fset->nfont) - goto error; - - if (!treat_family_as_pattern) { - // Remove all extra family names from original pattern. - // After this, FcFontRenderPrepare will select the most relevant family - // name in case there are more than one of them. - for (; family_cnt > 1; --family_cnt) - FcPatternRemove(pat, FC_FAMILY, family_cnt - 1); - } - - rpat = FcFontRenderPrepare(priv->config, pat, fset->fonts[curf]); - if (!rpat) - goto error; - - result = FcPatternGetInteger(rpat, FC_INDEX, 0, &r_index); - if (result != FcResultMatch) - goto error; - *index = r_index; - - result = FcPatternGetString(rpat, FC_FILE, 0, &r_file); - if (result != FcResultMatch) - goto error; - retval = strdup((const char *) r_file); - - result = FcPatternGetString(rpat, FC_FAMILY, 0, &r_family); - if (result != FcResultMatch) - r_family = NULL; - - result = FcPatternGetString(rpat, FC_FULLNAME, 0, &r_fullname); - if (result != FcResultMatch) - r_fullname = NULL; - - if (!treat_family_as_pattern && - !(r_family && strcasecmp((const char *) r_family, family) == 0) && - !(r_fullname && strcasecmp((const char *) r_fullname, family) == 0)) - ass_msg(library, MSGL_WARN, - "fontconfig: Selected font is not the requested one: " - "'%s' != '%s'", - (const char *) (r_fullname ? r_fullname : r_family), family); - - result = FcPatternGetString(rpat, FC_STYLE, 0, &r_style); - if (result != FcResultMatch) - r_style = NULL; - - result = FcPatternGetInteger(rpat, FC_SLANT, 0, &r_slant); - if (result != FcResultMatch) - r_slant = 0; - - result = FcPatternGetInteger(rpat, FC_WEIGHT, 0, &r_weight); - if (result != FcResultMatch) - r_weight = 0; - - result = FcPatternGetBool(rpat, FC_EMBOLDEN, 0, &r_embolden); - if (result != FcResultMatch) - r_embolden = 0; - - ass_msg(library, MSGL_V, - "Font info: family '%s', style '%s', fullname '%s'," - " slant %d, weight %d%s", (const char *) r_family, - (const char *) r_style, (const char *) r_fullname, r_slant, - r_weight, r_embolden ? ", embolden" : ""); - - error: - if (pat) - FcPatternDestroy(pat); - if (rpat) - FcPatternDestroy(rpat); - if (fsorted) - FcFontSetDestroy(fsorted); - if (ffullname) - FcFontSetDestroy(ffullname); - if (fset) - FcFontSetDestroy(fset); - return retval; -} - -/** - * \brief Find a font. Use default family or path if necessary. - * \param priv_ private data - * \param family font family - * \param treat_family_as_pattern treat family as fontconfig pattern - * \param bold font weight value - * \param italic font slant value - * \param index out: font index inside a file - * \param code: the character that should be present in the font, can be 0 - * \return font file path -*/ -char *fontconfig_select(ASS_Library *library, FCInstance *priv, - const char *family, int treat_family_as_pattern, - unsigned bold, unsigned italic, int *index, - uint32_t code) -{ - char *res = 0; - if (!priv->config) { - *index = priv->index_default; - res = priv->path_default ? strdup(priv->path_default) : 0; - return res; - } - if (family && *family) - res = - select_font(library, priv, family, treat_family_as_pattern, - bold, italic, index, code); - if (!res && priv->family_default) { - res = - select_font(library, priv, priv->family_default, 0, bold, - italic, index, code); - if (res) - ass_msg(library, MSGL_WARN, "fontconfig_select: Using default " - "font family: (%s, %d, %d) -> %s, %d", - family, bold, italic, res, *index); - } - if (!res && priv->path_default) { - res = strdup(priv->path_default); - *index = priv->index_default; - ass_msg(library, MSGL_WARN, "fontconfig_select: Using default font: " - "(%s, %d, %d) -> %s, %d", family, bold, italic, - res, *index); - } - if (!res) { - res = select_font(library, priv, "Arial", 0, bold, italic, - index, code); - if (res) - ass_msg(library, MSGL_WARN, "fontconfig_select: Using 'Arial' " - "font family: (%s, %d, %d) -> %s, %d", family, bold, - italic, res, *index); - } - if (res) - ass_msg(library, MSGL_V, - "fontconfig_select: (%s, %d, %d) -> %s, %d", family, bold, - italic, res, *index); - return res; -} - -/** - * \brief Process memory font. - * \param priv private data - * \param library library object - * \param ftlibrary freetype library object - * \param idx index of the processed font in library->fontdata - * - * Builds a font pattern in memory via FT_New_Memory_Face/FcFreeTypeQueryFace. -*/ -static void process_fontdata(FCInstance *priv, ASS_Library *library, - FT_Library ftlibrary, int idx) -{ - int rc; - const char *name = library->fontdata[idx].name; - const char *data = library->fontdata[idx].data; - int data_size = library->fontdata[idx].size; - - FT_Face face; - FcPattern *pattern; - FcFontSet *fset; - FcBool res; - int face_index, num_faces = 1; - - for (face_index = 0; face_index < num_faces; ++face_index) { - rc = FT_New_Memory_Face(ftlibrary, (unsigned char *) data, - data_size, face_index, &face); - if (rc) { - ass_msg(library, MSGL_WARN, "Error opening memory font: %s", - name); - return; - } - num_faces = face->num_faces; - - pattern = - FcFreeTypeQueryFace(face, (unsigned char *) name, face_index, - FcConfigGetBlanks(priv->config)); - if (!pattern) { - ass_msg(library, MSGL_WARN, "%s failed", "FcFreeTypeQueryFace"); - FT_Done_Face(face); - return; - } - - fset = FcConfigGetFonts(priv->config, FcSetSystem); // somehow it failes when asked for FcSetApplication - if (!fset) { - ass_msg(library, MSGL_WARN, "%s failed", "FcConfigGetFonts"); - FT_Done_Face(face); - return; - } - - res = FcFontSetAdd(fset, pattern); - if (!res) { - ass_msg(library, MSGL_WARN, "%s failed", "FcFontSetAdd"); - FT_Done_Face(face); - return; - } - - FT_Done_Face(face); - } -} - -/** - * \brief Init fontconfig. - * \param library libass library object - * \param ftlibrary freetype library object - * \param family default font family - * \param path default font path - * \param fc whether fontconfig should be used - * \param config path to a fontconfig configuration file, or NULL - * \param update whether the fontconfig cache should be built/updated - * \return pointer to fontconfig private data -*/ -FCInstance *fontconfig_init(ASS_Library *library, - FT_Library ftlibrary, const char *family, - const char *path, int fc, const char *config, - int update) -{ - int rc; - FCInstance *priv = calloc(1, sizeof(FCInstance)); - const char *dir = library->fonts_dir; - int i; - - if (!fc) { - ass_msg(library, MSGL_WARN, - "Fontconfig disabled, only default font will be used."); - goto exit; - } - - priv->config = FcConfigCreate(); - rc = FcConfigParseAndLoad(priv->config, (unsigned char *) config, FcTrue); - if (!rc) { - ass_msg(library, MSGL_WARN, "No usable fontconfig configuration " - "file found, using fallback."); - FcConfigDestroy(priv->config); - priv->config = FcInitLoadConfig(); - rc++; - } - if (rc && update) { - FcConfigBuildFonts(priv->config); - } - - if (!rc || !priv->config) { - ass_msg(library, MSGL_FATAL, - "No valid fontconfig configuration found!"); - FcConfigDestroy(priv->config); - goto exit; - } - - for (i = 0; i < library->num_fontdata; ++i) - process_fontdata(priv, library, ftlibrary, i); - - if (dir) { - ass_msg(library, MSGL_V, "Updating font cache"); - - rc = FcConfigAppFontAddDir(priv->config, (const FcChar8 *) dir); - if (!rc) { - ass_msg(library, MSGL_WARN, "%s failed", "FcConfigAppFontAddDir"); - } - } - - priv->family_default = family ? strdup(family) : NULL; -exit: - priv->path_default = path ? strdup(path) : NULL; - priv->index_default = 0; - - return priv; -} - -int fontconfig_update(FCInstance *priv) -{ - return FcConfigBuildFonts(priv->config); -} - -#else /* CONFIG_FONTCONFIG */ - -char *fontconfig_select(ASS_Library *library, FCInstance *priv, - const char *family, int treat_family_as_pattern, - unsigned bold, unsigned italic, int *index, - uint32_t code) -{ - *index = priv->index_default; - char* res = priv->path_default ? strdup(priv->path_default) : 0; - return res; -} - -FCInstance *fontconfig_init(ASS_Library *library, - FT_Library ftlibrary, const char *family, - const char *path, int fc, const char *config, - int update) -{ - FCInstance *priv; - - ass_msg(library, MSGL_WARN, - "Fontconfig disabled, only default font will be used."); - - priv = calloc(1, sizeof(FCInstance)); - - priv->path_default = path ? strdup(path) : 0; - priv->index_default = 0; - return priv; -} - -int fontconfig_update(FCInstance *priv) -{ - // Do nothing - return 1; -} - -#endif - -void fontconfig_done(FCInstance *priv) -{ - - if (priv) { -#ifdef CONFIG_FONTCONFIG - if (priv->config) - FcConfigDestroy(priv->config); -#endif - free(priv->path_default); - free(priv->family_default); - } - free(priv); -} diff --git a/lib/libass/libass/ass_fontconfig.h b/lib/libass/libass/ass_fontconfig.h deleted file mode 100644 index 396fb72d0d..0000000000 --- a/lib/libass/libass/ass_fontconfig.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef LIBASS_FONTCONFIG_H -#define LIBASS_FONTCONFIG_H - -#include <stdint.h> -#include "ass_types.h" -#include "ass.h" -#include <ft2build.h> -#include FT_FREETYPE_H - -#ifdef CONFIG_FONTCONFIG -#include <fontconfig/fontconfig.h> -#endif - -typedef struct fc_instance FCInstance; - -FCInstance *fontconfig_init(ASS_Library *library, - FT_Library ftlibrary, const char *family, - const char *path, int fc, const char *config, - int update); -char *fontconfig_select(ASS_Library *library, FCInstance *priv, - const char *family, int treat_family_as_pattern, - unsigned bold, unsigned italic, int *index, - uint32_t code); -void fontconfig_done(FCInstance *priv); -int fontconfig_update(FCInstance *priv); - -#endif /* LIBASS_FONTCONFIG_H */ diff --git a/lib/libass/libass/ass_library.c b/lib/libass/libass/ass_library.c deleted file mode 100644 index b33ca551b0..0000000000 --- a/lib/libass/libass/ass_library.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "config.h" - -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> - -#include "ass.h" -#include "ass_library.h" -#include "ass_utils.h" - -static void ass_msg_handler(int level, const char *fmt, va_list va, void *data) -{ - if (level > MSGL_INFO) - return; - fprintf(stderr, "[ass] "); - vfprintf(stderr, fmt, va); - fprintf(stderr, "\n"); -} - -ASS_Library *ass_library_init(void) -{ - ASS_Library* lib = calloc(1, sizeof(*lib)); - lib->msg_callback = ass_msg_handler; - - return lib; -} - -void ass_library_done(ASS_Library *priv) -{ - if (priv) { - ass_set_fonts_dir(priv, NULL); - ass_set_style_overrides(priv, NULL); - ass_clear_fonts(priv); - free(priv); - } -} - -void ass_set_fonts_dir(ASS_Library *priv, const char *fonts_dir) -{ - free(priv->fonts_dir); - - priv->fonts_dir = fonts_dir ? strdup(fonts_dir) : 0; -} - -void ass_set_extract_fonts(ASS_Library *priv, int extract) -{ - priv->extract_fonts = !!extract; -} - -void ass_set_style_overrides(ASS_Library *priv, char **list) -{ - char **p; - char **q; - int cnt; - - if (priv->style_overrides) { - for (p = priv->style_overrides; *p; ++p) - free(*p); - } - free(priv->style_overrides); - priv->style_overrides = NULL; - - if (!list) - return; - - for (p = list, cnt = 0; *p; ++p, ++cnt) { - } - - priv->style_overrides = malloc((cnt + 1) * sizeof(char *)); - for (p = list, q = priv->style_overrides; *p; ++p, ++q) - *q = strdup(*p); - priv->style_overrides[cnt] = NULL; -} - -static void grow_array(void **array, int nelem, size_t elsize) -{ - if (!(nelem & 31)) - *array = realloc(*array, (nelem + 32) * elsize); -} - -void ass_add_font(ASS_Library *priv, char *name, char *data, int size) -{ - int idx = priv->num_fontdata; - if (!name || !data || !size) - return; - grow_array((void **) &priv->fontdata, priv->num_fontdata, - sizeof(*priv->fontdata)); - - priv->fontdata[idx].name = strdup(name); - - priv->fontdata[idx].data = malloc(size); - memcpy(priv->fontdata[idx].data, data, size); - - priv->fontdata[idx].size = size; - - priv->num_fontdata++; -} - -void ass_clear_fonts(ASS_Library *priv) -{ - int i; - for (i = 0; i < priv->num_fontdata; ++i) { - free(priv->fontdata[i].name); - free(priv->fontdata[i].data); - } - free(priv->fontdata); - priv->fontdata = NULL; - priv->num_fontdata = 0; -} - -/* - * Register a message callback function with libass. Without setting one, - * a default handler is used which prints everything with MSGL_INFO or - * higher to the standard output. - * - * \param msg_cb the callback function - * \param data additional data that will be passed to the callback - */ -void ass_set_message_cb(ASS_Library *priv, - void (*msg_cb)(int, const char *, va_list, void *), - void *data) -{ - if (msg_cb) { - priv->msg_callback = msg_cb; - priv->msg_callback_data = data; - } -} diff --git a/lib/libass/libass/ass_library.h b/lib/libass/libass/ass_library.h deleted file mode 100644 index 8faf15e93f..0000000000 --- a/lib/libass/libass/ass_library.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef LIBASS_LIBRARY_H -#define LIBASS_LIBRARY_H - -#include <stdarg.h> - -typedef struct { - char *name; - char *data; - int size; -} ASS_Fontdata; - -struct ass_library { - char *fonts_dir; - int extract_fonts; - char **style_overrides; - - ASS_Fontdata *fontdata; - int num_fontdata; - void (*msg_callback)(int, const char *, va_list, void *); - void *msg_callback_data; -}; - -#endif /* LIBASS_LIBRARY_H */ diff --git a/lib/libass/libass/ass_parse.c b/lib/libass/libass/ass_parse.c deleted file mode 100644 index 92a47b3aeb..0000000000 --- a/lib/libass/libass/ass_parse.c +++ /dev/null @@ -1,1039 +0,0 @@ -/* - * Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "config.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> - -#include "ass_render.h" -#include "ass_parse.h" - -#define MAX_BE 127 -#define NBSP 0xa0 // unicode non-breaking space character - -#define skip_to(x) while ((*p != (x)) && (*p != '}') && (*p != 0)) { ++p;} -#define skip(x) if (*p == (x)) ++p; else { return p; } -#define skipopt(x) if (*p == (x)) { ++p; } - -/** - * \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) -{ - int len = strlen(sample); - if (strncmp(*p, sample, len) == 0) { - (*p) += len; - return 1; - } else - return 0; -} - -double ensure_font_size(ASS_Renderer *priv, double size) -{ - if (size < 1) - size = 1; - else if (size > priv->height * 2) - size = priv->height * 2; - - return size; -} - -static void change_font_size(ASS_Renderer *render_priv, double sz) -{ - render_priv->state.font_size = sz; -} - -/** - * \brief Change current font, using setting from render_priv->state. - */ -void update_font(ASS_Renderer *render_priv) -{ - unsigned val; - ASS_FontDesc desc; - desc.treat_family_as_pattern = render_priv->state.treat_family_as_pattern; - - if (render_priv->state.family[0] == '@') { - desc.vertical = 1; - desc.family = strdup(render_priv->state.family + 1); - } else { - desc.vertical = 0; - desc.family = strdup(render_priv->state.family); - } - - val = render_priv->state.bold; - // 0 = normal, 1 = bold, >1 = exact weight - if (val == 1 || val == -1) - val = 200; // bold - else if (val <= 0) - val = 80; // normal - desc.bold = val; - - val = render_priv->state.italic; - if (val == 1 || val == -1) - val = 110; // italic - else if (val <= 0) - val = 0; // normal - desc.italic = val; - - render_priv->state.font = - ass_font_new(render_priv->cache.font_cache, render_priv->library, - render_priv->ftlibrary, render_priv->fontconfig_priv, - &desc); - free(desc.family); - - if (render_priv->state.font) - change_font_size(render_priv, render_priv->state.font_size); -} - -/** - * \brief Change border width - * negative value resets border to style value - */ -void change_border(ASS_Renderer *render_priv, double border_x, - double border_y) -{ - int bord; - if (!render_priv->state.font) - return; - - if (border_x < 0 && border_y < 0) { - if (render_priv->state.style->BorderStyle == 1 || - render_priv->state.style->BorderStyle == 3) - border_x = border_y = render_priv->state.style->Outline; - else - border_x = border_y = 1.; - } - - render_priv->state.border_x = border_x; - render_priv->state.border_y = border_y; - - bord = 64 * border_x * render_priv->border_scale; - if (bord > 0 && border_x == border_y) { - if (!render_priv->state.stroker) { - int error; - error = - FT_Stroker_New(render_priv->ftlibrary, - &render_priv->state.stroker); - if (error) { - ass_msg(render_priv->library, MSGL_V, - "failed to get stroker"); - render_priv->state.stroker = 0; - } - } - if (render_priv->state.stroker) - FT_Stroker_Set(render_priv->state.stroker, bord, - FT_STROKER_LINECAP_ROUND, - FT_STROKER_LINEJOIN_ROUND, 0); - } else { - FT_Stroker_Done(render_priv->state.stroker); - render_priv->state.stroker = 0; - } -} - -/** - * \brief Calculate a weighted average of two colors - * calculates c1*(1-a) + c2*a, but separately for each component except alpha - */ -static void change_color(uint32_t *var, uint32_t new, double pwr) -{ - (*var) = ((uint32_t) (_r(*var) * (1 - pwr) + _r(new) * pwr) << 24) + - ((uint32_t) (_g(*var) * (1 - pwr) + _g(new) * pwr) << 16) + - ((uint32_t) (_b(*var) * (1 - pwr) + _b(new) * pwr) << 8) + _a(*var); -} - -// like change_color, but for alpha component only -inline void change_alpha(uint32_t *var, uint32_t new, double pwr) -{ - *var = - (_r(*var) << 24) + (_g(*var) << 16) + (_b(*var) << 8) + - (uint32_t) (_a(*var) * (1 - pwr) + _a(new) * pwr); -} - -/** - * \brief Multiply two alpha values - * \param a first value - * \param b second value - * \return result of multiplication - * Parameters and result are limited by 0xFF. - */ -inline uint32_t mult_alpha(uint32_t a, uint32_t b) -{ - return 0xFF - (0xFF - a) * (0xFF - b) / 0xFF; -} - -/** - * \brief Calculate alpha value by piecewise linear function - * Used for \fad, \fade implementation. - */ -static unsigned -interpolate_alpha(long long now, long long t1, long long t2, long long t3, - long long t4, unsigned a1, unsigned a2, unsigned a3) -{ - unsigned a; - double cf; - - if (now < t1) { - a = a1; - } else if (now >= t4) { - a = a3; - } else if (now < t2 && t2 > t1) { - cf = ((double) (now - t1)) / (t2 - t1); - a = a1 * (1 - cf) + a2 * cf; - } else if (now >= t3 && t4 > t3) { - cf = ((double) (now - t3)) / (t4 - t3); - a = a2 * (1 - cf) + a3 * cf; - } else { // t2 <= now < t3 - a = a2; - } - - return a; -} - -/** - * Parse a vector clip into an outline, using the proper scaling - * parameters. Translate it to correct for screen borders, if needed. - */ -static char *parse_vector_clip(ASS_Renderer *render_priv, char *p) -{ - int scale = 1; - int res = 0; - ASS_Drawing *drawing = render_priv->state.clip_drawing; - - ass_drawing_free(drawing); - render_priv->state.clip_drawing = - ass_drawing_new(render_priv->library, render_priv->ftlibrary); - drawing = render_priv->state.clip_drawing; - skipopt('('); - res = mystrtoi(&p, &scale); - skipopt(',') - if (!res) - scale = 1; - drawing->scale = scale; - drawing->scale_x = render_priv->font_scale_x * render_priv->font_scale; - drawing->scale_y = render_priv->font_scale; - while (*p != ')' && *p != '}' && p != 0) - ass_drawing_add_char(drawing, *p++); - skipopt(')'); - - return p; -} - -/** - * \brief Parse style override tag. - * \param p string to parse - * \param pwr multiplier for some tag effects (comes from \t tags) - */ -static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr) -{ - skip_to('\\'); - skip('\\'); - if ((*p == '}') || (*p == 0)) - return p; - - // New tags introduced in vsfilter 2.39 - if (mystrcmp(&p, "xbord")) { - double val; - if (mystrtod(&p, &val)) - val = render_priv->state.border_x * (1 - pwr) + val * pwr; - else - val = -1.; - change_border(render_priv, val, render_priv->state.border_y); - render_priv->state.bm_run_id++; - } else if (mystrcmp(&p, "ybord")) { - double val; - if (mystrtod(&p, &val)) - val = render_priv->state.border_y * (1 - pwr) + val * pwr; - else - val = -1.; - change_border(render_priv, render_priv->state.border_x, val); - } else if (mystrcmp(&p, "xshad")) { - double val; - if (mystrtod(&p, &val)) - val = render_priv->state.shadow_x * (1 - pwr) + val * pwr; - else - val = 0.; - render_priv->state.shadow_x = val; - render_priv->state.bm_run_id++; - } else if (mystrcmp(&p, "yshad")) { - double val; - if (mystrtod(&p, &val)) - val = render_priv->state.shadow_y * (1 - pwr) + val * pwr; - else - val = 0.; - render_priv->state.shadow_y = val; - render_priv->state.bm_run_id++; - } else if (mystrcmp(&p, "fax")) { - double val; - if (mystrtod(&p, &val)) - render_priv->state.fax = - val * pwr + render_priv->state.fax * (1 - pwr); - else - render_priv->state.fax = 0.; - } else if (mystrcmp(&p, "fay")) { - double val; - if (mystrtod(&p, &val)) - render_priv->state.fay = - val * pwr + render_priv->state.fay * (1 - pwr); - else - render_priv->state.fay = 0.; - } else if (mystrcmp(&p, "iclip")) { - int x0, y0, x1, y1; - int res = 1; - char *start = p; - skipopt('('); - res &= mystrtoi(&p, &x0); - skipopt(','); - res &= mystrtoi(&p, &y0); - skipopt(','); - res &= mystrtoi(&p, &x1); - skipopt(','); - res &= mystrtoi(&p, &y1); - skipopt(')'); - if (res) { - render_priv->state.clip_x0 = - render_priv->state.clip_x0 * (1 - pwr) + x0 * pwr; - render_priv->state.clip_x1 = - render_priv->state.clip_x1 * (1 - pwr) + x1 * pwr; - render_priv->state.clip_y0 = - render_priv->state.clip_y0 * (1 - pwr) + y0 * pwr; - render_priv->state.clip_y1 = - render_priv->state.clip_y1 * (1 - pwr) + y1 * pwr; - render_priv->state.clip_mode = 1; - } else if (!render_priv->state.clip_drawing) { - p = parse_vector_clip(render_priv, start); - render_priv->state.clip_drawing_mode = 1; - } else - render_priv->state.clip_mode = 0; - } else if (mystrcmp(&p, "blur")) { - double val; - if (mystrtod(&p, &val)) { - val = render_priv->state.blur * (1 - pwr) + val * pwr; - val = (val < 0) ? 0 : val; - val = (val > BLUR_MAX_RADIUS) ? BLUR_MAX_RADIUS : val; - render_priv->state.blur = val; - } else - render_priv->state.blur = 0.0; - render_priv->state.bm_run_id++; - // ASS standard tags - } else if (mystrcmp(&p, "fsc")) { - char tp = *p++; - double val; - if (tp == 'x') { - if (mystrtod(&p, &val)) { - val /= 100; - render_priv->state.scale_x = - render_priv->state.scale_x * (1 - pwr) + val * pwr; - } else - render_priv->state.scale_x = - render_priv->state.style->ScaleX; - } else if (tp == 'y') { - if (mystrtod(&p, &val)) { - val /= 100; - render_priv->state.scale_y = - render_priv->state.scale_y * (1 - pwr) + val * pwr; - } else - render_priv->state.scale_y = - render_priv->state.style->ScaleY; - } - } else if (mystrcmp(&p, "fsp")) { - double val; - if (mystrtod(&p, &val)) - render_priv->state.hspacing = - render_priv->state.hspacing * (1 - pwr) + val * pwr; - else - render_priv->state.hspacing = render_priv->state.style->Spacing; - } else if (mystrcmp(&p, "fs+")) { - double val; - if (mystrtod(&p, &val)) { - val = render_priv->state.font_size + pwr * val; - } else - val = render_priv->state.style->FontSize; - if (render_priv->state.font) - change_font_size(render_priv, val); - } else if (mystrcmp(&p, "fs-")) { - double val; - if (mystrtod(&p, &val)) - val = render_priv->state.font_size - pwr * val; - else - val = render_priv->state.style->FontSize; - if (render_priv->state.font) - change_font_size(render_priv, val); - } else if (mystrcmp(&p, "fs")) { - double val; - if (mystrtod(&p, &val)) - val = render_priv->state.font_size * (1 - pwr) + val * pwr; - else - val = render_priv->state.style->FontSize; - if (render_priv->state.font) - change_font_size(render_priv, val); - } else if (mystrcmp(&p, "bord")) { - double val; - if (mystrtod(&p, &val)) { - if (render_priv->state.border_x == render_priv->state.border_y) - val = render_priv->state.border_x * (1 - pwr) + val * pwr; - } else - val = -1.; // reset to default - change_border(render_priv, val, val); - render_priv->state.bm_run_id++; - } else if (mystrcmp(&p, "move")) { - double x1, x2, y1, y2; - long long t1, t2, delta_t, t; - double x, y; - double k; - skip('('); - mystrtod(&p, &x1); - skip(','); - mystrtod(&p, &y1); - skip(','); - mystrtod(&p, &x2); - skip(','); - mystrtod(&p, &y2); - if (*p == ',') { - skip(','); - mystrtoll(&p, &t1); - skip(','); - mystrtoll(&p, &t2); - ass_msg(render_priv->library, MSGL_DBG2, - "movement6: (%f, %f) -> (%f, %f), (%" PRId64 " .. %" - PRId64 ")\n", x1, y1, x2, y2, (int64_t) t1, - (int64_t) t2); - } else { - t1 = 0; - t2 = render_priv->state.event->Duration; - ass_msg(render_priv->library, MSGL_DBG2, - "movement: (%f, %f) -> (%f, %f)", x1, y1, x2, y2); - } - skip(')'); - delta_t = t2 - t1; - t = render_priv->time - render_priv->state.event->Start; - if (t < t1) - k = 0.; - else if (t > t2) - k = 1.; - else - k = ((double) (t - t1)) / delta_t; - x = k * (x2 - x1) + x1; - y = k * (y2 - y1) + y1; - if (render_priv->state.evt_type != EVENT_POSITIONED) { - render_priv->state.pos_x = x; - render_priv->state.pos_y = y; - render_priv->state.detect_collisions = 0; - render_priv->state.evt_type = EVENT_POSITIONED; - } - } else if (mystrcmp(&p, "frx")) { - double val; - if (mystrtod(&p, &val)) { - val *= M_PI / 180; - render_priv->state.frx = - val * pwr + render_priv->state.frx * (1 - pwr); - } else - render_priv->state.frx = 0.; - } else if (mystrcmp(&p, "fry")) { - double val; - if (mystrtod(&p, &val)) { - val *= M_PI / 180; - render_priv->state.fry = - val * pwr + render_priv->state.fry * (1 - pwr); - } else - render_priv->state.fry = 0.; - } else if (mystrcmp(&p, "frz") || mystrcmp(&p, "fr")) { - double val; - if (mystrtod(&p, &val)) { - val *= M_PI / 180; - render_priv->state.frz = - val * pwr + render_priv->state.frz * (1 - pwr); - } else - render_priv->state.frz = - M_PI * render_priv->state.style->Angle / 180.; - } else if (mystrcmp(&p, "fn")) { - char *start = p; - char *family; - skip_to('\\'); - if (p > start) { - family = malloc(p - start + 1); - strncpy(family, start, p - start); - family[p - start] = '\0'; - } else - family = strdup(render_priv->state.style->FontName); - free(render_priv->state.family); - render_priv->state.family = family; - update_font(render_priv); - } else if (mystrcmp(&p, "alpha")) { - uint32_t val; - int i; - int hex = render_priv->track->track_type == TRACK_TYPE_ASS; - if (strtocolor(render_priv->library, &p, &val, hex)) { - unsigned char a = val >> 24; - for (i = 0; i < 4; ++i) - change_alpha(&render_priv->state.c[i], a, pwr); - } else { - change_alpha(&render_priv->state.c[0], - render_priv->state.style->PrimaryColour, pwr); - change_alpha(&render_priv->state.c[1], - render_priv->state.style->SecondaryColour, pwr); - change_alpha(&render_priv->state.c[2], - render_priv->state.style->OutlineColour, pwr); - change_alpha(&render_priv->state.c[3], - render_priv->state.style->BackColour, pwr); - } - render_priv->state.bm_run_id++; - // FIXME: simplify - } else if (mystrcmp(&p, "an")) { - int val; - if (mystrtoi(&p, &val) && val) { - int v = (val - 1) / 3; // 0, 1 or 2 for vertical alignment - ass_msg(render_priv->library, MSGL_DBG2, "an %d", val); - if (v != 0) - v = 3 - v; - val = ((val - 1) % 3) + 1; // horizontal alignment - val += v * 4; - ass_msg(render_priv->library, MSGL_DBG2, "align %d", val); - if ((render_priv->state.parsed_tags & PARSED_A) == 0) { - render_priv->state.alignment = val; - render_priv->state.parsed_tags |= PARSED_A; - } - } else - render_priv->state.alignment = - render_priv->state.style->Alignment; - } else if (mystrcmp(&p, "a")) { - int val; - if (mystrtoi(&p, &val) && val) { - if ((render_priv->state.parsed_tags & PARSED_A) == 0) { - // take care of a vsfilter quirk: handle illegal \a8 like \a5 - render_priv->state.alignment = (val == 8) ? 5 : val; - render_priv->state.parsed_tags |= PARSED_A; - } - } else - render_priv->state.alignment = - render_priv->state.style->Alignment; - } else if (mystrcmp(&p, "pos")) { - double v1, v2; - skip('('); - mystrtod(&p, &v1); - skip(','); - mystrtod(&p, &v2); - skip(')'); - ass_msg(render_priv->library, MSGL_DBG2, "pos(%f, %f)", v1, v2); - if (render_priv->state.evt_type == EVENT_POSITIONED) { - ass_msg(render_priv->library, MSGL_V, "Subtitle has a new \\pos " - "after \\move or \\pos, ignoring"); - } else { - render_priv->state.evt_type = EVENT_POSITIONED; - render_priv->state.detect_collisions = 0; - render_priv->state.pos_x = v1; - render_priv->state.pos_y = v2; - } - } else if (mystrcmp(&p, "fad")) { - int a1, a2, a3; - long long t1, t2, t3, t4; - if (*p == 'e') - ++p; // either \fad or \fade - skip('('); - mystrtoi(&p, &a1); - skip(','); - mystrtoi(&p, &a2); - if (*p == ')') { - // 2-argument version (\fad, according to specs) - // a1 and a2 are fade-in and fade-out durations - t1 = 0; - t4 = render_priv->state.event->Duration; - t2 = a1; - t3 = t4 - a2; - a1 = 0xFF; - a2 = 0; - a3 = 0xFF; - } else { - // 6-argument version (\fade) - // a1 and a2 (and a3) are opacity values - skip(','); - mystrtoi(&p, &a3); - skip(','); - mystrtoll(&p, &t1); - skip(','); - mystrtoll(&p, &t2); - skip(','); - mystrtoll(&p, &t3); - skip(','); - mystrtoll(&p, &t4); - } - skip(')'); - if ((render_priv->state.parsed_tags & PARSED_FADE) == 0) { - render_priv->state.fade = - interpolate_alpha(render_priv->time - - render_priv->state.event->Start, t1, t2, - t3, t4, a1, a2, a3); - render_priv->state.parsed_tags |= PARSED_FADE; - } - } else if (mystrcmp(&p, "org")) { - int v1, v2; - skip('('); - mystrtoi(&p, &v1); - skip(','); - mystrtoi(&p, &v2); - skip(')'); - ass_msg(render_priv->library, MSGL_DBG2, "org(%d, %d)", v1, v2); - if (!render_priv->state.have_origin) { - render_priv->state.org_x = v1; - render_priv->state.org_y = v2; - render_priv->state.have_origin = 1; - render_priv->state.detect_collisions = 0; - } - } else if (mystrcmp(&p, "t")) { - double v[3]; - int v1, v2; - double v3; - int cnt; - long long t1, t2, t, delta_t; - double k; - skip('('); - for (cnt = 0; cnt < 3; ++cnt) { - if (*p == '\\') - break; - mystrtod(&p, &v[cnt]); - skip(','); - } - if (cnt == 3) { - v1 = v[0]; - v2 = (v[1] < v1) ? render_priv->state.event->Duration : v[1]; - v3 = v[2]; - } else if (cnt == 2) { - v1 = v[0]; - v2 = (v[1] < v1) ? render_priv->state.event->Duration : v[1]; - v3 = 1.; - } else if (cnt == 1) { - v1 = 0; - v2 = render_priv->state.event->Duration; - v3 = v[0]; - } else { // cnt == 0 - v1 = 0; - v2 = render_priv->state.event->Duration; - v3 = 1.; - } - render_priv->state.detect_collisions = 0; - t1 = v1; - t2 = v2; - delta_t = v2 - v1; - if (v3 < 0.) - v3 = 0.; - t = render_priv->time - render_priv->state.event->Start; // FIXME: move to render_context - if (t <= t1) - k = 0.; - else if (t >= t2) - k = 1.; - else { - assert(delta_t != 0.); - k = pow(((double) (t - t1)) / delta_t, v3); - } - while (*p == '\\') - p = parse_tag(render_priv, p, k); // maybe k*pwr ? no, specs forbid nested \t's - skip_to(')'); // in case there is some unknown tag or a comment - skip(')'); - } else if (mystrcmp(&p, "clip")) { - char *start = p; - int x0, y0, x1, y1; - int res = 1; - skipopt('('); - res &= mystrtoi(&p, &x0); - skipopt(','); - res &= mystrtoi(&p, &y0); - skipopt(','); - res &= mystrtoi(&p, &x1); - skipopt(','); - res &= mystrtoi(&p, &y1); - skipopt(')'); - if (res) { - render_priv->state.clip_x0 = - render_priv->state.clip_x0 * (1 - pwr) + x0 * pwr; - render_priv->state.clip_x1 = - render_priv->state.clip_x1 * (1 - pwr) + x1 * pwr; - render_priv->state.clip_y0 = - render_priv->state.clip_y0 * (1 - pwr) + y0 * pwr; - render_priv->state.clip_y1 = - render_priv->state.clip_y1 * (1 - pwr) + y1 * pwr; - // Might be a vector clip - } else if (!render_priv->state.clip_drawing) { - p = parse_vector_clip(render_priv, start); - render_priv->state.clip_drawing_mode = 0; - } else { - render_priv->state.clip_x0 = 0; - render_priv->state.clip_y0 = 0; - render_priv->state.clip_x1 = render_priv->track->PlayResX; - render_priv->state.clip_y1 = render_priv->track->PlayResY; - } - } else if (mystrcmp(&p, "c")) { - uint32_t val; - int hex = render_priv->track->track_type == TRACK_TYPE_ASS; - if (!strtocolor(render_priv->library, &p, &val, hex)) - val = render_priv->state.style->PrimaryColour; - ass_msg(render_priv->library, MSGL_DBG2, "color: %X", val); - change_color(&render_priv->state.c[0], val, pwr); - render_priv->state.bm_run_id++; - } else if ((*p >= '1') && (*p <= '4') && (++p) - && (mystrcmp(&p, "c") || mystrcmp(&p, "a"))) { - char n = *(p - 2); - int cidx = n - '1'; - char cmd = *(p - 1); - uint32_t val; - int hex = render_priv->track->track_type == TRACK_TYPE_ASS; - assert((n >= '1') && (n <= '4')); - if (!strtocolor(render_priv->library, &p, &val, hex)) - switch (n) { - case '1': - val = render_priv->state.style->PrimaryColour; - break; - case '2': - val = render_priv->state.style->SecondaryColour; - break; - case '3': - val = render_priv->state.style->OutlineColour; - break; - case '4': - val = render_priv->state.style->BackColour; - break; - default: - val = 0; - break; // impossible due to assert; avoid compilation warning - } - switch (cmd) { - case 'c': - change_color(render_priv->state.c + cidx, val, pwr); - render_priv->state.bm_run_id++; - break; - case 'a': - change_alpha(render_priv->state.c + cidx, val >> 24, pwr); - render_priv->state.bm_run_id++; - break; - default: - ass_msg(render_priv->library, MSGL_WARN, "Bad command: %c%c", - n, cmd); - break; - } - ass_msg(render_priv->library, MSGL_DBG2, "single c/a at %f: %c%c = %X", - pwr, n, cmd, render_priv->state.c[cidx]); - } else if (mystrcmp(&p, "r")) { - reset_render_context(render_priv); - } else if (mystrcmp(&p, "be")) { - int val; - if (mystrtoi(&p, &val)) { - // Clamp to a safe upper limit, since high values need excessive CPU - val = (val < 0) ? 0 : val; - val = (val > MAX_BE) ? MAX_BE : val; - render_priv->state.be = val; - } else - render_priv->state.be = 0; - render_priv->state.bm_run_id++; - } else if (mystrcmp(&p, "b")) { - int b; - if (mystrtoi(&p, &b)) { - if (pwr >= .5) - render_priv->state.bold = b; - } else - render_priv->state.bold = render_priv->state.style->Bold; - update_font(render_priv); - } else if (mystrcmp(&p, "i")) { - int i; - if (mystrtoi(&p, &i)) { - if (pwr >= .5) - render_priv->state.italic = i; - } else - render_priv->state.italic = render_priv->state.style->Italic; - update_font(render_priv); - } else if (mystrcmp(&p, "kf") || mystrcmp(&p, "K")) { - int val = 0; - mystrtoi(&p, &val); - render_priv->state.effect_type = EF_KARAOKE_KF; - if (render_priv->state.effect_timing) - render_priv->state.effect_skip_timing += - render_priv->state.effect_timing; - render_priv->state.effect_timing = val * 10; - } else if (mystrcmp(&p, "ko")) { - int val = 0; - mystrtoi(&p, &val); - render_priv->state.effect_type = EF_KARAOKE_KO; - if (render_priv->state.effect_timing) - render_priv->state.effect_skip_timing += - render_priv->state.effect_timing; - render_priv->state.effect_timing = val * 10; - } else if (mystrcmp(&p, "k")) { - int val = 0; - mystrtoi(&p, &val); - render_priv->state.effect_type = EF_KARAOKE; - if (render_priv->state.effect_timing) - render_priv->state.effect_skip_timing += - render_priv->state.effect_timing; - render_priv->state.effect_timing = val * 10; - } else if (mystrcmp(&p, "shad")) { - double val; - if (mystrtod(&p, &val)) { - if (render_priv->state.shadow_x == render_priv->state.shadow_y) - val = render_priv->state.shadow_x * (1 - pwr) + val * pwr; - } else - val = 0.; - render_priv->state.shadow_x = render_priv->state.shadow_y = val; - render_priv->state.bm_run_id++; - } else if (mystrcmp(&p, "s")) { - int val; - if (mystrtoi(&p, &val) && val) - render_priv->state.flags |= DECO_STRIKETHROUGH; - else - render_priv->state.flags &= ~DECO_STRIKETHROUGH; - render_priv->state.bm_run_id++; - } else if (mystrcmp(&p, "u")) { - int val; - if (mystrtoi(&p, &val) && val) - render_priv->state.flags |= DECO_UNDERLINE; - else - render_priv->state.flags &= ~DECO_UNDERLINE; - render_priv->state.bm_run_id++; - } else if (mystrcmp(&p, "pbo")) { - double val = 0; - if (mystrtod(&p, &val)) - render_priv->state.drawing->pbo = val; - } else if (mystrcmp(&p, "p")) { - int val; - if (!mystrtoi(&p, &val)) - val = 0; - if (val) - render_priv->state.drawing->scale = val; - render_priv->state.drawing_mode = !!val; - } else if (mystrcmp(&p, "q")) { - int val; - if (!mystrtoi(&p, &val)) - val = render_priv->track->WrapStyle; - render_priv->state.wrap_style = val; - } else if (mystrcmp(&p, "fe")) { - int val; - if (!mystrtoi(&p, &val)) - val = render_priv->state.style->Encoding; - render_priv->state.font_encoding = val; - } - - return p; -} - -void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event) -{ - int v[4]; - int cnt; - char *p = event->Effect; - - if (!p || !*p) - return; - - cnt = 0; - while (cnt < 4 && (p = strchr(p, ';'))) { - v[cnt++] = atoi(++p); - } - - if (strncmp(event->Effect, "Banner;", 7) == 0) { - int delay; - if (cnt < 1) { - ass_msg(render_priv->library, MSGL_V, - "Error parsing effect: '%s'", event->Effect); - return; - } - if (cnt >= 2 && v[1] == 0) // right-to-left - render_priv->state.scroll_direction = SCROLL_RL; - else // left-to-right - render_priv->state.scroll_direction = SCROLL_LR; - - delay = v[0]; - if (delay == 0) - delay = 1; // ? - render_priv->state.scroll_shift = - (render_priv->time - render_priv->state.event->Start) / delay; - render_priv->state.evt_type = EVENT_HSCROLL; - return; - } - - if (strncmp(event->Effect, "Scroll up;", 10) == 0) { - render_priv->state.scroll_direction = SCROLL_BT; - } else if (strncmp(event->Effect, "Scroll down;", 12) == 0) { - render_priv->state.scroll_direction = SCROLL_TB; - } else { - ass_msg(render_priv->library, MSGL_DBG2, - "Unknown transition effect: '%s'", event->Effect); - return; - } - // parse scroll up/down parameters - { - int delay; - int y0, y1; - if (cnt < 3) { - ass_msg(render_priv->library, MSGL_V, - "Error parsing effect: '%s'", event->Effect); - return; - } - delay = v[2]; - if (delay == 0) - delay = 1; // ? - render_priv->state.scroll_shift = - (render_priv->time - render_priv->state.event->Start) / delay; - if (v[0] < v[1]) { - y0 = v[0]; - y1 = v[1]; - } else { - y0 = v[1]; - y1 = v[0]; - } - if (y1 == 0) - y1 = render_priv->track->PlayResY; // y0=y1=0 means fullscreen scrolling - render_priv->state.clip_y0 = y0; - render_priv->state.clip_y1 = y1; - render_priv->state.evt_type = EVENT_VSCROLL; - render_priv->state.detect_collisions = 0; - } - -} - -/** - * \brief determine karaoke effects - * Karaoke effects cannot be calculated during parse stage (get_next_char()), - * so they are done in a separate step. - * Parse stage: when karaoke style override is found, its parameters are stored in the next glyph's - * (the first glyph of the karaoke word)'s effect_type and effect_timing. - * This function: - * 1. sets effect_type for all glyphs in the word (_karaoke_ word) - * 2. sets effect_timing for all glyphs to x coordinate of the border line between the left and right karaoke parts - * (left part is filled with PrimaryColour, right one - with SecondaryColour). - */ -void process_karaoke_effects(ASS_Renderer *render_priv) -{ - GlyphInfo *cur, *cur2; - GlyphInfo *s1, *e1; // start and end of the current word - GlyphInfo *s2; // start of the next word - int i; - int timing; // current timing - int tm_start, tm_end; // timings at start and end of the current word - int tm_current; - double dt; - int x; - int x_start, x_end; - - tm_current = render_priv->time - render_priv->state.event->Start; - timing = 0; - s1 = s2 = 0; - for (i = 0; i <= render_priv->text_info.length; ++i) { - cur = render_priv->text_info.glyphs + i; - if ((i == render_priv->text_info.length) - || (cur->effect_type != EF_NONE)) { - s1 = s2; - s2 = cur; - if (s1) { - e1 = s2 - 1; - tm_start = timing + s1->effect_skip_timing; - tm_end = tm_start + s1->effect_timing; - timing = tm_end; - x_start = 1000000; - x_end = -1000000; - for (cur2 = s1; cur2 <= e1; ++cur2) { - x_start = FFMIN(x_start, d6_to_int(cur2->bbox.xMin + cur2->pos.x)); - x_end = FFMAX(x_end, d6_to_int(cur2->bbox.xMax + cur2->pos.x)); - } - - dt = (tm_current - tm_start); - if ((s1->effect_type == EF_KARAOKE) - || (s1->effect_type == EF_KARAOKE_KO)) { - if (dt > 0) - x = x_end + 1; - else - x = x_start; - } else if (s1->effect_type == EF_KARAOKE_KF) { - dt /= (tm_end - tm_start); - x = x_start + (x_end - x_start) * dt; - } else { - ass_msg(render_priv->library, MSGL_ERR, - "Unknown effect type"); - continue; - } - - for (cur2 = s1; cur2 <= e1; ++cur2) { - cur2->effect_type = s1->effect_type; - cur2->effect_timing = x - d6_to_int(cur2->pos.x); - } - } - } - } -} - - -/** - * \brief Get next ucs4 char from string, parsing and executing style overrides - * \param str string pointer - * \return ucs4 code of the next char - * On return str points to the unparsed part of the string - */ -unsigned get_next_char(ASS_Renderer *render_priv, char **str) -{ - char *p = *str; - unsigned chr; - if (*p == '{') { // '\0' goes here - p++; - while (1) { - p = parse_tag(render_priv, p, 1.); - if (*p == '}') { // end of tag - p++; - if (*p == '{') { - p++; - continue; - } else - break; - } else if (*p != '\\') - ass_msg(render_priv->library, MSGL_V, - "Unable to parse: '%.30s'", p); - if (*p == 0) - break; - } - } - if (*p == '\t') { - ++p; - *str = p; - return ' '; - } - if (*p == '\\') { - if ((p[1] == 'N') || ((p[1] == 'n') && - (render_priv->state.wrap_style == 2))) { - p += 2; - *str = p; - return '\n'; - } else if (p[1] == 'n') { - p += 2; - *str = p; - return ' '; - } else if (p[1] == 'h') { - p += 2; - *str = p; - return NBSP; - } else if (p[1] == '{') { - p += 2; - *str = p; - return '{'; - } else if (p[1] == '}') { - p += 2; - *str = p; - return '}'; - } - } - chr = ass_utf8_get_char((char **) &p); - *str = p; - return chr; -} diff --git a/lib/libass/libass/ass_parse.h b/lib/libass/libass/ass_parse.h deleted file mode 100644 index 2e145dcbfa..0000000000 --- a/lib/libass/libass/ass_parse.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef LIBASS_PARSE_H -#define LIBASS_PARSE_H - -#define BLUR_MAX_RADIUS 100.0 - -#define _r(c) ((c) >> 24) -#define _g(c) (((c) >> 16) & 0xFF) -#define _b(c) (((c) >> 8) & 0xFF) -#define _a(c) ((c) & 0xFF) - -void update_font(ASS_Renderer *render_priv); -double ensure_font_size(ASS_Renderer *priv, double size); -void change_border(ASS_Renderer *render_priv, double border_x, - double border_y); -void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event); -void process_karaoke_effects(ASS_Renderer *render_priv); -unsigned get_next_char(ASS_Renderer *render_priv, char **str); -extern void change_alpha(uint32_t *var, uint32_t new, double pwr); -extern uint32_t mult_alpha(uint32_t a, uint32_t b); - - -#endif /* LIBASS_PARSE_H */ diff --git a/lib/libass/libass/ass_render.c b/lib/libass/libass/ass_render.c deleted file mode 100644 index 97befdded1..0000000000 --- a/lib/libass/libass/ass_render.c +++ /dev/null @@ -1,2539 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "config.h" - -#include <assert.h> -#include <math.h> - -#include "ass_render.h" -#include "ass_parse.h" -#include "ass_shaper.h" - -#define MAX_GLYPHS_INITIAL 1024 -#define MAX_LINES_INITIAL 64 -#define SUBPIXEL_MASK 63 -#define SUBPIXEL_ACCURACY 7 - -ASS_Renderer *ass_renderer_init(ASS_Library *library) -{ - int error; - FT_Library ft; - ASS_Renderer *priv = 0; - int vmajor, vminor, vpatch; - - error = FT_Init_FreeType(&ft); - if (error) { - ass_msg(library, MSGL_FATAL, "%s failed", "FT_Init_FreeType"); - goto ass_init_exit; - } - - FT_Library_Version(ft, &vmajor, &vminor, &vpatch); - ass_msg(library, MSGL_V, "Raster: FreeType %d.%d.%d", - vmajor, vminor, vpatch); - - priv = calloc(1, sizeof(ASS_Renderer)); - if (!priv) { - FT_Done_FreeType(ft); - goto ass_init_exit; - } - - priv->synth_priv = ass_synth_init(BLUR_MAX_RADIUS); - - priv->library = library; - priv->ftlibrary = ft; - // images_root and related stuff is zero-filled in calloc - - priv->cache.font_cache = ass_font_cache_create(); - priv->cache.bitmap_cache = ass_bitmap_cache_create(); - priv->cache.composite_cache = ass_composite_cache_create(); - priv->cache.outline_cache = ass_outline_cache_create(); - priv->cache.glyph_max = GLYPH_CACHE_MAX; - priv->cache.bitmap_max_size = BITMAP_CACHE_MAX_SIZE; - - priv->text_info.max_glyphs = MAX_GLYPHS_INITIAL; - priv->text_info.max_lines = MAX_LINES_INITIAL; - priv->text_info.glyphs = calloc(MAX_GLYPHS_INITIAL, sizeof(GlyphInfo)); - priv->text_info.lines = calloc(MAX_LINES_INITIAL, sizeof(LineInfo)); - - priv->settings.font_size_coeff = 1.; - - priv->shaper = ass_shaper_new(0); - ass_shaper_info(library); -#ifdef CONFIG_HARFBUZZ - priv->settings.shaper = ASS_SHAPING_COMPLEX; -#else - priv->settings.shaper = ASS_SHAPING_SIMPLE; -#endif - - ass_init_exit: - if (priv) - ass_msg(library, MSGL_V, "Initialized"); - else - ass_msg(library, MSGL_ERR, "Initialization failed"); - - return priv; -} - -static void free_list_clear(ASS_Renderer *render_priv) -{ - if (render_priv->free_head) { - FreeList *item = render_priv->free_head; - while(item) { - FreeList *oi = item; - free(item->object); - item = item->next; - free(oi); - } - render_priv->free_head = NULL; - } -} - -void ass_renderer_done(ASS_Renderer *render_priv) -{ - ass_cache_done(render_priv->cache.font_cache); - ass_cache_done(render_priv->cache.bitmap_cache); - ass_cache_done(render_priv->cache.composite_cache); - ass_cache_done(render_priv->cache.outline_cache); - - ass_free_images(render_priv->images_root); - ass_free_images(render_priv->prev_images_root); - - if (render_priv->state.stroker) { - FT_Stroker_Done(render_priv->state.stroker); - render_priv->state.stroker = 0; - } - if (render_priv->ftlibrary) - FT_Done_FreeType(render_priv->ftlibrary); - if (render_priv->fontconfig_priv) - fontconfig_done(render_priv->fontconfig_priv); - if (render_priv->synth_priv) - ass_synth_done(render_priv->synth_priv); - ass_shaper_free(render_priv->shaper); - free(render_priv->eimg); - free(render_priv->text_info.glyphs); - free(render_priv->text_info.lines); - - free(render_priv->settings.default_font); - free(render_priv->settings.default_family); - - free_list_clear(render_priv); - free(render_priv); -} - -/** - * \brief Create a new ASS_Image - * Parameters are the same as ASS_Image fields. - */ -static ASS_Image *my_draw_bitmap(unsigned char *bitmap, int bitmap_w, - int bitmap_h, int stride, int dst_x, - int dst_y, uint32_t color) -{ - ASS_Image *img = malloc(sizeof(ASS_Image)); - - if (img) { - img->w = bitmap_w; - img->h = bitmap_h; - img->stride = stride; - img->bitmap = bitmap; - img->color = color; - img->dst_x = dst_x; - img->dst_y = dst_y; - } - - return img; -} - -/** - * \brief Mapping between script and screen coordinates - */ -static double x2scr(ASS_Renderer *render_priv, double x) -{ - return x * render_priv->orig_width_nocrop / render_priv->font_scale_x / - render_priv->track->PlayResX + - FFMAX(render_priv->settings.left_margin, 0); -} -static double x2scr_pos(ASS_Renderer *render_priv, double x) -{ - return x * render_priv->orig_width / render_priv->font_scale_x / render_priv->track->PlayResX + - render_priv->settings.left_margin; -} -static double x2scr_scaled(ASS_Renderer *render_priv, double x) -{ - return x * render_priv->orig_width_nocrop / - render_priv->track->PlayResX + - FFMAX(render_priv->settings.left_margin, 0); -} -static double x2scr_pos_scaled(ASS_Renderer *render_priv, double x) -{ - return x * render_priv->orig_width / render_priv->track->PlayResX + - render_priv->settings.left_margin; -} -/** - * \brief Mapping between script and screen coordinates - */ -static double y2scr(ASS_Renderer *render_priv, double y) -{ - return y * render_priv->orig_height_nocrop / - render_priv->track->PlayResY + - FFMAX(render_priv->settings.top_margin, 0); -} -static double y2scr_pos(ASS_Renderer *render_priv, double y) -{ - return y * render_priv->orig_height / render_priv->track->PlayResY + - render_priv->settings.top_margin; -} - -// the same for toptitles -static double y2scr_top(ASS_Renderer *render_priv, double y) -{ - if (render_priv->settings.use_margins) - return y * render_priv->orig_height_nocrop / - render_priv->track->PlayResY; - else - return y * render_priv->orig_height_nocrop / - render_priv->track->PlayResY + - FFMAX(render_priv->settings.top_margin, 0); -} -// the same for subtitles -static double y2scr_sub(ASS_Renderer *render_priv, double y) -{ - if (render_priv->settings.use_margins) - return y * render_priv->orig_height_nocrop / - render_priv->track->PlayResY + - FFMAX(render_priv->settings.top_margin, 0) - + FFMAX(render_priv->settings.bottom_margin, 0); - else - return y * render_priv->orig_height_nocrop / - render_priv->track->PlayResY + - FFMAX(render_priv->settings.top_margin, 0); -} - -/* - * \brief Convert bitmap glyphs into ASS_Image list with inverse clipping - * - * Inverse clipping with the following strategy: - * - find rectangle from (x0, y0) to (cx0, y1) - * - find rectangle from (cx0, y0) to (cx1, cy0) - * - find rectangle from (cx0, cy1) to (cx1, y1) - * - find rectangle from (cx1, y0) to (x1, y1) - * These rectangles can be invalid and in this case are discarded. - * Afterwards, they are clipped against the screen coordinates. - * In an additional pass, the rectangles need to be split up left/right for - * karaoke effects. This can result in a lot of bitmaps (6 to be exact). - */ -static ASS_Image **render_glyph_i(ASS_Renderer *render_priv, - Bitmap *bm, int dst_x, int dst_y, - uint32_t color, uint32_t color2, int brk, - ASS_Image **tail) -{ - int i, j, x0, y0, x1, y1, cx0, cy0, cx1, cy1, sx, sy, zx, zy; - Rect r[4]; - ASS_Image *img; - - dst_x += bm->left; - dst_y += bm->top; - - // we still need to clip against screen boundaries - zx = x2scr_pos_scaled(render_priv, 0); - zy = y2scr_pos(render_priv, 0); - sx = x2scr_pos_scaled(render_priv, render_priv->track->PlayResX); - sy = y2scr_pos(render_priv, render_priv->track->PlayResY); - - x0 = 0; - y0 = 0; - x1 = bm->w; - y1 = bm->h; - cx0 = render_priv->state.clip_x0 - dst_x; - cy0 = render_priv->state.clip_y0 - dst_y; - cx1 = render_priv->state.clip_x1 - dst_x; - cy1 = render_priv->state.clip_y1 - dst_y; - - // calculate rectangles and discard invalid ones while we're at it. - i = 0; - r[i].x0 = x0; - r[i].y0 = y0; - r[i].x1 = (cx0 > x1) ? x1 : cx0; - r[i].y1 = y1; - if (r[i].x1 > r[i].x0 && r[i].y1 > r[i].y0) i++; - r[i].x0 = (cx0 < 0) ? x0 : cx0; - r[i].y0 = y0; - r[i].x1 = (cx1 > x1) ? x1 : cx1; - r[i].y1 = (cy0 > y1) ? y1 : cy0; - if (r[i].x1 > r[i].x0 && r[i].y1 > r[i].y0) i++; - r[i].x0 = (cx0 < 0) ? x0 : cx0; - r[i].y0 = (cy1 < 0) ? y0 : cy1; - r[i].x1 = (cx1 > x1) ? x1 : cx1; - r[i].y1 = y1; - if (r[i].x1 > r[i].x0 && r[i].y1 > r[i].y0) i++; - r[i].x0 = (cx1 < 0) ? x0 : cx1; - r[i].y0 = y0; - r[i].x1 = x1; - r[i].y1 = y1; - if (r[i].x1 > r[i].x0 && r[i].y1 > r[i].y0) i++; - - // clip each rectangle to screen coordinates - for (j = 0; j < i; j++) { - r[j].x0 = (r[j].x0 + dst_x < zx) ? zx - dst_x : r[j].x0; - r[j].y0 = (r[j].y0 + dst_y < zy) ? zy - dst_y : r[j].y0; - r[j].x1 = (r[j].x1 + dst_x > sx) ? sx - dst_x : r[j].x1; - r[j].y1 = (r[j].y1 + dst_y > sy) ? sy - dst_y : r[j].y1; - } - - // draw the rectangles - for (j = 0; j < i; j++) { - int lbrk = brk; - // kick out rectangles that are invalid now - if (r[j].x1 <= r[j].x0 || r[j].y1 <= r[j].y0) - continue; - // split up into left and right for karaoke, if needed - if (lbrk > r[j].x0) { - if (lbrk > r[j].x1) lbrk = r[j].x1; - img = my_draw_bitmap(bm->buffer + r[j].y0 * bm->stride + r[j].x0, - lbrk - r[j].x0, r[j].y1 - r[j].y0, - bm->stride, dst_x + r[j].x0, dst_y + r[j].y0, color); - if (!img) break; - *tail = img; - tail = &img->next; - } - if (lbrk < r[j].x1) { - if (lbrk < r[j].x0) lbrk = r[j].x0; - img = my_draw_bitmap(bm->buffer + r[j].y0 * bm->stride + lbrk, - r[j].x1 - lbrk, r[j].y1 - r[j].y0, - bm->stride, dst_x + lbrk, dst_y + r[j].y0, color2); - if (!img) break; - *tail = img; - tail = &img->next; - } - } - - return tail; -} - -/** - * \brief convert bitmap glyph into ASS_Image struct(s) - * \param bit freetype bitmap glyph, FT_PIXEL_MODE_GRAY - * \param dst_x bitmap x coordinate in video frame - * \param dst_y bitmap y coordinate in video frame - * \param color first color, RGBA - * \param color2 second color, RGBA - * \param brk x coordinate relative to glyph origin, color is used to the left of brk, color2 - to the right - * \param tail pointer to the last image's next field, head of the generated list should be stored here - * \return pointer to the new list tail - * Performs clipping. Uses my_draw_bitmap for actual bitmap convertion. - */ -static ASS_Image ** -render_glyph(ASS_Renderer *render_priv, Bitmap *bm, int dst_x, int dst_y, - uint32_t color, uint32_t color2, int brk, ASS_Image **tail) -{ - - // brk is relative to dst_x - // color = color left of brk - // color2 = color right of brk - int b_x0, b_y0, b_x1, b_y1; // visible part of the bitmap - int clip_x0, clip_y0, clip_x1, clip_y1; - int tmp; - ASS_Image *img; - - // Inverse clipping in use? - if (render_priv->state.clip_mode) - return render_glyph_i(render_priv, bm, dst_x, dst_y, color, color2, - brk, tail); - - dst_x += bm->left; - dst_y += bm->top; - brk -= bm->left; - - // clipping - clip_x0 = FFMINMAX(render_priv->state.clip_x0, 0, render_priv->width); - clip_y0 = FFMINMAX(render_priv->state.clip_y0, 0, render_priv->height); - clip_x1 = FFMINMAX(render_priv->state.clip_x1, 0, render_priv->width); - clip_y1 = FFMINMAX(render_priv->state.clip_y1, 0, render_priv->height); - b_x0 = 0; - b_y0 = 0; - b_x1 = bm->w; - b_y1 = bm->h; - - tmp = dst_x - clip_x0; - if (tmp < 0) { - ass_msg(render_priv->library, MSGL_DBG2, "clip left"); - b_x0 = -tmp; - } - tmp = dst_y - clip_y0; - if (tmp < 0) { - ass_msg(render_priv->library, MSGL_DBG2, "clip top"); - b_y0 = -tmp; - } - tmp = clip_x1 - dst_x - bm->w; - if (tmp < 0) { - ass_msg(render_priv->library, MSGL_DBG2, "clip right"); - b_x1 = bm->w + tmp; - } - tmp = clip_y1 - dst_y - bm->h; - if (tmp < 0) { - ass_msg(render_priv->library, MSGL_DBG2, "clip bottom"); - b_y1 = bm->h + tmp; - } - - if ((b_y0 >= b_y1) || (b_x0 >= b_x1)) - return tail; - - if (brk > b_x0) { // draw left part - if (brk > b_x1) - brk = b_x1; - img = my_draw_bitmap(bm->buffer + bm->stride * b_y0 + b_x0, - brk - b_x0, b_y1 - b_y0, bm->stride, - dst_x + b_x0, dst_y + b_y0, color); - if (!img) return tail; - *tail = img; - tail = &img->next; - } - if (brk < b_x1) { // draw right part - if (brk < b_x0) - brk = b_x0; - img = my_draw_bitmap(bm->buffer + bm->stride * b_y0 + brk, - b_x1 - brk, b_y1 - b_y0, bm->stride, - dst_x + brk, dst_y + b_y0, color2); - if (!img) return tail; - *tail = img; - tail = &img->next; - } - return tail; -} - -/** - * \brief Replace the bitmap buffer in ASS_Image with a copy - * \param img ASS_Image to operate on - * \return pointer to old bitmap buffer - */ -static unsigned char *clone_bitmap_buffer(ASS_Image *img) -{ - unsigned char *old_bitmap = img->bitmap; - int size = img->stride * (img->h - 1) + img->w; - img->bitmap = malloc(size); - memcpy(img->bitmap, old_bitmap, size); - return old_bitmap; -} - -/** - * \brief Calculate overlapping area of two consecutive bitmaps and in case they - * overlap, blend them together - * Mainly useful for translucent glyphs and especially borders, to avoid the - * luminance adding up where they overlap (which looks ugly) - */ -static void -render_overlap(ASS_Renderer *render_priv, ASS_Image **last_tail, - ASS_Image **tail) -{ - int left, top, bottom, right; - int old_left, old_top, w, h, cur_left, cur_top; - int x, y, opos, cpos; - char m; - CompositeHashKey hk; - CompositeHashValue *hv; - CompositeHashValue chv; - int ax = (*last_tail)->dst_x; - int ay = (*last_tail)->dst_y; - int aw = (*last_tail)->w; - int as = (*last_tail)->stride; - int ah = (*last_tail)->h; - int bx = (*tail)->dst_x; - int by = (*tail)->dst_y; - int bw = (*tail)->w; - int bs = (*tail)->stride; - int bh = (*tail)->h; - unsigned char *a; - unsigned char *b; - - if ((*last_tail)->bitmap == (*tail)->bitmap) - return; - - if ((*last_tail)->color != (*tail)->color) - return; - - // Calculate overlap coordinates - left = (ax > bx) ? ax : bx; - top = (ay > by) ? ay : by; - right = ((ax + aw) < (bx + bw)) ? (ax + aw) : (bx + bw); - bottom = ((ay + ah) < (by + bh)) ? (ay + ah) : (by + bh); - if ((right <= left) || (bottom <= top)) - return; - old_left = left - ax; - old_top = top - ay; - w = right - left; - h = bottom - top; - cur_left = left - bx; - cur_top = top - by; - - // Query cache - hk.a = (*last_tail)->bitmap; - hk.b = (*tail)->bitmap; - hk.aw = aw; - hk.ah = ah; - hk.bw = bw; - hk.bh = bh; - hk.ax = ax; - hk.ay = ay; - hk.bx = bx; - hk.by = by; - hk.as = as; - hk.bs = bs; - hv = ass_cache_get(render_priv->cache.composite_cache, &hk); - if (hv) { - (*last_tail)->bitmap = hv->a; - (*tail)->bitmap = hv->b; - return; - } - // Allocate new bitmaps and copy over data - a = clone_bitmap_buffer(*last_tail); - b = clone_bitmap_buffer(*tail); - - // Blend overlapping area - for (y = 0; y < h; y++) - for (x = 0; x < w; x++) { - opos = (old_top + y) * (as) + (old_left + x); - cpos = (cur_top + y) * (bs) + (cur_left + x); - m = FFMIN(a[opos] + b[cpos], 0xff); - (*last_tail)->bitmap[opos] = 0; - (*tail)->bitmap[cpos] = m; - } - - // Insert bitmaps into the cache - chv.a = (*last_tail)->bitmap; - chv.b = (*tail)->bitmap; - ass_cache_put(render_priv->cache.composite_cache, &hk, &chv); -} - -static void free_list_add(ASS_Renderer *render_priv, void *object) -{ - if (!render_priv->free_head) { - render_priv->free_head = calloc(1, sizeof(FreeList)); - render_priv->free_head->object = object; - render_priv->free_tail = render_priv->free_head; - } else { - FreeList *l = calloc(1, sizeof(FreeList)); - l->object = object; - render_priv->free_tail->next = l; - render_priv->free_tail = render_priv->free_tail->next; - } -} - -/** - * Iterate through a list of bitmaps and blend with clip vector, if - * applicable. The blended bitmaps are added to a free list which is freed - * at the start of a new frame. - */ -static void blend_vector_clip(ASS_Renderer *render_priv, - ASS_Image *head) -{ - FT_Outline *outline; - Bitmap *clip_bm = NULL; - ASS_Image *cur; - ASS_Drawing *drawing = render_priv->state.clip_drawing; - BitmapHashKey key; - BitmapHashValue *val; - - if (!drawing) - return; - - // Try to get mask from cache - memset(&key, 0, sizeof(key)); - key.type = BITMAP_CLIP; - key.u.clip.text = drawing->text; - val = ass_cache_get(render_priv->cache.bitmap_cache, &key); - - if (val) { - clip_bm = val->bm; - } else { - BitmapHashValue v; - - // Not found in cache, parse and rasterize it - outline = ass_drawing_parse(drawing, 1); - if (!outline) { - ass_msg(render_priv->library, MSGL_WARN, - "Clip vector parsing failed. Skipping."); - goto blend_vector_error; - } - - // We need to translate the clip according to screen borders - if (render_priv->settings.left_margin != 0 || - render_priv->settings.top_margin != 0) { - FT_Vector trans; - trans.x = int_to_d6(render_priv->settings.left_margin); - trans.y = -int_to_d6(render_priv->settings.top_margin); - FT_Outline_Translate(outline, trans.x, trans.y); - } - - ass_msg(render_priv->library, MSGL_DBG2, - "Parsed vector clip: scales (%f, %f) string [%s]\n", - drawing->scale_x, drawing->scale_y, drawing->text); - - clip_bm = outline_to_bitmap(render_priv->library, - render_priv->ftlibrary, outline, 0); - if (clip_bm == NULL) { - ass_msg(render_priv->library, MSGL_WARN, - "Clip vector rasterization failed. Skipping."); - } - - // Add to cache - memset(&v, 0, sizeof(v)); - key.u.clip.text = strdup(drawing->text); - v.bm = clip_bm; - ass_cache_put(render_priv->cache.bitmap_cache, &key, &v); - } -blend_vector_error: - - if (!clip_bm) goto blend_vector_exit; - - // Iterate through bitmaps and blend/clip them - for (cur = head; cur; cur = cur->next) { - int left, top, right, bottom, apos, bpos, y, x, w, h; - int ax, ay, aw, ah, as; - int bx, by, bw, bh, bs; - int aleft, atop, bleft, btop; - unsigned char *abuffer, *bbuffer, *nbuffer; - - abuffer = cur->bitmap; - bbuffer = clip_bm->buffer; - ax = cur->dst_x; - ay = cur->dst_y; - aw = cur->w; - ah = cur->h; - as = cur->stride; - bx = clip_bm->left; - by = clip_bm->top; - bw = clip_bm->w; - bh = clip_bm->h; - bs = clip_bm->stride; - - // Calculate overlap coordinates - left = (ax > bx) ? ax : bx; - top = (ay > by) ? ay : by; - right = ((ax + aw) < (bx + bw)) ? (ax + aw) : (bx + bw); - bottom = ((ay + ah) < (by + bh)) ? (ay + ah) : (by + bh); - aleft = left - ax; - atop = top - ay; - w = right - left; - h = bottom - top; - bleft = left - bx; - btop = top - by; - - if (render_priv->state.clip_drawing_mode) { - // Inverse clip - if (ax + aw < bx || ay + ah < by || ax > bx + bw || - ay > by + bh) { - continue; - } - - // Allocate new buffer and add to free list - nbuffer = malloc(as * ah); - if (!nbuffer) goto blend_vector_exit; - free_list_add(render_priv, nbuffer); - - // Blend together - memcpy(nbuffer, abuffer, as * (ah - 1) + aw); - for (y = 0; y < h; y++) - for (x = 0; x < w; x++) { - apos = (atop + y) * as + aleft + x; - bpos = (btop + y) * bs + bleft + x; - nbuffer[apos] = FFMAX(0, abuffer[apos] - bbuffer[bpos]); - } - } else { - // Regular clip - if (ax + aw < bx || ay + ah < by || ax > bx + bw || - ay > by + bh) { - cur->w = cur->h = 0; - continue; - } - - // Allocate new buffer and add to free list - nbuffer = calloc(as, ah); - if (!nbuffer) goto blend_vector_exit; - free_list_add(render_priv, nbuffer); - - // Blend together - for (y = 0; y < h; y++) - for (x = 0; x < w; x++) { - apos = (atop + y) * as + aleft + x; - bpos = (btop + y) * bs + bleft + x; - nbuffer[apos] = (abuffer[apos] * bbuffer[bpos] + 255) >> 8; - } - } - cur->bitmap = nbuffer; - } - -blend_vector_exit: - ass_drawing_free(render_priv->state.clip_drawing); - render_priv->state.clip_drawing = 0; -} - -/** - * \brief Convert TextInfo struct to ASS_Image list - * Splits glyphs in halves when needed (for \kf karaoke). - */ -static ASS_Image *render_text(ASS_Renderer *render_priv, int dst_x, int dst_y) -{ - int pen_x, pen_y; - int i; - Bitmap *bm; - ASS_Image *head; - ASS_Image **tail = &head; - ASS_Image **last_tail = 0; - ASS_Image **here_tail = 0; - TextInfo *text_info = &render_priv->text_info; - - for (i = 0; i < text_info->length; ++i) { - GlyphInfo *info = text_info->glyphs + i; - if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_s - || (info->shadow_x == 0 && info->shadow_y == 0) || info->skip) - continue; - - while (info) { - if (!info->bm_s) { - info = info->next; - continue; - } - - pen_x = - dst_x + (info->pos.x >> 6) + - (int) (info->shadow_x * render_priv->border_scale); - pen_y = - dst_y + (info->pos.y >> 6) + - (int) (info->shadow_y * render_priv->border_scale); - bm = info->bm_s; - - here_tail = tail; - tail = - render_glyph(render_priv, bm, pen_x, pen_y, info->c[3], 0, - 1000000, tail); - - if (last_tail && tail != here_tail && ((info->c[3] & 0xff) > 0)) - render_overlap(render_priv, last_tail, here_tail); - last_tail = here_tail; - - info = info->next; - } - } - - last_tail = 0; - for (i = 0; i < text_info->length; ++i) { - GlyphInfo *info = text_info->glyphs + i; - if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_o - || info->skip) - continue; - - while (info) { - if (!info->bm_o) { - info = info->next; - continue; - } - - pen_x = dst_x + (info->pos.x >> 6); - pen_y = dst_y + (info->pos.y >> 6); - bm = info->bm_o; - - if ((info->effect_type == EF_KARAOKE_KO) - && (info->effect_timing <= (info->bbox.xMax >> 6))) { - // do nothing - } else { - here_tail = tail; - tail = - render_glyph(render_priv, bm, pen_x, pen_y, info->c[2], - 0, 1000000, tail); - if (last_tail && tail != here_tail && ((info->c[2] & 0xff) > 0)) - render_overlap(render_priv, last_tail, here_tail); - - last_tail = here_tail; - } - info = info->next; - } - } - - for (i = 0; i < text_info->length; ++i) { - GlyphInfo *info = text_info->glyphs + i; - if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm - || info->skip) - continue; - - while (info) { - if (!info->bm) { - info = info->next; - continue; - } - - pen_x = dst_x + (info->pos.x >> 6); - pen_y = dst_y + (info->pos.y >> 6); - bm = info->bm; - - if ((info->effect_type == EF_KARAOKE) - || (info->effect_type == EF_KARAOKE_KO)) { - if (info->effect_timing > (info->bbox.xMax >> 6)) - tail = - render_glyph(render_priv, bm, pen_x, pen_y, - info->c[0], 0, 1000000, tail); - else - tail = - render_glyph(render_priv, bm, pen_x, pen_y, - info->c[1], 0, 1000000, tail); - } else if (info->effect_type == EF_KARAOKE_KF) { - tail = - render_glyph(render_priv, bm, pen_x, pen_y, info->c[0], - info->c[1], info->effect_timing, tail); - } else - tail = - render_glyph(render_priv, bm, pen_x, pen_y, info->c[0], - 0, 1000000, tail); - info = info->next; - } - } - - *tail = 0; - blend_vector_clip(render_priv, head); - - return head; -} - -static void compute_string_bbox(TextInfo *text, DBBox *bbox) -{ - int i; - - if (text->length > 0) { - bbox->xMin = 32000; - bbox->xMax = -32000; - bbox->yMin = -1 * text->lines[0].asc + d6_to_double(text->glyphs[0].pos.y); - bbox->yMax = text->height - text->lines[0].asc + - d6_to_double(text->glyphs[0].pos.y); - - for (i = 0; i < text->length; ++i) { - GlyphInfo *info = text->glyphs + i; - if (info->skip) continue; - while (info) { - double s = d6_to_double(info->pos.x); - double e = s + d6_to_double(info->advance.x); - bbox->xMin = FFMIN(bbox->xMin, s); - bbox->xMax = FFMAX(bbox->xMax, e); - info = info->next; - } - } - } else - bbox->xMin = bbox->xMax = bbox->yMin = bbox->yMax = 0.; -} - -/** - * \brief partially reset render_context to style values - * Works like {\r}: resets some style overrides - */ -void reset_render_context(ASS_Renderer *render_priv) -{ - render_priv->state.c[0] = render_priv->state.style->PrimaryColour; - render_priv->state.c[1] = render_priv->state.style->SecondaryColour; - render_priv->state.c[2] = render_priv->state.style->OutlineColour; - render_priv->state.c[3] = render_priv->state.style->BackColour; - render_priv->state.flags = - (render_priv->state.style->Underline ? DECO_UNDERLINE : 0) | - (render_priv->state.style->StrikeOut ? DECO_STRIKETHROUGH : 0); - render_priv->state.font_size = render_priv->state.style->FontSize; - - free(render_priv->state.family); - render_priv->state.family = NULL; - render_priv->state.family = strdup(render_priv->state.style->FontName); - render_priv->state.treat_family_as_pattern = - render_priv->state.style->treat_fontname_as_pattern; - render_priv->state.bold = render_priv->state.style->Bold; - render_priv->state.italic = render_priv->state.style->Italic; - update_font(render_priv); - - change_border(render_priv, -1., -1.); - render_priv->state.scale_x = render_priv->state.style->ScaleX; - render_priv->state.scale_y = render_priv->state.style->ScaleY; - render_priv->state.hspacing = render_priv->state.style->Spacing; - render_priv->state.be = 0; - render_priv->state.blur = 0.0; - render_priv->state.shadow_x = render_priv->state.style->Shadow; - render_priv->state.shadow_y = render_priv->state.style->Shadow; - render_priv->state.frx = render_priv->state.fry = 0.; - render_priv->state.frz = M_PI * render_priv->state.style->Angle / 180.; - render_priv->state.fax = render_priv->state.fay = 0.; - render_priv->state.wrap_style = render_priv->track->WrapStyle; - render_priv->state.font_encoding = render_priv->state.style->Encoding; -} - -/** - * \brief Start new event. Reset render_priv->state. - */ -static void -init_render_context(ASS_Renderer *render_priv, ASS_Event *event) -{ - render_priv->state.event = event; - render_priv->state.style = render_priv->track->styles + event->Style; - render_priv->state.parsed_tags = 0; - - reset_render_context(render_priv); - - render_priv->state.evt_type = EVENT_NORMAL; - render_priv->state.alignment = render_priv->state.style->Alignment; - render_priv->state.pos_x = 0; - render_priv->state.pos_y = 0; - render_priv->state.org_x = 0; - render_priv->state.org_y = 0; - render_priv->state.have_origin = 0; - render_priv->state.clip_x0 = 0; - render_priv->state.clip_y0 = 0; - render_priv->state.clip_x1 = render_priv->track->PlayResX; - render_priv->state.clip_y1 = render_priv->track->PlayResY; - render_priv->state.clip_mode = 0; - render_priv->state.detect_collisions = 1; - render_priv->state.fade = 0; - render_priv->state.drawing_mode = 0; - render_priv->state.effect_type = EF_NONE; - render_priv->state.effect_timing = 0; - render_priv->state.effect_skip_timing = 0; - render_priv->state.bm_run_id = 0; - ass_drawing_free(render_priv->state.drawing); - render_priv->state.drawing = ass_drawing_new(render_priv->library, - render_priv->ftlibrary); - - apply_transition_effects(render_priv, event); -} - -static void free_render_context(ASS_Renderer *render_priv) -{ - free(render_priv->state.family); - ass_drawing_free(render_priv->state.drawing); - - render_priv->state.family = NULL; - render_priv->state.drawing = NULL; -} - -/* - * Replace the outline of a glyph by a contour which makes up a simple - * opaque rectangle. - */ -static void draw_opaque_box(ASS_Renderer *render_priv, int asc, int desc, - FT_Outline *ol, FT_Vector advance, int sx, int sy) -{ - int i; - int adv = advance.x; - double scale_y = render_priv->state.scale_y; - double scale_x = render_priv->state.scale_x; - FT_Vector points[4]; - - // to avoid gaps - sx = FFMAX(64, sx); - sy = FFMAX(64, sy); - - // Emulate the WTFish behavior of VSFilter, i.e. double-scale - // the sizes of the opaque box. - adv += double_to_d6(render_priv->state.hspacing * render_priv->font_scale - * scale_x); - adv *= scale_x; - sx *= scale_x; - sy *= scale_y; - desc *= scale_y; - desc += asc * (scale_y - 1.0); - - points[0].x = -sx; - points[0].y = asc + sy; - points[1].x = adv + sx; - points[1].y = asc + sy; - points[2].x = adv + sx; - points[2].y = -desc - sy; - points[3].x = -sx; - points[3].y = -desc - sy; - - FT_Outline_New(render_priv->ftlibrary, 4, 1, ol); - - ol->n_points = ol->n_contours = 0; - for (i = 0; i < 4; i++) { - ol->points[ol->n_points] = points[i]; - ol->tags[ol->n_points++] = 1; - } - ol->contours[ol->n_contours++] = ol->n_points - 1; -} - -/* - * Stroke an outline glyph in x/y direction. Applies various fixups to get - * around limitations of the FreeType stroker. - */ -static void stroke_outline(ASS_Renderer *render_priv, FT_Outline *outline, - int sx, int sy) -{ - if (sx <= 0 && sy <= 0) - return; - - fix_freetype_stroker(outline, sx, sy); - - // Borders are equal; use the regular stroker - if (sx == sy && render_priv->state.stroker) { - int error; - unsigned n_points, n_contours; - - FT_StrokerBorder border = FT_Outline_GetOutsideBorder(outline); - error = FT_Stroker_ParseOutline(render_priv->state.stroker, outline, 0); - if (error) { - ass_msg(render_priv->library, MSGL_WARN, - "FT_Stroker_ParseOutline failed, error: %d", error); - } - error = FT_Stroker_GetBorderCounts(render_priv->state.stroker, border, - &n_points, &n_contours); - if (error) { - ass_msg(render_priv->library, MSGL_WARN, - "FT_Stroker_GetBorderCounts failed, error: %d", error); - } - FT_Outline_Done(render_priv->ftlibrary, outline); - FT_Outline_New(render_priv->ftlibrary, n_points, n_contours, outline); - outline->n_points = outline->n_contours = 0; - FT_Stroker_ExportBorder(render_priv->state.stroker, border, outline); - - // "Stroke" with the outline emboldener in two passes. - // The outlines look uglier, but the emboldening never adds any points - } else { - int i; - FT_Outline nol; - - FT_Outline_New(render_priv->ftlibrary, outline->n_points, - outline->n_contours, &nol); - FT_Outline_Copy(outline, &nol); - - FT_Outline_Embolden(outline, sx * 2); - FT_Outline_Translate(outline, -sx, -sx); - FT_Outline_Embolden(&nol, sy * 2); - FT_Outline_Translate(&nol, -sy, -sy); - - for (i = 0; i < outline->n_points; i++) - outline->points[i].y = nol.points[i].y; - - FT_Outline_Done(render_priv->ftlibrary, &nol); - } -} - -/** - * \brief Prepare glyph hash - */ -static void -fill_glyph_hash(ASS_Renderer *priv, OutlineHashKey *outline_key, - GlyphInfo *info) -{ - if (info->drawing) { - DrawingHashKey *key = &outline_key->u.drawing; - outline_key->type = OUTLINE_DRAWING; - key->scale_x = double_to_d16(info->scale_x); - key->scale_y = double_to_d16(info->scale_y); - key->outline.x = double_to_d16(info->border_x); - key->outline.y = double_to_d16(info->border_y); - key->border_style = priv->state.style->BorderStyle; - key->hash = info->drawing->hash; - key->text = info->drawing->text; - key->pbo = info->drawing->pbo; - key->scale = info->drawing->scale; - } else { - GlyphHashKey *key = &outline_key->u.glyph; - outline_key->type = OUTLINE_GLYPH; - key->font = info->font; - key->size = info->font_size; - key->face_index = info->face_index; - key->glyph_index = info->glyph_index; - key->bold = info->bold; - key->italic = info->italic; - key->scale_x = double_to_d16(info->scale_x); - key->scale_y = double_to_d16(info->scale_y); - key->outline.x = double_to_d16(info->border_x); - key->outline.y = double_to_d16(info->border_y); - key->flags = info->flags; - key->border_style = priv->state.style->BorderStyle; - } -} - -/** - * \brief Get normal and outline (border) glyphs - * \param info out: struct filled with extracted data - * 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 void -get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info) -{ - OutlineHashValue *val; - OutlineHashKey key; - - memset(&info->hash_key, 0, sizeof(key)); - - fill_glyph_hash(priv, &key, info); - val = ass_cache_get(priv->cache.outline_cache, &key); - - if (!val) { - OutlineHashValue v; - memset(&v, 0, sizeof(v)); - - if (info->drawing) { - ASS_Drawing *drawing = info->drawing; - ass_drawing_hash(drawing); - if(!ass_drawing_parse(drawing, 0)) - return; - outline_copy(priv->ftlibrary, &drawing->outline, - &v.outline); - v.advance.x = drawing->advance.x; - v.advance.y = drawing->advance.y; - v.asc = drawing->asc; - v.desc = drawing->desc; - key.u.drawing.text = strdup(drawing->text); - } else { - FT_Glyph glyph; - ass_face_set_size(info->font->faces[info->face_index], - info->font_size); - ass_font_set_transform(info->font, info->scale_x, - info->scale_y, NULL); - glyph = - ass_font_get_glyph(priv->fontconfig_priv, info->font, - info->symbol, info->face_index, info->glyph_index, - priv->settings.hinting, info->flags); - if (glyph != NULL) { - outline_copy(priv->ftlibrary, - &((FT_OutlineGlyph)glyph)->outline, &v.outline); - if (priv->settings.shaper == ASS_SHAPING_SIMPLE) { - v.advance.x = d16_to_d6(glyph->advance.x); - v.advance.y = d16_to_d6(glyph->advance.y); - } - FT_Done_Glyph(glyph); - ass_font_get_asc_desc(info->font, info->symbol, - &v.asc, &v.desc); - v.asc *= info->scale_y; - v.desc *= info->scale_y; - } - } - - if (!v.outline) - return; - - FT_Outline_Get_CBox(v.outline, &v.bbox_scaled); - - if (priv->state.style->BorderStyle == 3 && - (info->border_x > 0 || info->border_y > 0)) { - FT_Vector advance; - - v.border = calloc(1, sizeof(FT_Outline)); - - if (priv->settings.shaper == ASS_SHAPING_SIMPLE || info->drawing) - advance = v.advance; - else - advance = info->advance; - - draw_opaque_box(priv, v.asc, v.desc, v.border, advance, - double_to_d6(info->border_x * priv->border_scale), - double_to_d6(info->border_y * priv->border_scale)); - - } else if ((info->border_x > 0 || info->border_y > 0) - && double_to_d6(info->scale_x) && double_to_d6(info->scale_y)) { - - outline_copy(priv->ftlibrary, v.outline, &v.border); - stroke_outline(priv, v.border, - double_to_d6(info->border_x * priv->border_scale), - double_to_d6(info->border_y * priv->border_scale)); - } - - v.lib = priv->ftlibrary; - val = ass_cache_put(priv->cache.outline_cache, &key, &v); - } - - info->hash_key.u.outline.outline = val; - info->outline = val->outline; - info->border = val->border; - info->bbox = val->bbox_scaled; - if (info->drawing || priv->settings.shaper == ASS_SHAPING_SIMPLE) { - info->cluster_advance.x = info->advance.x = val->advance.x; - info->cluster_advance.y = info->advance.y = val->advance.y; - } - info->asc = val->asc; - info->desc = val->desc; - - ass_drawing_free(info->drawing); -} - -/** - * \brief Apply transformation to outline points of a glyph - * Applies rotations given by frx, fry and frz and projects the points back - * onto the screen plane. - */ -static void -transform_3d_points(FT_Vector shift, FT_Outline *outline, double frx, double fry, - double frz, double fax, double fay, double scale, - int yshift) -{ - double sx = sin(frx); - double sy = sin(fry); - double sz = sin(frz); - double cx = cos(frx); - double cy = cos(fry); - double cz = cos(frz); - FT_Vector *p = outline->points; - double x, y, z, xx, yy, zz; - int i, dist; - - dist = 20000 * scale; - for (i = 0; i < outline->n_points; i++) { - x = (double) p[i].x + shift.x + (fax * (yshift - p[i].y)); - y = (double) p[i].y + shift.y + (-fay * p[i].x); - z = 0.; - - xx = x * cz + y * sz; - yy = -(x * sz - y * cz); - zz = z; - - x = xx; - y = yy * cx + zz * sx; - z = yy * sx - zz * cx; - - xx = x * cy + z * sy; - yy = y; - zz = x * sy - z * cy; - - zz = FFMAX(zz, 1000 - dist); - - x = (xx * dist) / (zz + dist); - y = (yy * dist) / (zz + dist); - p[i].x = x - shift.x + 0.5; - p[i].y = y - shift.y + 0.5; - } -} - -/** - * \brief Apply 3d transformation to several objects - * \param shift FreeType vector - * \param glyph FreeType glyph - * \param glyph2 FreeType glyph - * \param frx x-axis rotation angle - * \param fry y-axis rotation angle - * \param frz z-axis rotation angle - * Rotates both glyphs by frx, fry and frz. Shift vector is added before rotation and subtracted after it. - */ -static void -transform_3d(FT_Vector shift, FT_Outline *outline, FT_Outline *border, - double frx, double fry, double frz, double fax, double fay, - double scale, int yshift) -{ - frx = -frx; - frz = -frz; - if (frx != 0. || fry != 0. || frz != 0. || fax != 0. || fay != 0.) { - if (outline) - transform_3d_points(shift, outline, frx, fry, frz, - fax, fay, scale, yshift); - - if (border) - transform_3d_points(shift, border, frx, fry, frz, - fax, fay, scale, yshift); - } -} - -/** - * \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(ASS_Renderer *render_priv, GlyphInfo *info) -{ - BitmapHashValue *val; - OutlineBitmapHashKey *key = &info->hash_key.u.outline; - - if (!info->outline || info->symbol == '\n' || info->symbol == 0 || info->skip) - return; - - val = ass_cache_get(render_priv->cache.bitmap_cache, &info->hash_key); - - if (!val) { - FT_Vector shift; - BitmapHashValue hash_val; - int error; - double fax_scaled, fay_scaled; - FT_Outline *outline, *border; - double scale_x = render_priv->font_scale_x; - FT_Matrix m; - - hash_val.bm = hash_val.bm_o = hash_val.bm_s = 0; - - outline_copy(render_priv->ftlibrary, info->outline, &outline); - outline_copy(render_priv->ftlibrary, info->border, &border); - - // calculating rotation shift vector (from rotation origin to the glyph basepoint) - shift.x = key->shift_x; - shift.y = key->shift_y; - fax_scaled = info->fax * render_priv->state.scale_x; - fay_scaled = info->fay * render_priv->state.scale_y; - - // apply rotation - transform_3d(shift, outline, border, - info->frx, info->fry, info->frz, fax_scaled, - fay_scaled, render_priv->font_scale, info->asc); - - // PAR correction scaling - m.xx = double_to_d16(scale_x); - m.xy = 0; - m.yx = 0; - m.yy = double_to_d16(1.0); - - // subpixel shift - if (outline) { - if (scale_x != 1.0) - FT_Outline_Transform(outline, &m); - FT_Outline_Translate(outline, key->advance.x, -key->advance.y); - } - if (border) { - if (scale_x != 1.0) - FT_Outline_Transform(border, &m); - FT_Outline_Translate(border, key->advance.x, -key->advance.y); - } - - // render glyph - error = outline_to_bitmap3(render_priv->library, - render_priv->synth_priv, - render_priv->ftlibrary, - outline, border, - &hash_val.bm, &hash_val.bm_o, - &hash_val.bm_s, info->be, - info->blur * render_priv->border_scale, - key->shadow_offset, - render_priv->state.style->BorderStyle); - if (error) - info->symbol = 0; - - val = ass_cache_put(render_priv->cache.bitmap_cache, &info->hash_key, - &hash_val); - - outline_free(render_priv->ftlibrary, outline); - outline_free(render_priv->ftlibrary, border); - } - - info->bm = val->bm; - info->bm_o = val->bm_o; - info->bm_s = val->bm_s; - - // VSFilter compatibility: invisible fill and no border? - // In this case no shadow is supposed to be rendered. - if (!info->border && (info->c[0] & 0xFF) == 0xFF) - info->bm_s = 0; -} - -/** - * This function goes through text_info and calculates text parameters. - * The following text_info fields are filled: - * height - * lines[].height - * lines[].asc - * lines[].desc - */ -static void measure_text(ASS_Renderer *render_priv) -{ - TextInfo *text_info = &render_priv->text_info; - int cur_line = 0; - double max_asc = 0., max_desc = 0.; - GlyphInfo *last = NULL; - int i; - int empty_line = 1; - text_info->height = 0.; - for (i = 0; i < text_info->length + 1; ++i) { - if ((i == text_info->length) || text_info->glyphs[i].linebreak) { - if (empty_line && cur_line > 0 && last && i < text_info->length) { - max_asc = d6_to_double(last->asc) / 2.0; - max_desc = d6_to_double(last->desc) / 2.0; - } - text_info->lines[cur_line].asc = max_asc; - text_info->lines[cur_line].desc = max_desc; - text_info->height += max_asc + max_desc; - cur_line++; - max_asc = max_desc = 0.; - empty_line = 1; - } else - empty_line = 0; - if (i < text_info->length) { - GlyphInfo *cur = text_info->glyphs + i; - if (d6_to_double(cur->asc) > max_asc) - max_asc = d6_to_double(cur->asc); - if (d6_to_double(cur->desc) > max_desc) - max_desc = d6_to_double(cur->desc); - if (cur->symbol != '\n' && cur->symbol != 0) - last = cur; - } - } - text_info->height += - (text_info->n_lines - - 1) * render_priv->settings.line_spacing; -} - -/** - * Mark extra whitespace for later removal. - */ -#define IS_WHITESPACE(x) ((x->symbol == ' ' || x->symbol == '\n') \ - && !x->linebreak) -static void trim_whitespace(ASS_Renderer *render_priv) -{ - int i, j; - GlyphInfo *cur; - TextInfo *ti = &render_priv->text_info; - - // Mark trailing spaces - i = ti->length - 1; - cur = ti->glyphs + i; - while (i && IS_WHITESPACE(cur)) { - cur->skip++; - cur = ti->glyphs + --i; - } - - // Mark leading whitespace - i = 0; - cur = ti->glyphs; - while (i < ti->length && IS_WHITESPACE(cur)) { - cur->skip++; - cur = ti->glyphs + ++i; - } - - // Mark all extraneous whitespace inbetween - for (i = 0; i < ti->length; ++i) { - cur = ti->glyphs + i; - if (cur->linebreak) { - // Mark whitespace before - j = i - 1; - cur = ti->glyphs + j; - while (j && IS_WHITESPACE(cur)) { - cur->skip++; - cur = ti->glyphs + --j; - } - // A break itself can contain a whitespace, too - cur = ti->glyphs + i; - if (cur->symbol == ' ') { - cur->skip++; - // Mark whitespace after - j = i + 1; - cur = ti->glyphs + j; - while (j < ti->length && IS_WHITESPACE(cur)) { - cur->skip++; - cur = ti->glyphs + ++j; - } - i = j - 1; - } - } - } -} -#undef IS_WHITESPACE - -/** - * \brief rearrange text between lines - * \param max_text_width maximal text line width in pixels - * The algo is similar to the one in libvo/sub.c: - * 1. Place text, wrapping it when current line is full - * 2. Try moving words from the end of a line to the beginning of the next one while it reduces - * the difference in lengths between this two lines. - * The result may not be optimal, but usually is good enough. - * - * FIXME: implement style 0 and 3 correctly - */ -static void -wrap_lines_smart(ASS_Renderer *render_priv, double max_text_width) -{ - int i; - GlyphInfo *cur, *s1, *e1, *s2, *s3, *w; - int last_space; - int break_type; - int exit; - double pen_shift_x; - double pen_shift_y; - int cur_line; - int run_offset; - TextInfo *text_info = &render_priv->text_info; - - last_space = -1; - text_info->n_lines = 1; - break_type = 0; - s1 = text_info->glyphs; // current line start - for (i = 0; i < text_info->length; ++i) { - int break_at = -1; - double s_offset, len; - cur = text_info->glyphs + i; - s_offset = d6_to_double(s1->bbox.xMin + s1->pos.x); - len = d6_to_double(cur->bbox.xMax + cur->pos.x) - s_offset; - - if (cur->symbol == '\n') { - break_type = 2; - break_at = i; - ass_msg(render_priv->library, MSGL_DBG2, - "forced line break at %d", break_at); - } else if (cur->symbol == ' ') { - last_space = i; - } else if (len >= max_text_width - && (render_priv->state.wrap_style != 2)) { - break_type = 1; - break_at = last_space; - if (break_at >= 0) - ass_msg(render_priv->library, MSGL_DBG2, "line break at %d", - break_at); - } - - if (break_at != -1) { - // need to use one more line - // marking break_at+1 as start of a new line - int lead = break_at + 1; // the first symbol of the new line - if (text_info->n_lines >= text_info->max_lines) { - // Raise maximum number of lines - text_info->max_lines *= 2; - text_info->lines = realloc(text_info->lines, - sizeof(LineInfo) * - text_info->max_lines); - } - if (lead < text_info->length) { - text_info->glyphs[lead].linebreak = break_type; - last_space = -1; - s1 = text_info->glyphs + lead; - s_offset = d6_to_double(s1->bbox.xMin + s1->pos.x); - text_info->n_lines++; - } - } - } -#define DIFF(x,y) (((x) < (y)) ? (y - x) : (x - y)) - exit = 0; - while (!exit && render_priv->state.wrap_style != 1) { - exit = 1; - w = s3 = text_info->glyphs; - s1 = s2 = 0; - for (i = 0; i <= text_info->length; ++i) { - cur = text_info->glyphs + i; - if ((i == text_info->length) || cur->linebreak) { - s1 = s2; - s2 = s3; - s3 = cur; - if (s1 && (s2->linebreak == 1)) { // have at least 2 lines, and linebreak is 'soft' - double l1, l2, l1_new, l2_new; - - w = s2; - do { - --w; - } while ((w > s1) && (w->symbol == ' ')); - while ((w > s1) && (w->symbol != ' ')) { - --w; - } - e1 = w; - while ((e1 > s1) && (e1->symbol == ' ')) { - --e1; - } - if (w->symbol == ' ') - ++w; - - l1 = d6_to_double(((s2 - 1)->bbox.xMax + (s2 - 1)->pos.x) - - (s1->bbox.xMin + s1->pos.x)); - l2 = d6_to_double(((s3 - 1)->bbox.xMax + (s3 - 1)->pos.x) - - (s2->bbox.xMin + s2->pos.x)); - l1_new = d6_to_double( - (e1->bbox.xMax + e1->pos.x) - - (s1->bbox.xMin + s1->pos.x)); - l2_new = d6_to_double( - ((s3 - 1)->bbox.xMax + (s3 - 1)->pos.x) - - (w->bbox.xMin + w->pos.x)); - - if (DIFF(l1_new, l2_new) < DIFF(l1, l2)) { - w->linebreak = 1; - s2->linebreak = 0; - exit = 0; - } - } - } - if (i == text_info->length) - break; - } - - } - assert(text_info->n_lines >= 1); -#undef DIFF - - measure_text(render_priv); - trim_whitespace(render_priv); - - pen_shift_x = 0.; - pen_shift_y = 0.; - cur_line = 1; - run_offset = 0; - - i = 0; - cur = text_info->glyphs + i; - while (i < text_info->length && cur->skip) - cur = text_info->glyphs + ++i; - pen_shift_x = d6_to_double(-cur->pos.x); - - for (i = 0; i < text_info->length; ++i) { - cur = text_info->glyphs + i; - if (cur->linebreak) { - double height; - while (i < text_info->length && cur->skip && cur->symbol != '\n') - cur = text_info->glyphs + ++i; - height = - text_info->lines[cur_line - 1].desc + - text_info->lines[cur_line].asc; - text_info->lines[cur_line - 1].len = i - - text_info->lines[cur_line - 1].offset; - text_info->lines[cur_line].offset = i; - cur_line++; - run_offset++; - pen_shift_x = d6_to_double(-cur->pos.x); - pen_shift_y += height + render_priv->settings.line_spacing; - ass_msg(render_priv->library, MSGL_DBG2, - "shifting from %d to %d by (%f, %f)", i, - text_info->length - 1, pen_shift_x, pen_shift_y); - } - cur->bm_run_id += run_offset; - cur->pos.x += double_to_d6(pen_shift_x); - cur->pos.y += double_to_d6(pen_shift_y); - } - text_info->lines[cur_line - 1].len = - text_info->length - text_info->lines[cur_line - 1].offset; - -#if 0 - // print line info - for (i = 0; i < text_info->n_lines; i++) { - printf("line %d offset %d length %d\n", i, text_info->lines[i].offset, - text_info->lines[i].len); - } -#endif -} - -/** - * \brief Calculate base point for positioning and rotation - * \param bbox text bbox - * \param alignment alignment - * \param bx, by out: base point coordinates - */ -static void get_base_point(DBBox *bbox, int alignment, double *bx, double *by) -{ - const int halign = alignment & 3; - const int valign = alignment & 12; - if (bx) - switch (halign) { - case HALIGN_LEFT: - *bx = bbox->xMin; - break; - case HALIGN_CENTER: - *bx = (bbox->xMax + bbox->xMin) / 2.0; - break; - case HALIGN_RIGHT: - *bx = bbox->xMax; - break; - } - if (by) - switch (valign) { - case VALIGN_TOP: - *by = bbox->yMin; - break; - case VALIGN_CENTER: - *by = (bbox->yMax + bbox->yMin) / 2.0; - break; - case VALIGN_SUB: - *by = bbox->yMax; - break; - } -} - -/** - * Prepare bitmap hash key of a glyph - */ -static void -fill_bitmap_hash(ASS_Renderer *priv, GlyphInfo *info, - OutlineBitmapHashKey *hash_key) -{ - hash_key->frx = rot_key(info->frx); - hash_key->fry = rot_key(info->fry); - hash_key->frz = rot_key(info->frz); - hash_key->fax = double_to_d16(info->fax); - hash_key->fay = double_to_d16(info->fay); - hash_key->be = info->be; - hash_key->blur = info->blur; - hash_key->shadow_offset.x = double_to_d6( - info->shadow_x * priv->border_scale - - (int) (info->shadow_x * priv->border_scale)); - hash_key->shadow_offset.y = double_to_d6( - info->shadow_y * priv->border_scale - - (int) (info->shadow_y * priv->border_scale)); -} - -/** - * \brief Main ass rendering function, glues everything together - * \param event event to render - * \param event_images struct containing resulting images, will also be initialized - * Process event, appending resulting ASS_Image's to images_root. - */ -static int -ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, - EventImages *event_images) -{ - char *p; - FT_UInt previous; - FT_UInt num_glyphs; - FT_Vector pen; - unsigned code; - DBBox bbox; - int i, j; - int MarginL, MarginR, MarginV; - int last_break; - int alignment, halign, valign; - double device_x = 0; - double device_y = 0; - TextInfo *text_info = &render_priv->text_info; - GlyphInfo *glyphs = render_priv->text_info.glyphs; - ASS_Drawing *drawing; - double max_text_width = 0; - FriBidiStrIndex *cmap = NULL; - int lineno = 1; - int left = 0; - - if (event->Style >= render_priv->track->n_styles) { - ass_msg(render_priv->library, MSGL_WARN, "No style found"); - return 1; - } - if (!event->Text) { - ass_msg(render_priv->library, MSGL_WARN, "Empty event"); - return 1; - } - - init_render_context(render_priv, event); - - drawing = render_priv->state.drawing; - text_info->length = 0; - num_glyphs = 0; - p = event->Text; - - // Event parsing. - while (1) { - // get next char, executing style override - // this affects render_context - do { - code = get_next_char(render_priv, &p); - if (render_priv->state.drawing_mode && code) - ass_drawing_add_char(drawing, (char) code); - } while (code && render_priv->state.drawing_mode); // skip everything in drawing mode - - if (text_info->length >= text_info->max_glyphs) { - // Raise maximum number of glyphs - text_info->max_glyphs *= 2; - text_info->glyphs = glyphs = - realloc(text_info->glyphs, - sizeof(GlyphInfo) * text_info->max_glyphs); - } - - // Clear current GlyphInfo - memset(&glyphs[text_info->length], 0, sizeof(GlyphInfo)); - - // Parse drawing - if (drawing->i) { - drawing->scale_x = render_priv->state.scale_x * - render_priv->font_scale; - drawing->scale_y = render_priv->state.scale_y * - render_priv->font_scale; - p--; - code = 0xfffc; // object replacement character - glyphs[text_info->length].drawing = drawing; - } - - // face could have been changed in get_next_char - if (!render_priv->state.font) { - free_render_context(render_priv); - return 1; - } - - if (code == 0) - break; - - // Fill glyph information - glyphs[text_info->length].symbol = code; - glyphs[text_info->length].font = render_priv->state.font; - for (i = 0; i < 4; ++i) { - uint32_t clr = render_priv->state.c[i]; - change_alpha(&clr, - mult_alpha(_a(clr), render_priv->state.fade), 1.); - glyphs[text_info->length].c[i] = clr; - } - glyphs[text_info->length].effect_type = render_priv->state.effect_type; - glyphs[text_info->length].effect_timing = - render_priv->state.effect_timing; - glyphs[text_info->length].effect_skip_timing = - render_priv->state.effect_skip_timing; - glyphs[text_info->length].font_size = ensure_font_size(render_priv, - render_priv->state.font_size * render_priv->font_scale); - glyphs[text_info->length].be = render_priv->state.be; - glyphs[text_info->length].blur = render_priv->state.blur; - glyphs[text_info->length].shadow_x = render_priv->state.shadow_x; - glyphs[text_info->length].shadow_y = render_priv->state.shadow_y; - glyphs[text_info->length].scale_x= render_priv->state.scale_x; - glyphs[text_info->length].scale_y = render_priv->state.scale_y; - glyphs[text_info->length].border_x= render_priv->state.border_x; - glyphs[text_info->length].border_y = render_priv->state.border_y; - glyphs[text_info->length].bold = render_priv->state.bold; - glyphs[text_info->length].italic = render_priv->state.italic; - glyphs[text_info->length].flags = render_priv->state.flags; - glyphs[text_info->length].frx = render_priv->state.frx; - glyphs[text_info->length].fry = render_priv->state.fry; - glyphs[text_info->length].frz = render_priv->state.frz; - glyphs[text_info->length].fax = render_priv->state.fax; - glyphs[text_info->length].fay = render_priv->state.fay; - glyphs[text_info->length].bm_run_id = render_priv->state.bm_run_id; - - if (glyphs[text_info->length].drawing) { - drawing = render_priv->state.drawing = - ass_drawing_new(render_priv->library, render_priv->ftlibrary); - } - - text_info->length++; - - render_priv->state.effect_type = EF_NONE; - render_priv->state.effect_timing = 0; - render_priv->state.effect_skip_timing = 0; - - } - - if (text_info->length == 0) { - // no valid symbols in the event; this can be smth like {comment} - free_render_context(render_priv); - return 1; - } - - // Find shape runs and shape text - ass_shaper_set_base_direction(render_priv->shaper, - resolve_base_direction(render_priv->state.font_encoding)); - ass_shaper_find_runs(render_priv->shaper, render_priv, glyphs, - text_info->length); - ass_shaper_shape(render_priv->shaper, text_info); - - // Retrieve glyphs - for (i = 0; i < text_info->length; i++) { - GlyphInfo *info = glyphs + i; - while (info) { - get_outline_glyph(render_priv, info); - info = info->next; - } - info = glyphs + i; - - // Add additional space after italic to non-italic style changes - if (i && glyphs[i - 1].italic && !info->italic) { - int back = i - 1; - GlyphInfo *og = &glyphs[back]; - while (back && og->bbox.xMax - og->bbox.xMin == 0 - && og->italic) - og = &glyphs[--back]; - if (og->bbox.xMax > og->cluster_advance.x) - og->cluster_advance.x = og->bbox.xMax; - } - - // add horizontal letter spacing - info->cluster_advance.x += double_to_d6(render_priv->state.hspacing * - render_priv->font_scale * info->scale_x); - - // add displacement for vertical shearing - info->cluster_advance.y += (info->fay * info->scale_y) * info->cluster_advance.x; - - } - - // Preliminary layout (for line wrapping) - previous = 0; - pen.x = 0; - pen.y = 0; - for (i = 0; i < text_info->length; i++) { - GlyphInfo *info = glyphs + i; - FT_Vector cluster_pen = pen; - while (info) { - info->pos.x = cluster_pen.x; - info->pos.y = cluster_pen.y; - - cluster_pen.x += info->advance.x; - cluster_pen.y += info->advance.y; - - // fill bitmap hash - info->hash_key.type = BITMAP_OUTLINE; - fill_bitmap_hash(render_priv, info, &info->hash_key.u.outline); - - info = info->next; - } - info = glyphs + i; - pen.x += info->cluster_advance.x; - pen.y += info->cluster_advance.y; - previous = info->symbol; - } - - - // depends on glyph x coordinates being monotonous, so it should be done before line wrap - process_karaoke_effects(render_priv); - - // alignments - alignment = render_priv->state.alignment; - halign = alignment & 3; - valign = alignment & 12; - - MarginL = - (event->MarginL) ? event->MarginL : render_priv->state.style->MarginL; - MarginR = - (event->MarginR) ? event->MarginR : render_priv->state.style->MarginR; - MarginV = - (event->MarginV) ? event->MarginV : render_priv->state.style->MarginV; - - // calculate max length of a line - max_text_width = - x2scr(render_priv, render_priv->track->PlayResX - MarginR) - - x2scr(render_priv, MarginL); - - // wrap lines - if (render_priv->state.evt_type != EVENT_HSCROLL) { - // rearrange text in several lines - wrap_lines_smart(render_priv, max_text_width); - } else { - // no breaking or wrapping, everything in a single line - text_info->lines[0].offset = 0; - text_info->lines[0].len = text_info->length; - text_info->n_lines = 1; - measure_text(render_priv); - } - - // Reorder text into visual order - cmap = ass_shaper_reorder(render_priv->shaper, text_info); - - // Reposition according to the map - pen.x = 0; - pen.y = 0; - for (i = 0; i < text_info->length; i++) { - GlyphInfo *info = glyphs + cmap[i]; - FT_Vector cluster_pen; - if (glyphs[i].linebreak) { - pen.x = 0; - pen.y += double_to_d6(text_info->lines[lineno-1].desc); - pen.y += double_to_d6(text_info->lines[lineno].asc); - pen.y += double_to_d6(render_priv->settings.line_spacing); - lineno++; - } - if (info->skip) continue; - cluster_pen = pen; - while (info) { - info->pos.x = info->offset.x + cluster_pen.x; - info->pos.y = info->offset.y + cluster_pen.y; - cluster_pen.x += info->advance.x; - cluster_pen.y += info->advance.y; - info = info->next; - } - info = glyphs + cmap[i]; - pen.x += info->cluster_advance.x; - pen.y += info->cluster_advance.y; - } - - // align lines - if (render_priv->state.evt_type != EVENT_HSCROLL) { - double width = 0; - last_break = -1; - for (i = 0; i <= text_info->length; ++i) { // (text_info->length + 1) is the end of the last line - if ((i == text_info->length) || glyphs[i].linebreak) { - double shift = 0; - // remove letter spacing (which is included in cluster_advance) - if (i > 0) - width -= render_priv->state.hspacing * render_priv->font_scale * - glyphs[i-1].scale_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 - shift = (max_text_width - width) / 2.0; - } - for (j = last_break + 1; j < i; ++j) { - GlyphInfo *info = glyphs + j; - while (info) { - info->pos.x += double_to_d6(shift); - info = info->next; - } - } - last_break = i - 1; - width = 0; - } - if (i < text_info->length && !glyphs[i].skip && - glyphs[i].symbol != '\n' && glyphs[i].symbol != 0) { - width += d6_to_double(glyphs[i].cluster_advance.x); - } - } - } - - // determing text bounding box - compute_string_bbox(text_info, &bbox); - - // determine device coordinates for text - - // x coordinate for everything except positioned events - if (render_priv->state.evt_type == EVENT_NORMAL || - render_priv->state.evt_type == EVENT_VSCROLL) { - device_x = x2scr(render_priv, MarginL); - } else if (render_priv->state.evt_type == EVENT_HSCROLL) { - if (render_priv->state.scroll_direction == SCROLL_RL) - device_x = - x2scr(render_priv, - render_priv->track->PlayResX - - render_priv->state.scroll_shift); - else if (render_priv->state.scroll_direction == SCROLL_LR) - device_x = - x2scr(render_priv, - render_priv->state.scroll_shift) - (bbox.xMax - - bbox.xMin); - } - - // y coordinate for everything except positioned events - if (render_priv->state.evt_type == EVENT_NORMAL || - render_priv->state.evt_type == EVENT_HSCROLL) { - if (valign == VALIGN_TOP) { // toptitle - device_y = - y2scr_top(render_priv, - MarginV) + text_info->lines[0].asc; - } else if (valign == VALIGN_CENTER) { // midtitle - double scr_y = - y2scr(render_priv, render_priv->track->PlayResY / 2.0); - device_y = scr_y - (bbox.yMax + bbox.yMin) / 2.0; - } else { // subtitle - double scr_y; - if (valign != VALIGN_SUB) - ass_msg(render_priv->library, MSGL_V, - "Invalid valign, assuming 0 (subtitle)"); - scr_y = - y2scr_sub(render_priv, - render_priv->track->PlayResY - MarginV); - device_y = scr_y; - device_y -= text_info->height; - device_y += text_info->lines[0].asc; - } - } else if (render_priv->state.evt_type == EVENT_VSCROLL) { - if (render_priv->state.scroll_direction == SCROLL_TB) - device_y = - y2scr(render_priv, - render_priv->state.clip_y0 + - render_priv->state.scroll_shift) - (bbox.yMax - - bbox.yMin); - else if (render_priv->state.scroll_direction == SCROLL_BT) - device_y = - y2scr(render_priv, - render_priv->state.clip_y1 - - render_priv->state.scroll_shift); - } - - // positioned events are totally different - if (render_priv->state.evt_type == EVENT_POSITIONED) { - double base_x = 0; - double base_y = 0; - ass_msg(render_priv->library, MSGL_DBG2, "positioned event at %f, %f", - render_priv->state.pos_x, render_priv->state.pos_y); - get_base_point(&bbox, alignment, &base_x, &base_y); - device_x = - x2scr_pos(render_priv, render_priv->state.pos_x) - base_x; - device_y = - y2scr_pos(render_priv, render_priv->state.pos_y) - base_y; - } - - // fix clip coordinates (they depend on alignment) - if (render_priv->state.evt_type == EVENT_NORMAL || - render_priv->state.evt_type == EVENT_HSCROLL || - render_priv->state.evt_type == EVENT_VSCROLL) { - render_priv->state.clip_x0 = - x2scr_scaled(render_priv, render_priv->state.clip_x0); - render_priv->state.clip_x1 = - x2scr_scaled(render_priv, render_priv->state.clip_x1); - if (valign == VALIGN_TOP) { - render_priv->state.clip_y0 = - y2scr_top(render_priv, render_priv->state.clip_y0); - render_priv->state.clip_y1 = - y2scr_top(render_priv, render_priv->state.clip_y1); - } else if (valign == VALIGN_CENTER) { - render_priv->state.clip_y0 = - y2scr(render_priv, render_priv->state.clip_y0); - render_priv->state.clip_y1 = - y2scr(render_priv, render_priv->state.clip_y1); - } else if (valign == VALIGN_SUB) { - render_priv->state.clip_y0 = - y2scr_sub(render_priv, render_priv->state.clip_y0); - render_priv->state.clip_y1 = - y2scr_sub(render_priv, render_priv->state.clip_y1); - } - } else if (render_priv->state.evt_type == EVENT_POSITIONED) { - render_priv->state.clip_x0 = - x2scr_pos_scaled(render_priv, render_priv->state.clip_x0); - render_priv->state.clip_x1 = - x2scr_pos_scaled(render_priv, render_priv->state.clip_x1); - render_priv->state.clip_y0 = - y2scr_pos(render_priv, render_priv->state.clip_y0); - render_priv->state.clip_y1 = - y2scr_pos(render_priv, render_priv->state.clip_y1); - } - - // calculate rotation parameters - { - DVector center; - - if (render_priv->state.have_origin) { - center.x = x2scr(render_priv, render_priv->state.org_x); - center.y = y2scr(render_priv, render_priv->state.org_y); - } else { - double bx = 0., by = 0.; - get_base_point(&bbox, alignment, &bx, &by); - center.x = device_x + bx; - center.y = device_y + by; - } - - for (i = 0; i < text_info->length; ++i) { - GlyphInfo *info = glyphs + i; - while (info) { - OutlineBitmapHashKey *key = &info->hash_key.u.outline; - - if (key->frx || key->fry || key->frz || key->fax || key->fay) { - key->shift_x = info->pos.x + double_to_d6(device_x - center.x); - key->shift_y = -(info->pos.y + double_to_d6(device_y - center.y)); - } else { - key->shift_x = 0; - key->shift_y = 0; - } - info = info->next; - } - } - } - - // convert glyphs to bitmaps - left = render_priv->settings.left_margin; - device_x = (device_x - left) * render_priv->font_scale_x + left; - for (i = 0; i < text_info->length; ++i) { - GlyphInfo *info = glyphs + i; - while (info) { - OutlineBitmapHashKey *key = &info->hash_key.u.outline; - info->pos.x *= render_priv->font_scale_x; - key->advance.x = - double_to_d6(device_x - (int) device_x + - d6_to_double(info->pos.x & SUBPIXEL_MASK)) & ~SUBPIXEL_ACCURACY; - key->advance.y = - double_to_d6(device_y - (int) device_y + - d6_to_double(info->pos.y & SUBPIXEL_MASK)) & ~SUBPIXEL_ACCURACY; - get_bitmap_glyph(render_priv, info); - info = info->next; - } - } - - memset(event_images, 0, sizeof(*event_images)); - event_images->top = device_y - text_info->lines[0].asc; - event_images->height = text_info->height; - event_images->left = - (device_x + bbox.xMin * render_priv->font_scale_x) + 0.5; - event_images->width = - (bbox.xMax - bbox.xMin) * render_priv->font_scale_x + 0.5; - event_images->detect_collisions = render_priv->state.detect_collisions; - event_images->shift_direction = (valign == VALIGN_TOP) ? 1 : -1; - event_images->event = event; - event_images->imgs = render_text(render_priv, (int) device_x, (int) device_y); - - ass_shaper_cleanup(render_priv->shaper, text_info); - free_render_context(render_priv); - - return 0; -} - -/** - * \brief deallocate image list - * \param img list pointer - */ -void ass_free_images(ASS_Image *img) -{ - while (img) { - ASS_Image *next = img->next; - free(img); - img = next; - } -} - -/** - * \brief Check cache limits and reset cache if they are exceeded - */ -static void check_cache_limits(ASS_Renderer *priv, CacheStore *cache) -{ - if (ass_cache_empty(cache->bitmap_cache, cache->bitmap_max_size)) { - ass_cache_empty(cache->composite_cache, 0); - ass_free_images(priv->prev_images_root); - priv->prev_images_root = 0; - } - if (ass_cache_empty(cache->outline_cache, cache->glyph_max)) { - ass_cache_empty(cache->bitmap_cache, 0); - ass_cache_empty(cache->composite_cache, 0); - ass_free_images(priv->prev_images_root); - priv->prev_images_root = 0; - } -} - -/** - * \brief Start a new frame - */ -static int -ass_start_frame(ASS_Renderer *render_priv, ASS_Track *track, - long long now) -{ - ASS_Settings *settings_priv = &render_priv->settings; - - if (!render_priv->settings.frame_width - && !render_priv->settings.frame_height) - return 1; // library not initialized - - if (render_priv->library != track->library) - return 1; - - if (!render_priv->fontconfig_priv) - return 1; - - free_list_clear(render_priv); - - if (track->n_events == 0) - return 1; // nothing to do - - render_priv->track = track; - render_priv->time = now; - - ass_lazy_track_init(render_priv->library, render_priv->track); - - render_priv->font_scale = settings_priv->font_size_coeff * - render_priv->orig_height / render_priv->track->PlayResY; - if (render_priv->track->ScaledBorderAndShadow) - render_priv->border_scale = - ((double) render_priv->orig_height) / - render_priv->track->PlayResY; - else - render_priv->border_scale = 1.; - - ass_shaper_set_kerning(render_priv->shaper, track->Kerning); - if (track->Language) - ass_shaper_set_language(render_priv->shaper, track->Language); - ass_shaper_set_level(render_priv->shaper, render_priv->settings.shaper); - - // PAR correction - render_priv->font_scale_x = render_priv->settings.aspect / - render_priv->settings.storage_aspect; - - render_priv->prev_images_root = render_priv->images_root; - render_priv->images_root = 0; - - check_cache_limits(render_priv, &render_priv->cache); - - return 0; -} - -static int cmp_event_layer(const void *p1, const void *p2) -{ - ASS_Event *e1 = ((EventImages *) p1)->event; - ASS_Event *e2 = ((EventImages *) p2)->event; - if (e1->Layer < e2->Layer) - return -1; - if (e1->Layer > e2->Layer) - return 1; - if (e1->ReadOrder < e2->ReadOrder) - return -1; - if (e1->ReadOrder > e2->ReadOrder) - return 1; - return 0; -} - -static ASS_RenderPriv *get_render_priv(ASS_Renderer *render_priv, - ASS_Event *event) -{ - if (!event->render_priv) - event->render_priv = calloc(1, sizeof(ASS_RenderPriv)); - if (render_priv->render_id != event->render_priv->render_id) { - memset(event->render_priv, 0, sizeof(ASS_RenderPriv)); - event->render_priv->render_id = render_priv->render_id; - } - - return event->render_priv; -} - -static int overlap(Segment *s1, Segment *s2) -{ - if (s1->a >= s2->b || s2->a >= s1->b || - s1->ha >= s2->hb || s2->ha >= s1->hb) - return 0; - return 1; -} - -static int cmp_segment(const void *p1, const void *p2) -{ - return ((Segment *) p1)->a - ((Segment *) p2)->a; -} - -static void -shift_event(ASS_Renderer *render_priv, EventImages *ei, int shift) -{ - ASS_Image *cur = ei->imgs; - while (cur) { - cur->dst_y += shift; - // clip top and bottom - if (cur->dst_y < 0) { - int clip = -cur->dst_y; - cur->h -= clip; - cur->bitmap += clip * cur->stride; - cur->dst_y = 0; - } - if (cur->dst_y + cur->h >= render_priv->height) { - int clip = cur->dst_y + cur->h - render_priv->height; - cur->h -= clip; - } - if (cur->h <= 0) { - cur->h = 0; - cur->dst_y = 0; - } - cur = cur->next; - } - ei->top += shift; -} - -// dir: 1 - move down -// -1 - move up -static int fit_segment(Segment *s, Segment *fixed, int *cnt, int dir) -{ - int i; - int shift = 0; - - if (dir == 1) // move down - for (i = 0; i < *cnt; ++i) { - if (s->b + shift <= fixed[i].a || s->a + shift >= fixed[i].b || - s->hb <= fixed[i].ha || s->ha >= fixed[i].hb) - continue; - shift = fixed[i].b - s->a; - } else // dir == -1, move up - for (i = *cnt - 1; i >= 0; --i) { - if (s->b + shift <= fixed[i].a || s->a + shift >= fixed[i].b || - s->hb <= fixed[i].ha || s->ha >= fixed[i].hb) - continue; - shift = fixed[i].a - s->b; - } - - fixed[*cnt].a = s->a + shift; - fixed[*cnt].b = s->b + shift; - fixed[*cnt].ha = s->ha; - fixed[*cnt].hb = s->hb; - (*cnt)++; - qsort(fixed, *cnt, sizeof(Segment), cmp_segment); - - return shift; -} - -static void -fix_collisions(ASS_Renderer *render_priv, EventImages *imgs, int cnt) -{ - Segment *used = malloc(cnt * sizeof(*used)); - int cnt_used = 0; - int i, j; - - // fill used[] with fixed events - for (i = 0; i < cnt; ++i) { - ASS_RenderPriv *priv; - if (!imgs[i].detect_collisions) - continue; - priv = get_render_priv(render_priv, imgs[i].event); - if (priv->height > 0) { // it's a fixed event - Segment s; - s.a = priv->top; - s.b = priv->top + priv->height; - s.ha = priv->left; - s.hb = priv->left + priv->width; - if (priv->height != imgs[i].height) { // no, it's not - ass_msg(render_priv->library, MSGL_WARN, - "Event height has changed"); - priv->top = 0; - priv->height = 0; - priv->left = 0; - priv->width = 0; - } - for (j = 0; j < cnt_used; ++j) - if (overlap(&s, used + j)) { // no, it's not - priv->top = 0; - priv->height = 0; - priv->left = 0; - priv->width = 0; - } - if (priv->height > 0) { // still a fixed event - used[cnt_used].a = priv->top; - used[cnt_used].b = priv->top + priv->height; - used[cnt_used].ha = priv->left; - used[cnt_used].hb = priv->left + priv->width; - cnt_used++; - shift_event(render_priv, imgs + i, priv->top - imgs[i].top); - } - } - } - qsort(used, cnt_used, sizeof(Segment), cmp_segment); - - // try to fit other events in free spaces - for (i = 0; i < cnt; ++i) { - ASS_RenderPriv *priv; - if (!imgs[i].detect_collisions) - continue; - priv = get_render_priv(render_priv, imgs[i].event); - if (priv->height == 0) { // not a fixed event - int shift; - Segment s; - s.a = imgs[i].top; - s.b = imgs[i].top + imgs[i].height; - s.ha = imgs[i].left; - s.hb = imgs[i].left + imgs[i].width; - shift = fit_segment(&s, used, &cnt_used, imgs[i].shift_direction); - if (shift) - shift_event(render_priv, imgs + i, shift); - // make it fixed - priv->top = imgs[i].top; - priv->height = imgs[i].height; - priv->left = imgs[i].left; - priv->width = imgs[i].width; - } - - } - - free(used); -} - -/** - * \brief compare two images - * \param i1 first image - * \param i2 second image - * \return 0 if identical, 1 if different positions, 2 if different content - */ -static int ass_image_compare(ASS_Image *i1, ASS_Image *i2) -{ - if (i1->w != i2->w) - return 2; - if (i1->h != i2->h) - return 2; - if (i1->stride != i2->stride) - return 2; - if (i1->color != i2->color) - return 2; - if (i1->bitmap != i2->bitmap) - return 2; - if (i1->dst_x != i2->dst_x) - return 1; - if (i1->dst_y != i2->dst_y) - return 1; - return 0; -} - -/** - * \brief compare current and previous image list - * \param priv library handle - * \return 0 if identical, 1 if different positions, 2 if different content - */ -static int ass_detect_change(ASS_Renderer *priv) -{ - ASS_Image *img, *img2; - int diff; - - img = priv->prev_images_root; - img2 = priv->images_root; - diff = 0; - while (img && diff < 2) { - ASS_Image *next, *next2; - next = img->next; - if (img2) { - int d = ass_image_compare(img, img2); - if (d > diff) - diff = d; - next2 = img2->next; - } else { - // previous list is shorter - diff = 2; - break; - } - img = next; - img2 = next2; - } - - // is the previous list longer? - if (img2) - diff = 2; - - return diff; -} - -/** - * \brief render a frame - * \param priv library handle - * \param track track - * \param now current video timestamp (ms) - * \param detect_change a value describing how the new images differ from the previous ones will be written here: - * 0 if identical, 1 if different positions, 2 if different content. - * Can be NULL, in that case no detection is performed. - */ -ASS_Image *ass_render_frame(ASS_Renderer *priv, ASS_Track *track, - long long now, int *detect_change) -{ - int i, cnt, rc; - EventImages *last; - ASS_Image **tail; - - // init frame - rc = ass_start_frame(priv, track, now); - if (rc != 0) - return 0; - - // render events separately - cnt = 0; - for (i = 0; i < track->n_events; ++i) { - ASS_Event *event = track->events + i; - if ((event->Start <= now) - && (now < (event->Start + event->Duration))) { - if (cnt >= priv->eimg_size) { - priv->eimg_size += 100; - priv->eimg = - realloc(priv->eimg, - priv->eimg_size * sizeof(EventImages)); - } - rc = ass_render_event(priv, event, priv->eimg + cnt); - if (!rc) - ++cnt; - } - } - - // sort by layer - qsort(priv->eimg, cnt, sizeof(EventImages), cmp_event_layer); - - // call fix_collisions for each group of events with the same layer - last = priv->eimg; - for (i = 1; i < cnt; ++i) - if (last->event->Layer != priv->eimg[i].event->Layer) { - fix_collisions(priv, last, priv->eimg + i - last); - last = priv->eimg + i; - } - if (cnt > 0) - fix_collisions(priv, last, priv->eimg + cnt - last); - - // concat lists - tail = &priv->images_root; - for (i = 0; i < cnt; ++i) { - ASS_Image *cur = priv->eimg[i].imgs; - while (cur) { - *tail = cur; - tail = &cur->next; - cur = cur->next; - } - } - - if (detect_change) - *detect_change = ass_detect_change(priv); - - // free the previous image list - ass_free_images(priv->prev_images_root); - priv->prev_images_root = 0; - - return priv->images_root; -} diff --git a/lib/libass/libass/ass_render.h b/lib/libass/libass/ass_render.h deleted file mode 100644 index d3c1bbbfc3..0000000000 --- a/lib/libass/libass/ass_render.h +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef LIBASS_RENDER_H -#define LIBASS_RENDER_H - -#include <inttypes.h> -#include <ft2build.h> -#include FT_FREETYPE_H -#include FT_STROKER_H -#include FT_GLYPH_H -#include FT_SYNTHESIS_H - -// XXX: fix the inclusion mess so we can avoid doing this here -typedef struct ass_shaper ASS_Shaper; - -#include "ass.h" -#include "ass_font.h" -#include "ass_bitmap.h" -#include "ass_cache.h" -#include "ass_utils.h" -#include "ass_fontconfig.h" -#include "ass_library.h" -#include "ass_drawing.h" - -#define GLYPH_CACHE_MAX 1000 -#define BITMAP_CACHE_MAX_SIZE 30 * 1048576 - -#define PARSED_FADE (1<<0) -#define PARSED_A (1<<1) - -typedef struct { - double xMin; - double xMax; - double yMin; - double yMax; -} DBBox; - -typedef struct { - double x; - double y; -} DVector; - -typedef struct free_list { - void *object; - struct free_list *next; -} FreeList; - -typedef struct { - int frame_width; - int frame_height; - double font_size_coeff; // font size multiplier - double line_spacing; // additional line spacing (in frame pixels) - int top_margin; // height of top margin. Everything except toptitles is shifted down by top_margin. - int bottom_margin; // height of bottom margin. (frame_height - top_margin - bottom_margin) is original video height. - int left_margin; - int right_margin; - 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. - double storage_aspect; // pixel ratio of the source image - ASS_Hinting hinting; - ASS_ShapingLevel shaper; - - char *default_font; - char *default_family; -} ASS_Settings; - -// a rendered event -typedef struct { - ASS_Image *imgs; - int top, height, left, width; - int detect_collisions; - int shift_direction; - ASS_Event *event; -} EventImages; - -typedef enum { - EF_NONE = 0, - EF_KARAOKE, - EF_KARAOKE_KF, - EF_KARAOKE_KO -} Effect; - -// describes a glyph -// GlyphInfo and TextInfo are used for text centering and word-wrapping operations -typedef struct glyph_info { - unsigned symbol; - unsigned skip; // skip glyph when layouting text - ASS_Font *font; - int face_index; - int glyph_index; - double font_size; - ASS_Drawing *drawing; - FT_Outline *outline; - FT_Outline *border; - Bitmap *bm; // glyph bitmap - Bitmap *bm_o; // outline bitmap - Bitmap *bm_s; // shadow bitmap - FT_BBox bbox; - FT_Vector pos; - FT_Vector offset; - char linebreak; // the first (leading) glyph of some line ? - uint32_t c[4]; // colors - FT_Vector advance; // 26.6 - FT_Vector cluster_advance; - Effect effect_type; - int effect_timing; // time duration of current karaoke word - // after process_karaoke_effects: distance in pixels from the glyph origin. - // part of the glyph to the left of it is displayed in a different color. - int effect_skip_timing; // delay after the end of last karaoke word - int asc, desc; // font max ascender and descender - int be; // blur edges - double blur; // gaussian blur - double shadow_x; - double shadow_y; - double frx, fry, frz; // rotation - double fax, fay; // text shearing - double scale_x, scale_y; - double border_x, border_y; - unsigned italic; - unsigned bold; - int flags; - - int bm_run_id; - int shape_run_id; - - BitmapHashKey hash_key; - - // next glyph in this cluster - struct glyph_info *next; -} GlyphInfo; - -typedef struct { - double asc, desc; - int offset, len; -} LineInfo; - -typedef struct { - GlyphInfo *glyphs; - int length; - LineInfo *lines; - int n_lines; - double height; - int max_glyphs; - int max_lines; -} TextInfo; - -// Renderer state. -// Values like current font face, color, screen position, clipping and so on are stored here. -typedef struct { - ASS_Event *event; - ASS_Style *style; - int parsed_tags; - - ASS_Font *font; - double font_size; - int flags; // decoration flags (underline/strike-through) - - FT_Stroker stroker; - int alignment; // alignment overrides go here; if zero, style value will be used - double frx, fry, frz; - double fax, fay; // text shearing - enum { - EVENT_NORMAL, // "normal" top-, sub- or mid- title - EVENT_POSITIONED, // happens after pos(,), margins are ignored - EVENT_HSCROLL, // "Banner" transition effect, text_width is unlimited - EVENT_VSCROLL // "Scroll up", "Scroll down" transition effects - } evt_type; - double pos_x, pos_y; // position - double org_x, org_y; // origin - char have_origin; // origin is explicitly defined; if 0, get_base_point() is used - double scale_x, scale_y; - double hspacing; // distance between letters, in pixels - double border_x; // outline width - double border_y; - uint32_t c[4]; // colors(Primary, Secondary, so on) in RGBA - int clip_x0, clip_y0, clip_x1, clip_y1; - char clip_mode; // 1 = iclip - char detect_collisions; - uint32_t fade; // alpha from \fad - char be; // blur edges - double blur; // gaussian blur - double shadow_x; - double shadow_y; - int drawing_mode; // not implemented; when != 0 text is discarded, except for style override tags - ASS_Drawing *drawing; // current drawing - ASS_Drawing *clip_drawing; // clip vector - int clip_drawing_mode; // 0 = regular clip, 1 = inverse clip - - Effect effect_type; - int effect_timing; - int effect_skip_timing; - - // bitmap run id (used for final bitmap rendering) - int bm_run_id; - - enum { - SCROLL_LR, // left-to-right - SCROLL_RL, - SCROLL_TB, // top-to-bottom - SCROLL_BT - } scroll_direction; // for EVENT_HSCROLL, EVENT_VSCROLL - int scroll_shift; - - // face properties - char *family; - unsigned bold; - unsigned italic; - int treat_family_as_pattern; - int wrap_style; - int font_encoding; -} RenderContext; - -typedef struct { - Cache *font_cache; - Cache *outline_cache; - Cache *bitmap_cache; - Cache *composite_cache; - size_t glyph_max; - size_t bitmap_max_size; -} CacheStore; - -struct ass_renderer { - ASS_Library *library; - FT_Library ftlibrary; - FCInstance *fontconfig_priv; - ASS_Settings settings; - int render_id; - ASS_SynthPriv *synth_priv; - ASS_Shaper *shaper; - - ASS_Image *images_root; // rendering result is stored here - ASS_Image *prev_images_root; - - EventImages *eimg; // temporary buffer for sorting rendered events - int eimg_size; // allocated buffer size - - // frame-global data - int width, height; // screen dimensions - int orig_height; // frame height ( = screen height - margins ) - int orig_width; // frame width ( = screen width - margins ) - int orig_height_nocrop; // frame height ( = screen height - margins + cropheight) - int orig_width_nocrop; // frame width ( = screen width - margins + cropwidth) - ASS_Track *track; - long long time; // frame's timestamp, ms - double font_scale; - double font_scale_x; // x scale applied to all glyphs to preserve text aspect ratio - double border_scale; - - RenderContext state; - TextInfo text_info; - CacheStore cache; - - FreeList *free_head; - FreeList *free_tail; -}; - -typedef struct render_priv { - int top, height, left, width; - int render_id; -} RenderPriv; - -typedef struct { - int x0; - int y0; - int x1; - int y1; -} Rect; - -typedef struct { - int a, b; // top and height - int ha, hb; // left and width -} Segment; - -void reset_render_context(ASS_Renderer *render_priv); -void ass_free_images(ASS_Image *img); - -// XXX: this is actually in ass.c, includes should be fixed later on -void ass_lazy_track_init(ASS_Library *lib, ASS_Track *track); - -#endif /* LIBASS_RENDER_H */ diff --git a/lib/libass/libass/ass_render_api.c b/lib/libass/libass/ass_render_api.c deleted file mode 100644 index 8bf9e5db6f..0000000000 --- a/lib/libass/libass/ass_render_api.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * Copyright (C) 2010 Grigori Goronzy <greg@geekmind.org> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "config.h" -#include "ass_render.h" - -static void ass_reconfigure(ASS_Renderer *priv) -{ - ASS_Settings *settings = &priv->settings; - - priv->render_id++; - ass_cache_empty(priv->cache.outline_cache, 0); - ass_cache_empty(priv->cache.bitmap_cache, 0); - ass_cache_empty(priv->cache.composite_cache, 0); - ass_free_images(priv->prev_images_root); - priv->prev_images_root = 0; - - priv->width = settings->frame_width; - priv->height = settings->frame_height; - priv->orig_width = settings->frame_width - settings->left_margin - - settings->right_margin; - priv->orig_height = settings->frame_height - settings->top_margin - - settings->bottom_margin; - priv->orig_width_nocrop = - settings->frame_width - FFMAX(settings->left_margin, 0) - - FFMAX(settings->right_margin, 0); - priv->orig_height_nocrop = - settings->frame_height - FFMAX(settings->top_margin, 0) - - FFMAX(settings->bottom_margin, 0); -} - -void ass_set_frame_size(ASS_Renderer *priv, int w, int h) -{ - if (priv->settings.frame_width != w || priv->settings.frame_height != h) { - priv->settings.frame_width = w; - priv->settings.frame_height = h; - if (priv->settings.aspect == 0.) { - priv->settings.aspect = ((double) w) / h; - priv->settings.storage_aspect = ((double) w) / h; - } - ass_reconfigure(priv); - } -} - -void ass_set_shaper(ASS_Renderer *priv, ASS_ShapingLevel level) -{ -#ifdef CONFIG_HARFBUZZ - // select the complex shaper for illegal values - if (level == ASS_SHAPING_SIMPLE || level == ASS_SHAPING_COMPLEX) - priv->settings.shaper = level; - else - priv->settings.shaper = ASS_SHAPING_COMPLEX; -#endif -} - -void ass_set_margins(ASS_Renderer *priv, int t, int b, int l, int r) -{ - if (priv->settings.left_margin != l || priv->settings.right_margin != r || - priv->settings.top_margin != t || priv->settings.bottom_margin != b) { - priv->settings.left_margin = l; - priv->settings.right_margin = r; - priv->settings.top_margin = t; - priv->settings.bottom_margin = b; - ass_reconfigure(priv); - } -} - -void ass_set_use_margins(ASS_Renderer *priv, int use) -{ - priv->settings.use_margins = use; -} - -void ass_set_aspect_ratio(ASS_Renderer *priv, double dar, double sar) -{ - if (priv->settings.aspect != dar || priv->settings.storage_aspect != sar) { - priv->settings.aspect = dar; - priv->settings.storage_aspect = sar; - ass_reconfigure(priv); - } -} - -void ass_set_font_scale(ASS_Renderer *priv, double font_scale) -{ - if (priv->settings.font_size_coeff != font_scale) { - priv->settings.font_size_coeff = font_scale; - ass_reconfigure(priv); - } -} - -void ass_set_hinting(ASS_Renderer *priv, ASS_Hinting ht) -{ - if (priv->settings.hinting != ht) { - priv->settings.hinting = ht; - ass_reconfigure(priv); - } -} - -void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing) -{ - priv->settings.line_spacing = line_spacing; -} - -void ass_set_fonts(ASS_Renderer *priv, const char *default_font, - const char *default_family, int fc, const char *config, - int update) -{ - free(priv->settings.default_font); - free(priv->settings.default_family); - priv->settings.default_font = default_font ? strdup(default_font) : 0; - priv->settings.default_family = - default_family ? strdup(default_family) : 0; - - if (priv->fontconfig_priv) - fontconfig_done(priv->fontconfig_priv); - priv->fontconfig_priv = - fontconfig_init(priv->library, priv->ftlibrary, default_family, - default_font, fc, config, update); -} - -int ass_fonts_update(ASS_Renderer *render_priv) -{ - return fontconfig_update(render_priv->fontconfig_priv); -} - -void ass_set_cache_limits(ASS_Renderer *render_priv, int glyph_max, - int bitmap_max) -{ - render_priv->cache.glyph_max = glyph_max ? glyph_max : GLYPH_CACHE_MAX; - render_priv->cache.bitmap_max_size = bitmap_max ? 1048576 * bitmap_max : - BITMAP_CACHE_MAX_SIZE; -} diff --git a/lib/libass/libass/ass_shaper.c b/lib/libass/libass/ass_shaper.c deleted file mode 100644 index 6adfc78f92..0000000000 --- a/lib/libass/libass/ass_shaper.c +++ /dev/null @@ -1,733 +0,0 @@ -/* - * Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "config.h" - -#include <fribidi/fribidi.h> - -#include "ass_shaper.h" -#include "ass_render.h" -#include "ass_font.h" -#include "ass_parse.h" -#include "ass_cache.h" - -#define MAX_RUNS 50 - -#ifdef CONFIG_HARFBUZZ -#include <hb-ft.h> -enum { - VERT = 0, - VKNA, - KERN -}; -#define NUM_FEATURES 3 -#endif - -struct ass_shaper { - ASS_ShapingLevel shaping_level; - - // FriBidi log2vis - int n_glyphs; - FriBidiChar *event_text; - FriBidiCharType *ctypes; - FriBidiLevel *emblevels; - FriBidiStrIndex *cmap; - FriBidiParType base_direction; - -#ifdef CONFIG_HARFBUZZ - // OpenType features - int n_features; - hb_feature_t *features; - hb_language_t language; - - // Glyph metrics cache, to speed up shaping - Cache *metrics_cache; -#endif -}; - -#ifdef CONFIG_HARFBUZZ -struct ass_shaper_metrics_data { - Cache *metrics_cache; - GlyphMetricsHashKey hash_key; - int vertical; -}; - -struct ass_shaper_font_data { - hb_font_t *fonts[ASS_FONT_MAX_FACES]; - hb_font_funcs_t *font_funcs[ASS_FONT_MAX_FACES]; - struct ass_shaper_metrics_data *metrics_data[ASS_FONT_MAX_FACES]; -}; -#endif - -/** - * \brief Print version information - */ -void ass_shaper_info(ASS_Library *lib) -{ - ass_msg(lib, MSGL_V, "Shaper: FriBidi " - FRIBIDI_VERSION " (SIMPLE)" -#ifdef CONFIG_HARFBUZZ - " HarfBuzz-ng %s (COMPLEX)", hb_version_string() -#endif - ); -} - -/** - * \brief grow arrays, if needed - * \param new_size requested size - */ -static void check_allocations(ASS_Shaper *shaper, size_t new_size) -{ - if (new_size > shaper->n_glyphs) { - shaper->event_text = realloc(shaper->event_text, sizeof(FriBidiChar) * new_size); - shaper->ctypes = realloc(shaper->ctypes, sizeof(FriBidiCharType) * new_size); - shaper->emblevels = realloc(shaper->emblevels, sizeof(FriBidiLevel) * new_size); - shaper->cmap = realloc(shaper->cmap, sizeof(FriBidiStrIndex) * new_size); - } -} - -/** - * \brief Free shaper and related data - */ -void ass_shaper_free(ASS_Shaper *shaper) -{ -#ifdef CONFIG_HARFBUZZ - ass_cache_done(shaper->metrics_cache); - free(shaper->features); -#endif - free(shaper->event_text); - free(shaper->ctypes); - free(shaper->emblevels); - free(shaper->cmap); - free(shaper); -} - -void ass_shaper_font_data_free(ASS_ShaperFontData *priv) -{ -#ifdef CONFIG_HARFBUZZ - int i; - for (i = 0; i < ASS_FONT_MAX_FACES; i++) - if (priv->fonts[i]) { - free(priv->metrics_data[i]); - hb_font_destroy(priv->fonts[i]); - hb_font_funcs_destroy(priv->font_funcs[i]); - } - free(priv); -#endif -} - -#ifdef CONFIG_HARFBUZZ -/** - * \brief set up the HarfBuzz OpenType feature list with some - * standard features. - */ -static void init_features(ASS_Shaper *shaper) -{ - shaper->features = calloc(sizeof(hb_feature_t), NUM_FEATURES); - - shaper->n_features = NUM_FEATURES; - shaper->features[VERT].tag = HB_TAG('v', 'e', 'r', 't'); - shaper->features[VERT].end = INT_MAX; - shaper->features[VKNA].tag = HB_TAG('v', 'k', 'n', 'a'); - shaper->features[VKNA].end = INT_MAX; - shaper->features[KERN].tag = HB_TAG('k', 'e', 'r', 'n'); - shaper->features[KERN].end = INT_MAX; -} - -/** - * \brief Set features depending on properties of the run - */ -static void set_run_features(ASS_Shaper *shaper, GlyphInfo *info) -{ - // enable vertical substitutions for @font runs - if (info->font->desc.vertical) - shaper->features[VERT].value = shaper->features[VKNA].value = 1; - else - shaper->features[VERT].value = shaper->features[VKNA].value = 0; -} - -/** - * \brief Update HarfBuzz's idea of font metrics - * \param hb_font HarfBuzz font - * \param face associated FreeType font face - */ -static void update_hb_size(hb_font_t *hb_font, FT_Face face) -{ - hb_font_set_scale (hb_font, - ((uint64_t) face->size->metrics.x_scale * (uint64_t) face->units_per_EM) >> 16, - ((uint64_t) face->size->metrics.y_scale * (uint64_t) face->units_per_EM) >> 16); - hb_font_set_ppem (hb_font, face->size->metrics.x_ppem, - face->size->metrics.y_ppem); -} - - -/* - * Cached glyph metrics getters follow - * - * These functions replace HarfBuzz' standard FreeType font functions - * and provide cached access to essential glyph metrics. This usually - * speeds up shaping a lot. It also allows us to use custom load flags. - * - */ - -GlyphMetricsHashValue * -get_cached_metrics(struct ass_shaper_metrics_data *metrics, FT_Face face, - hb_codepoint_t glyph) -{ - GlyphMetricsHashValue *val; - - metrics->hash_key.glyph_index = glyph; - val = ass_cache_get(metrics->metrics_cache, &metrics->hash_key); - - if (!val) { - int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH - | FT_LOAD_IGNORE_TRANSFORM; - GlyphMetricsHashValue new_val; - - if (FT_Load_Glyph(face, glyph, load_flags)) - return NULL; - - memcpy(&new_val.metrics, &face->glyph->metrics, sizeof(FT_Glyph_Metrics)); - val = ass_cache_put(metrics->metrics_cache, &metrics->hash_key, &new_val); - } - - return val; -} - -static hb_bool_t -get_glyph(hb_font_t *font, void *font_data, hb_codepoint_t unicode, - hb_codepoint_t variation, hb_codepoint_t *glyph, void *user_data) -{ - FT_Face face = font_data; - - if (variation) - *glyph = FT_Face_GetCharVariantIndex(face, unicode, variation); - else - *glyph = FT_Get_Char_Index(face, unicode); - - return *glyph != 0; -} - -static hb_position_t -cached_h_advance(hb_font_t *font, void *font_data, hb_codepoint_t glyph, - void *user_data) -{ - FT_Face face = font_data; - struct ass_shaper_metrics_data *metrics_priv = user_data; - GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, glyph); - - if (!metrics) - return 0; - - if (metrics_priv->vertical && glyph > VERTICAL_LOWER_BOUND) - return metrics->metrics.vertAdvance; - - return metrics->metrics.horiAdvance; -} - -static hb_position_t -cached_v_advance(hb_font_t *font, void *font_data, hb_codepoint_t glyph, - void *user_data) -{ - FT_Face face = font_data; - struct ass_shaper_metrics_data *metrics_priv = user_data; - GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, glyph); - - if (!metrics) - return 0; - - return metrics->metrics.vertAdvance; - -} - -static hb_bool_t -cached_h_origin(hb_font_t *font, void *font_data, hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y, void *user_data) -{ - return 1; -} - -static hb_bool_t -cached_v_origin(hb_font_t *font, void *font_data, hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y, void *user_data) -{ - FT_Face face = font_data; - struct ass_shaper_metrics_data *metrics_priv = user_data; - GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, glyph); - - if (!metrics) - return 0; - - *x = metrics->metrics.horiBearingX - metrics->metrics.vertBearingX; - *y = metrics->metrics.horiBearingY - (-metrics->metrics.vertBearingY); - - return 1; -} - -static hb_position_t -get_h_kerning(hb_font_t *font, void *font_data, hb_codepoint_t first, - hb_codepoint_t second, void *user_data) -{ - FT_Face face = font_data; - FT_Vector kern; - - if (FT_Get_Kerning (face, first, second, FT_KERNING_DEFAULT, &kern)) - return 0; - - return kern.x; -} - -static hb_position_t -get_v_kerning(hb_font_t *font, void *font_data, hb_codepoint_t first, - hb_codepoint_t second, void *user_data) -{ - return 0; -} - -static hb_bool_t -cached_extents(hb_font_t *font, void *font_data, hb_codepoint_t glyph, - hb_glyph_extents_t *extents, void *user_data) -{ - FT_Face face = font_data; - struct ass_shaper_metrics_data *metrics_priv = user_data; - GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, glyph); - - if (!metrics) - return 0; - - extents->x_bearing = metrics->metrics.horiBearingX; - extents->y_bearing = metrics->metrics.horiBearingY; - extents->width = metrics->metrics.width; - extents->height = metrics->metrics.height; - - return 1; -} - -static hb_bool_t -get_contour_point(hb_font_t *font, void *font_data, hb_codepoint_t glyph, - unsigned int point_index, hb_position_t *x, - hb_position_t *y, void *user_data) -{ - FT_Face face = font_data; - int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH - | FT_LOAD_IGNORE_TRANSFORM; - - if (FT_Load_Glyph(face, glyph, load_flags)) - return 0; - - if (point_index >= (unsigned)face->glyph->outline.n_points) - return 0; - - *x = face->glyph->outline.points[point_index].x; - *y = face->glyph->outline.points[point_index].y; - - return 1; -} - -/** - * \brief Retrieve HarfBuzz font from cache. - * Create it from FreeType font, if needed. - * \param info glyph cluster - * \return HarfBuzz font - */ -static hb_font_t *get_hb_font(ASS_Shaper *shaper, GlyphInfo *info) -{ - ASS_Font *font = info->font; - hb_font_t **hb_fonts; - struct ass_shaper_metrics_data *metrics; - hb_font_funcs_t *funcs; - - if (!font->shaper_priv) - font->shaper_priv = (ASS_ShaperFontData *) calloc(sizeof(ASS_ShaperFontData), 1); - - - hb_fonts = font->shaper_priv->fonts; - if (!hb_fonts[info->face_index]) { - hb_fonts[info->face_index] = - hb_ft_font_create(font->faces[info->face_index], NULL); - - // set up cached metrics access - font->shaper_priv->metrics_data[info->face_index] = (struct ass_shaper_metrics_data *) - calloc(sizeof(struct ass_shaper_metrics_data), 1); - metrics = font->shaper_priv->metrics_data[info->face_index]; - metrics->metrics_cache = shaper->metrics_cache; - metrics->vertical = info->font->desc.vertical; - - funcs = hb_font_funcs_create(); - font->shaper_priv->font_funcs[info->face_index] = funcs; - hb_font_funcs_set_glyph_func(funcs, get_glyph, - metrics, NULL); - hb_font_funcs_set_glyph_h_advance_func(funcs, cached_h_advance, - metrics, NULL); - hb_font_funcs_set_glyph_v_advance_func(funcs, cached_v_advance, - metrics, NULL); - hb_font_funcs_set_glyph_h_origin_func(funcs, cached_h_origin, - metrics, NULL); - hb_font_funcs_set_glyph_v_origin_func(funcs, cached_v_origin, - metrics, NULL); - hb_font_funcs_set_glyph_h_kerning_func(funcs, get_h_kerning, - metrics, NULL); - hb_font_funcs_set_glyph_v_kerning_func(funcs, get_v_kerning, - metrics, NULL); - hb_font_funcs_set_glyph_extents_func(funcs, cached_extents, - metrics, NULL); - hb_font_funcs_set_glyph_contour_point_func(funcs, get_contour_point, - metrics, NULL); - hb_font_set_funcs(hb_fonts[info->face_index], funcs, - font->faces[info->face_index], NULL); - } - - ass_face_set_size(font->faces[info->face_index], info->font_size); - update_hb_size(hb_fonts[info->face_index], font->faces[info->face_index]); - - // update hash key for cached metrics - metrics = font->shaper_priv->metrics_data[info->face_index]; - metrics->hash_key.font = info->font; - metrics->hash_key.face_index = info->face_index; - metrics->hash_key.size = info->font_size; - metrics->hash_key.scale_x = double_to_d6(info->scale_x); - metrics->hash_key.scale_y = double_to_d6(info->scale_y); - - return hb_fonts[info->face_index]; -} - -/** - * \brief Shape event text with HarfBuzz. Full OpenType shaping. - * \param glyphs glyph clusters - * \param len number of clusters - */ -static void shape_harfbuzz(ASS_Shaper *shaper, GlyphInfo *glyphs, size_t len) -{ - int i, j; - int run = 0; - struct { - int offset; - int end; - hb_buffer_t *buf; - hb_font_t *font; - } runs[MAX_RUNS]; - - - for (i = 0; i < len && run < MAX_RUNS; i++, run++) { - // get length and level of the current run - int k = i; - int level = glyphs[i].shape_run_id; - int direction = shaper->emblevels[k] % 2; - while (i < (len - 1) && level == glyphs[i+1].shape_run_id) - i++; - runs[run].offset = k; - runs[run].end = i; - runs[run].buf = hb_buffer_create(); - runs[run].font = get_hb_font(shaper, glyphs + k); - set_run_features(shaper, glyphs + k); - hb_buffer_pre_allocate(runs[run].buf, i - k + 1); - hb_buffer_set_direction(runs[run].buf, direction ? HB_DIRECTION_RTL : - HB_DIRECTION_LTR); - hb_buffer_set_language(runs[run].buf, shaper->language); - hb_buffer_add_utf32(runs[run].buf, shaper->event_text + k, i - k + 1, - 0, i - k + 1); - hb_shape(runs[run].font, runs[run].buf, shaper->features, - shaper->n_features); - } - - // Initialize: skip all glyphs, this is undone later as needed - for (i = 0; i < len; i++) - glyphs[i].skip = 1; - - // Update glyph indexes, positions and advances from the shaped runs - for (i = 0; i < run; i++) { - int num_glyphs = hb_buffer_get_length(runs[i].buf); - hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(runs[i].buf, NULL); - hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(runs[i].buf, NULL); - - for (j = 0; j < num_glyphs; j++) { - int idx = glyph_info[j].cluster + runs[i].offset; - GlyphInfo *info = glyphs + idx; - GlyphInfo *root = info; - - // if we have more than one glyph per cluster, allocate a new one - // and attach to the root glyph - if (info->skip == 0) { - while (info->next) - info = info->next; - info->next = malloc(sizeof(GlyphInfo)); - memcpy(info->next, info, sizeof(GlyphInfo)); - info = info->next; - info->next = NULL; - } - - // set position and advance - info->skip = 0; - info->glyph_index = glyph_info[j].codepoint; - info->offset.x = pos[j].x_offset * info->scale_x; - info->offset.y = -pos[j].y_offset * info->scale_y; - info->advance.x = pos[j].x_advance * info->scale_x; - info->advance.y = -pos[j].y_advance * info->scale_y; - - // accumulate advance in the root glyph - root->cluster_advance.x += info->advance.x; - root->cluster_advance.y += info->advance.y; - } - } - - // Free runs and associated data - for (i = 0; i < run; i++) { - hb_buffer_destroy(runs[i].buf); - } - -} -#endif - -/** - * \brief Shape event text with FriBidi. Does mirroring and simple - * Arabic shaping. - * \param len number of clusters - */ -static void shape_fribidi(ASS_Shaper *shaper, GlyphInfo *glyphs, size_t len) -{ - int i; - FriBidiJoiningType *joins = calloc(sizeof(*joins), len); - - // shape on codepoint level - fribidi_get_joining_types(shaper->event_text, len, joins); - fribidi_join_arabic(shaper->ctypes, len, shaper->emblevels, joins); - fribidi_shape(FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC, - shaper->emblevels, len, joins, shaper->event_text); - - // update indexes - for (i = 0; i < len; i++) { - GlyphInfo *info = glyphs + i; - FT_Face face = info->font->faces[info->face_index]; - info->symbol = shaper->event_text[i]; - info->glyph_index = FT_Get_Char_Index(face, shaper->event_text[i]); - } - - free(joins); -} - -/** - * \brief Toggle kerning for HarfBuzz shaping. - * NOTE: currently only works with OpenType fonts, the TrueType fallback *always* - * kerns. It's a bug in HarfBuzz. - */ -void ass_shaper_set_kerning(ASS_Shaper *shaper, int kern) -{ -#ifdef CONFIG_HARFBUZZ - shaper->features[KERN].value = !!kern; -#endif -} - -/** - * \brief Find shape runs according to the event's selected fonts - */ -void ass_shaper_find_runs(ASS_Shaper *shaper, ASS_Renderer *render_priv, - GlyphInfo *glyphs, size_t len) -{ - int i; - int shape_run = 0; - - for (i = 0; i < len; i++) { - GlyphInfo *last = glyphs + i - 1; - GlyphInfo *info = glyphs + i; - // skip drawings - if (info->symbol == 0xfffc) - continue; - // set size and get glyph index - ass_font_get_index(render_priv->fontconfig_priv, info->font, - info->symbol, &info->face_index, &info->glyph_index); - // shape runs share the same font face and size - if (i > 0 && (last->font != info->font || - last->font_size != info->font_size || - last->face_index != info->face_index)) - shape_run++; - info->shape_run_id = shape_run; - } - -} - -/** - * \brief Set base direction (paragraph direction) of the text. - * \param dir base direction - */ -void ass_shaper_set_base_direction(ASS_Shaper *shaper, FriBidiParType dir) -{ - shaper->base_direction = dir; -} - -/** - * \brief Set language hint. Some languages have specific character variants, - * like Serbian Cyrillic. - * \param lang ISO 639-1 two-letter language code - */ -void ass_shaper_set_language(ASS_Shaper *shaper, const char *code) -{ -#ifdef CONFIG_HARFBUZZ - shaper->language = hb_language_from_string(code, -1); -#endif -} - -/** - * Set shaping level. Essentially switches between FriBidi and HarfBuzz. - */ -void ass_shaper_set_level(ASS_Shaper *shaper, ASS_ShapingLevel level) -{ - shaper->shaping_level = level; -} - -/** - * \brief Shape an event's text. Calculates directional runs and shapes them. - * \param text_info event's text - */ -void ass_shaper_shape(ASS_Shaper *shaper, TextInfo *text_info) -{ - int i, last_break; - FriBidiParType dir; - GlyphInfo *glyphs = text_info->glyphs; - - check_allocations(shaper, text_info->length); - - // Get bidi character types and embedding levels - last_break = 0; - for (i = 0; i < text_info->length; i++) { - shaper->event_text[i] = glyphs[i].symbol; - // embedding levels should be calculated paragraph by paragraph - if (glyphs[i].symbol == '\n' || i == text_info->length - 1) { - dir = shaper->base_direction; - fribidi_get_bidi_types(shaper->event_text + last_break, - i - last_break + 1, shaper->ctypes + last_break); - fribidi_get_par_embedding_levels(shaper->ctypes + last_break, - i - last_break + 1, &dir, shaper->emblevels + last_break); - last_break = i + 1; - } - } - - // add embedding levels to shape runs for final runs - for (i = 0; i < text_info->length; i++) { - glyphs[i].shape_run_id += shaper->emblevels[i]; - } - -#ifdef CONFIG_HARFBUZZ - switch (shaper->shaping_level) { - case ASS_SHAPING_SIMPLE: - shape_fribidi(shaper, glyphs, text_info->length); - break; - case ASS_SHAPING_COMPLEX: - shape_harfbuzz(shaper, glyphs, text_info->length); - break; - } -#else - shape_fribidi(shaper, glyphs, text_info->length); -#endif - - - // clean up - for (i = 0; i < text_info->length; i++) { - // Skip direction override control characters - // NOTE: Behdad said HarfBuzz is supposed to remove these, but this hasn't - // been implemented yet - if (glyphs[i].symbol <= 0x202F && glyphs[i].symbol >= 0x202a) { - glyphs[i].symbol = 0; - glyphs[i].skip++; - } - } -} - -/** - * \brief Create a new shaper instance and preallocate data structures - * \param prealloc preallocation size - */ -ASS_Shaper *ass_shaper_new(size_t prealloc) -{ - ASS_Shaper *shaper = calloc(sizeof(*shaper), 1); - - shaper->base_direction = FRIBIDI_PAR_ON; - check_allocations(shaper, prealloc); - -#ifdef CONFIG_HARFBUZZ - init_features(shaper); - shaper->metrics_cache = ass_glyph_metrics_cache_create(); -#endif - - return shaper; -} - - -/** - * \brief clean up additional data temporarily needed for shaping and - * (e.g. additional glyphs allocated) - */ -void ass_shaper_cleanup(ASS_Shaper *shaper, TextInfo *text_info) -{ - int i; - - for (i = 0; i < text_info->length; i++) { - GlyphInfo *info = text_info->glyphs + i; - info = info->next; - while (info) { - GlyphInfo *next = info->next; - free(info); - info = next; - } - } -} - -/** - * \brief Calculate reorder map to render glyphs in visual order - */ -FriBidiStrIndex *ass_shaper_reorder(ASS_Shaper *shaper, TextInfo *text_info) -{ - int i; - - // Initialize reorder map - for (i = 0; i < text_info->length; i++) - shaper->cmap[i] = i; - - // Create reorder map line-by-line - for (i = 0; i < text_info->n_lines; i++) { - LineInfo *line = text_info->lines + i; - int level; - FriBidiParType dir = FRIBIDI_PAR_ON; - - level = fribidi_reorder_line(0, - shaper->ctypes + line->offset, line->len, 0, dir, - shaper->emblevels + line->offset, NULL, - shaper->cmap + line->offset); - } - - return shaper->cmap; -} - -/** - * \brief Resolve a Windows font encoding number to a suitable - * base direction. 177 and 178 are Hebrew and Arabic respectively, and - * they map to RTL. 1 is autodetection and is mapped to just that. - * Everything else is mapped to LTR. - * \param enc Windows font encoding - */ -FriBidiParType resolve_base_direction(int enc) -{ - switch (enc) { - case 1: - return FRIBIDI_PAR_ON; - case 177: - case 178: - return FRIBIDI_PAR_RTL; - default: - return FRIBIDI_PAR_LTR; - } -} diff --git a/lib/libass/libass/ass_shaper.h b/lib/libass/libass/ass_shaper.h deleted file mode 100644 index 81499dde8e..0000000000 --- a/lib/libass/libass/ass_shaper.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef LIBASS_SHAPER_H -#define LIBASS_SHAPER_H - -#include "config.h" - -#include <fribidi/fribidi.h> -#include "ass_render.h" - -void ass_shaper_info(ASS_Library *lib); -ASS_Shaper *ass_shaper_new(size_t prealloc); -void ass_shaper_free(ASS_Shaper *shaper); -void ass_shaper_set_kerning(ASS_Shaper *shaper, int kern); -void ass_shaper_find_runs(ASS_Shaper *shaper, ASS_Renderer *render_priv, - GlyphInfo *glyphs, size_t len); -void ass_shaper_set_base_direction(ASS_Shaper *shaper, FriBidiParType dir); -void ass_shaper_set_language(ASS_Shaper *shaper, const char *code); -void ass_shaper_set_level(ASS_Shaper *shaper, ASS_ShapingLevel level); -void ass_shaper_shape(ASS_Shaper *shaper, TextInfo *text_info); -void ass_shaper_cleanup(ASS_Shaper *shaper, TextInfo *text_info); -FriBidiStrIndex *ass_shaper_reorder(ASS_Shaper *shaper, TextInfo *text_info); -FriBidiParType resolve_base_direction(int font_encoding); - -void ass_shaper_font_data_free(ASS_ShaperFontData *priv); - -#endif diff --git a/lib/libass/libass/ass_strtod.c b/lib/libass/libass/ass_strtod.c deleted file mode 100644 index f55b37ae12..0000000000 --- a/lib/libass/libass/ass_strtod.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (c) 1988-1993 The Regents of the University of California. - * Copyright (c) 1994 Sun Microsystems, Inc. - * - * Permission to use, copy, modify, and distribute this - * software and its documentation for any purpose and without - * fee is hereby granted, provided that the above copyright - * notice appear in all copies. The University of California - * makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without - * express or implied warranty. - * - */ - -#include <stdlib.h> -#include <ctype.h> -#include <errno.h> - -const -static int maxExponent = 511; /* Largest possible base 10 exponent. Any - * exponent larger than this will already - * produce underflow or overflow, so there's - * no need to worry about additional digits. - */ - -const -static double powersOf10[] = { /* Table giving binary powers of 10. Entry */ - 10., /* is 10^2^i. Used to convert decimal */ - 100., /* exponents into floating-point numbers. */ - 1.0e4, - 1.0e8, - 1.0e16, - 1.0e32, - 1.0e64, - 1.0e128, - 1.0e256 -}; - -/* - *---------------------------------------------------------------------- - * - * strtod -- - * - * This procedure converts a floating-point number from an ASCII - * decimal representation to internal double-precision format. - * - * Results: - * The return value is the double-precision floating-point - * representation of the characters in string. If endPtr isn't - * NULL, then *endPtr is filled in with the address of the - * next character after the last one that was part of the - * floating-point number. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -double -ass_strtod(string, endPtr) - const char *string; /* A decimal ASCII floating-point number, - * optionally preceded by white space. - * Must have form "-I.FE-X", where I is the - * integer part of the mantissa, F is the - * fractional part of the mantissa, and X - * is the exponent. Either of the signs - * may be "+", "-", or omitted. Either I - * or F may be omitted, or both. The decimal - * point isn't necessary unless F is present. - * The "E" may actually be an "e". E and X - * may both be omitted (but not just one). - */ - char **endPtr; /* If non-NULL, store terminating character's - * address here. */ -{ - int sign, expSign = 0; - double fraction, dblExp, *d; - register const char *p; - register int c; - int exp = 0; /* Exponent read from "EX" field. */ - int fracExp = 0; /* Exponent that derives from the fractional - * part. Under normal circumstatnces, it is - * the negative of the number of digits in F. - * However, if I is very long, the last digits - * of I get dropped (otherwise a long I with a - * large negative exponent could cause an - * unnecessary overflow on I alone). In this - * case, fracExp is incremented one for each - * dropped digit. */ - int mantSize; /* Number of digits in mantissa. */ - int decPt; /* Number of mantissa digits BEFORE decimal - * point. */ - const char *pExp; /* Temporarily holds location of exponent - * in string. */ - - /* - * Strip off leading blanks and check for a sign. - */ - - p = string; - while (isspace(*p)) { - p += 1; - } - if (*p == '-') { - sign = 1; - p += 1; - } else { - if (*p == '+') { - p += 1; - } - sign = 0; - } - - /* - * Count the number of digits in the mantissa (including the decimal - * point), and also locate the decimal point. - */ - - decPt = -1; - for (mantSize = 0; ; mantSize += 1) - { - c = *p; - if (!isdigit(c)) { - if ((c != '.') || (decPt >= 0)) { - break; - } - decPt = mantSize; - } - p += 1; - } - - /* - * Now suck up the digits in the mantissa. Use two integers to - * collect 9 digits each (this is faster than using floating-point). - * If the mantissa has more than 18 digits, ignore the extras, since - * they can't affect the value anyway. - */ - - pExp = p; - p -= mantSize; - if (decPt < 0) { - decPt = mantSize; - } else { - mantSize -= 1; /* One of the digits was the point. */ - } - if (mantSize > 18) { - fracExp = decPt - 18; - mantSize = 18; - } else { - fracExp = decPt - mantSize; - } - if (mantSize == 0) { - fraction = 0.0; - p = string; - goto done; - } else { - int frac1, frac2; - frac1 = 0; - for ( ; mantSize > 9; mantSize -= 1) - { - c = *p; - p += 1; - if (c == '.') { - c = *p; - p += 1; - } - frac1 = 10*frac1 + (c - '0'); - } - frac2 = 0; - for (; mantSize > 0; mantSize -= 1) - { - c = *p; - p += 1; - if (c == '.') { - c = *p; - p += 1; - } - frac2 = 10*frac2 + (c - '0'); - } - fraction = (1.0e9 * frac1) + frac2; - } - - /* - * Skim off the exponent. - */ - - p = pExp; - if ((*p == 'E') || (*p == 'e')) { - p += 1; - if (*p == '-') { - expSign = 1; - p += 1; - } else { - if (*p == '+') { - p += 1; - } - expSign = 0; - } - while (isdigit(*p)) { - exp = exp * 10 + (*p - '0'); - p += 1; - } - } - if (expSign) { - exp = fracExp - exp; - } else { - exp = fracExp + exp; - } - - /* - * Generate a floating-point number that represents the exponent. - * Do this by processing the exponent one bit at a time to combine - * many powers of 2 of 10. Then combine the exponent with the - * fraction. - */ - - if (exp < 0) { - expSign = 1; - exp = -exp; - } else { - expSign = 0; - } - if (exp > maxExponent) { - exp = maxExponent; - errno = ERANGE; - } - dblExp = 1.0; - for (d = (double *) powersOf10; exp != 0; exp >>= 1, d += 1) { - if (exp & 01) { - dblExp *= *d; - } - } - if (expSign) { - fraction /= dblExp; - } else { - fraction *= dblExp; - } - -done: - if (endPtr != NULL) { - *endPtr = (char *) p; - } - - if (sign) { - return -fraction; - } - return fraction; -} diff --git a/lib/libass/libass/ass_types.h b/lib/libass/libass/ass_types.h deleted file mode 100644 index 20fd825ef1..0000000000 --- a/lib/libass/libass/ass_types.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef LIBASS_TYPES_H -#define LIBASS_TYPES_H - -#include <stdint.h> - -#define VALIGN_SUB 0 -#define VALIGN_CENTER 8 -#define VALIGN_TOP 4 -#define HALIGN_LEFT 1 -#define HALIGN_CENTER 2 -#define HALIGN_RIGHT 3 - -/* Opaque objects internally used by libass. Contents are private. */ -typedef struct ass_renderer ASS_Renderer; -typedef struct render_priv ASS_RenderPriv; -typedef struct parser_priv ASS_ParserPriv; -typedef struct ass_library ASS_Library; - -/* ASS Style: line */ -typedef struct ass_style { - char *Name; - char *FontName; - double FontSize; - uint32_t PrimaryColour; - uint32_t SecondaryColour; - uint32_t OutlineColour; - uint32_t BackColour; - int Bold; - int Italic; - int Underline; - int StrikeOut; - double ScaleX; - double ScaleY; - double Spacing; - int Angle; - int BorderStyle; - double Outline; - double Shadow; - int Alignment; - int MarginL; - int MarginR; - int MarginV; - int Encoding; - int treat_fontname_as_pattern; -} ASS_Style; - -/* - * ASS_Event corresponds to a single Dialogue line; - * text is stored as-is, style overrides will be parsed later. - */ -typedef struct ass_event { - long long Start; // ms - long long Duration; // ms - - int ReadOrder; - int Layer; - int Style; - char *Name; - int MarginL; - int MarginR; - int MarginV; - char *Effect; - char *Text; - - ASS_RenderPriv *render_priv; -} ASS_Event; - -/* - * ass track represent either an external script or a matroska subtitle stream - * (no real difference between them); it can be used in rendering after the - * headers are parsed (i.e. events format line read). - */ -typedef struct ass_track { - int n_styles; // amount used - int max_styles; // amount allocated - int n_events; - int max_events; - ASS_Style *styles; // array of styles, max_styles length, n_styles used - ASS_Event *events; // the same as styles - - char *style_format; // style format line (everything after "Format: ") - char *event_format; // event format line - - enum { - TRACK_TYPE_UNKNOWN = 0, - TRACK_TYPE_ASS, - TRACK_TYPE_SSA - } track_type; - - // Script header fields - int PlayResX; - int PlayResY; - double Timer; - int WrapStyle; - int ScaledBorderAndShadow; - int Kerning; - char *Language; - - int default_style; // index of default style - char *name; // file name in case of external subs, 0 for streams - - ASS_Library *library; - ASS_ParserPriv *parser_priv; -} ASS_Track; - -#endif /* LIBASS_TYPES_H */ diff --git a/lib/libass/libass/ass_utils.c b/lib/libass/libass/ass_utils.c deleted file mode 100644 index 2fd46c4b45..0000000000 --- a/lib/libass/libass/ass_utils.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "config.h" - -#include <stdlib.h> -#include <stdio.h> -#include <inttypes.h> -#include <ft2build.h> -#include FT_GLYPH_H -#ifndef _WIN32 -#include <strings.h> -#endif - -#include "ass_library.h" -#include "ass.h" -#include "ass_utils.h" - -#ifdef _WIN32 -FILE *fopen_utf8(const char *_Filename, const char *_Mode) -{ - return fopen(_Filename, _Mode); -} -#endif - -int mystrtoi(char **p, int *res) -{ - double temp_res; - char *start = *p; - temp_res = ass_strtod(*p, p); - *res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5)); - if (*p != start) - return 1; - else - return 0; -} - -int mystrtoll(char **p, long long *res) -{ - double temp_res; - char *start = *p; - temp_res = ass_strtod(*p, p); - *res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5)); - if (*p != start) - return 1; - else - return 0; -} - -int mystrtou32(char **p, int base, uint32_t *res) -{ - char *start = *p; - *res = strtoll(*p, p, base); - if (*p != start) - return 1; - else - return 0; -} - -int mystrtod(char **p, double *res) -{ - char *start = *p; - *res = ass_strtod(*p, p); - if (*p != start) - return 1; - else - return 0; -} - -int strtocolor(ASS_Library *library, char **q, uint32_t *res, int hex) -{ - uint32_t color = 0; - int result; - char *p = *q; - int base = hex ? 16 : 10; - - if (*p == '&') - ++p; - else - ass_msg(library, MSGL_DBG2, "suspicious color format: \"%s\"\n", p); - - if (*p == 'H' || *p == 'h') { - ++p; - result = mystrtou32(&p, 16, &color); - } else { - result = mystrtou32(&p, base, &color); - } - - { - unsigned char *tmp = (unsigned char *) (&color); - unsigned char b; - b = tmp[0]; - tmp[0] = tmp[3]; - tmp[3] = b; - b = tmp[1]; - tmp[1] = tmp[2]; - tmp[2] = b; - } - if (*p == '&') - ++p; - *q = p; - - *res = color; - return result; -} - -// Return a boolean value for a string -char parse_bool(char *str) -{ - while (*str == ' ' || *str == '\t') - str++; - if (!strncasecmp(str, "yes", 3)) - return 1; - else if (strtol(str, NULL, 10) > 0) - return 1; - return 0; -} - -void ass_msg(ASS_Library *priv, int lvl, char *fmt, ...) -{ - va_list va; - va_start(va, fmt); - priv->msg_callback(lvl, fmt, va, priv->msg_callback_data); - va_end(va); -} - -unsigned ass_utf8_get_char(char **str) -{ - uint8_t *strp = (uint8_t *) * str; - unsigned c = *strp++; - unsigned mask = 0x80; - int len = -1; - while (c & mask) { - mask >>= 1; - len++; - } - if (len <= 0 || len > 4) - goto no_utf8; - c &= mask - 1; - while ((*strp & 0xc0) == 0x80) { - if (len-- <= 0) - goto no_utf8; - c = (c << 6) | (*strp++ & 0x3f); - } - if (len) - goto no_utf8; - *str = (char *) strp; - return c; - - no_utf8: - strp = (uint8_t *) * str; - c = *strp++; - *str = (char *) strp; - return c; -} - -#ifdef CONFIG_ENCA -void *ass_guess_buffer_cp(ASS_Library *library, unsigned char *buffer, - int buflen, char *preferred_language, - char *fallback) -{ - const char **languages; - size_t langcnt; - EncaAnalyser analyser; - EncaEncoding encoding; - char *detected_sub_cp = NULL; - int i; - - languages = enca_get_languages(&langcnt); - ass_msg(library, MSGL_V, "ENCA supported languages"); - for (i = 0; i < langcnt; i++) { - ass_msg(library, MSGL_V, "lang %s", languages[i]); - } - - for (i = 0; i < langcnt; i++) { - const char *tmp; - - if (strcasecmp(languages[i], preferred_language) != 0) - continue; - analyser = enca_analyser_alloc(languages[i]); - encoding = enca_analyse_const(analyser, buffer, buflen); - tmp = enca_charset_name(encoding.charset, ENCA_NAME_STYLE_ICONV); - if (tmp && encoding.charset != ENCA_CS_UNKNOWN) { - detected_sub_cp = strdup(tmp); - ass_msg(library, MSGL_INFO, "ENCA detected charset: %s", tmp); - } - enca_analyser_free(analyser); - } - - free(languages); - - if (!detected_sub_cp) { - detected_sub_cp = strdup(fallback); - ass_msg(library, MSGL_INFO, - "ENCA detection failed: fallback to %s", fallback); - } - - return detected_sub_cp; -} -#endif diff --git a/lib/libass/libass/ass_utils.h b/lib/libass/libass/ass_utils.h deleted file mode 100644 index f0093973da..0000000000 --- a/lib/libass/libass/ass_utils.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef LIBASS_UTILS_H -#define LIBASS_UTILS_H - -#include <stdio.h> -#include <stdarg.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> - -#ifdef CONFIG_ENCA -#include <enca.h> -#endif - -#include "ass.h" - -#ifdef _WIN32 -#include "config.h" -// This is needed in debug build. Without those defines, those 3 symbols are taken from msvcr100.dll, and free() from msvcr100d.dll -// This cause a heap corruption each time a strdup is freed -// See http://www.altdevblogaday.com/2011/08/02/a-journey-into-linker-hell-and-a-mistake/ -#define strdup _strdup -#define stricmp _stricmp -#define strnicmp _strnicmp -#endif - -#define MSGL_FATAL 0 -#define MSGL_ERR 1 -#define MSGL_WARN 2 -#define MSGL_INFO 4 -#define MSGL_V 6 -#define MSGL_DBG2 7 - -#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) -#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) -#define FFMINMAX(c,a,b) FFMIN(FFMAX(c, a), b) - -int mystrtoi(char **p, int *res); -int mystrtoll(char **p, long long *res); -int mystrtou32(char **p, int base, uint32_t *res); -int mystrtod(char **p, double *res); -int strtocolor(ASS_Library *library, char **q, uint32_t *res, int hex); -char parse_bool(char *str); -unsigned ass_utf8_get_char(char **str); -void ass_msg(ASS_Library *priv, int lvl, char *fmt, ...); -#ifdef CONFIG_ENCA -void *ass_guess_buffer_cp(ASS_Library *library, unsigned char *buffer, - int buflen, char *preferred_language, - char *fallback); -#endif - -/* defined in ass_strtod.c */ -double ass_strtod(const char *string, char **endPtr); - -static inline int d6_to_int(int x) -{ - return (x + 32) >> 6; -} -static inline int d16_to_int(int x) -{ - return (x + 32768) >> 16; -} -static inline int int_to_d6(int x) -{ - return x << 6; -} -static inline int int_to_d16(int x) -{ - return x << 16; -} -static inline int d16_to_d6(int x) -{ - return (x + 512) >> 10; -} -static inline int d6_to_d16(int x) -{ - return x << 10; -} -static inline double d6_to_double(int x) -{ - return x / 64.; -} -static inline int double_to_d6(double x) -{ - return (int) (x * 64); -} -static inline double d16_to_double(int x) -{ - return ((double) x) / 0x10000; -} -static inline int double_to_d16(double x) -{ - return (int) (x * 0x10000); -} -static inline double d22_to_double(int x) -{ - return ((double) x) / 0x400000; -} -static inline int double_to_d22(double x) -{ - return (int) (x * 0x400000); -} - -// Calculate cache key for a rotational angle in degrees -static inline int rot_key(double a) -{ - const int m = double_to_d22(360.0); - return double_to_d22(a) % m; -} - -#define FNV1_32A_INIT (unsigned)0x811c9dc5 - -static inline 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 inline 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; -} - -#endif /* LIBASS_UTILS_H */ diff --git a/lib/libass/libass/libass.sym b/lib/libass/libass/libass.sym deleted file mode 100644 index f8fa1458a1..0000000000 --- a/lib/libass/libass/libass.sym +++ /dev/null @@ -1,37 +0,0 @@ -ass_library_init -ass_library_done -ass_set_fonts_dir -ass_set_extract_fonts -ass_set_style_overrides -ass_renderer_init -ass_renderer_done -ass_set_frame_size -ass_set_margins -ass_set_use_margins -ass_set_aspect_ratio -ass_set_font_scale -ass_set_hinting -ass_set_line_spacing -ass_set_fonts -ass_render_frame -ass_new_track -ass_free_track -ass_alloc_style -ass_alloc_event -ass_free_style -ass_free_event -ass_process_data -ass_process_codec_private -ass_process_chunk -ass_read_file -ass_read_memory -ass_read_styles -ass_add_font -ass_clear_fonts -ass_step_sub -ass_process_force_style -ass_set_message_cb -ass_fonts_update -ass_set_cache_limits -ass_flush_events -ass_set_shaper diff --git a/lib/libass/m4/.gitignore b/lib/libass/m4/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 --- a/lib/libass/m4/.gitignore +++ /dev/null diff --git a/lib/libass/test/Makefile.am b/lib/libass/test/Makefile.am deleted file mode 100644 index 208c9cf37b..0000000000 --- a/lib/libass/test/Makefile.am +++ /dev/null @@ -1,7 +0,0 @@ -AM_CFLAGS = -Wall - -noinst_PROGRAMS = test -test_SOURCES = test.c -test_CPPFLAGS = -I../libass -test_LDADD = ../libass/libass.la -test_LDFLAGS = $(AM_LDFLAGS) $(LIBPNG_LIBS) diff --git a/lib/libass/test/test.c b/lib/libass/test/test.c deleted file mode 100644 index d6cd9b8672..0000000000 --- a/lib/libass/test/test.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> - * Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org> - * - * This file is part of libass. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <ass.h> -#include <png.h> - -typedef struct image_s { - int width, height, stride; - unsigned char *buffer; // RGB24 -} image_t; - -ASS_Library *ass_library; -ASS_Renderer *ass_renderer; - -void msg_callback(int level, const char *fmt, va_list va, void *data) -{ - if (level > 6) - return; - printf("libass: "); - vprintf(fmt, va); - printf("\n"); -} - -static void write_png(char *fname, image_t *img) -{ - FILE *fp; - png_structp png_ptr; - png_infop info_ptr; - png_byte **row_pointers; - int k; - - png_ptr = - png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - info_ptr = png_create_info_struct(png_ptr); - fp = NULL; - - if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_write_struct(&png_ptr, &info_ptr); - fclose(fp); - return; - } - - fp = fopen(fname, "wb"); - if (fp == NULL) { - printf("PNG Error opening %s for writing!\n", fname); - return; - } - - png_init_io(png_ptr, fp); - png_set_compression_level(png_ptr, 0); - - png_set_IHDR(png_ptr, info_ptr, img->width, img->height, - 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - png_write_info(png_ptr, info_ptr); - - png_set_bgr(png_ptr); - - row_pointers = (png_byte **) malloc(img->height * sizeof(png_byte *)); - for (k = 0; k < img->height; k++) - row_pointers[k] = img->buffer + img->stride * k; - - png_write_image(png_ptr, row_pointers); - png_write_end(png_ptr, info_ptr); - png_destroy_write_struct(&png_ptr, &info_ptr); - - free(row_pointers); - - fclose(fp); -} - -static void init(int frame_w, int frame_h) -{ - ass_library = ass_library_init(); - if (!ass_library) { - printf("ass_library_init failed!\n"); - exit(1); - } - - ass_set_message_cb(ass_library, msg_callback, NULL); - - ass_renderer = ass_renderer_init(ass_library); - if (!ass_renderer) { - printf("ass_renderer_init failed!\n"); - exit(1); - } - - ass_set_frame_size(ass_renderer, frame_w, frame_h); - ass_set_fonts(ass_renderer, NULL, "Sans", 1, NULL, 1); -} - -static image_t *gen_image(int width, int height) -{ - image_t *img = malloc(sizeof(image_t)); - img->width = width; - img->height = height; - img->stride = width * 3; - img->buffer = (unsigned char *) calloc(1, height * width * 3); - memset(img->buffer, 63, img->stride * img->height); - //for (int i = 0; i < height * width * 3; ++i) - // img->buffer[i] = (i/3/50) % 100; - return img; -} - -#define _r(c) ((c)>>24) -#define _g(c) (((c)>>16)&0xFF) -#define _b(c) (((c)>>8)&0xFF) -#define _a(c) ((c)&0xFF) - -static void blend_single(image_t * frame, ASS_Image *img) -{ - int x, y; - unsigned char opacity = 255 - _a(img->color); - unsigned char r = _r(img->color); - unsigned char g = _g(img->color); - unsigned char b = _b(img->color); - - unsigned char *src; - unsigned char *dst; - - src = img->bitmap; - dst = frame->buffer + img->dst_y * frame->stride + img->dst_x * 3; - for (y = 0; y < img->h; ++y) { - for (x = 0; x < img->w; ++x) { - unsigned k = ((unsigned) src[x]) * opacity / 255; - // possible endianness problems - dst[x * 3] = (k * b + (255 - k) * dst[x * 3]) / 255; - dst[x * 3 + 1] = (k * g + (255 - k) * dst[x * 3 + 1]) / 255; - dst[x * 3 + 2] = (k * r + (255 - k) * dst[x * 3 + 2]) / 255; - } - src += img->stride; - dst += frame->stride; - } -} - -static void blend(image_t * frame, ASS_Image *img) -{ - int cnt = 0; - while (img) { - blend_single(frame, img); - ++cnt; - img = img->next; - } - printf("%d images blended\n", cnt); -} - -int main(int argc, char *argv[]) -{ - const int frame_w = 640; - const int frame_h = 480; - - if (argc < 4) { - printf("usage: %s <image file> <subtitle file> <time>\n", argv[0]); - exit(1); - } - char *imgfile = argv[1]; - char *subfile = argv[2]; - double tm = strtod(argv[3], 0); - - init(frame_w, frame_h); - ASS_Track *track = ass_read_file(ass_library, subfile, NULL); - if (!track) { - printf("track init failed!\n"); - return 1; - } - - ASS_Image *img = - ass_render_frame(ass_renderer, track, (int) (tm * 1000), NULL); - image_t *frame = gen_image(frame_w, frame_h); - blend(frame, img); - - ass_free_track(track); - ass_renderer_done(ass_renderer); - ass_library_done(ass_library); - - write_png(imgfile, frame); - free(frame->buffer); - free(frame); - - return 0; -} diff --git a/lib/libass/xbmc/libass_win32/config.h b/lib/libass/xbmc/libass_win32/config.h deleted file mode 100644 index ad0bc866fe..0000000000 --- a/lib/libass/xbmc/libass_win32/config.h +++ /dev/null @@ -1,183 +0,0 @@ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Define to 1 if you have the <dlfcn.h> header file. */ -#undef HAVE_DLFCN_H - -/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ -#undef HAVE_DOPRNT - -/* use enca */ -#define CONFIG_ENCA 1 - -/* Define to 1 if you have the <enca.h> header file. */ -#undef HAVE_ENCA_H - -/* found fontconfig via pkg-config */ -#define CONFIG_FONTCONFIG - -/* found freetype2 via pkg-config */ -#undef HAVE_FREETYPE - -/* Define to 1 if you have the <iconv.h> header file. */ -#undef HAVE_ICONV_H - -/* Define to 1 if you have the <inttypes.h> header file. */ -#undef HAVE_INTTYPES_H - -/* use libpng */ -#undef HAVE_LIBPNG - -/* Define to 1 if your system has a GNU libc compatible `malloc' function, and - to 0 otherwise. */ -#undef HAVE_MALLOC - -/* Define to 1 if you have the <memory.h> header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have the `memset' function. */ -#undef HAVE_MEMSET - -/* Define to 1 if you have the `mkdir' function. */ -#undef HAVE_MKDIR - -/* Define to 1 if your system has a GNU libc compatible `realloc' function, - and to 0 otherwise. */ -#undef HAVE_REALLOC - -/* Define to 1 if `stat' has the bug that it succeeds when given the - zero-length file name argument. */ -#undef HAVE_STAT_EMPTY_STRING_BUG - -/* Define to 1 if stdbool.h conforms to C99. */ -#undef HAVE_STDBOOL_H - -/* Define to 1 if you have the <stdint.h> header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the <stdlib.h> header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the `strcasecmp' function. */ -#undef HAVE_STRCASECMP - -/* Define to 1 if you have the `strchr' function. */ -#undef HAVE_STRCHR - -/* Define to 1 if you have the `strdup' function. */ -#undef HAVE_STRDUP - -/* Define to 1 if you have the `strerror' function. */ -#undef HAVE_STRERROR - -/* Define to 1 if you have the <strings.h> header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the <string.h> header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the `strstr' function. */ -#undef HAVE_STRSTR - -/* Define to 1 if you have the `strtol' function. */ -#undef HAVE_STRTOL - -/* Define to 1 if you have the <sys/stat.h> header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the <sys/time.h> header file. */ -#undef HAVE_SYS_TIME_H - -/* Define to 1 if you have the <sys/types.h> header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the <unistd.h> header file. */ -#undef HAVE_UNISTD_H - -/* Define to 1 if you have the `vprintf' function. */ -#undef HAVE_VPRINTF - -/* Define to 1 if the system has the type `_Bool'. */ -#undef HAVE__BOOL - -/* Define to 1 if `lstat' dereferences a symlink specified with a trailing - slash. */ -#undef LSTAT_FOLLOWS_SLASHED_SYMLINK - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Define to 1 if your <sys/time.h> declares `struct tm'. */ -#undef TM_IN_SYS_TIME - -/* use iconv */ -#define CONFIG_ICONV 1 - -/* Version number of package */ -#undef VERSION - -/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>, - <pthread.h>, or <semaphore.h> is not used. If the typedef was allowed, the - #define below would cause a syntax error. */ -#undef _UINT32_T - -/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>, - <pthread.h>, or <semaphore.h> is not used. If the typedef was allowed, the - #define below would cause a syntax error. */ -#undef _UINT8_T - -/* Define to empty if `const' does not conform to ANSI C. */ -#undef const - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -#define inline __inline -#endif - -/* Define to the type of a signed integer type of width exactly 64 bits if - such a type exists and the standard includes do not define it. */ -#undef int64_t - -/* Define to rpl_malloc if the replacement function should be used. */ -#undef malloc - -/* Define to rpl_realloc if the replacement function should be used. */ -#undef realloc - -/* Define to `unsigned int' if <sys/types.h> does not define. */ -#undef size_t - -/* Define to the type of an unsigned integer type of width exactly 32 bits if - such a type exists and the standard includes do not define it. */ -#undef uint32_t - -/* Define to the type of an unsigned integer type of width exactly 8 bits if - such a type exists and the standard includes do not define it. */ -#undef uint8_t - -#ifndef M_PI -#define M_PI 3.1415926535897932384626433832795 -#endif - -#define strncasecmp strnicmp -#define strcasecmp stricmp - -#define strtoll(p, e, b) _strtoi64(p, e, b) diff --git a/lib/libass/xbmc/libass_win32/getopt.h b/lib/libass/xbmc/libass_win32/getopt.h deleted file mode 100644 index ff0251dec0..0000000000 --- a/lib/libass/xbmc/libass_win32/getopt.h +++ /dev/null @@ -1,193 +0,0 @@ -/* Declarations for getopt. - Copyright (C) 1989-1994,1996-1999,2001,2003,2004,2009 - Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#ifndef _GETOPT_H - -#ifndef __need_getopt -# define _GETOPT_H 1 -#endif - -/* If __GNU_LIBRARY__ is not already defined, either we are being used - standalone, or this is the first header included in the source file. - If we are being used with glibc, we need to include <features.h>, but - that does not exist if we are standalone. So: if __GNU_LIBRARY__ is - not defined, include <ctype.h>, which will pull in <features.h> for us - if it's from glibc. (Why ctype.h? It's guaranteed to exist and it - doesn't flood the namespace with stuff the way some other headers do.) */ -#if !defined __GNU_LIBRARY__ -# include <ctype.h> -#endif - -#ifndef __THROW -# ifndef __GNUC_PREREQ -# define __GNUC_PREREQ(maj, min) (0) -# endif -# if defined __cplusplus && __GNUC_PREREQ (2,8) -# define __THROW throw () -# else -# define __THROW -# endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -extern char *optarg; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -extern int optind; - -/* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ - -extern int opterr; - -/* Set to an option character which was unrecognized. */ - -extern int optopt; - -#ifndef __need_getopt -/* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector - of `struct option' terminated by an element containing a name which is - zero. - - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. - - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ - -struct option -{ - const char *name; - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; - -/* Names for the values of the `has_arg' field of `struct option'. */ - -# define no_argument 0 -# define required_argument 1 -# define optional_argument 2 -#endif /* need getopt */ - - -/* Get definitions and prototypes for functions to process the - arguments in ARGV (ARGC of them, minus the program name) for - options given in OPTS. - - Return the option character from OPTS just read. Return -1 when - there are no more options. For unrecognized options, or options - missing arguments, `optopt' is set to the option letter, and '?' is - returned. - - The OPTS string is a list of characters which are recognized option - letters, optionally followed by colons, specifying that that letter - takes an argument, to be placed in `optarg'. - - If a letter in OPTS is followed by two colons, its argument is - optional. This behavior is specific to the GNU `getopt'. - - The argument `--' causes premature termination of argument - scanning, explicitly telling `getopt' that there are no more - options. - - If OPTS begins with `--', then non-option arguments are treated as - arguments to the option '\0'. This behavior is specific to the GNU - `getopt'. */ - -#ifdef __GNU_LIBRARY__ -/* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ -extern int getopt (int ___argc, char *const *___argv, const char *__shortopts) - __THROW; - -# if defined __need_getopt && defined __USE_POSIX2 \ - && !defined __USE_POSIX_IMPLICITLY && !defined __USE_GNU -/* The GNU getopt has more functionality than the standard version. The - additional functionality can be disable at runtime. This redirection - helps to also do this at runtime. */ -# ifdef __REDIRECT - extern int __REDIRECT (getopt, (int ___argc, char *const *___argv, - const char *__shortopts), - __posix_getopt) __THROW; -# else -extern int __posix_getopt (int ___argc, char *const *___argv, - const char *__shortopts) __THROW; -# define getopt __posix_getopt -# endif -# endif -#else /* not __GNU_LIBRARY__ */ -extern int getopt (); -#endif /* __GNU_LIBRARY__ */ - -#ifndef __need_getopt -extern int getopt_long (int ___argc, char *const *___argv, - const char *__shortopts, - const struct option *__longopts, int *__longind) - __THROW; -extern int getopt_long_only (int ___argc, char *const *___argv, - const char *__shortopts, - const struct option *__longopts, int *__longind) - __THROW; - -#endif - -#ifdef __cplusplus -} -#endif - -/* Make sure we later can get all the definitions and declarations. */ -#undef __need_getopt - -#endif /* getopt.h */ diff --git a/lib/libass/xbmc/libass_win32/inttypes.h b/lib/libass/xbmc/libass_win32/inttypes.h deleted file mode 100644 index 880d5329aa..0000000000 --- a/lib/libass/xbmc/libass_win32/inttypes.h +++ /dev/null @@ -1,306 +0,0 @@ -// 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 - -#define ssize_t int - -#endif // _MSC_INTTYPES_H_ ] diff --git a/lib/libass/xbmc/libass_win32/libass.def b/lib/libass/xbmc/libass_win32/libass.def deleted file mode 100644 index 07faca3f60..0000000000 --- a/lib/libass/xbmc/libass_win32/libass.def +++ /dev/null @@ -1,38 +0,0 @@ -LIBRARY libass.dll -EXPORTS - -ass_library_init @1 -ass_library_done @2 -ass_set_fonts_dir @3 -ass_set_extract_fonts @4 -ass_set_style_overrides @5 -ass_process_force_style @6 -ass_set_message_cb @7 -ass_renderer_init @8 -ass_renderer_done @9 -ass_set_frame_size @10 -ass_set_margins @11 -ass_set_use_margins @12 -ass_set_aspect_ratio @13 -ass_set_font_scale @14 -ass_set_hinting @15 -ass_set_line_spacing @16 -ass_set_fonts @17 -ass_fonts_update @18 -ass_set_cache_limits @19 -ass_render_frame @20 -ass_new_track @21 -ass_free_track @22 -ass_alloc_style @23 -ass_alloc_event @24 -ass_free_style @25 -ass_free_event @26 -ass_process_data @27 -ass_process_codec_private @28 -ass_process_chunk @29 -ass_read_file @30 -ass_read_memory @31 -ass_read_styles @32 -ass_add_font @33 -ass_clear_fonts @34 -ass_step_sub @35
\ No newline at end of file diff --git a/lib/libass/xbmc/libass_win32/libass_win32_vs2008.sln b/lib/libass/xbmc/libass_win32/libass_win32_vs2008.sln deleted file mode 100644 index 5e22aa1cac..0000000000 --- a/lib/libass/xbmc/libass_win32/libass_win32_vs2008.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual C++ Express 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libass_win32", "libass_win32_vs2008.vcproj", "{BA5B08FC-2ECB-4571-9F25-F8054522FC65}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {BA5B08FC-2ECB-4571-9F25-F8054522FC65}.Debug|Win32.ActiveCfg = Debug|Win32 - {BA5B08FC-2ECB-4571-9F25-F8054522FC65}.Debug|Win32.Build.0 = Debug|Win32 - {BA5B08FC-2ECB-4571-9F25-F8054522FC65}.Release|Win32.ActiveCfg = Release|Win32 - {BA5B08FC-2ECB-4571-9F25-F8054522FC65}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/lib/libass/xbmc/libass_win32/libass_win32_vs2010.vcxproj b/lib/libass/xbmc/libass_win32/libass_win32_vs2010.vcxproj deleted file mode 100644 index 0b226a1605..0000000000 --- a/lib/libass/xbmc/libass_win32/libass_win32_vs2010.vcxproj +++ /dev/null @@ -1,178 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup Label="ProjectConfigurations"> - <ProjectConfiguration Include="Debug|Win32"> - <Configuration>Debug</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Release|Win32"> - <Configuration>Release</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - </ItemGroup> - <PropertyGroup Label="Globals"> - <ProjectName>libass_dll</ProjectName> - <ProjectGuid>{BA5B08FC-2ECB-4571-9F25-F8054522FC65}</ProjectGuid> - <RootNamespace>libass_win32</RootNamespace> - <Keyword>Win32Proj</Keyword> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <CharacterSet>Unicode</CharacterSet> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <UseDebugLibraries>true</UseDebugLibraries> - <CharacterSet>Unicode</CharacterSet> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <ImportGroup Label="ExtensionSettings"> - </ImportGroup> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - <Import Project="..\..\..\..\project\VS2010Express\XBMC for Windows.props" /> - </ImportGroup> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - <Import Project="..\..\..\..\project\VS2010Express\XBMC for Windows.props" /> - </ImportGroup> - <PropertyGroup Label="UserMacros" /> - <PropertyGroup> - <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> - <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)libs\$(TargetName)\$(Configuration)\</OutDir> - <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)objs\$(TargetName)\$(Configuration)\</IntDir> - <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental> - <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)libs\$(TargetName)\$(Configuration)\</OutDir> - <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)objs\$(TargetName)\$(Configuration)\</IntDir> - <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental> - <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">libass</TargetName> - <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">libass</TargetName> - <CustomBuildAfterTargets Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Build</CustomBuildAfterTargets> - <CustomBuildAfterTargets Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Build</CustomBuildAfterTargets> - </PropertyGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <ClCompile> - <Optimization>Disabled</Optimization> - <AdditionalIncludeDirectories>.\;..\..\..\enca\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBASS_WIN32_EXPORTS;CONFIG_HARFBUZZ;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <MinimalRebuild>true</MinimalRebuild> - <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> - <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> - <PrecompiledHeader> - </PrecompiledHeader> - <WarningLevel>Level3</WarningLevel> - <DebugInformationFormat>EditAndContinue</DebugInformationFormat> - <DisableSpecificWarnings>4001;4996;4244;4267;4018;4005;%(DisableSpecificWarnings)</DisableSpecificWarnings> - <CompileAs>CompileAsC</CompileAs> - <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet> - </ClCompile> - <Link> - <AdditionalDependencies>fontconfig.lib;zlib.lib;harfbuzz.lib;%(AdditionalDependencies)</AdditionalDependencies> - <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> - <IgnoreSpecificDefaultLibraries>libcmt;libcmtd;msvcrt;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries> - <GenerateDebugInformation>true</GenerateDebugInformation> - <ProgramDatabaseFile>Debug/libass_win32.pdb</ProgramDatabaseFile> - <SubSystem>Windows</SubSystem> - <RandomizedBaseAddress>false</RandomizedBaseAddress> - <DataExecutionPrevention> - </DataExecutionPrevention> - <ImportLibrary>$(Configuration)\vs2010\$(TargetName)_win32.lib</ImportLibrary> - <TargetMachine>MachineX86</TargetMachine> - <AdditionalLibraryDirectories> - </AdditionalLibraryDirectories> - <ModuleDefinitionFile>libass.def</ModuleDefinitionFile> - </Link> - <CustomBuildStep> - <Command>copy /B /Y "$(TargetPath)" "$(SolutionDir)..\..\system\players\dvdplayer\$(TargetFileName)"</Command> - <Message>Copy Output</Message> - <Outputs>$(SolutionDir)..\..\system\players\dvdplayer\$(TargetFileName)</Outputs> - <Inputs>$(TargetPath)</Inputs> - </CustomBuildStep> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <ClCompile> - <Optimization>Full</Optimization> - <AdditionalIncludeDirectories>.\;..\..\..\enca\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBASS_WIN32_EXPORTS;CONFIG_HARFBUZZ;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> - <PrecompiledHeader> - </PrecompiledHeader> - <WarningLevel>Level3</WarningLevel> - <DebugInformationFormat> - </DebugInformationFormat> - <DisableSpecificWarnings>4001;4996;4244;4267;4018;4005;%(DisableSpecificWarnings)</DisableSpecificWarnings> - <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet> - </ClCompile> - <Link> - <AdditionalDependencies>fontconfig.lib;zlib.lib;harfbuzz.lib;%(AdditionalDependencies)</AdditionalDependencies> - <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> - <IgnoreSpecificDefaultLibraries>libcmt;libcmtd;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries> - <GenerateDebugInformation>true</GenerateDebugInformation> - <ProgramDatabaseFile>Release/$(TargetName).pdb</ProgramDatabaseFile> - <SubSystem>Windows</SubSystem> - <OptimizeReferences>true</OptimizeReferences> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <RandomizedBaseAddress>false</RandomizedBaseAddress> - <DataExecutionPrevention> - </DataExecutionPrevention> - <ImportLibrary>$(Configuration)\vs2010\$(TargetName)_win32.lib</ImportLibrary> - <TargetMachine>MachineX86</TargetMachine> - <AdditionalLibraryDirectories> - </AdditionalLibraryDirectories> - <ModuleDefinitionFile>libass.def</ModuleDefinitionFile> - </Link> - <CustomBuildStep> - <Command>copy /B /Y "$(TargetPath)" "$(SolutionDir)..\..\system\players\dvdplayer\$(TargetFileName)"</Command> - <Message>Copy Output</Message> - <Inputs>$(TargetPath)</Inputs> - <Outputs>$(SolutionDir)..\..\system\players\dvdplayer\$(TargetFileName)</Outputs> - </CustomBuildStep> - </ItemDefinitionGroup> - <ItemGroup> - <ClInclude Include="..\..\libass\ass.h" /> - <ClInclude Include="..\..\libass\ass_bitmap.h" /> - <ClInclude Include="..\..\libass\ass_cache.h" /> - <ClInclude Include="..\..\libass\ass_cache_template.h" /> - <ClInclude Include="..\..\libass\ass_drawing.h" /> - <ClInclude Include="..\..\libass\ass_font.h" /> - <ClInclude Include="..\..\libass\ass_fontconfig.h" /> - <ClInclude Include="..\..\libass\ass_library.h" /> - <ClInclude Include="..\..\libass\ass_parse.h" /> - <ClInclude Include="..\..\libass\ass_render.h" /> - <ClInclude Include="..\..\libass\ass_shaper.h" /> - <ClInclude Include="..\..\libass\ass_types.h" /> - <ClInclude Include="..\..\libass\ass_utils.h" /> - <ClInclude Include="config.h" /> - </ItemGroup> - <ItemGroup> - <ClCompile Include="..\..\libass\ass.c" /> - <ClCompile Include="..\..\libass\ass_bitmap.c" /> - <ClCompile Include="..\..\libass\ass_cache.c" /> - <ClCompile Include="..\..\libass\ass_drawing.c" /> - <ClCompile Include="..\..\libass\ass_font.c" /> - <ClCompile Include="..\..\libass\ass_fontconfig.c" /> - <ClCompile Include="..\..\libass\ass_library.c" /> - <ClCompile Include="..\..\libass\ass_parse.c" /> - <ClCompile Include="..\..\libass\ass_render.c" /> - <ClCompile Include="..\..\libass\ass_render_api.c" /> - <ClCompile Include="..\..\libass\ass_shaper.c" /> - <ClCompile Include="..\..\libass\ass_strtod.c" /> - <ClCompile Include="..\..\libass\ass_utils.c"> - <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Default</CompileAs> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\..\..\enca\libenca_win32\libenca_win32.vcxproj"> - <Project>{22b25aec-7223-46fc-8356-4418327efde1}</Project> - <ReferenceOutputAssembly>false</ReferenceOutputAssembly> - </ProjectReference> - </ItemGroup> - <ItemGroup> - <None Include="libass.def" /> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> -</Project> diff --git a/lib/libass/xbmc/libass_win32/stdint.h b/lib/libass/xbmc/libass_win32/stdint.h deleted file mode 100644 index b23840f1d5..0000000000 --- a/lib/libass/xbmc/libass_win32/stdint.h +++ /dev/null @@ -1,222 +0,0 @@ -// 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_ ] diff --git a/lib/libass/xbmc/libass_win32/unistd.h b/lib/libass/xbmc/libass_win32/unistd.h deleted file mode 100644 index 4799c2bffe..0000000000 --- a/lib/libass/xbmc/libass_win32/unistd.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of the Mingw32 package. - * - * unistd.h maps (roughly) to io.h - */ - -#ifndef _UNISTD_H -#define _UNISTD_H - -#include <io.h> -#include <process.h> - -#define __UNISTD_GETOPT__ -#include <getopt.h> -#undef __UNISTD_GETOPT__ - -/* These are also defined in stdio.h. */ -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif - -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif - -#ifndef SEEK_END -#define SEEK_END 2 -#endif - -#ifdef __cplusplus -extern "C" { -#endif - - -/* This is defined as a real library function to allow autoconf - to verify its existence. */ -//int ftruncate(int, off_t); -//__CRT_INLINE int ftruncate(int __fd, off_t __length) -//{ -// return _chsize (__fd, __length); -//} - -#ifdef __cplusplus -} -#endif - -#endif /* _UNISTD_H */ |