diff -Nru libass-0.12.2/aclocal.m4 libass-0.13.0/aclocal.m4 --- libass-0.12.2/aclocal.m4 2015-05-07 19:47:24.000000000 +0000 +++ libass-0.13.0/aclocal.m4 2015-10-03 18:20:38.000000000 +0000 @@ -1,6 +1,6 @@ -# generated automatically by aclocal 1.14.1 -*- Autoconf -*- +# generated automatically by aclocal 1.15 -*- Autoconf -*- -# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -235,7 +235,7 @@ AS_VAR_IF([$1], [""], [$5], [$4])dnl ])# PKG_CHECK_VAR -# Copyright (C) 2002-2013 Free Software Foundation, Inc. +# Copyright (C) 2002-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -247,10 +247,10 @@ # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], -[am__api_version='1.14' +[am__api_version='1.15' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.14.1], [], +m4_if([$1], [1.15], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -266,14 +266,14 @@ # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.14.1])dnl +[AM_AUTOMAKE_VERSION([1.15])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # Figure out how to run the assembler. -*- Autoconf -*- -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -293,7 +293,7 @@ # AM_AUX_DIR_EXPAND -*- Autoconf -*- -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -345,7 +345,7 @@ # AM_COND_IF -*- Autoconf -*- -# Copyright (C) 2008-2013 Free Software Foundation, Inc. +# Copyright (C) 2008-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -382,7 +382,7 @@ # AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997-2013 Free Software Foundation, Inc. +# Copyright (C) 1997-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -413,7 +413,7 @@ Usually this means the macro was only invoked conditionally.]]) fi])]) -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -604,7 +604,7 @@ # Generate code to set up dependency tracking. -*- Autoconf -*- -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -680,7 +680,7 @@ # Do all the work for Automake. -*- Autoconf -*- -# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -770,8 +770,8 @@ # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) -# We need awk for the "check" target. The system "awk" is bad on -# some platforms. +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl @@ -845,6 +845,9 @@ AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi +dnl The trailing newline in this macro's definition is deliberate, for +dnl backward compatibility and to allow trailing 'dnl'-style comments +dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not @@ -874,7 +877,7 @@ done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -885,7 +888,7 @@ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -if test x"${install_sh}" != xset; then +if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; @@ -895,7 +898,7 @@ fi AC_SUBST([install_sh])]) -# Copyright (C) 2003-2013 Free Software Foundation, Inc. +# Copyright (C) 2003-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -916,7 +919,7 @@ # Check to see how 'make' treats includes. -*- Autoconf -*- -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -966,7 +969,7 @@ # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- -# Copyright (C) 1997-2013 Free Software Foundation, Inc. +# Copyright (C) 1997-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1005,7 +1008,7 @@ # Helper functions for option handling. -*- Autoconf -*- -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1034,7 +1037,7 @@ AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1081,7 +1084,7 @@ # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1100,7 +1103,7 @@ # Check to make sure that the build environment is sane. -*- Autoconf -*- -# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1181,7 +1184,7 @@ rm -f conftest.file ]) -# Copyright (C) 2009-2013 Free Software Foundation, Inc. +# Copyright (C) 2009-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1241,7 +1244,7 @@ _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1269,7 +1272,7 @@ INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) -# Copyright (C) 2006-2013 Free Software Foundation, Inc. +# Copyright (C) 2006-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1288,7 +1291,7 @@ # Check how to create a tarball. -*- Autoconf -*- -# Copyright (C) 2004-2013 Free Software Foundation, Inc. +# Copyright (C) 2004-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff -Nru libass-0.12.2/Changelog libass-0.13.0/Changelog --- libass-0.12.2/Changelog 2015-05-07 19:25:37.000000000 +0000 +++ libass-0.13.0/Changelog 2015-10-03 18:18:46.000000000 +0000 @@ -1,3 +1,43 @@ +libass (0.13.0) + * Add native font selection backends for OSX (CoreText) and Windows + (DirectWrite). You can now run libass without fontconfig on these + platforms. This fixes problems with fontconfig behaving badly on + these platforms (it could take minutes to scan all system fonts). + Even on Linux, this speeds up loading of embedded fonts (such as + provided by ass_add_font()). + The DirectWrite backend only works on Windows Vista and later. On + XP, fontconfig is still needed. libass can be compiled with both + DirectWrite and fontconfig, and then it will fallback to fontconfig + automatically if DirectWrite is not available at runtime. + * Add ass_get_available_font_providers() API function. + * Change the 4th parameter of ass_set_fonts(). This now selects the + font provider. This is somewhat backwards compatible with the old + behavior, but if you ever passed values other than 0 or 1, your + application might break with this libass release. + * The ass_fonts_update() function now does nothing. It's kept for + backward compatibility only. + * Much faster gaussian blur. This can bring a large speedup with big + blurred signs and such. + * Drop ENCA support + * Bug fixes + * Fix compilation of the freetype rasterizer (disabled by default) + * Fix rendering with some cases of consecutive line breaks (\N\N). + * Fix some memory allocation failure checks + * Avoid system locale dependent behavior by reinventing some standard + C functions + * Fix rendering errors with strikes (GH #193) + * MSVC compilation fixes + +libass (0.12.3) + * VSFilter blur compatibility changes + * VSFilter color/alpha parsing compatibility changes + * Bugfixes + * Fix some potential memory leaks and crashes + * Fix large timestamps (larger than about 600 hours) + * Fix a potential crash with the new rasterizer and complex fonts + * Do not apply user-configured line position to non-dialog events + * Strictly clip non-dialog events to the video rectangle + libass (0.12.2) * Add extern "C" guards to the public headers for C++ compatibility * Improvements to style override API and implementation diff -Nru libass-0.12.2/compile libass-0.13.0/compile --- libass-0.12.2/compile 2015-05-07 19:47:27.000000000 +0000 +++ libass-0.13.0/compile 2015-09-07 12:54:15.000000000 +0000 @@ -3,7 +3,7 @@ scriptversion=2012-10-14.11; # UTC -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify diff -Nru libass-0.12.2/config.h.in libass-0.13.0/config.h.in --- libass-0.12.2/config.h.in 2015-05-07 19:47:26.000000000 +0000 +++ libass-0.13.0/config.h.in 2015-10-03 18:20:41.000000000 +0000 @@ -3,8 +3,11 @@ /* ASM enabled */ #undef CONFIG_ASM -/* found enca via pkg-config */ -#undef CONFIG_ENCA +/* found CoreText in System library */ +#undef CONFIG_CORETEXT + +/* found DirectWrite */ +#undef CONFIG_DIRECTWRITE /* found fontconfig via pkg-config */ #undef CONFIG_FONTCONFIG @@ -45,9 +48,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H -/* Define to 1 if you have the `mkdir' function. */ -#undef HAVE_MKDIR - /* Define to 1 if stdbool.h conforms to C99. */ #undef HAVE_STDBOOL_H @@ -57,9 +57,6 @@ /* Define to 1 if you have the 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 `strdup' function. */ #undef HAVE_STRDUP @@ -72,15 +69,9 @@ /* Define to 1 if you have the `strndup' function. */ #undef HAVE_STRNDUP -/* Define to 1 if you have the `strtol' function. */ -#undef HAVE_STRTOL - /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TIME_H - /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H @@ -120,37 +111,3 @@ /* Version number of package */ #undef VERSION - -/* Define for Solaris 2.5.1 so the uint32_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -#undef _UINT32_T - -/* Define for Solaris 2.5.1 so the uint8_t typedef from , - , or is not used. If the typedef were 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 -#undef 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 `unsigned int' if 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 diff -Nru libass-0.12.2/configure libass-0.13.0/configure --- libass-0.12.2/configure 2015-05-07 19:47:25.000000000 +0000 +++ libass-0.13.0/configure 2015-10-03 18:20:38.000000000 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for libass 0.12.2. +# Generated by GNU Autoconf 2.69 for libass 0.13.0. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -587,8 +587,8 @@ # Identity of this package. PACKAGE_NAME='libass' PACKAGE_TARNAME='libass' -PACKAGE_VERSION='0.12.2' -PACKAGE_STRING='libass 0.12.2' +PACKAGE_VERSION='0.13.0' +PACKAGE_STRING='libass 0.13.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -643,10 +643,12 @@ HAVE_LIBPNG_TRUE LIBPNG_LIBS LIBPNG_CFLAGS -ENCA_LIBS -ENCA_CFLAGS HARFBUZZ_LIBS HARFBUZZ_CFLAGS +DIRECTWRITE_FALSE +DIRECTWRITE_TRUE +CORETEXT_FALSE +CORETEXT_TRUE FONTCONFIG_LIBS FONTCONFIG_CFLAGS FRIBIDI_LIBS @@ -769,6 +771,7 @@ docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -802,8 +805,10 @@ enable_libtool_lock enable_test enable_profile -enable_enca enable_fontconfig +enable_directwrite +enable_coretext +enable_require_system_font_provider enable_harfbuzz enable_asm enable_rasterizer @@ -831,8 +836,6 @@ FONTCONFIG_LIBS HARFBUZZ_CFLAGS HARFBUZZ_LIBS -ENCA_CFLAGS -ENCA_LIBS LIBPNG_CFLAGS LIBPNG_LIBS' @@ -873,6 +876,7 @@ sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1125,6 +1129,15 @@ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1262,7 +1275,7 @@ for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1375,7 +1388,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures libass 0.12.2 to adapt to many kinds of systems. +\`configure' configures libass 0.13.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1415,6 +1428,7 @@ --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -1445,7 +1459,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of libass 0.12.2:";; + short | recursive ) echo "Configuration of libass 0.13.0:";; esac cat <<\_ACEOF @@ -1466,9 +1480,13 @@ --disable-libtool-lock avoid locking (might break parallel builds) --enable-test enable test program (requires libpng) [default=no] --enable-profile enable profiling program [default=no] - --disable-enca disable enca (charset autodetect) support - [default=check] --disable-fontconfig disable fontconfig support [default=enabled] + --disable-directwrite disable DirectWrite support (win32 only) + [default=check] + --disable-coretext disable CoreText support (OSX only) [default=check] + --disable-require-system-font-provider + allow compilation even if no system font provider + was found [default=enabled:>@ --disable-harfbuzz disable HarfBuzz support [default=check] --disable-asm disable compiling with ASM [default=check] --disable-rasterizer disable internal rasterizer [default=enabled] @@ -1517,8 +1535,6 @@ C compiler flags for HARFBUZZ, overriding pkg-config HARFBUZZ_LIBS linker flags for HARFBUZZ, overriding pkg-config - ENCA_CFLAGS C compiler flags for ENCA, overriding pkg-config - ENCA_LIBS linker flags for ENCA, overriding pkg-config LIBPNG_CFLAGS C compiler flags for LIBPNG, overriding pkg-config LIBPNG_LIBS linker flags for LIBPNG, overriding pkg-config @@ -1589,7 +1605,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -libass configure 0.12.2 +libass configure 0.13.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2004,141 +2020,11 @@ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel - -# ac_fn_c_find_intX_t LINENO BITS VAR -# ----------------------------------- -# Finds a signed integer type with width BITS, setting cache variable VAR -# accordingly. -ac_fn_c_find_intX_t () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 -$as_echo_n "checking for int$2_t... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=no" - # Order is important - never check a type that is potentially smaller - # than half of the expected target width. - for ac_type in int$2_t 'int' 'long int' \ - 'long long int' 'short int' 'signed char'; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default - enum { N = $2 / 2 - 1 }; -int -main () -{ -static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default - enum { N = $2 / 2 - 1 }; -int -main () -{ -static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) - < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - case $ac_type in #( - int$2_t) : - eval "$3=yes" ;; #( - *) : - eval "$3=\$ac_type" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - if eval test \"x\$"$3"\" = x"no"; then : - -else - break -fi - done -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_find_intX_t - -# ac_fn_c_find_uintX_t LINENO BITS VAR -# ------------------------------------ -# Finds an unsigned integer type with width BITS, setting cache variable VAR -# accordingly. -ac_fn_c_find_uintX_t () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 -$as_echo_n "checking for uint$2_t... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=no" - # Order is important - never check a type that is potentially smaller - # than half of the expected target width. - for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ - 'unsigned long long int' 'unsigned short int' 'unsigned char'; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - case $ac_type in #( - uint$2_t) : - eval "$3=yes" ;; #( - *) : - eval "$3=\$ac_type" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - if eval test \"x\$"$3"\" = x"no"; then : - -else - break -fi - done -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_find_uintX_t cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by libass $as_me 0.12.2, which was +It was created by libass $as_me 0.13.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2486,7 +2372,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu -am__api_version='1.14' +am__api_version='1.15' ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do @@ -2707,7 +2593,7 @@ $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi -if test x"${install_sh}" != xset; then +if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; @@ -3001,7 +2887,7 @@ # Define the identity of the package. PACKAGE='libass' - VERSION='0.12.2' + VERSION='0.13.0' cat >>confdefs.h <<_ACEOF @@ -3035,8 +2921,8 @@ # mkdir_p='$(MKDIR_P)' -# We need awk for the "check" target. The system "awk" is bad on -# some platforms. +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' @@ -3095,8 +2981,7 @@ fi -# Disable C++/Fortran checks - +# Disable Fortran checks case `pwd` in *\ * | *\ *) @@ -12943,7 +12828,7 @@ fi -for ac_header in inttypes.h stdint.h stdlib.h string.h sys/time.h unistd.h iconv.h +for ac_header in stdint.h iconv.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -12957,196 +12842,79 @@ done -# Checks for typedefs, structures, and compiler characteristics. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 -$as_echo_n "checking for an ANSI C-conforming const... " >&6; } -if ${ac_cv_c_const+:} false; then : +# Checks for library functions. +for ac_func in strdup strndup +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +# Checks for libraries. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing libiconv_open" >&5 +$as_echo_n "checking for library containing libiconv_open... " >&6; } +if ${ac_cv_search_libiconv_open+:} false; then : $as_echo_n "(cached) " >&6 else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char libiconv_open (); int main () { - -#ifndef __cplusplus - /* Ultrix mips cc rejects this sort of thing. */ - typedef int charset[2]; - const charset cs = { 0, 0 }; - /* SunOS 4.1.1 cc rejects this. */ - char const *const *pcpcc; - char **ppc; - /* NEC SVR4.0.2 mips cc rejects this. */ - struct point {int x, y;}; - static struct point const zero = {0,0}; - /* AIX XL C 1.02.0.0 rejects this. - It does not let you subtract one const X* pointer from another in - an arm of an if-expression whose if-part is not a constant - expression */ - const char *g = "string"; - pcpcc = &g + (g ? g-g : 0); - /* HPUX 7.0 cc rejects these. */ - ++pcpcc; - ppc = (char**) pcpcc; - pcpcc = (char const *const *) ppc; - { /* SCO 3.2v4 cc rejects this sort of thing. */ - char tx; - char *t = &tx; - char const *s = 0 ? (char *) 0 : (char const *) 0; - - *t++ = 0; - if (s) return 0; - } - { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ - int x[] = {25, 17}; - const int *foo = &x[0]; - ++foo; - } - { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ - typedef const int *iptr; - iptr p = 0; - ++p; - } - { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying - "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ - struct s { int j; const int *ap[3]; } bx; - struct s *b = &bx; b->j = 5; - } - { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ - const int foo = 10; - if (!foo) return 0; - } - return !cs[0] && !zero.x; -#endif - +return libiconv_open (); ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_const=yes -else - ac_cv_c_const=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 -$as_echo "$ac_cv_c_const" >&6; } -if test $ac_cv_c_const = no; then - -$as_echo "#define const /**/" >>confdefs.h - +for ac_lib in '' iconv; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_libiconv_open=$ac_res fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 -$as_echo_n "checking for inline... " >&6; } -if ${ac_cv_c_inline+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_c_inline=no -for ac_kw in inline __inline__ __inline; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __cplusplus -typedef int foo_t; -static $ac_kw foo_t static_foo () {return 0; } -$ac_kw foo_t foo () {return 0; } -#endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_inline=$ac_kw +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_libiconv_open+:} false; then : + break fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - test "$ac_cv_c_inline" != no && break done - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 -$as_echo "$ac_cv_c_inline" >&6; } - -case $ac_cv_c_inline in - inline | yes) ;; - *) - case $ac_cv_c_inline in - no) ac_val=;; - *) ac_val=$ac_cv_c_inline;; - esac - cat >>confdefs.h <<_ACEOF -#ifndef __cplusplus -#define inline $ac_val -#endif -_ACEOF - ;; -esac - -ac_fn_c_find_intX_t "$LINENO" "64" "ac_cv_c_int64_t" -case $ac_cv_c_int64_t in #( - no|yes) ;; #( - *) - -cat >>confdefs.h <<_ACEOF -#define int64_t $ac_cv_c_int64_t -_ACEOF -;; -esac - -ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = xyes; then : +if ${ac_cv_search_libiconv_open+:} false; then : else - -cat >>confdefs.h <<_ACEOF -#define size_t unsigned int -_ACEOF - + ac_cv_search_libiconv_open=no fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_libiconv_open" >&5 +$as_echo "$ac_cv_search_libiconv_open" >&6; } +ac_res=$ac_cv_search_libiconv_open +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" -ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" -case $ac_cv_c_uint32_t in #( - no|yes) ;; #( - *) - -$as_echo "#define _UINT32_T 1" >>confdefs.h - - -cat >>confdefs.h <<_ACEOF -#define uint32_t $ac_cv_c_uint32_t -_ACEOF -;; - esac - -ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t" -case $ac_cv_c_uint8_t in #( - no|yes) ;; #( - *) - -$as_echo "#define _UINT8_T 1" >>confdefs.h - - -cat >>confdefs.h <<_ACEOF -#define uint8_t $ac_cv_c_uint8_t -_ACEOF -;; - esac - - -# Checks for library functions. -for ac_func in mkdir strcasecmp strdup strndup strtol -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF +$as_echo "#define CONFIG_ICONV 1" >>confdefs.h fi -done - -# Checks for libraries. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing iconv_open" >&5 $as_echo_n "checking for library containing iconv_open... " >&6; } if ${ac_cv_search_iconv_open+:} false; then : @@ -13262,16 +13030,26 @@ enableval=$enable_profile; fi -# Check whether --enable-enca was given. -if test "${enable_enca+set}" = set; then : - enableval=$enable_enca; -fi - # Check whether --enable-fontconfig was given. if test "${enable_fontconfig+set}" = set; then : enableval=$enable_fontconfig; fi +# Check whether --enable-directwrite was given. +if test "${enable_directwrite+set}" = set; then : + enableval=$enable_directwrite; +fi + +# Check whether --enable-coretext was given. +if test "${enable_coretext+set}" = set; then : + enableval=$enable_coretext; +fi + +# Check whether --enable-require-system-font-provider was given. +if test "${enable_require_system_font_provider+set}" = set; then : + enableval=$enable_require_system_font_provider; +fi + # Check whether --enable-harfbuzz was given. if test "${enable_harfbuzz+set}" = set; then : enableval=$enable_harfbuzz; @@ -13711,6 +13489,7 @@ $as_echo "yes" >&6; } CFLAGS="$CFLAGS $FREETYPE_CFLAGS" + CXXFLAGS="$CFLAGS $FREETYPE_CFLAGS" LIBS="$LIBS $FREETYPE_LIBS" $as_echo "#define CONFIG_FREETYPE 1" >>confdefs.h @@ -13876,31 +13655,11 @@ # Put the nasty error message in config.log where it belongs echo "$FONTCONFIG_PKG_ERRORS" >&5 - as_fn_error $? "Package requirements (fontconfig >= 2.4.2) were not met: - -$FONTCONFIG_PKG_ERRORS - -Consider adjusting the PKG_CONFIG_PATH environment variable if you -installed software in a non-standard prefix. - -Alternatively, you may set the environment variables FONTCONFIG_CFLAGS -and FONTCONFIG_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details." "$LINENO" 5 + fontconfig=false elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it -is in your PATH or set the PKG_CONFIG environment variable to the full -path to pkg-config. - -Alternatively, you may set the environment variables FONTCONFIG_CFLAGS -and FONTCONFIG_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details. - -To get pkg-config, see . -See \`config.log' for more details" "$LINENO" 5; } + fontconfig=false else FONTCONFIG_CFLAGS=$pkg_cv_FONTCONFIG_CFLAGS FONTCONFIG_LIBS=$pkg_cv_FONTCONFIG_LIBS @@ -13917,6 +13676,103 @@ fi fi +if test x$enable_coretext != xno; then +OLDLIBS="$LIBS" +# Linking to CoreText directly only works from Mountain Lion and iOS6. In +# earlier OS releases CoreText was part of the ApplicationServices umbrella +# framework. +LIBS="$LIBS -framework CoreText -framework CoreFoundation -framework CoreGraphics" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CORETEXT" >&5 +$as_echo_n "checking for CORETEXT... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include +int +main () +{ +CTFontCreateWithFontDescriptor(NULL, 0.0, NULL); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + +$as_echo "#define CONFIG_CORETEXT 1" >>confdefs.h + + coretext=true + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +else + + LIBS="$OLDLIBS" + coretext=false + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + if test x$coretext = xtrue; then + CORETEXT_TRUE= + CORETEXT_FALSE='#' +else + CORETEXT_TRUE='#' + CORETEXT_FALSE= +fi + + + + +if test x$enable_directwrite != xno; then +# Linking to DirectWrite directly only works from Windows +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for DIRECTWRITE" >&5 +$as_echo_n "checking for DIRECTWRITE... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include +int +main () +{ +; + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + +$as_echo "#define CONFIG_DIRECTWRITE 1" >>confdefs.h + + directwrite=true + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +else + + directwrite=false + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + if test x$directwrite = xtrue; then + DIRECTWRITE_TRUE= + DIRECTWRITE_FALSE='#' +else + DIRECTWRITE_TRUE='#' + DIRECTWRITE_FALSE= +fi + + if test x$enable_harfbuzz != xno; then pkg_failed=no @@ -13998,87 +13854,6 @@ fi fi -if test x$enable_enca != xno; then - -pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ENCA" >&5 -$as_echo_n "checking for ENCA... " >&6; } - -if test -n "$ENCA_CFLAGS"; then - pkg_cv_ENCA_CFLAGS="$ENCA_CFLAGS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"enca\""; } >&5 - ($PKG_CONFIG --exists --print-errors "enca") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_ENCA_CFLAGS=`$PKG_CONFIG --cflags "enca" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried -fi -if test -n "$ENCA_LIBS"; then - pkg_cv_ENCA_LIBS="$ENCA_LIBS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"enca\""; } >&5 - ($PKG_CONFIG --exists --print-errors "enca") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_ENCA_LIBS=`$PKG_CONFIG --libs "enca" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried -fi - - - -if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - -if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then - _pkg_short_errors_supported=yes -else - _pkg_short_errors_supported=no -fi - if test $_pkg_short_errors_supported = yes; then - ENCA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "enca" 2>&1` - else - ENCA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "enca" 2>&1` - fi - # Put the nasty error message in config.log where it belongs - echo "$ENCA_PKG_ERRORS" >&5 - - enca=false -elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - enca=false -else - ENCA_CFLAGS=$pkg_cv_ENCA_CFLAGS - ENCA_LIBS=$pkg_cv_ENCA_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - - CFLAGS="$CFLAGS $ENCA_CFLAGS" - LIBS="$LIBS $ENCA_LIBS" - -$as_echo "#define CONFIG_ENCA 1" >>confdefs.h - - enca=true - -fi -fi - libpng=false if test x$enable_test = xyes; then @@ -14201,9 +13976,6 @@ pkg_libs="-lm" pkg_requires="freetype2 >= 9.10.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.4.2, ${pkg_requires}" fi @@ -14211,6 +13983,17 @@ pkg_requires="harfbuzz >= 0.9.5, ${pkg_requires}" fi +if test x$enable_require_system_font_provider != xno && + test x$fontconfig != xtrue && + test x$directwrite != xtrue && + test x$coretext != xtrue +then + as_fn_error $? "\ +Either DirectWrite (on Windows), CoreText (on OSX), or Fontconfig\ +(Linux, other) is required. If you really want to compile without\ +a system font provider, add --disable-require-system-font-provider" "$LINENO" 5 +fi + PKG_LIBS_DEFAULT=$(test x$enable_shared = xno && echo ${pkg_libs}) PKG_REQUIRES_DEFAULT=$(test x$enable_shared = xno && echo ${pkg_requires}) @@ -14428,6 +14211,14 @@ as_fn_error $? "conditional \"ENABLE_LARGE_TILES\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${CORETEXT_TRUE}" && test -z "${CORETEXT_FALSE}"; then + as_fn_error $? "conditional \"CORETEXT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DIRECTWRITE_TRUE}" && test -z "${DIRECTWRITE_FALSE}"; then + as_fn_error $? "conditional \"DIRECTWRITE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${HAVE_LIBPNG_TRUE}" && test -z "${HAVE_LIBPNG_FALSE}"; then as_fn_error $? "conditional \"HAVE_LIBPNG\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 @@ -14833,7 +14624,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by libass $as_me 0.12.2, which was +This file was extended by libass $as_me 0.13.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -14899,7 +14690,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -libass config.status 0.12.2 +libass config.status 0.13.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -Nru libass-0.12.2/configure.ac libass-0.13.0/configure.ac --- libass-0.12.2/configure.ac 2015-05-07 18:56:28.000000000 +0000 +++ libass-0.13.0/configure.ac 2015-10-03 18:18:46.000000000 +0000 @@ -1,8 +1,7 @@ -AC_INIT(libass, 0.12.2) +AC_INIT(libass, 0.13.0) AM_INIT_AUTOMAKE AC_CONFIG_MACRO_DIR([m4]) -# Disable C++/Fortran checks -define([AC_LIBTOOL_LANG_CXX_CONFIG], [:]) +# Disable Fortran checks define([AC_LIBTOOL_LANG_F77_CONFIG], [:]) LT_INIT AC_CONFIG_SRCDIR([libass/ass.c]) @@ -17,20 +16,13 @@ # 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 +AC_CHECK_HEADERS([stdint.h iconv.h]) # Checks for library functions. -AC_CHECK_FUNCS([mkdir strcasecmp strdup strndup strtol]) +AC_CHECK_FUNCS([strdup strndup]) # Checks for libraries. +AC_SEARCH_LIBS([libiconv_open], [iconv], AC_DEFINE(CONFIG_ICONV, 1, [use iconv])) AC_SEARCH_LIBS([iconv_open], [iconv], AC_DEFINE(CONFIG_ICONV, 1, [use iconv])) AC_CHECK_LIB([m], [fabs]) @@ -39,10 +31,14 @@ [enable test program (requires libpng) @<:@default=no@:>@])) AC_ARG_ENABLE([profile], AS_HELP_STRING([--enable-profile], [enable profiling program @<:@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([directwrite], AS_HELP_STRING([--disable-directwrite], + [disable DirectWrite support (win32 only) @<:@default=check@:>@])) +AC_ARG_ENABLE([coretext], AS_HELP_STRING([--disable-coretext], + [disable CoreText support (OSX only) @<:@default=check@:>@])) +AC_ARG_ENABLE([require-system-font-provider], AS_HELP_STRING([--disable-require-system-font-provider], + [allow compilation even if no system font provider was found @<:@default=enabled:>@])) AC_ARG_ENABLE([harfbuzz], AS_HELP_STRING([--disable-harfbuzz], [disable HarfBuzz support @<:@default=check@:>@])) AC_ARG_ENABLE([asm], AS_HELP_STRING([--disable-asm], @@ -132,6 +128,7 @@ PKG_CHECK_MODULES([FREETYPE], freetype2 >= 9.10.3, [ CFLAGS="$CFLAGS $FREETYPE_CFLAGS" + CXXFLAGS="$CFLAGS $FREETYPE_CFLAGS" LIBS="$LIBS $FREETYPE_LIBS" AC_DEFINE(CONFIG_FREETYPE, 1, [found freetype2 via pkg-config]) ]) @@ -148,8 +145,51 @@ LIBS="$LIBS $FONTCONFIG_LIBS" AC_DEFINE(CONFIG_FONTCONFIG, 1, [found fontconfig via pkg-config]) fontconfig=true - ]) + ], [fontconfig=false]) +fi + +if test x$enable_coretext != xno; then +OLDLIBS="$LIBS" +# Linking to CoreText directly only works from Mountain Lion and iOS6. In +# earlier OS releases CoreText was part of the ApplicationServices umbrella +# framework. +LIBS="$LIBS -framework CoreText -framework CoreFoundation -framework CoreGraphics" +AC_MSG_CHECKING([for CORETEXT]) +AC_LINK_IFELSE([ + AC_LANG_PROGRAM( + [[#include ]], + [[CTFontCreateWithFontDescriptor(NULL, 0.0, NULL);]],) + ], [ + AC_DEFINE(CONFIG_CORETEXT, 1, [found CoreText in System library]) + coretext=true + AC_MSG_RESULT([yes]) + ], [ + LIBS="$OLDLIBS" + coretext=false + AC_MSG_RESULT([no]) + ]) +fi +AM_CONDITIONAL([CORETEXT], [test x$coretext = xtrue]) + + + +if test x$enable_directwrite != xno; then +# Linking to DirectWrite directly only works from Windows +AC_MSG_CHECKING([for DIRECTWRITE]) +AC_LINK_IFELSE([ + AC_LANG_PROGRAM( + [[#include ]], + [[;]],) + ], [ + AC_DEFINE(CONFIG_DIRECTWRITE, 1, [found DirectWrite]) + directwrite=true + AC_MSG_RESULT([yes]) + ], [ + directwrite=false + AC_MSG_RESULT([no]) + ]) fi +AM_CONDITIONAL([DIRECTWRITE], [test x$directwrite = xtrue]) if test x$enable_harfbuzz != xno; then PKG_CHECK_MODULES([HARFBUZZ], harfbuzz >= 0.9.5, [ @@ -160,15 +200,6 @@ ], [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, [ @@ -185,9 +216,6 @@ pkg_libs="-lm" pkg_requires="freetype2 >= 9.10.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.4.2, ${pkg_requires}" fi @@ -195,6 +223,17 @@ pkg_requires="harfbuzz >= 0.9.5, ${pkg_requires}" fi +if test x$enable_require_system_font_provider != xno && + test x$fontconfig != xtrue && + test x$directwrite != xtrue && + test x$coretext != xtrue +then + AC_MSG_ERROR([\ +Either DirectWrite (on Windows), CoreText (on OSX), or Fontconfig\ +(Linux, other) is required. If you really want to compile without\ +a system font provider, add --disable-require-system-font-provider]) +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})]) diff -Nru libass-0.12.2/debian/changelog libass-0.13.0/debian/changelog --- libass-0.12.2/debian/changelog 2015-05-08 12:34:57.000000000 +0000 +++ libass-0.13.0/debian/changelog 2015-12-10 22:54:01.000000000 +0000 @@ -1,21 +1,54 @@ -libass (0.12.2-1~trusty) trusty; urgency=medium +libass (0.13.0-1~trusty) trusty; urgency=medium - * New bug fix release - - Add extern "C" guards to the public headers for C++ compatibility - - Improvements to style override API and implementation - * Bugfixes - - Fix some rasterizer bugs of unknown severity - - Fix a broken memset() of unknown severity - - Make timestamp parsing more lenient, which makes libass accept invalid files accepted by most other ASS parsers - - Increase compatibility with broken ASS drawings accepted by VSFilter + * Fortrusty - -- Doug McMahon Fri, 08 May 2015 08:32:18 -0400 + -- Doug McMahon Thu, 10 Dec 2015 17:53:31 -0500 -libass (0.12.1-1~trusty) trusty; urgency=medium +libass (0.13.0-1~wily) wily; urgency=medium - * For trusty + * For wily test - -- Doug McMahon Mon, 04 May 2015 17:23:51 -0400 + -- Doug McMahon Sun, 06 Dec 2015 11:55:46 -0500 + +libass (0.13.0-1) unstable; urgency=medium + + * New upstream release. + * debian/libass5.symbols: + - Add new symbol. + - Update version of ass_set_fonts. + * debian/copyright: + - Add new copyright holders. + - Update copyright years. + + -- Sebastian Ramacher Mon, 05 Oct 2015 20:55:19 +0200 + +libass (0.12.3-2) unstable; urgency=medium + + [ Thorsten Glaser ] + * Do not depend on yasm on x32 to disable asm. (Closes: #793754) + + [ Sebastian Ramacher ] + * debian/rules: Build with --disable-asm on x32. + + -- Sebastian Ramacher Mon, 27 Jul 2015 18:04:26 +0200 + +libass (0.12.3-1) unstable; urgency=medium + + * New upstream release. + + -- Sebastian Ramacher Sun, 12 Jul 2015 18:08:04 +0200 + +libass (0.12.2-1) unstable; urgency=medium + + * New upstream release. + + -- Sebastian Ramacher Mon, 11 May 2015 20:34:24 +0200 + +libass (0.12.1-2) unstable; urgency=medium + + * Upload to unstable. + + -- Sebastian Ramacher Sat, 25 Apr 2015 10:43:49 +0200 libass (0.12.1-1) experimental; urgency=medium diff -Nru libass-0.12.2/debian/control libass-0.13.0/debian/control --- libass-0.12.2/debian/control 2015-05-04 21:24:54.000000000 +0000 +++ libass-0.13.0/debian/control 2015-07-27 15:57:15.000000000 +0000 @@ -12,8 +12,8 @@ libfreetype6-dev, libfribidi-dev, libharfbuzz-dev, - yasm [any-amd64] -Standards-Version: 3.9.5 + yasm [amd64 kfreebsd-amd64] +Standards-Version: 3.9.6 Section: libs Homepage: https://github.com/libass/libass Vcs-Git: git://anonscm.debian.org/pkg-multimedia/libass.git diff -Nru libass-0.12.2/debian/copyright libass-0.13.0/debian/copyright --- libass-0.12.2/debian/copyright 2014-11-11 15:10:46.000000000 +0000 +++ libass-0.13.0/debian/copyright 2015-10-05 18:55:00.000000000 +0000 @@ -5,28 +5,31 @@ Files: * Copyright: - 2009-2011 Grigori Goronzy - 2006 Evgeniy Stepanov - 2013 Rodget combs + 2009-2011,2015 Grigori Goronzy + 2006 Evgeniy Stepanov + 2013 Rodger Combs + 2015 Oleg Oshmyan + 2015 Stephan Vedder + 2015 Vabishchevich Nikolay + 2011-2014 Yu Zhuohuang License: ISC Files: libass/ass_strtod.c Copyright: - 1994 Sun Microsystems, Inc - 1988-1993 The Regents of the University of California + 1994 Sun Microsystems, Inc + 1988-1993 The Regents of the University of California License: other-1 Files: ltmain.sh Copyright: - 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, - 2005, 2006, 2007 2008 Free Software Foundation, Inc + 1996-2008 Free Software Foundation, Inc License: GPL-2+ Files: debian/* Copyright: - 2011-2013 Alessio Treglia - 2008 Christophe Mutricy , - 2014 Sebastian Ramacher + 2011-2013 Alessio Treglia + 2008 Christophe Mutricy , + 2014-2015 Sebastian Ramacher License: GPL-2+ License: ISC diff -Nru libass-0.12.2/debian/libass5.symbols libass-0.13.0/debian/libass5.symbols --- libass-0.12.2/debian/libass5.symbols 2014-11-11 15:12:58.000000000 +0000 +++ libass-0.13.0/debian/libass5.symbols 2015-10-05 18:45:03.000000000 +0000 @@ -8,6 +8,7 @@ ass_free_event@Base 0.10.2 ass_free_style@Base 0.10.2 ass_free_track@Base 0.10.2 + ass_get_available_font_providers@Base 0.13.0 ass_library_done@Base 0.10.2 ass_library_init@Base 0.10.2 ass_library_version@Base 0.12.0 @@ -26,7 +27,7 @@ ass_set_cache_limits@Base 0.10.2 ass_set_extract_fonts@Base 0.10.2 ass_set_font_scale@Base 0.10.2 - ass_set_fonts@Base 0.10.2 + ass_set_fonts@Base 0.13.0 ass_set_fonts_dir@Base 0.10.2 ass_set_frame_size@Base 0.10.2 ass_set_hinting@Base 0.10.2 diff -Nru libass-0.12.2/debian/rules libass-0.13.0/debian/rules --- libass-0.12.2/debian/rules 2014-11-11 15:19:09.000000000 +0000 +++ libass-0.13.0/debian/rules 2015-07-27 16:01:01.000000000 +0000 @@ -1,7 +1,13 @@ #!/usr/bin/make -f -export V=1 export DEB_LDFLAGS_MAINT_APPEND=-Wl,--as-needed %: dh $@ --parallel --with autoreconf + +override_dh_auto_configure: +ifeq (,$(filter-out x32,$(shell dpkg-architecture -qDEB_HOST_ARCH))) + dh_auto_configure -- --disable-asm +else + dh_auto_configure +endif diff -Nru libass-0.12.2/depcomp libass-0.13.0/depcomp --- libass-0.12.2/depcomp 2015-05-07 19:47:27.000000000 +0000 +++ libass-0.13.0/depcomp 2015-09-07 12:54:16.000000000 +0000 @@ -3,7 +3,7 @@ scriptversion=2013-05-30.07; # UTC -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff -Nru libass-0.12.2/install-sh libass-0.13.0/install-sh --- libass-0.12.2/install-sh 2015-05-07 19:47:27.000000000 +0000 +++ libass-0.13.0/install-sh 2015-09-07 12:54:15.000000000 +0000 @@ -1,7 +1,7 @@ #!/bin/sh # install - install a program, script, or datafile -scriptversion=2011-11-20.07; # UTC +scriptversion=2014-09-12.12; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the @@ -41,19 +41,15 @@ # This script is compatible with the BSD install script, but was written # from scratch. +tab=' ' nl=' ' -IFS=" "" $nl" +IFS=" $tab$nl" -# set DOITPROG to echo to test this script +# Set DOITPROG to "echo" to test this script. -# Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} -if test -z "$doit"; then - doit_exec=exec -else - doit_exec=$doit -fi +doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. @@ -68,17 +64,6 @@ rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} -posix_glob='?' -initialize_posix_glob=' - test "$posix_glob" != "?" || { - if (set -f) 2>/dev/null; then - posix_glob= - else - posix_glob=: - fi - } -' - posix_mkdir= # Desired mode of installed file. @@ -97,7 +82,7 @@ dst_arg= copy_on_change=false -no_target_directory= +is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE @@ -137,46 +122,57 @@ -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" - shift;; + shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 - case $mode in - *' '* | *' '* | *' -'* | *'*'* | *'?'* | *'['*) - echo "$0: invalid mode: $mode" >&2 - exit 1;; - esac - shift;; + case $mode in + *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; -o) chowncmd="$chownprog $2" - shift;; + shift;; -s) stripcmd=$stripprog;; - -t) dst_arg=$2 - # Protect names problematic for 'test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - shift;; + -t) + is_target_a_directory=always + dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; - -T) no_target_directory=true;; + -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; - --) shift - break;; + --) shift + break;; - -*) echo "$0: invalid option: $1" >&2 - exit 1;; + -*) echo "$0: invalid option: $1" >&2 + exit 1;; *) break;; esac shift done +# We allow the use of options -d and -T together, by making -d +# take the precedence; this is for compatibility with GNU install. + +if test -n "$dir_arg"; then + if test -n "$dst_arg"; then + echo "$0: target directory not allowed when installing a directory." >&2 + exit 1 + fi +fi + if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. @@ -208,6 +204,15 @@ fi if test -z "$dir_arg"; then + if test $# -gt 1 || test "$is_target_a_directory" = always; then + if test ! -d "$dst_arg"; then + echo "$0: $dst_arg: Is not a directory." >&2 + exit 1 + fi + fi +fi + +if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 @@ -223,16 +228,16 @@ *[0-7]) if test -z "$stripcmd"; then - u_plus_rw= + u_plus_rw= else - u_plus_rw='% 200' + u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then - u_plus_rw= + u_plus_rw= else - u_plus_rw=,u+rw + u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac @@ -269,41 +274,15 @@ # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then - if test -n "$no_target_directory"; then - echo "$0: $dst_arg: Is a directory" >&2 - exit 1 + if test "$is_target_a_directory" = never; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else - # Prefer dirname, but fall back on a substitute if dirname fails. - dstdir=` - (dirname "$dst") 2>/dev/null || - expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$dst" : 'X\(//\)[^/]' \| \ - X"$dst" : 'X\(//\)$' \| \ - X"$dst" : 'X\(/\)' \| . 2>/dev/null || - echo X"$dst" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q' - ` - + dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi @@ -314,74 +293,81 @@ if test $dstdir_status != 0; then case $posix_mkdir in '') - # Create intermediate dirs using mode 755 as modified by the umask. - # This is like FreeBSD 'install' as of 1997-10-28. - umask=`umask` - case $stripcmd.$umask in - # Optimize common cases. - *[2367][2367]) mkdir_umask=$umask;; - .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; - - *[0-7]) - mkdir_umask=`expr $umask + 22 \ - - $umask % 100 % 40 + $umask % 20 \ - - $umask % 10 % 4 + $umask % 2 - `;; - *) mkdir_umask=$umask,go-w;; - esac - - # With -d, create the new directory with the user-specified mode. - # Otherwise, rely on $mkdir_umask. - if test -n "$dir_arg"; then - mkdir_mode=-m$mode - else - mkdir_mode= - fi - - posix_mkdir=false - case $umask in - *[123567][0-7][0-7]) - # POSIX mkdir -p sets u+wx bits regardless of umask, which - # is incompatible with FreeBSD 'install' when (umask & 300) != 0. - ;; - *) - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 - - if (umask $mkdir_umask && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - ls_ld_tmpdir=`ls -ld "$tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/d" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null - fi - trap '' 0;; - esac;; + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + # $RANDOM is not portable (e.g. dash); use it when possible to + # lower collision chance + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 + + # As "mkdir -p" follows symlinks and we work in /tmp possibly; so + # create the $tmpdir first (and fail if unsuccessful) to make sure + # that nobody tries to guess the $tmpdir name. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null + fi + trap '' 0;; + esac;; esac if $posix_mkdir && ( - umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else @@ -391,53 +377,51 @@ # directory the slow way, step by step, checking for races as we go. case $dstdir in - /*) prefix='/';; - [-=\(\)!]*) prefix='./';; - *) prefix='';; + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; esac - eval "$initialize_posix_glob" - oIFS=$IFS IFS=/ - $posix_glob set -f + set -f set fnord $dstdir shift - $posix_glob set +f + set +f IFS=$oIFS prefixes= for d do - test X"$d" = X && continue + test X"$d" = X && continue - prefix=$prefix$d - if test -d "$prefix"; then - prefixes= - else - if $posix_mkdir; then - (umask=$mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break - # Don't fail if two instances are running concurrently. - test -d "$prefix" || exit 1 - else - case $prefix in - *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; - *) qprefix=$prefix;; - esac - prefixes="$prefixes '$qprefix'" - fi - fi - prefix=$prefix/ + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ done if test -n "$prefixes"; then - # Don't fail if two instances are running concurrently. - (umask $mkdir_umask && - eval "\$doit_exec \$mkdirprog $prefixes") || - test -d "$dstdir" || exit 1 - obsolete_mkdir_used=true + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true fi fi fi @@ -472,15 +456,12 @@ # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && - old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && - new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && - - eval "$initialize_posix_glob" && - $posix_glob set -f && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && - $posix_glob set +f && - + set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then @@ -493,24 +474,24 @@ # to itself, or perhaps because mv is so ancient that it does not # support -f. { - # Now remove or move aside any old file at destination location. - # We try this two ways since rm can't unlink itself on some - # systems and the destination file might be busy for other - # reasons. In this case, the final cleanup might fail but the new - # file should still install successfully. - { - test ! -f "$dst" || - $doit $rmcmd -f "$dst" 2>/dev/null || - { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } - } || - { echo "$0: cannot unlink or rename $dst" >&2 - (exit 1); exit 1 - } - } && + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && - # Now rename the file to the real destination. - $doit $mvcmd "$dsttmp" "$dst" + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 diff -Nru libass-0.12.2/libass/ass_bitmap.c libass-0.13.0/libass/ass_bitmap.c --- libass-0.12.2/libass/ass_bitmap.c 2015-03-06 12:23:04.000000000 +0000 +++ libass-0.13.0/libass/ass_bitmap.c 2015-09-24 08:34:34.000000000 +0000 @@ -19,6 +19,7 @@ */ #include "config.h" +#include "ass_compat.h" #include #include @@ -33,122 +34,57 @@ #include "ass_bitmap.h" #include "ass_render.h" -#if (defined(__i386__) || defined(__x86_64__)) && CONFIG_ASM -#include "x86/be_blur.h" -#endif - -static const unsigned base = 256; - -struct ass_synth_priv { - size_t tmp_allocated; - void *tmp; - - int g_r; - int g_w; - double *g0; - unsigned *g; - unsigned *gt2; - - double radius; - - BEBlurFunc be_blur_func; -}; - -static bool 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 (radius < 0) - return false; - if (radius + 2.0 > INT_MAX / 2) - radius = INT_MAX / 2; - - if (priv->radius == radius) - return true; - else - priv->radius = radius; - - priv->g_r = ceil(radius); - priv->g_w = 2 * priv->g_r + 1; - - if (priv->g_r) { - priv->g0 = ass_realloc_array(priv->g0, priv->g_w, sizeof(double)); - priv->g = ass_realloc_array(priv->g, priv->g_w, sizeof(unsigned)); - priv->gt2 = ass_realloc_array(priv->gt2, priv->g_w, 256 * sizeof(unsigned)); - if (!priv->g || !priv->g0 || !priv->gt2) { - free(priv->g0); - free(priv->g); - free(priv->gt2); - return false; - } - } - - if (priv->g_r) { - // exact gaussian curve - for (i = 0; i < priv->g_w; ++i) { - priv->g0[i] = exp(A * (i - priv->g_r) * (i - priv->g_r)); - } - - // integer gaussian curve with volume = 65536 - 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) (priv->g0[i] * volume_factor + .5); - volume += priv->g[i]; - } - if (volume > 65536) - volume_factor -= volume_diff; - } - volume = 0; - for (i = 0; i < priv->g_w; ++i) { - priv->g[i] = (unsigned) (priv->g0[i] * volume_factor + .5); - volume += priv->g[i]; - } +#define ALIGN C_ALIGN_ORDER +#define DECORATE(func) ass_##func##_c +#include "ass_func_template.h" +#undef ALIGN +#undef DECORATE - // 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]; - } - } - } +#if (defined(__i386__) || defined(__x86_64__)) && CONFIG_ASM - return true; -} +#define ALIGN 4 +#define DECORATE(func) ass_##func##_sse2 +#include "ass_func_template.h" +#undef ALIGN +#undef DECORATE + +#define ALIGN 5 +#define DECORATE(func) ass_##func##_avx2 +#include "ass_func_template.h" +#undef ALIGN +#undef DECORATE -static bool resize_tmp(ASS_SynthPriv *priv, int w, int h) -{ - if (w >= INT_MAX || (w + 1) > SIZE_MAX / 2 / sizeof(unsigned) / FFMAX(h, 1)) - return false; - size_t needed = sizeof(unsigned) * (w + 1) * h; - if (priv->tmp && priv->tmp_allocated >= needed) - return true; +#endif - ass_aligned_free(priv->tmp); - priv->tmp_allocated = FFMAX(needed, priv->tmp_allocated * 2); - priv->tmp = ass_aligned_alloc(32, priv->tmp_allocated); - return !!priv->tmp; -} -void ass_synth_blur(ASS_SynthPriv *priv_blur, int opaque_box, int be, +void ass_synth_blur(const BitmapEngine *engine, int opaque_box, int be, double blur_radius, Bitmap *bm_g, Bitmap *bm_o) { - if(blur_radius > 0.0 || be){ - if (bm_o && !resize_tmp(priv_blur, bm_o->w, bm_o->h)) - return; - if ((!bm_o || opaque_box) && !resize_tmp(priv_blur, bm_g->w, bm_g->h)) - return; + bool blur_g = !bm_o || opaque_box; + if (blur_g && !bm_g) + return; + + // Apply gaussian blur + double r2 = blur_radius * blur_radius / log(256); + if (r2 > 0.001) { + if (bm_o) + ass_gaussian_blur(engine, bm_o, r2); + if (blur_g) + ass_gaussian_blur(engine, bm_g, r2); } // Apply box blur (multiple passes, if requested) if (be) { - uint16_t* tmp = priv_blur->tmp; + size_t size_o = 0, size_g = 0; + if (bm_o) + size_o = sizeof(uint16_t) * bm_o->stride * 2; + if (blur_g) + size_g = sizeof(uint16_t) * bm_g->stride * 2; + size_t size = FFMAX(size_o, size_g); + uint16_t *tmp = size ? ass_aligned_alloc(32, size) : NULL; + if (!tmp) + return; if (bm_o) { unsigned passes = be; unsigned w = bm_o->w; @@ -156,108 +92,89 @@ unsigned stride = bm_o->stride; unsigned char *buf = bm_o->buffer; if(w && h){ - while(passes--){ - memset(tmp, 0, stride * 2); - if(w < 16){ - be_blur_c(buf, w, h, stride, tmp); - }else{ - priv_blur->be_blur_func(buf, w, h, stride, tmp); + if(passes > 1){ + be_blur_pre(buf, w, h, stride); + while(--passes){ + memset(tmp, 0, stride * 2); + engine->be_blur(buf, w, h, stride, tmp); } + be_blur_post(buf, w, h, stride); } + memset(tmp, 0, stride * 2); + engine->be_blur(buf, w, h, stride, tmp); } } - if (!bm_o || opaque_box) { + if (blur_g) { unsigned passes = be; unsigned w = bm_g->w; unsigned h = bm_g->h; unsigned stride = bm_g->stride; unsigned char *buf = bm_g->buffer; if(w && h){ - while(passes--){ - memset(tmp, 0, stride * 2); - priv_blur->be_blur_func(buf, w, h, stride, tmp); + if(passes > 1){ + be_blur_pre(buf, w, h, stride); + while(--passes){ + memset(tmp, 0, stride * 2); + engine->be_blur(buf, w, h, stride, tmp); + } + be_blur_post(buf, w, h, stride); } + memset(tmp, 0, stride * 2); + engine->be_blur(buf, w, h, stride, tmp); } } - } - - // Apply gaussian blur - if (blur_radius > 0.0 && 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, - priv_blur->gt2, priv_blur->g_r, - priv_blur->g_w); - if (!bm_o || opaque_box) - ass_gauss_blur(bm_g->buffer, priv_blur->tmp, - bm_g->w, bm_g->h, bm_g->stride, - priv_blur->gt2, priv_blur->g_r, - priv_blur->g_w); + ass_aligned_free(tmp); } } -ASS_SynthPriv *ass_synth_init(double radius) +static bool alloc_bitmap_buffer(const BitmapEngine *engine, Bitmap *bm, int w, int h) { - ASS_SynthPriv *priv = calloc(1, sizeof(ASS_SynthPriv)); - if (!priv || !generate_tables(priv, radius)) { - free(priv); - return NULL; - } - #if (defined(__i386__) || defined(__x86_64__)) && CONFIG_ASM - int avx2 = has_avx2(); - #ifdef __x86_64__ - priv->be_blur_func = avx2 ? ass_be_blur_avx2 : ass_be_blur_sse2; - #else - priv->be_blur_func = be_blur_c; - #endif - #else - priv->be_blur_func = be_blur_c; - #endif - return priv; -} - -void ass_synth_done(ASS_SynthPriv *priv) -{ - ass_aligned_free(priv->tmp); - free(priv->g0); - free(priv->g); - free(priv->gt2); - free(priv); -} - -static Bitmap *alloc_bitmap_raw(int w, int h) -{ - Bitmap *bm; - - unsigned align = (w >= 32) ? 32 : ((w >= 16) ? 16 : 1); + unsigned align = 1 << engine->align_order; size_t s = ass_align(align, w); // Too often we use ints as offset for bitmaps => use INT_MAX. if (s > (INT_MAX - 32) / FFMAX(h, 1)) - return NULL; - bm = malloc(sizeof(Bitmap)); + return false; + uint8_t *buf = ass_aligned_alloc(align, s * h + 32); + if (!buf) + return false; + bm->w = w; + bm->h = h; + bm->stride = s; + bm->buffer = buf; + return true; +} + +static Bitmap *alloc_bitmap_raw(const BitmapEngine *engine, int w, int h) +{ + Bitmap *bm = malloc(sizeof(Bitmap)); if (!bm) return NULL; - bm->buffer = ass_aligned_alloc(align, s * h + 32); - if (!bm->buffer) { + if (!alloc_bitmap_buffer(engine, bm, w, h)) { free(bm); return NULL; } - bm->w = w; - bm->h = h; - bm->stride = s; - bm->left = bm->top = 0; return bm; } -Bitmap *alloc_bitmap(int w, int h) +Bitmap *alloc_bitmap(const BitmapEngine *engine, int w, int h) { - Bitmap *bm = alloc_bitmap_raw(w, h); + Bitmap *bm = alloc_bitmap_raw(engine, w, h); if(!bm) return NULL; memset(bm->buffer, 0, bm->stride * bm->h + 32); + bm->left = bm->top = 0; return bm; } +bool realloc_bitmap(const BitmapEngine *engine, Bitmap *bm, int w, int h) +{ + uint8_t *old = bm->buffer; + if (!alloc_bitmap_buffer(engine, bm, w, h)) + return false; + ass_aligned_free(old); + return true; +} + void ass_free_bitmap(Bitmap *bm) { if (bm) @@ -265,9 +182,9 @@ free(bm); } -Bitmap *copy_bitmap(const Bitmap *src) +Bitmap *copy_bitmap(const BitmapEngine *engine, const Bitmap *src) { - Bitmap *dst = alloc_bitmap_raw(src->w, src->h); + Bitmap *dst = alloc_bitmap_raw(engine, src->w, src->h); if (!dst) return NULL; dst->left = src->left; @@ -281,7 +198,7 @@ Bitmap *outline_to_bitmap(ASS_Renderer *render_priv, ASS_Outline *outline, int bord) { - ASS_Rasterizer *rst = &render_priv->rasterizer; + RasterizerData *rst = &render_priv->rasterizer; if (!rasterizer_set_outline(rst, outline)) { ass_msg(render_priv->library, MSGL_WARN, "Failed to process glyph outline!\n"); return NULL; @@ -291,7 +208,7 @@ return NULL; if (rst->x_min >= rst->x_max || rst->y_min >= rst->y_max) { - Bitmap *bm = alloc_bitmap(2 * bord, 2 * bord); + Bitmap *bm = alloc_bitmap(render_priv->engine, 2 * bord, 2 * bord); if (!bm) return NULL; bm->left = bm->top = -bord; @@ -308,7 +225,7 @@ int w = x_max - x_min; int h = y_max - y_min; - int mask = (1 << rst->tile_order) - 1; + int mask = (1 << render_priv->engine->tile_order) - 1; if (w < 0 || h < 0 || w > 8000000 / FFMAX(h, 1) || w > INT_MAX - (2 * bord + mask) || h > INT_MAX - (2 * bord + mask)) { @@ -319,13 +236,13 @@ int tile_w = (w + 2 * bord + mask) & ~mask; int tile_h = (h + 2 * bord + mask) & ~mask; - Bitmap *bm = alloc_bitmap_raw(tile_w, tile_h); + Bitmap *bm = alloc_bitmap_raw(render_priv->engine, tile_w, tile_h); if (!bm) return NULL; bm->left = x_min - bord; bm->top = y_min - bord; - if (!rasterizer_fill(rst, bm->buffer, + if (!rasterizer_fill(render_priv->engine, rst, bm->buffer, x_min - bord, y_min - bord, bm->stride, tile_h, bm->stride)) { ass_msg(render_priv->library, MSGL_WARN, "Failed to rasterize glyph!\n"); @@ -349,7 +266,7 @@ FT_Outline_Get_CBox(outline, &bbox); if (bbox.xMin >= bbox.xMax || bbox.yMin >= bbox.yMax) { - bm = alloc_bitmap(2 * bord, 2 * bord); + bm = alloc_bitmap(render_priv->engine, 2 * bord, 2 * bord); if (!bm) return NULL; bm->left = bm->top = -bord; @@ -379,7 +296,7 @@ } // allocate and set up bitmap - bm = alloc_bitmap(w + 2 * bord, h + 2 * bord); + bm = alloc_bitmap(render_priv->engine, w + 2 * bord, h + 2 * bord); if (!bm) return NULL; bm->left = bbox.xMin - bord; @@ -507,166 +424,48 @@ } } -/* - * Gaussian blur. An fast pure C implementation from MPlayer. - */ -void ass_gauss_blur(unsigned char *buffer, unsigned *tmp2, - int width, int height, int stride, - unsigned *m2, int r, int mwidth) -{ - - int x, y; - - unsigned char *s = buffer; - unsigned *t = tmp2 + 1; - for (y = 0; y < height; y++) { - memset(t - 1, 0, (width + 1) * sizeof(unsigned)); - t[-1] = 32768; - - for (x = 0; x < r; x++) { - const int src = s[x]; - if (src) { - register unsigned *dstp = t + x - r; - int mx; - unsigned *m3 = 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 *dstp = t + x - r; - int mx; - unsigned *m3 = 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 *dstp = t + x - r; - int mx; - const int x2 = r + width - x; - unsigned *m3 = 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 *srcp = t + y * (width + 1) + 1; - int src = *srcp; - if (src) { - register unsigned *dstp = srcp - 1 - y * (width + 1); - const int src2 = (src + 32768) >> 16; - unsigned *m3 = m2 + src2 * mwidth; - - int mx; - *srcp = 32768; - for (mx = r - y; mx < mwidth; mx++) { - *dstp += m3[mx]; - dstp += width + 1; - } - } - } - for (; y < height - r; y++) { - unsigned *srcp = t + y * (width + 1) + 1; - int src = *srcp; - if (src) { - register unsigned *dstp = srcp - 1 - r * (width + 1); - const int src2 = (src + 32768) >> 16; - unsigned *m3 = m2 + src2 * mwidth; - - int mx; - *srcp = 32768; - for (mx = 0; mx < mwidth; mx++) { - *dstp += m3[mx]; - dstp += width + 1; - } - } - } - for (; y < height; y++) { - unsigned *srcp = t + y * (width + 1) + 1; - int src = *srcp; - if (src) { - const int y2 = r + height - y; - register unsigned *dstp = srcp - 1 - r * (width + 1); - const int src2 = (src + 32768) >> 16; - unsigned *m3 = m2 + src2 * mwidth; - - int mx; - *srcp = 32768; - 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] >> 16; - } - s += stride; - t += width + 1; - } -} - /** - * \brief Blur with [[1,2,1]. [2,4,2], [1,2,1]] kernel + * \brief Blur with [[1,2,1], [2,4,2], [1,2,1]] kernel * This blur is the same as the one employed by vsfilter. * Pure C implementation. */ -void be_blur_c(uint8_t *buf, intptr_t w, - intptr_t h, intptr_t stride, - uint16_t *tmp) +void ass_be_blur_c(uint8_t *buf, intptr_t w, intptr_t h, + intptr_t stride, uint16_t *tmp) { - unsigned short *col_pix_buf = tmp; - unsigned short *col_sum_buf = tmp + w * sizeof(unsigned short); + uint16_t *col_pix_buf = tmp; + uint16_t *col_sum_buf = tmp + w; unsigned x, y, old_pix, old_sum, temp1, temp2; - unsigned char *src, *dst; - memset(col_pix_buf, 0, w * sizeof(unsigned short)); - memset(col_sum_buf, 0, w * sizeof(unsigned short)); + uint8_t *src, *dst; + memset(tmp, 0, sizeof(uint16_t) * w * 2); + y = 0; + { - y = 0; src=buf+y*stride; - x = 2; + x = 1; old_pix = src[x-1]; - old_sum = old_pix + src[x-2]; + old_sum = old_pix; for ( ; x < w; x++) { temp1 = src[x]; temp2 = old_pix + temp1; old_pix = temp1; temp1 = old_sum + temp2; old_sum = temp2; - col_pix_buf[x] = temp1; + col_pix_buf[x-1] = temp1; + col_sum_buf[x-1] = temp1; } + temp1 = old_sum + old_pix; + col_pix_buf[x-1] = temp1; + col_sum_buf[x-1] = temp1; } - { - y = 1; + + for (y++; y < h; y++) { src=buf+y*stride; + dst=buf+(y-1)*stride; - x = 2; + x = 1; old_pix = src[x-1]; - old_sum = old_pix + src[x-2]; + old_sum = old_pix; for ( ; x < w; x++) { temp1 = src[x]; temp2 = old_pix + temp1; @@ -674,34 +473,83 @@ temp1 = old_sum + temp2; old_sum = temp2; - temp2 = col_pix_buf[x] + temp1; - col_pix_buf[x] = temp1; - col_sum_buf[x] = temp2; - } + temp2 = col_pix_buf[x-1] + temp1; + col_pix_buf[x-1] = temp1; + dst[x-1] = (col_sum_buf[x-1] + temp2) >> 4; + col_sum_buf[x-1] = temp2; + } + temp1 = old_sum + old_pix; + temp2 = col_pix_buf[x-1] + temp1; + col_pix_buf[x-1] = temp1; + dst[x-1] = (col_sum_buf[x-1] + temp2) >> 4; + col_sum_buf[x-1] = temp2; } - for (y = 2; y < h; y++) { - src=buf+y*stride; + { dst=buf+(y-1)*stride; + for (x = 0; x < w; x++) + dst[x] = (col_sum_buf[x] + col_pix_buf[x]) >> 4; + } +} - x = 2; - old_pix = src[x-1]; - old_sum = old_pix + src[x-2]; - for ( ; x < w; x++) { - temp1 = src[x]; - temp2 = old_pix + temp1; - old_pix = temp1; - temp1 = old_sum + temp2; - old_sum = temp2; +void be_blur_pre(uint8_t *buf, intptr_t w, intptr_t h, intptr_t stride) +{ + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + // This is equivalent to (value * 64 + 127) / 255 for all + // values from 0 to 256 inclusive. Assist vectorizing + // compilers by noting that all temporaries fit in 8 bits. + buf[y * stride + x] = + (uint8_t) ((buf[y * stride + x] >> 1) + 1) >> 1; + } + } +} - temp2 = col_pix_buf[x] + temp1; - col_pix_buf[x] = temp1; - dst[x-1] = (col_sum_buf[x] + temp2) >> 4; - col_sum_buf[x] = temp2; +void be_blur_post(uint8_t *buf, intptr_t w, intptr_t h, intptr_t stride) +{ + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + // This is equivalent to (value * 255 + 32) / 64 for all values + // from 0 to 96 inclusive, and we only care about 0 to 64. + uint8_t value = buf[y * stride + x]; + buf[y * stride + x] = (value << 2) - (value > 32); } } } +/* + * To find these values, simulate blur on the border between two + * half-planes, one zero-filled (background) and the other filled + * with the maximum supported value (foreground). Keep incrementing + * the \be argument. The necessary padding is the distance by which + * the blurred foreground image extends beyond the original border + * and into the background. Initially it increases along with \be, + * but very soon it grinds to a halt. At some point, the blurred + * image actually reaches a stationary point and stays unchanged + * forever after, simply _shifting_ by one pixel for each \be + * step--moving in the direction of the non-zero half-plane and + * thus decreasing the necessary padding (although the large + * padding is still needed for intermediate results). In practice, + * images are finite rather than infinite like half-planes, but + * this can only decrease the required padding. Half-planes filled + * with extreme values are the theoretical limit of the worst case. + * Make sure to use the right pixel value range in the simulation! + */ +int be_padding(int be) +{ + if (be <= 3) + return be; + if (be <= 7) + return 4; + if (be <= 123) + return 5; + return FFMAX(128 - be, 0); +} + int outline_to_bitmap2(ASS_Renderer *render_priv, ASS_Outline *outline, ASS_Outline *border, Bitmap **bm_g, Bitmap **bm_o) @@ -729,9 +577,9 @@ * \brief Add two bitmaps together at a given position * Uses additive blending, clipped to [0,255]. Pure C implementation. */ -void add_bitmaps_c(uint8_t *dst, intptr_t dst_stride, - uint8_t *src, intptr_t src_stride, - intptr_t height, intptr_t width) +void ass_add_bitmaps_c(uint8_t *dst, intptr_t dst_stride, + uint8_t *src, intptr_t src_stride, + intptr_t height, intptr_t width) { unsigned out; uint8_t* end = dst + dst_stride * height; @@ -745,9 +593,9 @@ } } -void sub_bitmaps_c(uint8_t *dst, intptr_t dst_stride, - uint8_t *src, intptr_t src_stride, - intptr_t height, intptr_t width) +void ass_sub_bitmaps_c(uint8_t *dst, intptr_t dst_stride, + uint8_t *src, intptr_t src_stride, + intptr_t height, intptr_t width) { short out; uint8_t* end = dst + dst_stride * height; @@ -761,10 +609,10 @@ } } -void mul_bitmaps_c(uint8_t *dst, intptr_t dst_stride, - uint8_t *src1, intptr_t src1_stride, - uint8_t *src2, intptr_t src2_stride, - intptr_t w, intptr_t h) +void ass_mul_bitmaps_c(uint8_t *dst, intptr_t dst_stride, + uint8_t *src1, intptr_t src1_stride, + uint8_t *src2, intptr_t src2_stride, + intptr_t w, intptr_t h) { uint8_t* end = src1 + src1_stride * h; while (src1 < end) { diff -Nru libass-0.12.2/libass/ass_bitmap.h libass-0.13.0/libass/ass_bitmap.h --- libass-0.12.2/libass/ass_bitmap.h 2015-03-06 12:23:04.000000000 +0000 +++ libass-0.13.0/libass/ass_bitmap.h 2015-07-07 18:25:48.000000000 +0000 @@ -19,15 +19,76 @@ #ifndef LIBASS_BITMAP_H #define LIBASS_BITMAP_H +#include #include #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); +struct segment; +typedef void (*FillSolidTileFunc)(uint8_t *buf, ptrdiff_t stride, int set); +typedef void (*FillHalfplaneTileFunc)(uint8_t *buf, ptrdiff_t stride, + int32_t a, int32_t b, int64_t c, int32_t scale); +typedef void (*FillGenericTileFunc)(uint8_t *buf, ptrdiff_t stride, + const struct segment *line, size_t n_lines, + int winding); + +typedef void (*BitmapBlendFunc)(uint8_t *dst, intptr_t dst_stride, + uint8_t *src, intptr_t src_stride, + intptr_t height, intptr_t width); +typedef void (*BitmapMulFunc)(uint8_t *dst, intptr_t dst_stride, + uint8_t *src1, intptr_t src1_stride, + uint8_t *src2, intptr_t src2_stride, + intptr_t width, intptr_t height); + +typedef void (*BeBlurFunc)(uint8_t *buf, intptr_t w, intptr_t h, + intptr_t stride, uint16_t *tmp); + +// intermediate bitmaps represented as sets of verical stripes of int16_t[alignment / 2] +typedef void (*Convert8to16Func)(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, + uintptr_t width, uintptr_t height); +typedef void (*Convert16to8Func)(uint8_t *dst, ptrdiff_t dst_stride, const int16_t *src, + uintptr_t width, uintptr_t height); +typedef void (*FilterFunc)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height); +typedef void (*ParamFilterFunc)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height, + const int16_t *param); + +#define C_ALIGN_ORDER 5 + +typedef struct { + int align_order; // log2(alignment) + + // rasterizer functions +#if CONFIG_RASTERIZER + int tile_order; // log2(tile_size) + FillSolidTileFunc fill_solid; + FillHalfplaneTileFunc fill_halfplane; + FillGenericTileFunc fill_generic; +#endif + + // blend functions + BitmapBlendFunc add_bitmaps, sub_bitmaps; + BitmapMulFunc mul_bitmaps; + + // be blur function + BeBlurFunc be_blur; + + // gaussian blur functions + Convert8to16Func stripe_unpack; + Convert16to8Func stripe_pack; + FilterFunc shrink_horz, shrink_vert; + FilterFunc expand_horz, expand_vert; + FilterFunc pre_blur_horz[3], pre_blur_vert[3]; + ParamFilterFunc main_blur_horz[3], main_blur_vert[3]; +} BitmapEngine; + +extern const BitmapEngine ass_bitmap_engine_c; +extern const BitmapEngine ass_bitmap_engine_sse2; +extern const BitmapEngine ass_bitmap_engine_avx2; + typedef struct { size_t n_contours, max_contours; @@ -46,12 +107,15 @@ unsigned char *buffer; // h * stride buffer } Bitmap; +Bitmap *alloc_bitmap(const BitmapEngine *engine, int w, int h); +bool realloc_bitmap(const BitmapEngine *engine, Bitmap *bm, int w, int h); +Bitmap *copy_bitmap(const BitmapEngine *engine, const Bitmap *src); +void ass_free_bitmap(Bitmap *bm); + Bitmap *outline_to_bitmap(ASS_Renderer *render_priv, ASS_Outline *outline, int bord); -Bitmap *alloc_bitmap(int w, int h); - -void ass_synth_blur(ASS_SynthPriv *priv_blur, int opaque_box, int be, +void ass_synth_blur(const BitmapEngine *engine, int opaque_box, int be, double blur_radius, Bitmap *bm_g, Bitmap *bm_o); /** @@ -65,25 +129,13 @@ ASS_Outline *outline, ASS_Outline *border, Bitmap **bm_g, Bitmap **bm_o); -void ass_free_bitmap(Bitmap *bm); -void ass_gauss_blur(unsigned char *buffer, unsigned *tmp2, - int width, int height, int stride, - unsigned *m2, int r, int mwidth); -void be_blur_c(uint8_t *buf, intptr_t w, - intptr_t h, intptr_t stride, - uint16_t *tmp); -void add_bitmaps_c(uint8_t *dst, intptr_t dst_stride, - uint8_t *src, intptr_t src_stride, - intptr_t height, intptr_t width); -void sub_bitmaps_c(uint8_t *dst, intptr_t dst_stride, - uint8_t *src, intptr_t src_stride, - intptr_t height, intptr_t width); -void mul_bitmaps_c(uint8_t *dst, intptr_t dst_stride, - uint8_t *src1, intptr_t src1_stride, - uint8_t *src2, intptr_t src2_stride, - intptr_t w, intptr_t h); +int be_padding(int be); +void be_blur_pre(uint8_t *buf, intptr_t w, + intptr_t h, intptr_t stride); +void be_blur_post(uint8_t *buf, intptr_t w, + intptr_t h, intptr_t stride); +bool ass_gaussian_blur(const BitmapEngine *engine, Bitmap *bm, double r2); void shift_bitmap(Bitmap *bm, int shift_x, int shift_y); void fix_outline(Bitmap *bm_g, Bitmap *bm_o); -Bitmap *copy_bitmap(const Bitmap *src); #endif /* LIBASS_BITMAP_H */ diff -Nru libass-0.12.2/libass/ass_blur.c libass-0.13.0/libass/ass_blur.c --- libass-0.12.2/libass/ass_blur.c 1970-01-01 00:00:00.000000000 +0000 +++ libass-0.13.0/libass/ass_blur.c 2015-09-24 08:34:34.000000000 +0000 @@ -0,0 +1,912 @@ +/* + * Copyright (C) 2015 Vabishchevich Nikolay + * + * 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_compat.h" + +#include +#include + +#include "ass_utils.h" +#include "ass_bitmap.h" + + +/* + * Cascade Blur Algorithm + * + * The main idea is simple: to approximate gaussian blur with large radius + * you can downscale, then apply filter with small pattern, then upscale back. + * + * To achieve desired precision down/upscaling should be done with sufficiently smooth kernel. + * Experiment shows that downscaling of factor 2 with kernel [1, 5, 10, 10, 5, 1] and + * corresponding upscaling are enough for 8-bit precision. + * + * For central filter here is used generic 9-tap filter with one of 3 different patterns + * combined with one of optional prefilters with fixed kernels. Kernel coefficients + * of the main filter are obtained from solution of least squares problem + * for Fourier transform of resulting kernel. + */ + + +#define STRIPE_WIDTH (1 << (C_ALIGN_ORDER - 1)) +#define STRIPE_MASK (STRIPE_WIDTH - 1) +static int16_t zero_line[STRIPE_WIDTH]; +static int16_t dither_line[2 * STRIPE_WIDTH] = { +#if STRIPE_WIDTH > 8 + 8, 40, 8, 40, 8, 40, 8, 40, 8, 40, 8, 40, 8, 40, 8, 40, + 56, 24, 56, 24, 56, 24, 56, 24, 56, 24, 56, 24, 56, 24, 56, 24, +#else + 8, 40, 8, 40, 8, 40, 8, 40, + 56, 24, 56, 24, 56, 24, 56, 24, +#endif +}; + +inline static const int16_t *get_line(const int16_t *ptr, uintptr_t offs, uintptr_t size) +{ + return offs < size ? ptr + offs : zero_line; +} + +inline static void copy_line(int16_t *buf, const int16_t *ptr, uintptr_t offs, uintptr_t size) +{ + ptr = get_line(ptr, offs, size); + for (int k = 0; k < STRIPE_WIDTH; ++k) + buf[k] = ptr[k]; +} + +/* + * Unpack/Pack Functions + * + * Convert between regular 8-bit bitmap and internal format. + * Internal image is stored as set of vertical stripes of size [STRIPE_WIDTH x height]. + * Each pixel is represented as 16-bit integer in range of [0-0x4000]. + */ + +void ass_stripe_unpack_c(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, + uintptr_t width, uintptr_t height) +{ + for (uintptr_t y = 0; y < height; ++y) { + int16_t *ptr = dst; + for (uintptr_t x = 0; x < width; x += STRIPE_WIDTH) { + for (int k = 0; k < STRIPE_WIDTH; ++k) + ptr[k] = (uint16_t)(((src[x + k] << 7) | (src[x + k] >> 1)) + 1) >> 1; + //ptr[k] = (0x4000 * src[x + k] + 127) / 255; + ptr += STRIPE_WIDTH * height; + } + dst += STRIPE_WIDTH; + src += src_stride; + } +} + +void ass_stripe_pack_c(uint8_t *dst, ptrdiff_t dst_stride, const int16_t *src, + uintptr_t width, uintptr_t height) +{ + for (uintptr_t x = 0; x < width; x += STRIPE_WIDTH) { + uint8_t *ptr = dst; + for (uintptr_t y = 0; y < height; ++y) { + const int16_t *dither = dither_line + (y & 1) * STRIPE_WIDTH; + for (int k = 0; k < STRIPE_WIDTH; ++k) + ptr[k] = (uint16_t)(src[k] - (src[k] >> 8) + dither[k]) >> 6; + //ptr[k] = (255 * src[k] + 0x1FFF) / 0x4000; + ptr += dst_stride; + src += STRIPE_WIDTH; + } + dst += STRIPE_WIDTH; + } + uintptr_t left = dst_stride - ((width + STRIPE_MASK) & ~STRIPE_MASK); + for (uintptr_t y = 0; y < height; ++y) { + for (uintptr_t x = 0; x < left; ++x) + dst[x] = 0; + dst += dst_stride; + } +} + +/* + * Contract Filters + * + * Contract image by factor 2 with kernel [1, 5, 10, 10, 5, 1]. + */ + +static inline int16_t shrink_func(int16_t p1p, int16_t p1n, + int16_t z0p, int16_t z0n, + int16_t n1p, int16_t n1n) +{ + /* + return (1 * p1p + 5 * p1n + 10 * z0p + 10 * z0n + 5 * n1p + 1 * n1n + 16) >> 5; + */ + int32_t r = (p1p + p1n + n1p + n1n) >> 1; + r = (r + z0p + z0n) >> 1; + r = (r + p1n + n1p) >> 1; + return (r + z0p + z0n + 2) >> 2; +} + +void ass_shrink_horz_c(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height) +{ + uintptr_t dst_width = (src_width + 5) >> 1; + uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height; + uintptr_t step = STRIPE_WIDTH * src_height; + + uintptr_t offs = 0; + int16_t buf[3 * STRIPE_WIDTH]; + int16_t *ptr = buf + STRIPE_WIDTH; + for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) { + for (uintptr_t y = 0; y < src_height; ++y) { + copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); + copy_line(ptr + 0 * STRIPE_WIDTH, src, offs + 0 * step, size); + copy_line(ptr + 1 * STRIPE_WIDTH, src, offs + 1 * step, size); + for (int k = 0; k < STRIPE_WIDTH; ++k) + dst[k] = shrink_func(ptr[2 * k - 4], ptr[2 * k - 3], + ptr[2 * k - 2], ptr[2 * k - 1], + ptr[2 * k + 0], ptr[2 * k + 1]); + dst += STRIPE_WIDTH; + offs += STRIPE_WIDTH; + } + offs += step; + } +} + +void ass_shrink_vert_c(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height) +{ + uintptr_t dst_height = (src_height + 5) >> 1; + uintptr_t step = STRIPE_WIDTH * src_height; + + for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) { + uintptr_t offs = 0; + for (uintptr_t y = 0; y < dst_height; ++y) { + const int16_t *p1p = get_line(src, offs - 4 * STRIPE_WIDTH, step); + const int16_t *p1n = get_line(src, offs - 3 * STRIPE_WIDTH, step); + const int16_t *z0p = get_line(src, offs - 2 * STRIPE_WIDTH, step); + const int16_t *z0n = get_line(src, offs - 1 * STRIPE_WIDTH, step); + const int16_t *n1p = get_line(src, offs - 0 * STRIPE_WIDTH, step); + const int16_t *n1n = get_line(src, offs + 1 * STRIPE_WIDTH, step); + for (int k = 0; k < STRIPE_WIDTH; ++k) + dst[k] = shrink_func(p1p[k], p1n[k], z0p[k], z0n[k], n1p[k], n1n[k]); + dst += STRIPE_WIDTH; + offs += 2 * STRIPE_WIDTH; + } + src += step; + } +} + +/* + * Expand Filters + * + * Expand image by factor 2 with kernel [5, 10, 1], [1, 10, 5]. + */ + +static inline void expand_func(int16_t *rp, int16_t *rn, + int16_t p1, int16_t z0, int16_t n1) +{ + /* + *rp = (5 * p1 + 10 * z0 + 1 * n1 + 8) >> 4; + *rn = (1 * p1 + 10 * z0 + 5 * n1 + 8) >> 4; + */ + uint16_t r = (uint16_t)(((uint16_t)(p1 + n1) >> 1) + z0) >> 1; + *rp = (uint16_t)(((uint16_t)(r + p1) >> 1) + z0 + 1) >> 1; + *rn = (uint16_t)(((uint16_t)(r + n1) >> 1) + z0 + 1) >> 1; +} + +void ass_expand_horz_c(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height) +{ + uintptr_t dst_width = 2 * src_width + 4; + uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height; + uintptr_t step = STRIPE_WIDTH * src_height; + + uintptr_t offs = 0; + int16_t buf[2 * STRIPE_WIDTH]; + int16_t *ptr = buf + STRIPE_WIDTH; + for (uintptr_t x = STRIPE_WIDTH; x < dst_width; x += 2 * STRIPE_WIDTH) { + for (uintptr_t y = 0; y < src_height; ++y) { + copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); + copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size); + for (int k = 0; k < STRIPE_WIDTH / 2; ++k) + expand_func(&dst[2 * k], &dst[2 * k + 1], + ptr[k - 2], ptr[k - 1], ptr[k]); + int16_t *next = dst + step - STRIPE_WIDTH; + for (int k = STRIPE_WIDTH / 2; k < STRIPE_WIDTH; ++k) + expand_func(&next[2 * k], &next[2 * k + 1], + ptr[k - 2], ptr[k - 1], ptr[k]); + dst += STRIPE_WIDTH; + offs += STRIPE_WIDTH; + } + dst += step; + } + if ((dst_width - 1) & STRIPE_WIDTH) + return; + + for (uintptr_t y = 0; y < src_height; ++y) { + copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); + copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size); + for (int k = 0; k < STRIPE_WIDTH / 2; ++k) + expand_func(&dst[2 * k], &dst[2 * k + 1], + ptr[k - 2], ptr[k - 1], ptr[k]); + dst += STRIPE_WIDTH; + offs += STRIPE_WIDTH; + } +} + +void ass_expand_vert_c(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height) +{ + uintptr_t dst_height = 2 * src_height + 4; + uintptr_t step = STRIPE_WIDTH * src_height; + + for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) { + uintptr_t offs = 0; + for (uintptr_t y = 0; y < dst_height; y += 2) { + const int16_t *p1 = get_line(src, offs - 2 * STRIPE_WIDTH, step); + const int16_t *z0 = get_line(src, offs - 1 * STRIPE_WIDTH, step); + const int16_t *n1 = get_line(src, offs - 0 * STRIPE_WIDTH, step); + for (int k = 0; k < STRIPE_WIDTH; ++k) + expand_func(&dst[k], &dst[k + STRIPE_WIDTH], + p1[k], z0[k], n1[k]); + dst += 2 * STRIPE_WIDTH; + offs += STRIPE_WIDTH; + } + src += step; + } +} + +/* + * First Supplementary Filters + * + * Perform 1D convolution with kernel [1, 2, 1]. + */ + +static inline int16_t pre_blur1_func(int16_t p1, int16_t z0, int16_t n1) +{ + /* + return (1 * p1 + 2 * z0 + 1 * n1 + 2) >> 2; + */ + return (uint16_t)(((uint16_t)(p1 + n1) >> 1) + z0 + 1) >> 1; +} + +void ass_pre_blur1_horz_c(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height) +{ + uintptr_t dst_width = src_width + 2; + uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height; + uintptr_t step = STRIPE_WIDTH * src_height; + + uintptr_t offs = 0; + int16_t buf[2 * STRIPE_WIDTH]; + int16_t *ptr = buf + STRIPE_WIDTH; + for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) { + for (uintptr_t y = 0; y < src_height; ++y) { + copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); + copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size); + for (int k = 0; k < STRIPE_WIDTH; ++k) + dst[k] = pre_blur1_func(ptr[k - 2], ptr[k - 1], ptr[k]); + dst += STRIPE_WIDTH; + offs += STRIPE_WIDTH; + } + } +} + +void ass_pre_blur1_vert_c(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height) +{ + uintptr_t dst_height = src_height + 2; + uintptr_t step = STRIPE_WIDTH * src_height; + + for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) { + uintptr_t offs = 0; + for (uintptr_t y = 0; y < dst_height; ++y) { + const int16_t *p1 = get_line(src, offs - 2 * STRIPE_WIDTH, step); + const int16_t *z0 = get_line(src, offs - 1 * STRIPE_WIDTH, step); + const int16_t *n1 = get_line(src, offs - 0 * STRIPE_WIDTH, step); + for (int k = 0; k < STRIPE_WIDTH; ++k) + dst[k] = pre_blur1_func(p1[k], z0[k], n1[k]); + dst += STRIPE_WIDTH; + offs += STRIPE_WIDTH; + } + src += step; + } +} + +/* + * Second Supplementary Filters + * + * Perform 1D convolution with kernel [1, 4, 6, 4, 1]. + */ + +static inline int16_t pre_blur2_func(int16_t p2, int16_t p1, int16_t z0, + int16_t n1, int16_t n2) +{ + /* + return (1 * p2 + 4 * p1 + 6 * z0 + 4 * n1 + 1 * n2 + 8) >> 4; + */ + uint16_t r1 = ((uint16_t)(((uint16_t)(p2 + n2) >> 1) + z0) >> 1) + z0; + uint16_t r2 = p1 + n1; + uint16_t r = ((uint16_t)(r1 + r2) >> 1) | (0x8000 & r1 & r2); + return (uint16_t)(r + 1) >> 1; +} + +void ass_pre_blur2_horz_c(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height) +{ + uintptr_t dst_width = src_width + 4; + uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height; + uintptr_t step = STRIPE_WIDTH * src_height; + + uintptr_t offs = 0; + int16_t buf[2 * STRIPE_WIDTH]; + int16_t *ptr = buf + STRIPE_WIDTH; + for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) { + for (uintptr_t y = 0; y < src_height; ++y) { + copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); + copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size); + for (int k = 0; k < STRIPE_WIDTH; ++k) + dst[k] = pre_blur2_func(ptr[k - 4], ptr[k - 3], ptr[k - 2], ptr[k - 1], ptr[k]); + dst += STRIPE_WIDTH; + offs += STRIPE_WIDTH; + } + } +} + +void ass_pre_blur2_vert_c(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height) +{ + uintptr_t dst_height = src_height + 4; + uintptr_t step = STRIPE_WIDTH * src_height; + + for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) { + uintptr_t offs = 0; + for (uintptr_t y = 0; y < dst_height; ++y) { + const int16_t *p2 = get_line(src, offs - 4 * STRIPE_WIDTH, step); + const int16_t *p1 = get_line(src, offs - 3 * STRIPE_WIDTH, step); + const int16_t *z0 = get_line(src, offs - 2 * STRIPE_WIDTH, step); + const int16_t *n1 = get_line(src, offs - 1 * STRIPE_WIDTH, step); + const int16_t *n2 = get_line(src, offs - 0 * STRIPE_WIDTH, step); + for (int k = 0; k < STRIPE_WIDTH; ++k) + dst[k] = pre_blur2_func(p2[k], p1[k], z0[k], n1[k], n2[k]); + dst += STRIPE_WIDTH; + offs += STRIPE_WIDTH; + } + src += step; + } +} + +/* + * Third Supplementary Filters + * + * Perform 1D convolution with kernel [1, 6, 15, 20, 15, 6, 1]. + */ + +static inline int16_t pre_blur3_func(int16_t p3, int16_t p2, int16_t p1, int16_t z0, + int16_t n1, int16_t n2, int16_t n3) +{ + /* + return (1 * p3 + 6 * p2 + 15 * p1 + 20 * z0 + 15 * n1 + 6 * n2 + 1 * n3 + 32) >> 6; + */ + return (20 * (uint16_t)z0 + + 15 * (uint16_t)(p1 + n1) + + 6 * (uint16_t)(p2 + n2) + + 1 * (uint16_t)(p3 + n3) + 32) >> 6; +} + +void ass_pre_blur3_horz_c(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height) +{ + uintptr_t dst_width = src_width + 6; + uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height; + uintptr_t step = STRIPE_WIDTH * src_height; + + uintptr_t offs = 0; + int16_t buf[2 * STRIPE_WIDTH]; + int16_t *ptr = buf + STRIPE_WIDTH; + for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) { + for (uintptr_t y = 0; y < src_height; ++y) { + copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); + copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size); + for (int k = 0; k < STRIPE_WIDTH; ++k) + dst[k] = pre_blur3_func(ptr[k - 6], ptr[k - 5], ptr[k - 4], ptr[k - 3], + ptr[k - 2], ptr[k - 1], ptr[k]); + dst += STRIPE_WIDTH; + offs += STRIPE_WIDTH; + } + } +} + +void ass_pre_blur3_vert_c(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height) +{ + uintptr_t dst_height = src_height + 6; + uintptr_t step = STRIPE_WIDTH * src_height; + + for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) { + uintptr_t offs = 0; + for (uintptr_t y = 0; y < dst_height; ++y) { + const int16_t *p3 = get_line(src, offs - 6 * STRIPE_WIDTH, step); + const int16_t *p2 = get_line(src, offs - 5 * STRIPE_WIDTH, step); + const int16_t *p1 = get_line(src, offs - 4 * STRIPE_WIDTH, step); + const int16_t *z0 = get_line(src, offs - 3 * STRIPE_WIDTH, step); + const int16_t *n1 = get_line(src, offs - 2 * STRIPE_WIDTH, step); + const int16_t *n2 = get_line(src, offs - 1 * STRIPE_WIDTH, step); + const int16_t *n3 = get_line(src, offs - 0 * STRIPE_WIDTH, step); + for (int k = 0; k < STRIPE_WIDTH; ++k) + dst[k] = pre_blur3_func(p3[k], p2[k], p1[k], z0[k], n1[k], n2[k], n3[k]); + dst += STRIPE_WIDTH; + offs += STRIPE_WIDTH; + } + src += step; + } +} + +/* + * Main 9-tap Parametric Filters + * + * Perform 1D convolution with kernel + * [c3, c2, c1, c0, d, c0, c1, c2, c3] or + * [c3, 0, c2, c1, c0, d, c0, c1, c2, 0, c3] or + * [c3, 0, c2, 0, c1, c0, d, c0, c1, 0, c2, 0, c3] accordingly. + * + * cN = param[N], d = 1 - 2 * (c0 + c1 + c2 + c3). + */ + +static inline int16_t blur_func(int16_t p4, int16_t p3, int16_t p2, int16_t p1, int16_t z0, + int16_t n1, int16_t n2, int16_t n3, int16_t n4, const int16_t c[]) +{ + p1 -= z0; + p2 -= z0; + p3 -= z0; + p4 -= z0; + n1 -= z0; + n2 -= z0; + n3 -= z0; + n4 -= z0; + return (((p1 + n1) * c[0] + + (p2 + n2) * c[1] + + (p3 + n3) * c[2] + + (p4 + n4) * c[3] + + 0x8000) >> 16) + z0; +} + +void ass_blur1234_horz_c(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height, + const int16_t *param) +{ + uintptr_t dst_width = src_width + 8; + uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height; + uintptr_t step = STRIPE_WIDTH * src_height; + + uintptr_t offs = 0; + int16_t buf[2 * STRIPE_WIDTH]; + int16_t *ptr = buf + STRIPE_WIDTH; + for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) { + for (uintptr_t y = 0; y < src_height; ++y) { + copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); + copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size); + for (int k = 0; k < STRIPE_WIDTH; ++k) + dst[k] = blur_func(ptr[k - 8], ptr[k - 7], ptr[k - 6], ptr[k - 5], ptr[k - 4], + ptr[k - 3], ptr[k - 2], ptr[k - 1], ptr[k - 0], param); + dst += STRIPE_WIDTH; + offs += STRIPE_WIDTH; + } + } +} + +void ass_blur1234_vert_c(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height, + const int16_t *param) +{ + uintptr_t dst_height = src_height + 8; + uintptr_t step = STRIPE_WIDTH * src_height; + + for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) { + uintptr_t offs = 0; + for (uintptr_t y = 0; y < dst_height; ++y) { + const int16_t *p4 = get_line(src, offs - 8 * STRIPE_WIDTH, step); + const int16_t *p3 = get_line(src, offs - 7 * STRIPE_WIDTH, step); + const int16_t *p2 = get_line(src, offs - 6 * STRIPE_WIDTH, step); + const int16_t *p1 = get_line(src, offs - 5 * STRIPE_WIDTH, step); + const int16_t *z0 = get_line(src, offs - 4 * STRIPE_WIDTH, step); + const int16_t *n1 = get_line(src, offs - 3 * STRIPE_WIDTH, step); + const int16_t *n2 = get_line(src, offs - 2 * STRIPE_WIDTH, step); + const int16_t *n3 = get_line(src, offs - 1 * STRIPE_WIDTH, step); + const int16_t *n4 = get_line(src, offs - 0 * STRIPE_WIDTH, step); + for (int k = 0; k < STRIPE_WIDTH; ++k) + dst[k] = blur_func(p4[k], p3[k], p2[k], p1[k], z0[k], + n1[k], n2[k], n3[k], n4[k], param); + dst += STRIPE_WIDTH; + offs += STRIPE_WIDTH; + } + src += step; + } +} + +void ass_blur1235_horz_c(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height, + const int16_t *param) +{ + uintptr_t dst_width = src_width + 10; + uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height; + uintptr_t step = STRIPE_WIDTH * src_height; + + uintptr_t offs = 0; +#if STRIPE_WIDTH < 10 + int16_t buf[3 * STRIPE_WIDTH]; + int16_t *ptr = buf + 2 * STRIPE_WIDTH; +#else + int16_t buf[2 * STRIPE_WIDTH]; + int16_t *ptr = buf + STRIPE_WIDTH; +#endif + for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) { + for (uintptr_t y = 0; y < src_height; ++y) { +#if STRIPE_WIDTH < 10 + copy_line(ptr - 2 * STRIPE_WIDTH, src, offs - 2 * step, size); +#endif + copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); + copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size); + for (int k = 0; k < STRIPE_WIDTH; ++k) + dst[k] = blur_func(ptr[k - 10], ptr[k - 8], ptr[k - 7], ptr[k - 6], ptr[k - 5], + ptr[k - 4], ptr[k - 3], ptr[k - 2], ptr[k - 0], param); + dst += STRIPE_WIDTH; + offs += STRIPE_WIDTH; + } + } +} + +void ass_blur1235_vert_c(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height, + const int16_t *param) +{ + uintptr_t dst_height = src_height + 10; + uintptr_t step = STRIPE_WIDTH * src_height; + + for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) { + uintptr_t offs = 0; + for (uintptr_t y = 0; y < dst_height; ++y) { + const int16_t *p4 = get_line(src, offs - 10 * STRIPE_WIDTH, step); + const int16_t *p3 = get_line(src, offs - 8 * STRIPE_WIDTH, step); + const int16_t *p2 = get_line(src, offs - 7 * STRIPE_WIDTH, step); + const int16_t *p1 = get_line(src, offs - 6 * STRIPE_WIDTH, step); + const int16_t *z0 = get_line(src, offs - 5 * STRIPE_WIDTH, step); + const int16_t *n1 = get_line(src, offs - 4 * STRIPE_WIDTH, step); + const int16_t *n2 = get_line(src, offs - 3 * STRIPE_WIDTH, step); + const int16_t *n3 = get_line(src, offs - 2 * STRIPE_WIDTH, step); + const int16_t *n4 = get_line(src, offs - 0 * STRIPE_WIDTH, step); + for (int k = 0; k < STRIPE_WIDTH; ++k) + dst[k] = blur_func(p4[k], p3[k], p2[k], p1[k], z0[k], + n1[k], n2[k], n3[k], n4[k], param); + dst += STRIPE_WIDTH; + offs += STRIPE_WIDTH; + } + src += step; + } +} + +void ass_blur1246_horz_c(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height, + const int16_t *param) +{ + uintptr_t dst_width = src_width + 12; + uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height; + uintptr_t step = STRIPE_WIDTH * src_height; + + uintptr_t offs = 0; +#if STRIPE_WIDTH < 12 + int16_t buf[3 * STRIPE_WIDTH]; + int16_t *ptr = buf + 2 * STRIPE_WIDTH; +#else + int16_t buf[2 * STRIPE_WIDTH]; + int16_t *ptr = buf + STRIPE_WIDTH; +#endif + for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) { + for (uintptr_t y = 0; y < src_height; ++y) { +#if STRIPE_WIDTH < 12 + copy_line(ptr - 2 * STRIPE_WIDTH, src, offs - 2 * step, size); +#endif + copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); + copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size); + for (int k = 0; k < STRIPE_WIDTH; ++k) + dst[k] = blur_func(ptr[k - 12], ptr[k - 10], ptr[k - 8], ptr[k - 7], ptr[k - 6], + ptr[k - 5], ptr[k - 4], ptr[k - 2], ptr[k - 0], param); + dst += STRIPE_WIDTH; + offs += STRIPE_WIDTH; + } + } +} + +void ass_blur1246_vert_c(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height, + const int16_t *param) +{ + uintptr_t dst_height = src_height + 12; + uintptr_t step = STRIPE_WIDTH * src_height; + + for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) { + uintptr_t offs = 0; + for (uintptr_t y = 0; y < dst_height; ++y) { + const int16_t *p4 = get_line(src, offs - 12 * STRIPE_WIDTH, step); + const int16_t *p3 = get_line(src, offs - 10 * STRIPE_WIDTH, step); + const int16_t *p2 = get_line(src, offs - 8 * STRIPE_WIDTH, step); + const int16_t *p1 = get_line(src, offs - 7 * STRIPE_WIDTH, step); + const int16_t *z0 = get_line(src, offs - 6 * STRIPE_WIDTH, step); + const int16_t *n1 = get_line(src, offs - 5 * STRIPE_WIDTH, step); + const int16_t *n2 = get_line(src, offs - 4 * STRIPE_WIDTH, step); + const int16_t *n3 = get_line(src, offs - 2 * STRIPE_WIDTH, step); + const int16_t *n4 = get_line(src, offs - 0 * STRIPE_WIDTH, step); + for (int k = 0; k < STRIPE_WIDTH; ++k) + dst[k] = blur_func(p4[k], p3[k], p2[k], p1[k], z0[k], + n1[k], n2[k], n3[k], n4[k], param); + dst += STRIPE_WIDTH; + offs += STRIPE_WIDTH; + } + src += step; + } +} + + + +static void calc_gauss(double *res, int n, double r2) +{ + double alpha = 0.5 / r2; + double mul = exp(-alpha), mul2 = mul * mul; + double cur = sqrt(alpha / M_PI); + + res[0] = cur; + cur *= mul; + res[1] = cur; + for (int i = 2; i <= n; ++i) { + mul *= mul2; + cur *= mul; + res[i] = cur; + } +} + +static void coeff_blur121(double *coeff, int n) +{ + double prev = coeff[1]; + for (int i = 0; i <= n; ++i) { + double res = (prev + 2 * coeff[i] + coeff[i + 1]) / 4; + prev = coeff[i]; + coeff[i] = res; + } +} + +static void coeff_filter(double *coeff, int n, const double kernel[4]) +{ + double prev1 = coeff[1], prev2 = coeff[2], prev3 = coeff[3]; + for (int i = 0; i <= n; ++i) { + double res = coeff[i + 0] * kernel[0] + + (prev1 + coeff[i + 1]) * kernel[1] + + (prev2 + coeff[i + 2]) * kernel[2] + + (prev3 + coeff[i + 3]) * kernel[3]; + prev3 = prev2; + prev2 = prev1; + prev1 = coeff[i]; + coeff[i] = res; + } +} + +static void calc_matrix(double mat[4][4], const double *mat_freq, const int *index) +{ + for (int i = 0; i < 4; ++i) { + mat[i][i] = mat_freq[2 * index[i]] + 3 * mat_freq[0] - 4 * mat_freq[index[i]]; + for (int j = i + 1; j < 4; ++j) + mat[i][j] = mat[j][i] = + mat_freq[index[i] + index[j]] + mat_freq[index[j] - index[i]] + + 2 * (mat_freq[0] - mat_freq[index[i]] - mat_freq[index[j]]); + } + + // invert transpose + for (int k = 0; k < 4; ++k) { + int ip = k, jp = k; // pivot + double z = 1 / mat[ip][jp]; + mat[ip][jp] = 1; + for (int i = 0; i < 4; ++i) { + if (i == ip) + continue; + + double mul = mat[i][jp] * z; + mat[i][jp] = 0; + for (int j = 0; j < 4; ++j) + mat[i][j] -= mat[ip][j] * mul; + } + for (int j = 0; j < 4; ++j) + mat[ip][j] *= z; + } +} + +/** + * \brief Solve least squares problem for kernel of the main filter + * \param mu out: output coefficients + * \param index in: filter tap positions + * \param prefilter in: supplementary filter type + * \param r2 in: desired standard deviation squared + * \param mul in: scale multiplier + */ +static void calc_coeff(double mu[4], const int index[4], int prefilter, double r2, double mul) +{ + double mul2 = mul * mul, mul3 = mul2 * mul; + double kernel[] = { + (5204 + 2520 * mul + 1092 * mul2 + 3280 * mul3) / 12096, + (2943 - 210 * mul - 273 * mul2 - 2460 * mul3) / 12096, + ( 486 - 924 * mul - 546 * mul2 + 984 * mul3) / 12096, + ( 17 - 126 * mul + 273 * mul2 - 164 * mul3) / 12096, + }; + + double mat_freq[13]; + memcpy(mat_freq, kernel, sizeof(kernel)); + memset(mat_freq + 4, 0, sizeof(mat_freq) - sizeof(kernel)); + int n = 6; + coeff_filter(mat_freq, n, kernel); + for (int k = 0; k < 2 * prefilter; ++k) + coeff_blur121(mat_freq, ++n); + + double vec_freq[13]; + n = index[3] + prefilter + 3; + calc_gauss(vec_freq, n, r2); + memset(vec_freq + n + 1, 0, sizeof(vec_freq) - (n + 1) * sizeof(vec_freq[0])); + n -= 3; + coeff_filter(vec_freq, n, kernel); + for (int k = 0; k < prefilter; ++k) + coeff_blur121(vec_freq, --n); + + double mat[4][4]; + calc_matrix(mat, mat_freq, index); + + double vec[4]; + for (int i = 0; i < 4; ++i) + vec[i] = mat_freq[0] - mat_freq[index[i]] - vec_freq[0] + vec_freq[index[i]]; + + for (int i = 0; i < 4; ++i) { + double res = 0; + for (int j = 0; j < 4; ++j) + res += mat[i][j] * vec[j]; + mu[i] = FFMAX(0, res); + } +} + +typedef struct { + int level, prefilter, filter; + int16_t coeff[4]; +} BlurMethod; + +static void find_best_method(BlurMethod *blur, double r2) +{ + static const int index[][4] = { + { 1, 2, 3, 4 }, + { 1, 2, 3, 5 }, + { 1, 2, 4, 6 }, + }; + + double mu[5]; + if (r2 < 1.9) { + blur->level = blur->prefilter = blur->filter = 0; + + if (r2 < 0.5) { + mu[2] = 0.085 * r2 * r2 * r2; + mu[1] = 0.5 * r2 - 4 * mu[2]; + mu[3] = mu[4] = 0; + } else { + calc_gauss(mu, 4, r2); + } + } else { + double mul = 1; + if (r2 < 6.693) { + blur->level = 0; + + if (r2 < 2.8) + blur->prefilter = 1; + else if (r2 < 4.4) + blur->prefilter = 2; + else + blur->prefilter = 3; + + blur->filter = blur->prefilter - 1; + } else { + frexp((r2 + 0.7) / 26.5, &blur->level); + blur->level = (blur->level + 3) >> 1; + mul = pow(0.25, blur->level); + r2 *= mul; + + if (r2 < 3.15 - 1.5 * mul) + blur->prefilter = 0; + else if (r2 < 5.3 - 5.2 * mul) + blur->prefilter = 1; + else + blur->prefilter = 2; + + blur->filter = blur->prefilter; + } + calc_coeff(mu + 1, index[blur->filter], blur->prefilter, r2, mul); + } + + for (int i = 1; i <= 4; ++i) + blur->coeff[i - 1] = (int)(0x10000 * mu[i] + 0.5); +} + +/** + * \brief Perform approximate gaussian blur + * \param r2 in: desired standard deviation squared + */ +bool ass_gaussian_blur(const BitmapEngine *engine, Bitmap *bm, double r2) +{ + BlurMethod blur; + find_best_method(&blur, r2); + + int w = bm->w, h = bm->h; + int offset = ((2 * (blur.prefilter + blur.filter) + 17) << blur.level) - 5; + int end_w = ((w + offset) & ~((1 << blur.level) - 1)) - 4; + int end_h = ((h + offset) & ~((1 << blur.level) - 1)) - 4; + + const int stripe_width = 1 << (engine->align_order - 1); + int size = end_h * ((end_w + stripe_width - 1) & ~(stripe_width - 1)); + int16_t *tmp = ass_aligned_alloc(2 * stripe_width, 4 * size); + if (!tmp) + return false; + + engine->stripe_unpack(tmp, bm->buffer, bm->stride, w, h); + int16_t *buf[2] = {tmp, tmp + size}; + int index = 0; + + for (int i = 0; i < blur.level; ++i) { + engine->shrink_vert(buf[index ^ 1], buf[index], w, h); + h = (h + 5) >> 1; + index ^= 1; + } + for (int i = 0; i < blur.level; ++i) { + engine->shrink_horz(buf[index ^ 1], buf[index], w, h); + w = (w + 5) >> 1; + index ^= 1; + } + if (blur.prefilter) { + engine->pre_blur_horz[blur.prefilter - 1](buf[index ^ 1], buf[index], w, h); + w += 2 * blur.prefilter; + index ^= 1; + } + engine->main_blur_horz[blur.filter](buf[index ^ 1], buf[index], w, h, blur.coeff); + w += 2 * blur.filter + 8; + index ^= 1; + for (int i = 0; i < blur.level; ++i) { + engine->expand_horz(buf[index ^ 1], buf[index], w, h); + w = 2 * w + 4; + index ^= 1; + } + if (blur.prefilter) { + engine->pre_blur_vert[blur.prefilter - 1](buf[index ^ 1], buf[index], w, h); + h += 2 * blur.prefilter; + index ^= 1; + } + engine->main_blur_vert[blur.filter](buf[index ^ 1], buf[index], w, h, blur.coeff); + h += 2 * blur.filter + 8; + index ^= 1; + for (int i = 0; i < blur.level; ++i) { + engine->expand_vert(buf[index ^ 1], buf[index], w, h); + h = 2 * h + 4; + index ^= 1; + } + assert(w == end_w && h == end_h); + + if (!realloc_bitmap(engine, bm, w, h)) { + ass_aligned_free(tmp); + return false; + } + offset = ((blur.prefilter + blur.filter + 8) << blur.level) - 4; + bm->left -= offset; + bm->top -= offset; + + engine->stripe_pack(bm->buffer, bm->stride, buf[index], w, h); + ass_aligned_free(tmp); + return true; +} + diff -Nru libass-0.12.2/libass/ass.c libass-0.13.0/libass/ass.c --- libass-0.12.2/libass/ass.c 2015-03-22 15:31:49.000000000 +0000 +++ libass-0.13.0/libass/ass.c 2015-09-24 08:34:34.000000000 +0000 @@ -17,18 +17,16 @@ */ #include "config.h" +#include "ass_compat.h" #include #include #include -#include #include #include #include #include -#include #include -#include #ifdef CONFIG_ICONV #include @@ -37,6 +35,7 @@ #include "ass.h" #include "ass_utils.h" #include "ass_library.h" +#include "ass_string.h" #define ass_atof(STR) (ass_strtod((STR),NULL)) @@ -188,7 +187,7 @@ ass_msg(library, MSGL_WARN, "Bad timestamp"); return 0; } - tm = ((h * 60 + m) * 60 + s) * 1000 + ms * 10; + tm = ((h * 60LL + m) * 60 + s) * 1000 + ms * 10; return tm; } @@ -212,7 +211,7 @@ #define ALIAS(alias,name) \ - if (strcasecmp(tname, #alias) == 0) {tname = #name;} + if (ass_strcasecmp(tname, #alias) == 0) {tname = #name;} /* One section started with PARSE_START and PARSE_END parses a single token * (contained in the variable named token) for the header indicated by the @@ -228,32 +227,29 @@ #define PARSE_END } #define ANYVAL(name,func) \ - } else if (strcasecmp(tname, #name) == 0) { \ + } else if (ass_strcasecmp(tname, #name) == 0) { \ target->name = func(token); #define STRVAL(name) \ - } else if (strcasecmp(tname, #name) == 0) { \ + } else if (ass_strcasecmp(tname, #name) == 0) { \ if (target->name != NULL) free(target->name); \ target->name = strdup(token); #define STARREDSTRVAL(name) \ - } else if (strcasecmp(tname, #name) == 0) { \ + } else if (ass_strcasecmp(tname, #name) == 0) { \ if (target->name != NULL) free(target->name); \ while (*token == '*') ++token; \ target->name = strdup(token); -#define COLORVAL(name) \ - } else if (strcasecmp(tname, #name) == 0) { \ - target->name = string2color(track->library, token, 0); - +#define COLORVAL(name) ANYVAL(name,parse_color_header) #define INTVAL(name) ANYVAL(name,atoi) #define FPVAL(name) ANYVAL(name,ass_atof) #define TIMEVAL(name) \ - } else if (strcasecmp(tname, #name) == 0) { \ + } else if (ass_strcasecmp(tname, #name) == 0) { \ target->name = string2timecode(track->library, token); #define STYLEVAL(name) \ - } else if (strcasecmp(tname, #name) == 0) { \ + } else if (ass_strcasecmp(tname, #name) == 0) { \ target->name = lookup_style(track, token); static char *next_token(char **str) @@ -312,7 +308,7 @@ while (1) { NEXT(q, tname); - if (strcasecmp(tname, "Text") == 0) { + if (ass_strcasecmp(tname, "Text") == 0) { char *last; event->Text = strdup(p); if (*event->Text != 0) { @@ -365,19 +361,19 @@ *eq = '\0'; token = eq + 1; - if (!strcasecmp(*fs, "PlayResX")) + if (!ass_strcasecmp(*fs, "PlayResX")) track->PlayResX = atoi(token); - else if (!strcasecmp(*fs, "PlayResY")) + else if (!ass_strcasecmp(*fs, "PlayResY")) track->PlayResY = atoi(token); - else if (!strcasecmp(*fs, "Timer")) + else if (!ass_strcasecmp(*fs, "Timer")) track->Timer = ass_atof(token); - else if (!strcasecmp(*fs, "WrapStyle")) + else if (!ass_strcasecmp(*fs, "WrapStyle")) track->WrapStyle = atoi(token); - else if (!strcasecmp(*fs, "ScaledBorderAndShadow")) + else if (!ass_strcasecmp(*fs, "ScaledBorderAndShadow")) track->ScaledBorderAndShadow = parse_bool(token); - else if (!strcasecmp(*fs, "Kerning")) + else if (!ass_strcasecmp(*fs, "Kerning")) track->Kerning = parse_bool(token); - else if (!strcasecmp(*fs, "YCbCr Matrix")) + else if (!ass_strcasecmp(*fs, "YCbCr Matrix")) track->YCbCrMatrix = parse_ycbcr_matrix(token); dt = strrchr(*fs, '.'); @@ -391,7 +387,7 @@ } for (sid = 0; sid < track->n_styles; ++sid) { if (style == NULL - || strcasecmp(track->styles[sid].Name, style) == 0) { + || ass_strcasecmp(track->styles[sid].Name, style) == 0) { target = track->styles + sid; PARSE_START STRVAL(FontName) @@ -578,7 +574,7 @@ track->YCbCrMatrix = parse_ycbcr_matrix(str + 13); } else if (!strncmp(str, "Language:", 9)) { char *p = str + 9; - while (*p && isspace(*p)) p++; + while (*p && ass_isspace(*p)) p++; track->Language = strndup(p, 2); } return 0; @@ -746,17 +742,17 @@ */ static int process_line(ASS_Track *track, char *str) { - if (!strncasecmp(str, "[Script Info]", 13)) { + if (!ass_strncasecmp(str, "[Script Info]", 13)) { track->parser_priv->state = PST_INFO; - } else if (!strncasecmp(str, "[V4 Styles]", 11)) { + } else if (!ass_strncasecmp(str, "[V4 Styles]", 11)) { track->parser_priv->state = PST_STYLES; track->track_type = TRACK_TYPE_SSA; - } else if (!strncasecmp(str, "[V4+ Styles]", 12)) { + } else if (!ass_strncasecmp(str, "[V4+ Styles]", 12)) { track->parser_priv->state = PST_STYLES; track->track_type = TRACK_TYPE_ASS; - } else if (!strncasecmp(str, "[Events]", 8)) { + } else if (!ass_strncasecmp(str, "[Events]", 8)) { track->parser_priv->state = PST_EVENTS; - } else if (!strncasecmp(str, "[Fonts]", 7)) { + } else if (!ass_strncasecmp(str, "[Fonts]", 7)) { track->parser_priv->state = PST_FONTS; } else { switch (track->parser_priv->state) { @@ -945,31 +941,12 @@ 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"); -#ifdef CONFIG_ENCA - if (cp_tmp != codepage) { - free((void*)cp_tmp); - } -#endif - } - - if (icdsc == (iconv_t) (-1)) + if ((icdsc = iconv_open(tocp, codepage)) != (iconv_t) (-1)) { + ass_msg(library, MSGL_V, "Opened iconv descriptor"); + } else { + ass_msg(library, MSGL_ERR, "Error opening iconv descriptor"); return NULL; + } { size_t osize = size; @@ -1021,7 +998,6 @@ out: if (icdsc != (iconv_t) (-1)) { (void) iconv_close(icdsc); - icdsc = (iconv_t) (-1); ass_msg(library, MSGL_V, "Closed iconv descriptor"); } @@ -1035,7 +1011,7 @@ * \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) +char *read_file(ASS_Library *library, char *fname, size_t *bufsize) { int res; long sz; @@ -1232,12 +1208,13 @@ buf = tmpbuf; } if (!buf) - return 0; + return 1; #endif old_state = track->parser_priv->state; track->parser_priv->state = PST_STYLES; process_text(track, buf); + free(buf); track->parser_priv->state = old_state; return 0; diff -Nru libass-0.12.2/libass/ass_cache.c libass-0.13.0/libass/ass_cache.c --- libass-0.12.2/libass/ass_cache.c 2015-03-06 12:23:04.000000000 +0000 +++ libass-0.13.0/libass/ass_cache.c 2015-09-24 08:34:34.000000000 +0000 @@ -18,6 +18,7 @@ */ #include "config.h" +#include "ass_compat.h" #include #include @@ -43,8 +44,6 @@ 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; } @@ -59,8 +58,6 @@ 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; diff -Nru libass-0.12.2/libass/ass_compat.h libass-0.13.0/libass/ass_compat.h --- libass-0.12.2/libass/ass_compat.h 1970-01-01 00:00:00.000000000 +0000 +++ libass-0.13.0/libass/ass_compat.h 2015-09-24 08:34:34.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015 Oleg Oshmyan + * + * 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_COMPAT_H +#define LIBASS_COMPAT_H + +#ifdef _MSC_VER +#define _CRT_NONSTDC_NO_DEPRECATE +#define _CRT_SECURE_NO_WARNINGS +#define _USE_MATH_DEFINES +#define inline __inline +#endif + +#endif /* LIBASS_COMPAT_H */ diff -Nru libass-0.12.2/libass/ass_coretext.c libass-0.13.0/libass/ass_coretext.c --- libass-0.12.2/libass/ass_coretext.c 1970-01-01 00:00:00.000000000 +0000 +++ libass-0.13.0/libass/ass_coretext.c 2015-09-24 08:34:34.000000000 +0000 @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2013 Stefano Pigozzi + * + * 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_compat.h" + +#include +#include + +#include "ass_coretext.h" + +#define SAFE_CFRelease(x) do { if (x) CFRelease(x); } while(0) + +static const ASS_FontMapping font_substitutions[] = { + {"sans-serif", "Helvetica"}, + {"serif", "Times"}, + {"monospace", "Courier"} +}; + +static char *cfstr2buf(CFStringRef string) +{ + const int encoding = kCFStringEncodingUTF8; + const char *buf_ptr = CFStringGetCStringPtr(string, encoding); + if (buf_ptr) { + return strdup(buf_ptr); + } else { + size_t len = CFStringGetLength(string); + CFIndex buf_len = CFStringGetMaximumSizeForEncoding(len, encoding); + char *buf = malloc(buf_len); + CFStringGetCString(string, buf, buf_len, encoding); + return buf; + } +} + +static void destroy_font(void *priv) +{ + CFCharacterSetRef set = priv; + SAFE_CFRelease(set); +} + +static int check_glyph(void *priv, uint32_t code) +{ + CFCharacterSetRef set = priv; + + if (!set) + return 1; + + if (code == 0) + return 1; + + return CFCharacterSetIsLongCharacterMember(set, code); +} + +static char *get_font_file(CTFontDescriptorRef fontd) +{ + CFURLRef url = CTFontDescriptorCopyAttribute(fontd, kCTFontURLAttribute); + CFStringRef path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); + char *buffer = cfstr2buf(path); + SAFE_CFRelease(path); + SAFE_CFRelease(url); + return buffer; +} + +static void get_name(CTFontDescriptorRef fontd, CFStringRef attr, + char **array, int *idx) +{ + + CFStringRef name = CTFontDescriptorCopyAttribute(fontd, attr); + if (name) { + array[*idx] = cfstr2buf(name); + SAFE_CFRelease(name); + *idx += 1; + } +} + +static void get_trait(CFDictionaryRef traits, CFStringRef attribute, + float *trait) +{ + CFNumberRef cftrait = CFDictionaryGetValue(traits, attribute); + if (!CFNumberGetValue(cftrait, kCFNumberFloatType, trait)) + *trait = 0.0; +} + +static void get_font_traits(CTFontDescriptorRef fontd, + ASS_FontProviderMetaData *meta) +{ + float weight, slant, width; + + CFDictionaryRef traits = + CTFontDescriptorCopyAttribute(fontd, kCTFontTraitsAttribute); + + get_trait(traits, kCTFontWeightTrait, &weight); + get_trait(traits, kCTFontSlantTrait, &slant); + get_trait(traits, kCTFontWidthTrait, &width); + + SAFE_CFRelease(traits); + + // Printed all of my system fonts (see if'deffed code below). Here is how + // CoreText 'normalized' weights maps to CSS/libass: + + // opentype: 0 100 200 300 400 500 600 700 800 900 + // css: LIGHT REG MED SBOLD BOLD BLACK EXTRABL + // libass: LIGHT MEDIUM BOLD + // coretext: -0.4 0.0 0.23 0.3 0.4 0.62 + + if (weight >= 0.62) + meta->weight = 800; + else if (weight >= 0.4) + meta->weight = 700; + else if (weight >= 0.3) + meta->weight = 600; + else if (weight >= 0.23) + meta->weight = 500; + else if (weight >= -0.4) + meta->weight = 400; + else + meta->weight = 200; + + if (slant > 0.03) + meta->slant = FONT_SLANT_ITALIC; + else + meta->slant = FONT_SLANT_NONE; + + if (width <= -0.2) + meta->width = FONT_WIDTH_CONDENSED; + else if (width >= 0.2) + meta->width = FONT_WIDTH_EXPANDED; + else + meta->width = FONT_WIDTH_NORMAL; + +#if 0 + char *name[1]; + int idx = 0; + get_name(fontd, kCTFontDisplayNameAttribute, name, &idx); + char *file = get_font_file(fontd); + printf( + "Font traits for: %-40s [%-50s] " + ", , \n", + name[0], file, + slant, meta->slant, weight, meta->weight, width, meta->width); + free(name[0]); + free(file); +#endif +} + +static void process_descriptors(ASS_FontProvider *provider, CFArrayRef fontsd) +{ + ASS_FontProviderMetaData meta; + char *families[1]; + char *identifiers[1]; + char *fullnames[1]; + + if (!fontsd) + return; + + for (int i = 0; i < CFArrayGetCount(fontsd); i++) { + CTFontDescriptorRef fontd = CFArrayGetValueAtIndex(fontsd, i); + int index = -1; + + char *path = get_font_file(fontd); + if (strcmp("", path) == 0) { + // skip the font if the URL field in the font descriptor is empty + free(path); + continue; + } + + memset(&meta, 0, sizeof(meta)); + get_font_traits(fontd, &meta); + + get_name(fontd, kCTFontFamilyNameAttribute, families, &meta.n_family); + meta.families = families; + + int zero = 0; + get_name(fontd, kCTFontNameAttribute, identifiers, &zero); + get_name(fontd, kCTFontDisplayNameAttribute, fullnames, &meta.n_fullname); + meta.fullnames = fullnames; + + CFCharacterSetRef chset = + CTFontDescriptorCopyAttribute(fontd, kCTFontCharacterSetAttribute); + ass_font_provider_add_font(provider, &meta, path, index, + identifiers[0], (void*)chset); + + for (int j = 0; j < meta.n_family; j++) + free(meta.families[j]); + + for (int j = 0; j < meta.n_fullname; j++) + free(meta.fullnames[j]); + + free(identifiers[0]); + + free(path); + } +} + +static void match_fonts(ASS_Library *lib, ASS_FontProvider *provider, + char *name) +{ + const size_t attributes_n = 3; + CTFontDescriptorRef ctdescrs[attributes_n]; + CFMutableDictionaryRef cfattrs[attributes_n]; + CFStringRef attributes[attributes_n] = { + kCTFontFamilyNameAttribute, + kCTFontDisplayNameAttribute, + kCTFontNameAttribute, + }; + + CFStringRef cfname = + CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8); + + for (int i = 0; i < attributes_n; i++) { + cfattrs[i] = CFDictionaryCreateMutable(NULL, 0, 0, 0); + CFDictionaryAddValue(cfattrs[i], attributes[i], cfname); + ctdescrs[i] = CTFontDescriptorCreateWithAttributes(cfattrs[i]); + } + + CFArrayRef descriptors = + CFArrayCreate(NULL, (const void **)&ctdescrs, attributes_n, NULL); + + CTFontCollectionRef ctcoll = + CTFontCollectionCreateWithFontDescriptors(descriptors, 0); + + CFArrayRef fontsd = + CTFontCollectionCreateMatchingFontDescriptors(ctcoll); + + process_descriptors(provider, fontsd); + + SAFE_CFRelease(fontsd); + SAFE_CFRelease(ctcoll); + + for (int i = 0; i < attributes_n; i++) { + SAFE_CFRelease(cfattrs[i]); + SAFE_CFRelease(ctdescrs[i]); + } + + SAFE_CFRelease(descriptors); + SAFE_CFRelease(cfname); +} + +static char *get_fallback(void *priv, const char *family, uint32_t codepoint) +{ + CFStringRef name = CFStringCreateWithBytes( + 0, (UInt8 *)family, strlen(family), kCFStringEncodingUTF8, false); + CTFontRef font = CTFontCreateWithName(name, 0, NULL); + uint32_t codepointle = OSSwapHostToLittleInt32(codepoint); + CFStringRef r = CFStringCreateWithBytes( + 0, (UInt8*)&codepointle, sizeof(codepointle), + kCFStringEncodingUTF32LE, false); + CTFontRef fb = CTFontCreateForString(font, r, CFRangeMake(0, 1)); + CFStringRef cffamily = CTFontCopyFamilyName(fb); + char *res_family = cfstr2buf(cffamily); + + SAFE_CFRelease(name); + SAFE_CFRelease(font); + SAFE_CFRelease(r); + SAFE_CFRelease(fb); + SAFE_CFRelease(cffamily); + + return res_family; +} + +static void get_substitutions(void *priv, const char *name, + ASS_FontProviderMetaData *meta) +{ + const int n = sizeof(font_substitutions) / sizeof(font_substitutions[0]); + ass_map_font(font_substitutions, n, name, meta); +} + +static ASS_FontProviderFuncs coretext_callbacks = { + .check_glyph = check_glyph, + .destroy_font = destroy_font, + .match_fonts = match_fonts, + .get_substitutions = get_substitutions, + .get_fallback = get_fallback, +}; + +ASS_FontProvider * +ass_coretext_add_provider(ASS_Library *lib, ASS_FontSelector *selector, + const char *config) +{ + return ass_font_provider_new(selector, &coretext_callbacks, NULL); +} diff -Nru libass-0.12.2/libass/ass_coretext.h libass-0.13.0/libass/ass_coretext.h --- libass-0.12.2/libass/ass_coretext.h 1970-01-01 00:00:00.000000000 +0000 +++ libass-0.13.0/libass/ass_coretext.h 2015-09-24 08:34:34.000000000 +0000 @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2013 Stefano Pigozzi + * + * 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 "ass_types.h" +#include "ass_fontselect.h" + +#ifndef ASS_CORETEXT_H +#define ASS_CORETEXT_H + +#ifdef CONFIG_CORETEXT + +ASS_FontProvider * +ass_coretext_add_provider(ASS_Library *lib, ASS_FontSelector *selector, + const char *config); + +#endif + +#endif diff -Nru libass-0.12.2/libass/ass_directwrite.c libass-0.13.0/libass/ass_directwrite.c --- libass-0.12.2/libass/ass_directwrite.c 1970-01-01 00:00:00.000000000 +0000 +++ libass-0.13.0/libass/ass_directwrite.c 2015-09-24 08:34:34.000000000 +0000 @@ -0,0 +1,716 @@ +/* + * Copyright (C) 2015 Stephan Vedder + * + * 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. + */ +#define COBJMACROS + +#include "config.h" +#include "ass_compat.h" + +#include +#include +#include + +#include "dwrite_c.h" + +#include "ass_directwrite.h" +#include "ass_utils.h" + +#define NAME_MAX_LENGTH 256 +#define FALLBACK_DEFAULT_FONT L"Arial" + +static const ASS_FontMapping font_substitutions[] = { + {"sans-serif", "Arial"}, + {"serif", "Times New Roman"}, + {"monospace", "Courier New"} +}; + +/* + * The private data stored for every font, detected by this backend. + */ +typedef struct { + IDWriteFont *font; + IDWriteFontFileStream *stream; +} FontPrivate; + +typedef struct { + HMODULE directwrite_lib; + IDWriteFactory *factory; +} ProviderPrivate; + +/** + * Custom text renderer class for logging the fonts used. It does not + * actually render anything or do anything apart from that. + */ + +typedef struct FallbackLogTextRenderer { + IDWriteTextRenderer iface; + IDWriteTextRendererVtbl vtbl; + IDWriteFactory *dw_factory; + LONG ref_count; +} FallbackLogTextRenderer; + +static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_IsPixelSnappingDisabled( + IDWriteTextRenderer *This, + _In_opt_ void* clientDrawingContext, + _Out_ BOOL* isDisabled + ) +{ + *isDisabled = true; + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_GetCurrentTransform( + IDWriteTextRenderer *This, + _In_opt_ void* clientDrawingContext, + _Out_ DWRITE_MATRIX* transform + ) +{ + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_GetPixelsPerDip( + IDWriteTextRenderer *This, + _In_opt_ void* clientDrawingContext, + _Out_ FLOAT* pixelsPerDip + ) +{ + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_DrawGlyphRun( + IDWriteTextRenderer *This, + _In_opt_ void* clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + DWRITE_MEASURING_MODE measuringMode, + _In_ DWRITE_GLYPH_RUN const* glyphRun, + _In_ DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, + IUnknown* clientDrawingEffect + ) +{ + FallbackLogTextRenderer *this = (FallbackLogTextRenderer *)This; + HRESULT hr; + IDWriteFontCollection *font_coll = NULL; + IDWriteFont **font = (IDWriteFont **)clientDrawingContext; + + hr = IDWriteFactory_GetSystemFontCollection(this->dw_factory, &font_coll, FALSE); + if (FAILED(hr)) + return E_FAIL; + + hr = IDWriteFontCollection_GetFontFromFontFace(font_coll, glyphRun->fontFace, + font); + if (FAILED(hr)) + return E_FAIL; + + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_DrawUnderline( + IDWriteTextRenderer *This, + _In_opt_ void* clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + _In_ DWRITE_UNDERLINE const* underline, + IUnknown* clientDrawingEffect + ) +{ + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_DrawStrikethrough( + IDWriteTextRenderer *This, + _In_opt_ void* clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + _In_ DWRITE_STRIKETHROUGH const* strikethrough, + IUnknown* clientDrawingEffect + ) +{ + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_DrawInlineObject( + IDWriteTextRenderer *This, + void *clientDrawingContext, + FLOAT originX, + FLOAT originY, + IDWriteInlineObject *inlineObject, + BOOL isSideways, + BOOL isRightToLeft, + IUnknown *clientDrawingEffect + ) +{ + return S_OK; +} + +// IUnknown methods + +static ULONG STDMETHODCALLTYPE FallbackLogTextRenderer_AddRef( + IDWriteTextRenderer *This + ) +{ + FallbackLogTextRenderer *this = (FallbackLogTextRenderer *)This; + return InterlockedIncrement(&this->ref_count); +} + +static ULONG STDMETHODCALLTYPE FallbackLogTextRenderer_Release( + IDWriteTextRenderer *This + ) +{ + FallbackLogTextRenderer *this = (FallbackLogTextRenderer *)This; + unsigned long new_count = InterlockedDecrement(&this->ref_count); + if (new_count == 0) { + free(this); + return 0; + } + + return new_count; +} + +static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_QueryInterface( + IDWriteTextRenderer *This, + REFIID riid, + void **ppvObject + ) +{ + if (IsEqualGUID(riid, &IID_IDWriteTextRenderer) + || IsEqualGUID(riid, &IID_IDWritePixelSnapping) + || IsEqualGUID(riid, &IID_IUnknown)) { + *ppvObject = This; + } else { + *ppvObject = NULL; + return E_FAIL; + } + + This->lpVtbl->AddRef(This); + return S_OK; +} + +static void init_FallbackLogTextRenderer(FallbackLogTextRenderer *r, + IDWriteFactory *factory) +{ + *r = (FallbackLogTextRenderer){ + .iface = { + .lpVtbl = &r->vtbl, + }, + .vtbl = { + FallbackLogTextRenderer_QueryInterface, + FallbackLogTextRenderer_AddRef, + FallbackLogTextRenderer_Release, + FallbackLogTextRenderer_IsPixelSnappingDisabled, + FallbackLogTextRenderer_GetCurrentTransform, + FallbackLogTextRenderer_GetPixelsPerDip, + FallbackLogTextRenderer_DrawGlyphRun, + FallbackLogTextRenderer_DrawUnderline, + FallbackLogTextRenderer_DrawStrikethrough, + FallbackLogTextRenderer_DrawInlineObject, + }, + .dw_factory = factory, + }; +} + +/* + * This function is called whenever a font is used for the first + * time. It will create a FontStream for memory reading, which + * will be stored within the private data. + */ +static bool init_font_private(FontPrivate *priv) +{ + HRESULT hr = S_OK; + IDWriteFont *font = priv->font; + IDWriteFontFace *face = NULL; + IDWriteFontFile *file = NULL; + IDWriteFontFileStream *stream = NULL; + IDWriteFontFileLoader *loader = NULL; + UINT32 n_files = 1; + const void *refKey = NULL; + UINT32 keySize = 0; + + if (priv->stream != NULL) + return true; + + hr = IDWriteFont_CreateFontFace(font, &face); + if (FAILED(hr) || !face) + return false; + + /* DirectWrite only supports one file per face */ + hr = IDWriteFontFace_GetFiles(face, &n_files, &file); + if (FAILED(hr) || !file) { + IDWriteFontFace_Release(face); + return false; + } + + hr = IDWriteFontFile_GetReferenceKey(file, &refKey, &keySize); + if (FAILED(hr)) { + IDWriteFontFile_Release(file); + IDWriteFontFace_Release(face); + return false; + } + + hr = IDWriteFontFile_GetLoader(file, &loader); + if (FAILED(hr) || !loader) { + IDWriteFontFile_Release(file); + IDWriteFontFace_Release(face); + return false; + } + + hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, refKey, keySize, &stream); + if (FAILED(hr) || !stream) { + IDWriteFontFile_Release(file); + IDWriteFontFace_Release(face); + return false; + } + + priv->stream = stream; + IDWriteFontFile_Release(file); + IDWriteFontFace_Release(face); + + return true; +} + +/* + * Read a specified part of a fontfile into memory. + * If the font wasn't used before first creates a + * FontStream and save it into the private data for later usage. + * If the parameter "buf" is NULL libass wants to know the + * size of the Fontfile + */ +static size_t get_data(void *data, unsigned char *buf, size_t offset, + size_t length) +{ + HRESULT hr = S_OK; + FontPrivate *priv = (FontPrivate *) data; + const void *fileBuf = NULL; + void *fragContext = NULL; + + if (!init_font_private(priv)) + return 0; + + if (buf == NULL) { + UINT64 fileSize; + hr = IDWriteFontFileStream_GetFileSize(priv->stream, &fileSize); + if (FAILED(hr)) + return 0; + + return fileSize; + } + + hr = IDWriteFontFileStream_ReadFileFragment(priv->stream, &fileBuf, offset, + length, &fragContext); + + if (FAILED(hr) || !fileBuf) + return 0; + + memcpy(buf, fileBuf, length); + + IDWriteFontFileStream_ReleaseFileFragment(priv->stream, fragContext); + + return length; +} + +/* + * Checks if the passed font has a specific unicode + * character. Returns 0 for failure and 1 for success + */ +static int check_glyph(void *data, uint32_t code) +{ + HRESULT hr = S_OK; + FontPrivate *priv = (FontPrivate *) data; + BOOL exists = FALSE; + + if (code == 0) + return 1; + + IDWriteFont_HasCharacter(priv->font, code, &exists); + if (FAILED(hr)) + return 0; + + return exists; +} + +/* + * This will release the directwrite backend + */ +static void destroy_provider(void *priv) +{ + ProviderPrivate *provider_priv = (ProviderPrivate *)priv; + provider_priv->factory->lpVtbl->Release(provider_priv->factory); + FreeLibrary(provider_priv->directwrite_lib); + free(provider_priv); +} + +/* + * This will destroy a specific font and it's + * Fontstream (in case it does exist) + */ + +static void destroy_font(void *data) +{ + FontPrivate *priv = (FontPrivate *) data; + + IDWriteFont_Release(priv->font); + if (priv->stream != NULL) + IDWriteFontFileStream_Release(priv->stream); + + free(priv); +} + +static int encode_utf16(wchar_t *chars, uint32_t codepoint) +{ + if (codepoint < 0x10000) { + chars[0] = codepoint; + return 1; + } else { + chars[0] = (codepoint >> 10) + 0xD7C0; + chars[1] = (codepoint & 0x3FF) + 0xDC00; + return 2; + } +} + +static char *get_fallback(void *priv, const char *base, uint32_t codepoint) +{ + HRESULT hr; + ProviderPrivate *provider_priv = (ProviderPrivate *)priv; + IDWriteFactory *dw_factory = provider_priv->factory; + IDWriteTextFormat *text_format = NULL; + IDWriteTextLayout *text_layout = NULL; + FallbackLogTextRenderer renderer; + + init_FallbackLogTextRenderer(&renderer, dw_factory); + + hr = IDWriteFactory_CreateTextFormat(dw_factory, FALLBACK_DEFAULT_FONT, NULL, + DWRITE_FONT_WEIGHT_MEDIUM, DWRITE_FONT_STYLE_NORMAL, + DWRITE_FONT_STRETCH_NORMAL, 1.0f, L"", &text_format); + if (FAILED(hr)) { + return NULL; + } + + // Encode codepoint as UTF-16 + wchar_t char_string[2]; + int char_len = encode_utf16(char_string, codepoint); + + // Create a text_layout, a high-level text rendering facility, using + // the given codepoint and dummy format. + hr = IDWriteFactory_CreateTextLayout(dw_factory, char_string, char_len, text_format, + 0.0f, 0.0f, &text_layout); + if (FAILED(hr)) { + IDWriteTextFormat_Release(text_format); + return NULL; + } + + // Draw the layout with a dummy renderer, which logs the + // font used and stores it. + IDWriteFont *font = NULL; + hr = IDWriteTextLayout_Draw(text_layout, &font, &renderer.iface, 0.0f, 0.0f); + if (FAILED(hr) || font == NULL) { + IDWriteTextLayout_Release(text_layout); + IDWriteTextFormat_Release(text_format); + return NULL; + } + + // We're done with these now + IDWriteTextLayout_Release(text_layout); + IDWriteTextFormat_Release(text_format); + + // Now, just extract the first family name + BOOL exists = FALSE; + IDWriteLocalizedStrings *familyNames = NULL; + hr = IDWriteFont_GetInformationalStrings(font, + DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, + &familyNames, &exists); + if (FAILED(hr) || !exists) { + IDWriteFont_Release(font); + return NULL; + } + + wchar_t temp_name[NAME_MAX_LENGTH]; + hr = IDWriteLocalizedStrings_GetString(familyNames, 0, temp_name, NAME_MAX_LENGTH); + if (FAILED(hr)) { + IDWriteLocalizedStrings_Release(familyNames); + IDWriteFont_Release(font); + return NULL; + } + temp_name[NAME_MAX_LENGTH-1] = 0; + + // DirectWrite may not have found a valid fallback, so check that + // the selected font actually has the requested glyph. + if (codepoint > 0) { + hr = IDWriteFont_HasCharacter(font, codepoint, &exists); + if (FAILED(hr) || !exists) { + IDWriteLocalizedStrings_Release(familyNames); + IDWriteFont_Release(font); + return NULL; + } + } + + int size_needed = WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, NULL, 0,NULL, NULL); + char *family = (char *) malloc(size_needed); + WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, family, size_needed, NULL, NULL); + + IDWriteLocalizedStrings_Release(familyNames); + IDWriteFont_Release(font); + return family; +} + +static int map_width(enum DWRITE_FONT_STRETCH stretch) +{ + switch (stretch) { + case DWRITE_FONT_STRETCH_ULTRA_CONDENSED: return 50; + case DWRITE_FONT_STRETCH_EXTRA_CONDENSED: return 63; + case DWRITE_FONT_STRETCH_CONDENSED: return FONT_WIDTH_CONDENSED; + case DWRITE_FONT_STRETCH_SEMI_CONDENSED: return 88; + case DWRITE_FONT_STRETCH_MEDIUM: return FONT_WIDTH_NORMAL; + case DWRITE_FONT_STRETCH_SEMI_EXPANDED: return 113; + case DWRITE_FONT_STRETCH_EXPANDED: return FONT_WIDTH_EXPANDED; + case DWRITE_FONT_STRETCH_EXTRA_EXPANDED: return 150; + case DWRITE_FONT_STRETCH_ULTRA_EXPANDED: return 200; + default: + return FONT_WIDTH_NORMAL; + } +} + +/* + * Scan every system font on the current machine and add it + * to the libass lookup. Stores the FontPrivate as private data + * for later memory reading + */ +static void scan_fonts(IDWriteFactory *factory, + ASS_FontProvider *provider) +{ + HRESULT hr = S_OK; + IDWriteFontCollection *fontCollection = NULL; + IDWriteFont *font = NULL; + DWRITE_FONT_METRICS metrics; + DWRITE_FONT_STYLE style; + ASS_FontProviderMetaData meta = {0}; + hr = IDWriteFactory_GetSystemFontCollection(factory, &fontCollection, FALSE); + wchar_t temp_name[NAME_MAX_LENGTH]; + int size_needed = 0; + + if (FAILED(hr) || !fontCollection) + return; + + UINT32 familyCount = IDWriteFontCollection_GetFontFamilyCount(fontCollection); + + for (UINT32 i = 0; i < familyCount; ++i) { + IDWriteFontFamily *fontFamily = NULL; + IDWriteLocalizedStrings *familyNames = NULL; + IDWriteLocalizedStrings *fontNames = NULL; + IDWriteLocalizedStrings *psNames = NULL; + BOOL exists = FALSE; + char *psName = NULL; + + hr = IDWriteFontCollection_GetFontFamily(fontCollection, i, &fontFamily); + if (FAILED(hr)) + continue; + + UINT32 fontCount = IDWriteFontFamily_GetFontCount(fontFamily); + for (UINT32 j = 0; j < fontCount; ++j) { + hr = IDWriteFontFamily_GetFont(fontFamily, j, &font); + if (FAILED(hr)) + continue; + + // Simulations for bold or oblique are sometimes synthesized by + // DirectWrite. We are only interested in physical fonts. + if (IDWriteFont_GetSimulations(font) != 0) { + IDWriteFont_Release(font); + continue; + } + + meta.weight = IDWriteFont_GetWeight(font); + meta.width = map_width(IDWriteFont_GetStretch(font)); + IDWriteFont_GetMetrics(font, &metrics); + style = IDWriteFont_GetStyle(font); + meta.slant = (style == DWRITE_FONT_STYLE_NORMAL) ? FONT_SLANT_NONE : + (style == DWRITE_FONT_STYLE_OBLIQUE)? FONT_SLANT_OBLIQUE : + (style == DWRITE_FONT_STYLE_ITALIC) ? FONT_SLANT_ITALIC : FONT_SLANT_NONE; + + hr = IDWriteFont_GetInformationalStrings(font, + DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, &psNames,&exists); + if (FAILED(hr)) { + IDWriteFont_Release(font); + continue; + } + + if (exists) { + hr = IDWriteLocalizedStrings_GetString(psNames, 0, temp_name, NAME_MAX_LENGTH); + if (FAILED(hr)) { + IDWriteLocalizedStrings_Release(psNames); + IDWriteFont_Release(font); + continue; + } + + temp_name[NAME_MAX_LENGTH-1] = 0; + size_needed = WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, NULL, 0,NULL, NULL); + psName = (char *) malloc(size_needed); + WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, psName, size_needed, NULL, NULL); + IDWriteLocalizedStrings_Release(psNames); + } + + hr = IDWriteFont_GetInformationalStrings(font, + DWRITE_INFORMATIONAL_STRING_FULL_NAME, &fontNames,&exists); + if (FAILED(hr)) { + IDWriteFont_Release(font); + continue; + } + + if (exists) { + meta.n_fullname = IDWriteLocalizedStrings_GetCount(fontNames); + meta.fullnames = (char **) calloc(meta.n_fullname, sizeof(char *)); + for (UINT32 k = 0; k < meta.n_fullname; ++k) { + hr = IDWriteLocalizedStrings_GetString(fontNames, k, + temp_name, + NAME_MAX_LENGTH); + if (FAILED(hr)) { + continue; + } + + temp_name[NAME_MAX_LENGTH-1] = 0; + size_needed = WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, NULL, 0, NULL, NULL); + char *mbName = (char *) malloc(size_needed); + WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, mbName, size_needed, NULL, NULL); + meta.fullnames[k] = mbName; + } + IDWriteLocalizedStrings_Release(fontNames); + } + + hr = IDWriteFont_GetInformationalStrings(font, + DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &familyNames, &exists); + if (!exists) + hr = IDWriteFontFamily_GetFamilyNames(fontFamily, &familyNames); + if (FAILED(hr)) { + IDWriteFont_Release(font); + continue; + } + + meta.n_family = IDWriteLocalizedStrings_GetCount(familyNames); + meta.families = (char **) calloc(meta.n_family, sizeof(char *)); + for (UINT32 k = 0; k < meta.n_family; ++k) { + hr = IDWriteLocalizedStrings_GetString(familyNames, k, + temp_name, + NAME_MAX_LENGTH); + if (FAILED(hr)) { + continue; + } + + temp_name[NAME_MAX_LENGTH-1] = 0; + size_needed = WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, NULL, 0,NULL, NULL); + char *mbName = (char *) malloc(size_needed); + WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, mbName, size_needed, NULL, NULL); + meta.families[k] = mbName; + } + IDWriteLocalizedStrings_Release(familyNames); + + FontPrivate *font_priv = (FontPrivate *) calloc(1, sizeof(*font_priv)); + font_priv->font = font; + + ass_font_provider_add_font(provider, &meta, NULL, 0, psName, font_priv); + + for (UINT32 k = 0; k < meta.n_family; ++k) + free(meta.families[k]); + for (UINT32 k = 0; k < meta.n_fullname; ++k) + free(meta.fullnames[k]); + free(meta.fullnames); + free(meta.families); + free(psName); + } + } +} + +static void get_substitutions(void *priv, const char *name, + ASS_FontProviderMetaData *meta) +{ + const int n = sizeof(font_substitutions) / sizeof(font_substitutions[0]); + ass_map_font(font_substitutions, n, name, meta); +} + +/* + * Called by libass when the provider should perform the + * specified task + */ +static ASS_FontProviderFuncs directwrite_callbacks = { + .get_data = get_data, + .check_glyph = check_glyph, + .destroy_font = destroy_font, + .destroy_provider = destroy_provider, + .get_substitutions = get_substitutions, + .get_fallback = get_fallback, +}; + +typedef HRESULT (WINAPI *DWriteCreateFactoryFn)( + _In_ DWRITE_FACTORY_TYPE factoryType, + _In_ REFIID iid, + _Out_ IUnknown **factory +); + +/* + * Register the directwrite provider. Upon registering + * scans all system fonts. The private data for this + * provider is IDWriteFactory + * On failure returns NULL + */ +ASS_FontProvider *ass_directwrite_add_provider(ASS_Library *lib, + ASS_FontSelector *selector, + const char *config) +{ + HRESULT hr = S_OK; + IDWriteFactory *dwFactory = NULL; + ASS_FontProvider *provider = NULL; + DWriteCreateFactoryFn DWriteCreateFactoryPtr = NULL; + ProviderPrivate *priv = NULL; + + HMODULE directwrite_lib = LoadLibraryW(L"Dwrite.dll"); + if (!directwrite_lib) + goto cleanup; + + DWriteCreateFactoryPtr = (DWriteCreateFactoryFn)GetProcAddress(directwrite_lib, + "DWriteCreateFactory"); + if (!DWriteCreateFactoryPtr) + goto cleanup; + + hr = DWriteCreateFactoryPtr(DWRITE_FACTORY_TYPE_SHARED, + &IID_IDWriteFactory, + (IUnknown **) (&dwFactory)); + if (FAILED(hr) || !dwFactory) { + ass_msg(lib, MSGL_WARN, "Failed to initialize directwrite."); + dwFactory = NULL; + goto cleanup; + } + + priv = (ProviderPrivate *)calloc(sizeof(*priv), 1); + if (!priv) + goto cleanup; + + priv->directwrite_lib = directwrite_lib; + priv->factory = dwFactory; + provider = ass_font_provider_new(selector, &directwrite_callbacks, priv); + if (!provider) + goto cleanup; + + scan_fonts(dwFactory, provider); + return provider; + +cleanup: + + free(priv); + if (dwFactory) + dwFactory->lpVtbl->Release(dwFactory); + if (directwrite_lib) + FreeLibrary(directwrite_lib); + + return NULL; +} diff -Nru libass-0.12.2/libass/ass_directwrite.h libass-0.13.0/libass/ass_directwrite.h --- libass-0.12.2/libass/ass_directwrite.h 1970-01-01 00:00:00.000000000 +0000 +++ libass-0.13.0/libass/ass_directwrite.h 2015-09-24 08:34:34.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015 Stephan Vedder + * + * 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 "ass_types.h" +#include "ass_fontselect.h" + +#ifndef ASS_DIRECTWRITE_H +#define ASS_DIRECTWRITE_H + +ASS_FontProvider * +ass_directwrite_add_provider(ASS_Library *lib, ASS_FontSelector *selector, + const char *config); + +#endif diff -Nru libass-0.12.2/libass/ass_drawing.c libass-0.13.0/libass/ass_drawing.c --- libass-0.12.2/libass/ass_drawing.c 2015-03-09 21:18:25.000000000 +0000 +++ libass-0.13.0/libass/ass_drawing.c 2015-09-24 08:34:34.000000000 +0000 @@ -16,6 +16,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "config.h" +#include "ass_compat.h" + #include #include FT_OUTLINE_H #include FT_BBOX_H @@ -296,7 +299,10 @@ drawing->scale_x = 1.; drawing->scale_y = 1.; - outline_alloc(&drawing->outline, GLYPH_INITIAL_POINTS, GLYPH_INITIAL_CONTOURS); + if (!outline_alloc(&drawing->outline, GLYPH_INITIAL_POINTS, GLYPH_INITIAL_CONTOURS)) { + free(drawing); + return NULL; + } return drawing; } diff -Nru libass-0.12.2/libass/ass_font.c libass-0.13.0/libass/ass_font.c --- libass-0.12.2/libass/ass_font.c 2015-03-06 12:21:09.000000000 +0000 +++ libass-0.13.0/libass/ass_font.c 2015-09-24 08:34:34.000000000 +0000 @@ -17,6 +17,7 @@ */ #include "config.h" +#include "ass_compat.h" #include #include @@ -25,13 +26,12 @@ #include FT_GLYPH_H #include FT_TRUETYPE_TABLES_H #include FT_OUTLINE_H -#include #include #include "ass.h" #include "ass_library.h" #include "ass_font.h" -#include "ass_fontconfig.h" +#include "ass_fontselect.h" #include "ass_utils.h" #include "ass_shaper.h" @@ -39,7 +39,7 @@ * Select a good charmap, prefer Microsoft Unicode charmaps. * Otherwise, let FreeType decide. */ -static void charmap_magic(ASS_Library *library, FT_Face face) +void charmap_magic(ASS_Library *library, FT_Face face) { int i; int ms_cmap = -1; @@ -92,18 +92,6 @@ } } -/** - * \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. @@ -123,57 +111,108 @@ } } +static unsigned long +read_stream_font(FT_Stream stream, unsigned long offset, unsigned char *buffer, + unsigned long count) +{ + ASS_FontStream *font = (ASS_FontStream *)stream->descriptor.pointer; + + font->func(font->priv, buffer, offset, count); + return count; +} + +static void +close_stream_font(FT_Stream stream) +{ + free(stream->descriptor.pointer); + free(stream); +} + /** * \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) +static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch) { char *path; - int index; + char *postscript_name = NULL; + int i, index, uid, error; + ASS_FontStream stream = { NULL, NULL }; 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); + path = ass_font_select(fontsel, font->library, font , &index, + &postscript_name, &uid, &stream, 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); + for (i = 0; i < font->n_faces; i++) { + if (font->faces_uid[i] == uid) { + ass_msg(font->library, MSGL_INFO, + "Got a font face that already is available! Skipping."); + return i; + } + } + + if (stream.func) { + FT_Open_Args args; + FT_Stream ftstream = calloc(1, sizeof(FT_StreamRec)); + ASS_FontStream *fs = calloc(1, sizeof(ASS_FontStream)); + + *fs = stream; + ftstream->size = stream.func(stream.priv, NULL, 0, 0); + ftstream->read = read_stream_font; + ftstream->close = close_stream_font; + ftstream->descriptor.pointer = (void *)fs; + + memset(&args, 0, sizeof(FT_Open_Args)); + args.flags = FT_OPEN_STREAM; + args.stream = ftstream; + + error = FT_Open_Face(font->ftlibrary, &args, 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; } + + if (postscript_name && index < 0 && face->num_faces > 0) { + // The font provider gave us a post_script name and is not sure + // about the face index.. so use the postscript name to find the + // correct face_index in the collection! + for (int i = 0; i < face->num_faces; i++) { + FT_Done_Face(face); + error = FT_New_Face(font->ftlibrary, path, i, &face); + if (error) { + ass_msg(font->library, MSGL_WARN, + "Error opening font: '%s', %d", path, i); + return -1; + } + + if (strcmp(FT_Get_Postscript_Name(face), postscript_name) == 0) + break; + } + } } + charmap_magic(font->library, face); buggy_font_workaround(face); - font->faces[font->n_faces++] = face; + font->faces[font->n_faces] = face; + font->faces_uid[font->n_faces++] = uid; ass_face_set_size(face, font->size); - free(path); return font->n_faces - 1; } @@ -181,7 +220,7 @@ * \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, + FT_Library ftlibrary, ASS_FontSelector *fontsel, ASS_FontDesc *desc) { int error; @@ -197,7 +236,6 @@ 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; @@ -206,7 +244,7 @@ font.v.x = font.v.y = 0; font.size = 0.; - error = add_face(fc_priv, &font, 0); + error = add_face(fontsel, &font, 0); if (error == -1) { free(font.desc.family); return 0; @@ -338,7 +376,7 @@ 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; - int bear, advance, y_scale, i, dir; + int advance, y_scale, i, dir; if (!under && !through) return 0; @@ -357,11 +395,7 @@ if (!ASS_REALLOC_ARRAY(ol->contours, ol->n_contours + i)) return 0; - // 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; + advance = d16_to_d6(glyph->advance.x); y_scale = face->size->metrics.y_scale; // Reverse drawing direction for non-truetype fonts @@ -369,24 +403,23 @@ // Add points to the outline if (under && ps) { - int pos = FT_MulFix(ps->underlinePosition, y_scale * font->scale_y); - int size = FT_MulFix(ps->underlineThickness, - y_scale * font->scale_y / 2); + int pos = FT_MulFix(ps->underlinePosition, y_scale); + int size = FT_MulFix(ps->underlineThickness, y_scale / 2); if (pos > 0 || size <= 0) return 1; - add_line(ol, bear, advance, dir, pos, size); + add_line(ol, 0, advance, dir, pos, size); } if (through && os2) { - int pos = FT_MulFix(os2->yStrikeoutPosition, y_scale * font->scale_y); - int size = FT_MulFix(os2->yStrikeoutSize, y_scale * font->scale_y / 2); + int pos = FT_MulFix(os2->yStrikeoutPosition, y_scale); + int size = FT_MulFix(os2->yStrikeoutSize, y_scale / 2); if (pos < 0 || size <= 0) return 1; - add_line(ol, bear, advance, dir, pos, size); + add_line(ol, 0, advance, dir, pos, size); } return 0; @@ -484,8 +517,8 @@ * 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 ass_font_get_index(ASS_FontSelector *fontsel, ASS_Font *font, + uint32_t symbol, int *face_index, int *glyph_index) { int index = 0; int i; @@ -519,14 +552,13 @@ *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); + face_idx = *face_index = add_face(fontsel, font, symbol); if (face_idx >= 0) { face = font->faces[face_idx]; index = FT_Get_Char_Index(face, ass_font_index_magic(face, symbol)); @@ -547,7 +579,7 @@ } } } -#endif + // FIXME: make sure we have a valid face_index. this is a HACK. *face_index = FFMAX(*face_index, 0); *glyph_index = index; @@ -559,9 +591,8 @@ * \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) +FT_Glyph ass_font_get_glyph(ASS_Font *font, uint32_t ch, int face_index, + int index, ASS_Hinting hinting, int deco) { int error; FT_Glyph glyph; @@ -597,7 +628,7 @@ } if (!(face->style_flags & FT_STYLE_FLAG_BOLD) && - (font->desc.bold > 80)) { + (font->desc.bold > 400)) { ass_glyph_embolden(face->glyph); } error = FT_Get_Glyph(face->glyph, &glyph); @@ -623,6 +654,9 @@ glyph->advance.x = face->glyph->linearVertAdvance; } + ass_strike_outline_glyph(face, font, glyph, deco & DECO_UNDERLINE, + deco & DECO_STRIKETHROUGH); + // Apply scaling and shift FT_Matrix scale = { double_to_d16(font->scale_x), 0, 0, double_to_d16(font->scale_y) }; @@ -631,9 +665,6 @@ 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; } @@ -671,9 +702,10 @@ int i; if (font->shaper_priv) ass_shaper_font_data_free(font->shaper_priv); - for (i = 0; i < font->n_faces; ++i) + for (i = 0; i < font->n_faces; ++i) { if (font->faces[i]) FT_Done_Face(font->faces[i]); + } free(font->desc.family); free(font); } diff -Nru libass-0.12.2/libass/ass_fontconfig.c libass-0.13.0/libass/ass_fontconfig.c --- libass-0.12.2/libass/ass_fontconfig.c 2014-11-18 18:40:49.000000000 +0000 +++ libass-0.13.0/libass/ass_fontconfig.c 2015-09-24 08:34:34.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Evgeniy Stepanov + * Copyright (C) 2011 Grigori Goronzy * * This file is part of libass. * @@ -17,546 +17,290 @@ */ #include "config.h" +#include "ass_compat.h" + +#ifdef CONFIG_FONTCONFIG -#include #include -#include -#include -#include +#include #include -#include -#include -#include -#include FT_FREETYPE_H -#include "ass_utils.h" -#include "ass.h" -#include "ass_library.h" -#include "ass_fontconfig.h" - -#ifdef CONFIG_FONTCONFIG #include #include -#endif -struct fc_instance { -#ifdef CONFIG_FONTCONFIG - FcConfig *config; -#endif - char *family_default; - char *path_default; - int index_default; -}; +#include "ass_fontconfig.h" +#include "ass_fontselect.h" +#include "ass_utils.h" -#ifdef CONFIG_FONTCONFIG +#define MAX_NAME 100 -/** - * \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) +typedef struct fc_private { + FcConfig *config; + FcFontSet *fallbacks; + FcCharSet *fallback_chars; +} ProviderPrivate; + +static int check_glyph(void *priv, uint32_t code) { - FcFontSet *sets[2]; - FcFontSet *result = FcFontSetCreate(); - int nsets = 0; - int i, fi; + FcPattern *pat = (FcPattern *)priv; + FcCharSet *charset; - if (!result) - return NULL; + if (!pat) + return 1; - 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; - } - } - } - } + if (code == 0) + return 1; - return result; + FcResult result = FcPatternGetCharSet(pat, FC_CHARSET, 0, &charset); + if (result != FcResultMatch) + return 0; + if (FcCharSetHasChar(charset, code) == FcTrue) + return 1; + return 0; } -/** - * \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) +static void destroy(void *priv) { - 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); + ProviderPrivate *fc = (ProviderPrivate *)priv; - // 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); - if (!s) - goto error; - 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); + if (fc->fallback_chars) + FcCharSetDestroy(fc->fallback_chars); + if (fc->fallbacks) + FcFontSetDestroy(fc->fallbacks); + FcConfigDestroy(fc->config); + free(fc); +} - FcDefaultSubstitute(pat); +static void scan_fonts(FcConfig *config, ASS_FontProvider *provider) +{ + int i; + FcFontSet *fonts; + ASS_FontProviderMetaData meta; - rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern); - if (!rc) - goto error; - /* Fontconfig defaults include a language setting, which it sets based on - * some environment variables or defaults to "en". Unset this as we don't - * know the real language, and because some some attached fonts lack - * non-ascii characters included in fontconfig's list of characters - * required for English support and therefore don't match the lang=en - * criterion. - */ - FcPatternDel(pat, "lang"); - - fsorted = FcFontSort(priv->config, pat, FcFalse, 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); - } + // get list of fonts + fonts = FcConfigGetFonts(config, FcSetSystem); - for (curf = 0; curf < fset->nfont; ++curf) { - FcPattern *curp = fset->fonts[curf]; + // fill font_info list + for (i = 0; i < fonts->nfont; i++) { + FcPattern *pat = fonts->fonts[i]; + FcBool outline; + int index, weight; + char *path; + char *fullnames[MAX_NAME]; + char *families[MAX_NAME]; + + // skip non-outline fonts + FcResult result = FcPatternGetBool(pat, FC_OUTLINE, 0, &outline); + if (result != FcResultMatch || outline != FcTrue) + continue; - result = FcPatternGetBool(curp, FC_OUTLINE, 0, &r_outline); + // simple types + result = FcPatternGetInteger(pat, FC_SLANT, 0, &meta.slant); + result |= FcPatternGetInteger(pat, FC_WIDTH, 0, &meta.width); + result |= FcPatternGetInteger(pat, FC_WEIGHT, 0, &weight); + result |= FcPatternGetInteger(pat, FC_INDEX, 0, &index); if (result != FcResultMatch) continue; - if (r_outline != FcTrue) - continue; - if (!code) - break; - result = FcPatternGetCharSet(curp, FC_CHARSET, 0, &r_charset); + + // fontconfig uses its own weight scale, apparently derived + // from typographical weight. we're using truetype weights, so + // convert appropriately + if (weight <= FC_WEIGHT_LIGHT) + meta.weight = FONT_WEIGHT_LIGHT; + else if (weight <= FC_WEIGHT_MEDIUM) + meta.weight = FONT_WEIGHT_MEDIUM; + else + meta.weight = FONT_WEIGHT_BOLD; + + // path + result = FcPatternGetString(pat, FC_FILE, 0, (FcChar8 **)&path); if (result != FcResultMatch) continue; - if (FcCharSetHasChar(r_charset, code)) - break; - } - if (curf >= fset->nfont) - goto error; + // read and strdup fullnames + meta.n_family = 0; + while (FcPatternGetString(pat, FC_FAMILY, meta.n_family, + (FcChar8 **)&families[meta.n_family]) == FcResultMatch + && meta.n_family < MAX_NAME) + meta.n_family++; + meta.families = families; + + // read and strdup fullnames + meta.n_fullname = 0; + while (FcPatternGetString(pat, FC_FULLNAME, meta.n_fullname, + (FcChar8 **)&fullnames[meta.n_fullname]) == FcResultMatch + && meta.n_fullname < MAX_NAME) + meta.n_fullname++; + meta.fullnames = fullnames; - 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); + ass_font_provider_add_font(provider, &meta, path, index, NULL, + (void *)pat); } +} - rpat = FcFontRenderPrepare(priv->config, pat, fset->fonts[curf]); - if (!rpat) - goto error; +static void cache_fallbacks(ProviderPrivate *fc) +{ + FcResult result; - result = FcPatternGetInteger(rpat, FC_INDEX, 0, &r_index); - if (result != FcResultMatch) - goto error; - *index = r_index; + if (fc->fallbacks) + return; - result = FcPatternGetString(rpat, FC_FILE, 0, &r_file); - if (result != FcResultMatch) - goto error; - retval = strdup((const char *) r_file); - if (!retval) - goto error; + // Create a suitable pattern + FcPattern *pat = FcPatternCreate(); + FcPatternAddString(pat, FC_FAMILY, (FcChar8 *)"sans-serif"); + FcPatternAddBool(pat, FC_OUTLINE, FcTrue); + FcConfigSubstitute (fc->config, pat, FcMatchPattern); + FcDefaultSubstitute (pat); - result = FcPatternGetString(rpat, FC_FAMILY, 0, &r_family); - if (result != FcResultMatch) - r_family = NULL; + // FC_LANG is automatically set according to locale, but this results + // in strange sorting sometimes, so remove the attribute completely. + FcPatternDel(pat, FC_LANG); + + // Sort installed fonts and eliminate duplicates; this can be very + // expensive. + fc->fallbacks = FcFontSort(fc->config, pat, FcTrue, &fc->fallback_chars, + &result); - result = FcPatternGetString(rpat, FC_FULLNAME, 0, &r_fullname); + // If this fails, just add an empty set if (result != FcResultMatch) - r_fullname = NULL; + fc->fallbacks = FcFontSetCreate(); + + FcPatternDestroy(pat); +} - if (!treat_family_as_pattern && - !(r_family && strcasecmp((const char *) r_family, family) == 0) && - !(r_fullname && strcasecmp((const char *) r_fullname, family) == 0)) { - char *fallback = (char *) (r_fullname ? r_fullname : r_family); - if (code) { - ass_msg(library, MSGL_WARN, - "fontconfig: cannot find glyph U+%04X in font '%s', falling back to '%s'", - (unsigned int)code, family, fallback); +static char *get_fallback(void *priv, const char *family, uint32_t codepoint) +{ + ProviderPrivate *fc = (ProviderPrivate *)priv; + FcResult result; + + cache_fallbacks(fc); + + if (!fc->fallbacks || fc->fallbacks->nfont == 0) + return NULL; + + if (codepoint == 0) { + char *family = NULL; + result = FcPatternGetString(fc->fallbacks->fonts[0], FC_FAMILY, 0, + (FcChar8 **)&family); + if (result == FcResultMatch) { + return strdup(family); } else { - ass_msg(library, MSGL_WARN, - "fontconfig: cannot find font '%s', falling back to '%s'", - family, fallback); + return NULL; } } - 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; + // fallback_chars is the union of all available charsets, so + // if we can't find the glyph in there, the system does not + // have any font to render this glyph. + if (FcCharSetHasChar(fc->fallback_chars, codepoint) == FcFalse) + return NULL; - result = FcPatternGetBool(rpat, FC_EMBOLDEN, 0, &r_embolden); - if (result != FcResultMatch) - r_embolden = 0; + for (int j = 0; j < fc->fallbacks->nfont; j++) { + FcPattern *pattern = fc->fallbacks->fonts[j]; - 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; -} + FcCharSet *charset; + result = FcPatternGetCharSet(pattern, FC_CHARSET, 0, &charset); -/** - * \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; - if (res) - 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 (result == FcResultMatch && FcCharSetHasChar(charset, + codepoint)) { + char *family = NULL; + result = FcPatternGetString(pattern, FC_FAMILY, 0, + (FcChar8 **)&family); + if (result == FcResultMatch) { + return strdup(family); + } else { + return NULL; + } + } } - if (res) - ass_msg(library, MSGL_V, - "fontconfig_select: (%s, %d, %d) -> %s, %d", family, bold, - italic, res, *index); - return res; + + // we shouldn't get here + return NULL; } -/** - * \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) +static void get_substitutions(void *priv, const char *name, + ASS_FontProviderMetaData *meta) { - 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) { - ass_msg(library, MSGL_V, "Adding memory font '%s'", name); - - 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; - } + ProviderPrivate *fc = (ProviderPrivate *)priv; - 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; - } + FcPattern *pat = FcPatternCreate(); + if (!pat) + return; - res = FcFontSetAdd(fset, pattern); - if (!res) { - ass_msg(library, MSGL_WARN, "%s failed", "FcFontSetAdd"); - FT_Done_Face(face); - return; - } + FcPatternAddString(pat, FC_FAMILY, (FcChar8 *)name); + FcPatternAddString(pat, FC_FAMILY, (FcChar8 *)"__libass_delimiter"); + FcPatternAddBool(pat, FC_OUTLINE, FcTrue); + if (!FcConfigSubstitute(fc->config, pat, FcMatchPattern)) + goto cleanup; - FT_Done_Face(face); + // read and strdup fullnames + meta->n_fullname = 0; + meta->fullnames = calloc(MAX_NAME, sizeof(char *)); + if (!meta->fullnames) + goto cleanup; + + char *alias = NULL; + while (FcPatternGetString(pat, FC_FAMILY, meta->n_fullname, + (FcChar8 **)&alias) == FcResultMatch + && meta->n_fullname < MAX_NAME + && strcmp(alias, "__libass_delimiter") != 0) { + alias = strdup(alias); + if (!alias) + goto cleanup; + meta->fullnames[meta->n_fullname] = alias; + meta->n_fullname++; } + +cleanup: + FcPatternDestroy(pat); } -/** - * \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) +static ASS_FontProviderFuncs fontconfig_callbacks = { + .check_glyph = check_glyph, + .destroy_provider = destroy, + .get_substitutions = get_substitutions, + .get_fallback = get_fallback, +}; + +ASS_FontProvider * +ass_fontconfig_add_provider(ASS_Library *lib, ASS_FontSelector *selector, + const char *config) { int rc; - FCInstance *priv = calloc(1, sizeof(FCInstance)); - const char *dir = library->fonts_dir; - int i; + ProviderPrivate *fc = NULL; + ASS_FontProvider *provider = NULL; - if (!priv) + fc = calloc(1, sizeof(ProviderPrivate)); + if (fc == NULL) return NULL; - 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); + // build and load fontconfig configuration + fc->config = FcConfigCreate(); + rc = FcConfigParseAndLoad(fc->config, (unsigned char *) config, FcTrue); if (!rc) { - ass_msg(library, MSGL_WARN, "No usable fontconfig configuration " + ass_msg(lib, MSGL_WARN, "No usable fontconfig configuration " "file found, using fallback."); - FcConfigDestroy(priv->config); - priv->config = FcInitLoadConfig(); - rc++; - } - if (rc && update) { - FcConfigBuildFonts(priv->config); + FcConfigDestroy(fc->config); + fc->config = FcInitLoadConfig(); } + if (fc->config) + rc = FcConfigBuildFonts(fc->config); - if (!rc || !priv->config) { - ass_msg(library, MSGL_FATAL, + if (!rc || !fc->config) { + ass_msg(lib, 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"); - } + FcConfigDestroy(fc->config); + free(fc); + return NULL; } - priv->family_default = family ? strdup(family) : NULL; -exit: - priv->path_default = path ? strdup(path) : NULL; - priv->index_default = 0; + // create font provider + provider = ass_font_provider_new(selector, &fontconfig_callbacks, fc); - return priv; -} + // build database from system fonts + scan_fonts(fc->config, provider); -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)); - if (!priv) - return NULL; - - priv->path_default = path ? strdup(path) : 0; - priv->index_default = 0; - return priv; -} - -int fontconfig_update(FCInstance *priv) -{ - // Do nothing - return 1; + return provider; } #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 -Nru libass-0.12.2/libass/ass_fontconfig.h libass-0.13.0/libass/ass_fontconfig.h --- libass-0.12.2/libass/ass_fontconfig.h 2014-01-31 20:42:18.000000000 +0000 +++ libass-0.13.0/libass/ass_fontconfig.h 2015-09-24 08:34:34.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Evgeniy Stepanov + * Copyright (C) 2011 Grigori Goronzy * * This file is part of libass. * @@ -16,30 +16,18 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef LIBASS_FONTCONFIG_H -#define LIBASS_FONTCONFIG_H - -#include #include "ass_types.h" -#include "ass.h" -#include -#include FT_FREETYPE_H +#include "ass_fontselect.h" + +#ifndef ASS_FONTCONFIG_H +#define ASS_FONTCONFIG_H #ifdef CONFIG_FONTCONFIG -#include -#endif -typedef struct fc_instance FCInstance; +ASS_FontProvider * +ass_fontconfig_add_provider(ASS_Library *lib, ASS_FontSelector *selector, + const char *config); -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 -#endif /* LIBASS_FONTCONFIG_H */ +#endif diff -Nru libass-0.12.2/libass/ass_font.h libass-0.13.0/libass/ass_font.h --- libass-0.12.2/libass/ass_font.h 2014-12-13 03:11:15.000000000 +0000 +++ libass-0.13.0/libass/ass_font.h 2015-09-07 09:44:16.000000000 +0000 @@ -24,8 +24,13 @@ #include FT_GLYPH_H #include FT_OUTLINE_H +typedef struct ass_font ASS_Font; +typedef struct ass_font_desc ASS_FontDesc; + #include "ass.h" #include "ass_types.h" +#include "ass_fontselect.h" +#include "ass_cache.h" #define VERTICAL_LOWER_BOUND 0x02f1 @@ -33,32 +38,29 @@ #define DECO_UNDERLINE 1 #define DECO_STRIKETHROUGH 2 -typedef struct ass_shaper_font_data ASS_ShaperFontData; - -typedef struct { +struct ass_font_desc { char *family; unsigned bold; unsigned italic; - int treat_family_as_pattern; int vertical; // @font vertical layout -} ASS_FontDesc; +}; -typedef struct { +struct ass_font { ASS_FontDesc desc; ASS_Library *library; FT_Library ftlibrary; + int faces_uid[ASS_FONT_MAX_FACES]; 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" +}; +void charmap_magic(ASS_Library *library, FT_Face face); ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library, - FT_Library ftlibrary, void *fc_priv, + FT_Library ftlibrary, ASS_FontSelector *fontsel, ASS_FontDesc *desc); void ass_font_set_transform(ASS_Font *font, double scale_x, double scale_y, FT_Vector *v); @@ -66,10 +68,10 @@ 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); +int ass_font_get_index(ASS_FontSelector *fontsel, ASS_Font *font, + uint32_t symbol, int *face_index, int *glyph_index); uint32_t ass_font_index_magic(FT_Face face, uint32_t symbol); -FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font, +FT_Glyph ass_font_get_glyph(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); diff -Nru libass-0.12.2/libass/ass_fontselect.c libass-0.13.0/libass/ass_fontselect.c --- libass-0.12.2/libass/ass_fontselect.c 1970-01-01 00:00:00.000000000 +0000 +++ libass-0.13.0/libass/ass_fontselect.c 2015-09-24 08:34:34.000000000 +0000 @@ -0,0 +1,1048 @@ +/* + * Copyright (C) 2006 Evgeniy Stepanov + * Copyright (C) 2011 Grigori Goronzy + * + * 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_compat.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include FT_FREETYPE_H +#include FT_SFNT_NAMES_H +#include FT_TRUETYPE_IDS_H + +#include "ass_utils.h" +#include "ass.h" +#include "ass_library.h" +#include "ass_fontselect.h" +#include "ass_fontconfig.h" +#include "ass_coretext.h" +#include "ass_directwrite.h" +#include "ass_font.h" +#include "ass_string.h" + +#define ABS(x) ((x) < 0 ? -(x) : (x)) +#define MAX_FULLNAME 100 + +// internal font database element +// all strings are utf-8 +struct font_info { + int uid; // unique font face id + + char **families; // family name + char **fullnames; // list of localized fullnames (e.g. Arial Bold Italic) + int n_family; + int n_fullname; + + int slant; + int weight; // TrueType scale, 100-900 + int width; + + // how to access this face + char *path; // absolute path + int index; // font index inside font collections + char *postscript_name; // can be used as an alternative to index to + // identify a font inside a collection + + // font source + ASS_FontProvider *provider; + + // private data for callbacks + void *priv; +}; + +struct font_selector { + // uid counter + int uid; + + // fallbacks + char *family_default; + char *path_default; + int index_default; + + // font database + int n_font; + int alloc_font; + ASS_FontInfo *font_infos; + + ASS_FontProvider *default_provider; + ASS_FontProvider *embedded_provider; +}; + +struct font_provider { + ASS_FontSelector *parent; + ASS_FontProviderFuncs funcs; + void *priv; +}; + +typedef struct font_data_ft FontDataFT; +struct font_data_ft { + ASS_Library *lib; + FT_Face face; + int idx; +}; + +static int check_glyph_ft(void *data, uint32_t codepoint) +{ + FontDataFT *fd = (FontDataFT *)data; + + if (!codepoint) + return 1; + + return !!FT_Get_Char_Index(fd->face, codepoint); +} + +static void destroy_font_ft(void *data) +{ + FontDataFT *fd = (FontDataFT *)data; + + FT_Done_Face(fd->face); + free(fd); +} + +static size_t +get_data_embedded(void *data, unsigned char *buf, size_t offset, size_t len) +{ + FontDataFT *ft = (FontDataFT *)data; + ASS_Fontdata *fd = ft->lib->fontdata; + int i = ft->idx; + + if (buf == NULL) + return fd[i].size; + + if (offset >= fd[i].size) + return 0; + + if (len > fd[i].size - offset) + len = fd[i].size - offset; + + memcpy(buf, fd[i].data + offset, len); + return len; +} + +static ASS_FontProviderFuncs ft_funcs = { + get_data_embedded, + check_glyph_ft, + destroy_font_ft, + NULL, + NULL, + NULL, + NULL +}; + +static void load_fonts_from_dir(ASS_Library *library, const char *dir) +{ + DIR *d = opendir(dir); + if (!d) + return; + while (1) { + struct dirent *entry = readdir(d); + if (!entry) + break; + if (entry->d_name[0] == '.') + continue; + char fullname[4096]; + snprintf(fullname, sizeof(fullname), "%s/%s", dir, entry->d_name); + size_t bufsize = 0; + ass_msg(library, MSGL_WARN, "Loading font file '%s'", fullname); + void *data = read_file(library, fullname, &bufsize); + if (data) { + ass_add_font(library, entry->d_name, data, bufsize); + free(data); + } + } + closedir(d); +} + +/** + * \brief Create a bare font provider. + * \param selector parent selector. The provider will be attached to it. + * \param funcs callback/destroy functions + * \param data private data of the provider + * \return the font provider + */ +ASS_FontProvider * +ass_font_provider_new(ASS_FontSelector *selector, ASS_FontProviderFuncs *funcs, + void *data) +{ + ASS_FontProvider *provider = calloc(1, sizeof(ASS_FontProvider)); + if (provider == NULL) + return NULL; + + provider->parent = selector; + provider->funcs = *funcs; + provider->priv = data; + + return provider; +} + +/** + * Free all data associated with a FontInfo struct. Handles FontInfo structs + * with incomplete allocations well. + * + * \param info FontInfo struct to free associated data from + */ +static void ass_font_provider_free_fontinfo(ASS_FontInfo *info) +{ + int j; + + if (info->fullnames) { + for (j = 0; j < info->n_fullname; j++) + free(info->fullnames[j]); + free(info->fullnames); + } + + if (info->families) { + for (j = 0; j < info->n_family; j++) + free(info->families[j]); + free(info->families); + } + + if (info->path) + free(info->path); + + if (info->postscript_name) + free(info->postscript_name); + +} + +/** + * \brief Add a font to a font provider. + * \param provider the font provider + * \param meta basic metadata of the font + * \param path path to the font file, or NULL + * \param index face index inside the file + * \param psname PostScript name of the face (overrides index if present) + * \param data private data for the font + * \return success + */ +int +ass_font_provider_add_font(ASS_FontProvider *provider, + ASS_FontProviderMetaData *meta, const char *path, + unsigned int index, const char *psname, void *data) +{ + int i; + int weight, slant, width; + ASS_FontSelector *selector = provider->parent; + ASS_FontInfo *info; + +#if 0 + int j; + printf("new font:\n"); + printf(" families: "); + for (j = 0; j < meta->n_family; j++) + printf("'%s' ", meta->families[j]); + printf("\n"); + printf(" fullnames: "); + for (j = 0; j < meta->n_fullname; j++) + printf("'%s' ", meta->fullnames[j]); + printf("\n"); + printf(" slant: %d\n", meta->slant); + printf(" weight: %d\n", meta->weight); + printf(" width: %d\n", meta->width); + printf(" path: %s\n", path); + printf(" index: %d\n", index); +#endif + + weight = meta->weight; + slant = meta->slant; + width = meta->width; + + // check slant/weight for validity, use defaults if they're invalid + if (weight < 100 || weight > 900) + weight = 400; + if (slant < 0 || slant > 110) + slant = 0; + if (width < 50 || width > 200) + width = 100; + + // check size + if (selector->n_font >= selector->alloc_font) { + selector->alloc_font = FFMAX(1, 2 * selector->alloc_font); + selector->font_infos = realloc(selector->font_infos, + selector->alloc_font * sizeof(ASS_FontInfo)); + } + + // copy over metadata + info = selector->font_infos + selector->n_font; + memset(info, 0, sizeof(ASS_FontInfo)); + + // set uid + info->uid = selector->uid++; + + info->slant = slant; + info->weight = weight; + info->width = width; + info->n_fullname = meta->n_fullname; + info->n_family = meta->n_family; + info->families = calloc(meta->n_family, sizeof(char *)); + if (meta->n_fullname) { + info->fullnames = calloc(meta->n_fullname, sizeof(char *)); + if (info->fullnames == NULL) + goto error; + } + + if (info->families == NULL) + goto error; + + for (i = 0; i < info->n_family; i++) { + info->families[i] = strdup(meta->families[i]); + if (info->families[i] == NULL) + goto error; + } + + for (i = 0; i < info->n_fullname; i++) { + info->fullnames[i] = strdup(meta->fullnames[i]); + if (info->fullnames[i] == NULL) + goto error; + } + + if (path) { + info->path = strdup(path); + if (info->path == NULL) + goto error; + } + + if (psname) { + info->postscript_name = strdup(psname); + if (info->postscript_name == NULL) + goto error; + } + + info->index = index; + info->priv = data; + info->provider = provider; + + selector->n_font++; + return 0; + +error: + ass_font_provider_free_fontinfo(info); + return 1; +} + +/** + * \brief Clean up font database. Deletes all fonts that have an invalid + * font provider (NULL). + * \param selector the font selector + */ +static void ass_fontselect_cleanup(ASS_FontSelector *selector) +{ + int i, w; + + for (i = 0, w = 0; i < selector->n_font; i++) { + ASS_FontInfo *info = selector->font_infos + i; + + // update write pointer + if (info->provider != NULL) { + // rewrite, if needed + if (w != i) + memcpy(selector->font_infos + w, selector->font_infos + i, + sizeof(ASS_FontInfo)); + w++; + } + + } + + selector->n_font = w; +} + +void ass_font_provider_free(ASS_FontProvider *provider) +{ + int i; + ASS_FontSelector *selector = provider->parent; + + // free all fonts and mark their entries + for (i = 0; i < selector->n_font; i++) { + ASS_FontInfo *info = selector->font_infos + i; + + if (info->provider == provider) { + ass_font_provider_free_fontinfo(info); + + if (info->provider->funcs.destroy_font) + info->provider->funcs.destroy_font(info->priv); + + info->provider = NULL; + } + + } + + // delete marked entries + ass_fontselect_cleanup(selector); + + // free private data of the provider + if (provider->funcs.destroy_provider) + provider->funcs.destroy_provider(provider->priv); + + free(provider); +} + +/** + * \brief Return whether the given font is in the given family. + */ +static bool matches_family_name(ASS_FontInfo *f, const char *family) +{ + for (int i = 0; i < f->n_family; i++) { + if (ass_strcasecmp(f->families[i], family) == 0) + return true; + } + return false; +} + +/** + * \brief Return whether the given font has the given fullname. + */ +static bool matches_fullname(ASS_FontInfo *f, const char *fullname) +{ + for (int i = 0; i < f->n_fullname; i++) { + if (ass_strcasecmp(f->fullnames[i], fullname) == 0) + return true; + } + return false; +} + +/** + * \brief Compare attributes of font (a) against a font request (req). Returns + * a matching score - the lower the better. + * Ignores font names/families! + * \param a font + * \param b font request + * \return matching score + */ +static unsigned font_attributes_similarity(ASS_FontInfo *a, ASS_FontInfo *req) +{ + unsigned similarity = 0; + similarity += ABS(a->weight - req->weight); + similarity += ABS(a->slant - req->slant); + similarity += ABS(a->width - req->width); + + return similarity; +} + +#if 0 +// dump font information +static void font_info_dump(ASS_FontInfo *font_infos, size_t len) +{ + int i, j; + + // dump font infos + for (i = 0; i < len; i++) { + printf("font %d\n", i); + printf(" families: "); + for (j = 0; j < font_infos[i].n_family; j++) + printf("'%s' ", font_infos[i].families[j]); + printf(" fullnames: "); + for (j = 0; j < font_infos[i].n_fullname; j++) + printf("'%s' ", font_infos[i].fullnames[j]); + printf("\n"); + printf(" slant: %d\n", font_infos[i].slant); + printf(" weight: %d\n", font_infos[i].weight); + printf(" width: %d\n", font_infos[i].width); + printf(" path: %s\n", font_infos[i].path); + printf(" index: %d\n", font_infos[i].index); + printf(" score: %d\n", font_infos[i].score); + + } +} +#endif + +static int check_glyph(ASS_FontInfo *fi, uint32_t code) +{ + ASS_FontProvider *provider = fi->provider; + assert(provider && provider->funcs.check_glyph); + + return provider->funcs.check_glyph(fi->priv, code); +} + +static char * +find_font(ASS_FontSelector *priv, ASS_Library *library, + ASS_FontProviderMetaData meta, unsigned bold, unsigned italic, + int *index, char **postscript_name, int *uid, ASS_FontStream *stream, + uint32_t code, bool *name_match) +{ + ASS_FontInfo req = {0}; + ASS_FontInfo *selected = NULL; + + // do we actually have any fonts? + if (!priv->n_font) + return NULL; + + // fill font request + req.slant = italic; + req.weight = bold; + req.width = 100; + + // Match font family name against font list + unsigned score_min = UINT_MAX; + for (int i = 0; i < meta.n_fullname; i++) { + const char *fullname = meta.fullnames[i]; + + for (int x = 0; x < priv->n_font; x++) { + ASS_FontInfo *font = &priv->font_infos[x]; + unsigned score = UINT_MAX; + + if (matches_family_name(font, fullname)) { + // If there's a family match, compare font attributes + // to determine best match in that particular family + score = font_attributes_similarity(font, &req); + *name_match = true; + } else if (matches_fullname(font, fullname)) { + // If we don't have any match, compare fullnames against request + // if there is a match now, assign lowest score possible. This means + // the font should be chosen instantly, without further search. + score = 0; + *name_match = true; + } + + // Consider updating idx if score is better than current minimum + if (score < score_min) { + // Check if the font has the requested glyph. + // We are doing this here, for every font face, because + // coverage might differ between the variants of a font + // family. In practice, it is common that the regular + // style has the best coverage while bold/italic/etc + // variants cover less (e.g. FreeSans family). + // We want to be able to match even if the closest variant + // does not have the requested glyph, but another member + // of the family has the glyph. + if (!check_glyph(font, code)) + continue; + + score_min = score; + selected = font; + } + + // Lowest possible score instantly matches; this is typical + // for fullname matches, but can also occur with family matches. + if (score == 0) + break; + } + + // The list of names is sorted by priority. If we matched anything, + // we can and should stop. + if (selected != NULL) + break; + } + + // found anything? + char *result = NULL; + if (selected) { + // successfully matched, set up return values + *postscript_name = selected->postscript_name; + *index = selected->index; + *uid = selected->uid; + + // set up memory stream if there is no path + if (selected->path == NULL) { + ASS_FontProvider *provider = selected->provider; + stream->func = provider->funcs.get_data; + stream->priv = selected->priv; + // Prefer PostScript name because it is unique. This is only + // used for display purposes so it doesn't matter that much, + // though. + if (selected->postscript_name) + result = selected->postscript_name; + else + result = selected->families[0]; + } else + result = selected->path; + } + + return result; +} + +static char *select_font(ASS_FontSelector *priv, ASS_Library *library, + const char *family, unsigned bold, unsigned italic, + int *index, char **postscript_name, int *uid, + ASS_FontStream *stream, uint32_t code) +{ + ASS_FontProvider *default_provider = priv->default_provider; + ASS_FontProviderMetaData meta = {0}; + char *family_trim = strdup_trimmed(family); + char *result = NULL; + bool name_match = false; + + if (family_trim == NULL) + return NULL; + + ASS_FontProviderMetaData default_meta = { + .n_fullname = 1, + .fullnames = &family_trim, + }; + + // Get a list of substitutes if applicable, and use it for matching. + if (default_provider && default_provider->funcs.get_substitutions) { + default_provider->funcs.get_substitutions(default_provider->priv, + family_trim, &meta); + } + + if (!meta.n_fullname) { + meta = default_meta; + } + + result = find_font(priv, library, meta, bold, italic, index, + postscript_name, uid, stream, code, &name_match); + + // If no matching font was found, it might not exist in the font list + // yet. Call the match_fonts callback to fill in the missing fonts + // on demand, and retry the search for a match. + if (result == NULL && name_match == false && default_provider && + default_provider->funcs.match_fonts) { + // TODO: consider changing the API to make more efficient + // implementations possible. + for (int i = 0; i < meta.n_fullname; i++) { + default_provider->funcs.match_fonts(library, default_provider, + meta.fullnames[i]); + } + result = find_font(priv, library, meta, bold, italic, index, + postscript_name, uid, stream, code, &name_match); + } + + // cleanup + free(family_trim); + if (meta.fullnames != default_meta.fullnames) { + for (int i = 0; i < meta.n_fullname; i++) + free(meta.fullnames[i]); + free(meta.fullnames); + } + + return result; +} + + +/** + * \brief Find a font. Use default family or path if necessary. + * \param library ASS library handle + * \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 *ass_font_select(ASS_FontSelector *priv, ASS_Library *library, + ASS_Font *font, int *index, char **postscript_name, + int *uid, ASS_FontStream *data, uint32_t code) +{ + char *res = 0; + const char *family = font->desc.family; + unsigned bold = font->desc.bold; + unsigned italic = font->desc.italic; + ASS_FontProvider *default_provider = priv->default_provider; + + if (family && *family) + res = select_font(priv, library, family, bold, italic, index, + postscript_name, uid, data, code); + + if (!res && priv->family_default) { + res = select_font(priv, library, priv->family_default, bold, + italic, index, postscript_name, uid, data, code); + if (res) + ass_msg(library, MSGL_WARN, "fontselect: Using default " + "font family: (%s, %d, %d) -> %s, %d, %s", + family, bold, italic, res, *index, + *postscript_name ? *postscript_name : "(none)"); + } + + if (!res && default_provider && default_provider->funcs.get_fallback) { + const char *search_family = family; + if (!search_family || !*search_family) + search_family = "Arial"; + char *fallback_family = default_provider->funcs.get_fallback( + default_provider->priv, search_family, code); + + if (fallback_family) { + res = select_font(priv, library, fallback_family, bold, italic, + index, postscript_name, uid, data, code); + free(fallback_family); + } + } + + if (!res && priv->path_default) { + res = priv->path_default; + *index = priv->index_default; + ass_msg(library, MSGL_WARN, "fontselect: Using default font: " + "(%s, %d, %d) -> %s, %d, %s", family, bold, italic, + priv->path_default, *index, + *postscript_name ? *postscript_name : "(none)"); + } + + if (res) + ass_msg(library, MSGL_INFO, + "fontselect: (%s, %d, %d) -> %s, %d, %s", family, bold, + italic, res, *index, *postscript_name ? *postscript_name : "(none)"); + + return res; +} + + +/** + * \brief Read basic metadata (names, weight, slant) from a FreeType face, + * as required for the FontSelector for matching and sorting. + * \param lib FreeType library + * \param face FreeType face + * \param info metadata, returned here + * \return success + */ +static int +get_font_info(FT_Library lib, FT_Face face, ASS_FontProviderMetaData *info) +{ + int i; + int num_fullname = 0; + int num_family = 0; + int num_names = FT_Get_Sfnt_Name_Count(face); + int slant, weight; + char *fullnames[MAX_FULLNAME]; + char *families[MAX_FULLNAME]; + + // we're only interested in outlines + if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) + return 0; + + for (i = 0; i < num_names; i++) { + FT_SfntName name; + + if (FT_Get_Sfnt_Name(face, i, &name)) + continue; + + if (name.platform_id == TT_PLATFORM_MICROSOFT && + (name.name_id == TT_NAME_ID_FULL_NAME || + name.name_id == TT_NAME_ID_FONT_FAMILY)) { + char buf[1024]; + ass_utf16be_to_utf8(buf, sizeof(buf), (uint8_t *)name.string, + name.string_len); + + if (name.name_id == TT_NAME_ID_FULL_NAME) { + fullnames[num_fullname] = strdup_trimmed(buf); + if (fullnames[num_fullname] == NULL) + goto error; + num_fullname++; + } + + if (name.name_id == TT_NAME_ID_FONT_FAMILY) { + families[num_family] = strdup_trimmed(buf); + if (families[num_family] == NULL) + goto error; + num_family++; + } + } + + } + + // check if we got a valid family - if not use whatever FreeType gives us + if (num_family == 0 && face->family_name) { + families[0] = strdup(face->family_name); + if (families[0] == NULL) + goto error; + num_family++; + } + + // we absolutely need a name + if (num_family == 0) + goto error; + + // calculate sensible slant and weight from style attributes + slant = 110 * !!(face->style_flags & FT_STYLE_FLAG_ITALIC); + weight = 300 * !!(face->style_flags & FT_STYLE_FLAG_BOLD) + 400; + + // fill our struct + info->slant = slant; + info->weight = weight; + info->width = 100; // FIXME, should probably query the OS/2 table + info->families = calloc(sizeof(char *), num_family); + + if (info->families == NULL) + goto error; + + memcpy(info->families, &families, sizeof(char *) * num_family); + info->n_family = num_family; + + if (num_fullname) { + info->fullnames = calloc(sizeof(char *), num_fullname); + if (info->fullnames == NULL) + goto error; + memcpy(info->fullnames, &fullnames, sizeof(char *) * num_fullname); + info->n_fullname = num_fullname; + } + + return 0; + +error: + for (i = 0; i < num_family; i++) + free(families[i]); + + for (i = 0; i < num_fullname; i++) + free(fullnames[i]); + + free(info->families); + free(info->fullnames); + + return 1; +} + +/** + * \brief Free the dynamically allocated fields of metadata + * created by get_font_info. + * \param meta metadata created by get_font_info + */ +static void free_font_info(ASS_FontProviderMetaData *meta) +{ + int i; + + for (i = 0; i < meta->n_family; i++) + free(meta->families[i]); + + for (i = 0; i < meta->n_fullname; i++) + free(meta->fullnames[i]); + + free(meta->families); + free(meta->fullnames); +} + +/** + * \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 FontInfo with FreeType and some table reading. +*/ +static void process_fontdata(ASS_FontProvider *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; + int face_index, num_faces = 1; + + for (face_index = 0; face_index < num_faces; ++face_index) { + ASS_FontProviderMetaData info; + FontDataFT *ft; + + 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); + continue; + } + + num_faces = face->num_faces; + + charmap_magic(library, face); + + memset(&info, 0, sizeof(ASS_FontProviderMetaData)); + if (get_font_info(ftlibrary, face, &info)) { + ass_msg(library, MSGL_WARN, + "Error getting metadata for embedded font '%s'", name); + FT_Done_Face(face); + continue; + } + + ft = calloc(1, sizeof(FontDataFT)); + + if (ft == NULL) { + free_font_info(&info); + FT_Done_Face(face); + continue; + } + + ft->lib = library; + ft->face = face; + ft->idx = idx; + + if (ass_font_provider_add_font(priv, &info, NULL, face_index, + NULL, ft)) { + ass_msg(library, MSGL_WARN, "Failed to add embedded font '%s'", + name); + } + + free_font_info(&info); + } +} + +/** + * \brief Create font provider for embedded fonts. This parses the fonts known + * to the current ASS_Library and adds them to the selector. + * \param lib library + * \param selector font selector + * \param ftlib FreeType library - used for querying fonts + * \return font provider + */ +static ASS_FontProvider * +ass_embedded_fonts_add_provider(ASS_Library *lib, ASS_FontSelector *selector, + FT_Library ftlib) +{ + int i; + ASS_FontProvider *priv = ass_font_provider_new(selector, &ft_funcs, NULL); + if (priv == NULL) + return NULL; + + if (lib->fonts_dir && lib->fonts_dir[0]) { + load_fonts_from_dir(lib, lib->fonts_dir); + } + + for (i = 0; i < lib->num_fontdata; ++i) + process_fontdata(priv, lib, ftlib, i); + + return priv; +} + +struct font_constructors { + ASS_DefaultFontProvider id; + ASS_FontProvider *(*constructor)(ASS_Library *, ASS_FontSelector *, + const char *); + const char *name; +}; + +struct font_constructors font_constructors[] = { +#ifdef CONFIG_CORETEXT + { ASS_FONTPROVIDER_CORETEXT, &ass_coretext_add_provider, "coretext"}, +#endif +#ifdef CONFIG_DIRECTWRITE + { ASS_FONTPROVIDER_DIRECTWRITE, &ass_directwrite_add_provider, "directwrite"}, +#endif +#ifdef CONFIG_FONTCONFIG + { ASS_FONTPROVIDER_FONTCONFIG, &ass_fontconfig_add_provider, "fontconfig"}, +#endif + { ASS_FONTPROVIDER_NONE, NULL, NULL }, +}; + +/** + * \brief Init font selector. + * \param library libass library object + * \param ftlibrary freetype library object + * \param family default font family + * \param path default font path + * \return newly created font selector + */ +ASS_FontSelector * +ass_fontselect_init(ASS_Library *library, + FT_Library ftlibrary, const char *family, + const char *path, const char *config, + ASS_DefaultFontProvider dfp) +{ + ASS_FontSelector *priv = calloc(1, sizeof(ASS_FontSelector)); + if (priv == NULL) + return NULL; + + priv->uid = 1; + priv->family_default = family ? strdup(family) : NULL; + priv->path_default = path ? strdup(path) : NULL; + priv->index_default = 0; + + priv->embedded_provider = ass_embedded_fonts_add_provider(library, priv, + ftlibrary); + + if (priv->embedded_provider == NULL) { + ass_msg(library, MSGL_WARN, "failed to create embedded font provider"); + } + + if (dfp >= ASS_FONTPROVIDER_AUTODETECT) { + for (int i = 0; font_constructors[i].constructor; i++ ) + if (dfp == font_constructors[i].id || + dfp == ASS_FONTPROVIDER_AUTODETECT) { + priv->default_provider = + font_constructors[i].constructor(library, priv, config); + if (priv->default_provider) { + ass_msg(library, MSGL_INFO, "Using font provider %s", + font_constructors[i].name); + break; + } + } + + if (!priv->default_provider) + ass_msg(library, MSGL_WARN, "can't find selected font provider"); + + } + + return priv; +} + +void ass_get_available_font_providers(ASS_Library *priv, + ASS_DefaultFontProvider **providers, + size_t *size) +{ + size_t offset = 2; + + *size = offset; + for (int i = 0; font_constructors[i].constructor; i++) + (*size)++; + + *providers = calloc(*size, sizeof(ASS_DefaultFontProvider)); + + if (*providers == NULL) { + *size = (size_t)-1; + return; + } + + (*providers)[0] = ASS_FONTPROVIDER_NONE; + (*providers)[1] = ASS_FONTPROVIDER_AUTODETECT; + + for (int i = offset; i < *size; i++) + (*providers)[i] = font_constructors[i-offset].id; +} + +/** + * \brief Free font selector and release associated data + * \param the font selector + */ +void ass_fontselect_free(ASS_FontSelector *priv) +{ + if (priv->default_provider) + ass_font_provider_free(priv->default_provider); + if (priv->embedded_provider) + ass_font_provider_free(priv->embedded_provider); + + free(priv->font_infos); + free(priv->path_default); + free(priv->family_default); + + free(priv); +} + +void ass_map_font(const ASS_FontMapping *map, int len, const char *name, + ASS_FontProviderMetaData *meta) +{ + for (int i = 0; i < len; i++) { + if (ass_strcasecmp(map[i].from, name) == 0) { + meta->fullnames = calloc(1, sizeof(char *)); + if (meta->fullnames) { + meta->fullnames[0] = strdup(map[i].to); + if (meta->fullnames[0]) + meta->n_fullname = 1; + } + return; + } + } +} diff -Nru libass-0.12.2/libass/ass_fontselect.h libass-0.13.0/libass/ass_fontselect.h --- libass-0.12.2/libass/ass_fontselect.h 1970-01-01 00:00:00.000000000 +0000 +++ libass-0.13.0/libass/ass_fontselect.h 2015-09-07 14:01:36.000000000 +0000 @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2006 Evgeniy Stepanov + * + * 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 +#include +#include FT_FREETYPE_H + +typedef struct ass_shaper_font_data ASS_ShaperFontData; +typedef struct font_selector ASS_FontSelector; +typedef struct font_info ASS_FontInfo; + +#include "ass_types.h" +#include "ass.h" +#include "ass_font.h" + +typedef struct font_provider ASS_FontProvider; + +/* Font Provider */ +typedef struct ass_font_provider_meta_data ASS_FontProviderMetaData; + +/** + * Get font data. This is a stream interface which can be used as an + * alternative to providing a font path (which may not be available). + * + * This is called by fontselect if a given font was added without a + * font path (i.e. the path was set to NULL). + * + * \param font_priv font private data + * \param output buffer; set to NULL to query stream size + * \param offset stream offset + * \param len bytes to read into output buffer from stream + * \return actual number of bytes read, or stream size if data == NULL + */ +typedef size_t (*GetDataFunc)(void *font_priv, unsigned char *data, + size_t offset, size_t len); + +/** + * Check if a glyph is supported by a font. + * + * \param font_priv font private data + * \param codepont Unicode codepoint (UTF-32) + * \return non-zero value if codepoint is supported by the font + */ +typedef int (*CheckGlyphFunc)(void *font_priv, uint32_t codepoint); + +/** + * Destroy a font's private data. + * + * \param font_priv font private data + */ +typedef void (*DestroyFontFunc)(void *font_priv); + +/** + * Destroy a font provider's private data. + * + * \param priv font provider private data + */ +typedef void (*DestroyProviderFunc)(void *priv); + +/** + * Add fonts for a given font name; this should add all fonts matching the + * given name to the fontselect database. + * + * This is called by fontselect whenever a new logical font is created. The + * font provider set as default is used. + * + * \param lib ASS_Library instance + * \param provider font provider instance + * \param name font name (as specified in script) + */ +typedef void (*MatchFontsFunc)(ASS_Library *lib, + ASS_FontProvider *provider, + char *name); + +/** + * Substitute font name by another. This implements generic font family + * substitutions (e.g. sans-serif, serif, monospace) as well as font aliases. + * + * The generic families should map to sensible platform-specific font families. + * Aliases are sometimes used to map from common fonts that don't exist on + * a particular platform to similar alternatives. For example, a Linux + * system with fontconfig may map "Arial" to "Liberation Sans" and Windows + * maps "Helvetica" to "Arial". + * + * This is called by fontselect when a new logical font is created. The font + * provider set as default is used. + * + * \param priv font provider private data + * \param name input string for substitution, as specified in the script + * \param meta metadata (fullnames and n_fullname) to be filled in + */ +typedef void (*SubstituteFontFunc)(void *priv, const char *name, + ASS_FontProviderMetaData *meta); + +/** + * Get an appropriate fallback font for a given codepoint. + * + * This is called by fontselect whenever a glyph is not found in the + * physical font list of a logical font. fontselect will try to add the + * font family with match_fonts if it does not exist in the font list + * add match_fonts is not NULL. Note that the returned font family should + * contain the requested codepoint. + * + * Note that fontselect uses the font provider set as default to determine + * fallbacks. + * + * \param priv font provider private data + * \param family original font family name (try matching a similar font) (never NULL) + * \param codepoint Unicode codepoint (UTF-32) + * \return output font family, allocated with malloc(), must be freed + * by caller. + */ +typedef char *(*GetFallbackFunc)(void *priv, + const char *family, + uint32_t codepoint); + +typedef struct font_provider_funcs { + GetDataFunc get_data; /* optional/mandatory */ + CheckGlyphFunc check_glyph; /* mandatory */ + DestroyFontFunc destroy_font; /* optional */ + DestroyProviderFunc destroy_provider; /* optional */ + MatchFontsFunc match_fonts; /* optional */ + SubstituteFontFunc get_substitutions; /* optional */ + GetFallbackFunc get_fallback; /* optional */ +} ASS_FontProviderFuncs; + +/* + * Basic font metadata. All strings must be encoded with UTF-8. + * At minimum one family is required. + */ +struct ass_font_provider_meta_data { + + /** + * List of localized font family names, e.g. "Arial". + */ + char **families; + + /** + * List of localized full names, e.g. "Arial Bold". + * The English name should be listed first to speed up typical matching. + */ + char **fullnames; + int n_family; // Number of localized family names + int n_fullname; // Number of localized full names + + int slant; // Font slant value from FONT_SLANT_* + int weight; // Font weight in TrueType scale, 100-900 + // See FONT_WEIGHT_* + int width; // Font weight in percent, normally 100 + // See FONT_WIDTH_* +}; + +typedef struct ass_font_stream ASS_FontStream; + +struct ass_font_stream { + // GetDataFunc + size_t (*func)(void *font_priv, unsigned char *data, + size_t offset, size_t len); + void *priv; +}; + + +typedef struct ass_font_mapping ASS_FontMapping; + +struct ass_font_mapping { + const char *from; + const char *to; +}; + +/** + * Simple font substitution helper. This can be used to implement basic + * mappings from one name to another. This is useful for supporting + * generic font families in font providers. + * + * \param map list of mappings + * \param len length of list of mappings + * \param name font name to map from + * \param meta metadata struct, mapped fonts will be stored into this + */ +void ass_map_font(const ASS_FontMapping *map, int len, const char *name, + ASS_FontProviderMetaData *meta); + +ASS_FontSelector * +ass_fontselect_init(ASS_Library *library, + FT_Library ftlibrary, const char *family, + const char *path, const char *config, + ASS_DefaultFontProvider dfp); +char *ass_font_select(ASS_FontSelector *priv, ASS_Library *library, + ASS_Font *font, int *index, char **postscript_name, + int *uid, ASS_FontStream *data, uint32_t code); +void ass_fontselect_free(ASS_FontSelector *priv); + +// Font provider functions +ASS_FontProvider *ass_font_provider_new(ASS_FontSelector *selector, + ASS_FontProviderFuncs *funcs, void *data); + +/** + * \brief Create an empty font provider. A font provider can be used to + * provide additional fonts to libass. + * \param priv parent renderer + * \param funcs callback functions + * \param private data for provider callbacks + * + */ +ASS_FontProvider * +ass_create_font_provider(ASS_Renderer *priv, ASS_FontProviderFuncs *funcs, + void *data); + +/** + * \brief Add a font to a font provider. + * \param provider the font provider + * \param meta font metadata. See struct definition for more information. + * \param path absolute path to font, or NULL for memory-based fonts + * \param index index inside a font collection file + * \param psname PostScript name of the face (overrides index if present) + * \param data private data for font callbacks + * \return success + * + */ +int +ass_font_provider_add_font(ASS_FontProvider *provider, + ASS_FontProviderMetaData *meta, const char *path, + unsigned int index, const char *psname, void *data); + +/** + * \brief Free font provider and associated fonts. + * \param provider the font provider + * + */ +void ass_font_provider_free(ASS_FontProvider *provider); + +#endif /* LIBASS_FONTCONFIG_H */ diff -Nru libass-0.12.2/libass/ass_func_template.h libass-0.13.0/libass/ass_func_template.h --- libass-0.12.2/libass/ass_func_template.h 1970-01-01 00:00:00.000000000 +0000 +++ libass-0.13.0/libass/ass_func_template.h 2015-07-07 18:25:48.000000000 +0000 @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2015 Vabishchevich Nikolay + * + * 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. + */ + + + +void DECORATE(fill_solid_tile16)(uint8_t *buf, ptrdiff_t stride, int set); +void DECORATE(fill_solid_tile32)(uint8_t *buf, ptrdiff_t stride, int set); +void DECORATE(fill_halfplane_tile16)(uint8_t *buf, ptrdiff_t stride, + int32_t a, int32_t b, int64_t c, int32_t scale); +void DECORATE(fill_halfplane_tile32)(uint8_t *buf, ptrdiff_t stride, + int32_t a, int32_t b, int64_t c, int32_t scale); +void DECORATE(fill_generic_tile16)(uint8_t *buf, ptrdiff_t stride, + const struct segment *line, size_t n_lines, + int winding); +void DECORATE(fill_generic_tile32)(uint8_t *buf, ptrdiff_t stride, + const struct segment *line, size_t n_lines, + int winding); + +void DECORATE(add_bitmaps)(uint8_t *dst, intptr_t dst_stride, + uint8_t *src, intptr_t src_stride, + intptr_t height, intptr_t width); +void DECORATE(sub_bitmaps)(uint8_t *dst, intptr_t dst_stride, + uint8_t *src, intptr_t src_stride, + intptr_t height, intptr_t width); +void DECORATE(mul_bitmaps)(uint8_t *dst, intptr_t dst_stride, + uint8_t *src1, intptr_t src1_stride, + uint8_t *src2, intptr_t src2_stride, + intptr_t width, intptr_t height); + +void DECORATE(be_blur)(uint8_t *buf, intptr_t w, intptr_t h, + intptr_t stride, uint16_t *tmp); + +void DECORATE(stripe_unpack)(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, + uintptr_t width, uintptr_t height); +void DECORATE(stripe_pack)(uint8_t *dst, ptrdiff_t dst_stride, const int16_t *src, + uintptr_t width, uintptr_t height); +void DECORATE(shrink_horz)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height); +void DECORATE(shrink_vert)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height); +void DECORATE(expand_horz)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height); +void DECORATE(expand_vert)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height); +void DECORATE(pre_blur1_horz)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height); +void DECORATE(pre_blur1_vert)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height); +void DECORATE(pre_blur2_horz)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height); +void DECORATE(pre_blur2_vert)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height); +void DECORATE(pre_blur3_horz)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height); +void DECORATE(pre_blur3_vert)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height); +void DECORATE(blur1234_horz)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height, + const int16_t *param); +void DECORATE(blur1234_vert)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height, + const int16_t *param); +void DECORATE(blur1235_horz)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height, + const int16_t *param); +void DECORATE(blur1235_vert)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height, + const int16_t *param); +void DECORATE(blur1246_horz)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height, + const int16_t *param); +void DECORATE(blur1246_vert)(int16_t *dst, const int16_t *src, + uintptr_t src_width, uintptr_t src_height, + const int16_t *param); + + +const BitmapEngine DECORATE(bitmap_engine) = { + .align_order = ALIGN, + +#if CONFIG_RASTERIZER +#if CONFIG_LARGE_TILES + .tile_order = 5, + .fill_solid = DECORATE(fill_solid_tile32), + .fill_halfplane = DECORATE(fill_halfplane_tile32), + .fill_generic = DECORATE(fill_generic_tile32), +#else + .tile_order = 4, + .fill_solid = DECORATE(fill_solid_tile16), + .fill_halfplane = DECORATE(fill_halfplane_tile16), + .fill_generic = DECORATE(fill_generic_tile16), +#endif +#endif + + .add_bitmaps = DECORATE(add_bitmaps), +#ifdef __x86_64__ + .sub_bitmaps = DECORATE(sub_bitmaps), + .mul_bitmaps = DECORATE(mul_bitmaps), +#else + .sub_bitmaps = ass_sub_bitmaps_c, + .mul_bitmaps = ass_mul_bitmaps_c, +#endif + +#ifdef __x86_64__ + .be_blur = DECORATE(be_blur), +#else + .be_blur = ass_be_blur_c, +#endif + + .stripe_unpack = DECORATE(stripe_unpack), + .stripe_pack = DECORATE(stripe_pack), + .shrink_horz = DECORATE(shrink_horz), + .shrink_vert = DECORATE(shrink_vert), + .expand_horz = DECORATE(expand_horz), + .expand_vert = DECORATE(expand_vert), + .pre_blur_horz = { DECORATE(pre_blur1_horz), DECORATE(pre_blur2_horz), DECORATE(pre_blur3_horz) }, + .pre_blur_vert = { DECORATE(pre_blur1_vert), DECORATE(pre_blur2_vert), DECORATE(pre_blur3_vert) }, + .main_blur_horz = { DECORATE(blur1234_horz), DECORATE(blur1235_horz), DECORATE(blur1246_horz) }, + .main_blur_vert = { DECORATE(blur1234_vert), DECORATE(blur1235_vert), DECORATE(blur1246_vert) }, +}; diff -Nru libass-0.12.2/libass/ass.h libass-0.13.0/libass/ass.h --- libass-0.12.2/libass/ass.h 2015-05-07 18:56:41.000000000 +0000 +++ libass-0.13.0/libass/ass.h 2015-10-03 18:18:46.000000000 +0000 @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 Evgeniy Stepanov + * Copyright (C) 2011 Grigori Goronzy * * This file is part of libass. * @@ -23,7 +24,7 @@ #include #include "ass_types.h" -#define LIBASS_VERSION 0x01202000 +#define LIBASS_VERSION 0x01300000 #ifdef __cplusplus extern "C" { @@ -175,6 +176,24 @@ int ass_library_version(void); /** + * \brief Default Font provider to load fonts in libass' database + * + * NONE don't use any default font provider for font lookup + * AUTODETECT use the first available font provider + * CORETEXT force a CoreText based font provider (OS X only) + * FONTCONFIG force a Fontconfig based font provider + * + * libass uses the best shaper available by default. + */ +typedef enum { + ASS_FONTPROVIDER_NONE = 0, + ASS_FONTPROVIDER_AUTODETECT = 1, + ASS_FONTPROVIDER_CORETEXT, + ASS_FONTPROVIDER_FONTCONFIG, + ASS_FONTPROVIDER_DIRECTWRITE, +} ASS_DefaultFontProvider; + +/** * \brief Initialize the library. * \return library handle or NULL if failed */ @@ -383,11 +402,29 @@ void ass_set_line_position(ASS_Renderer *priv, double line_position); /** + * \brief Get the list of available font providers. The output array + * is allocated with malloc and can be released with free(). If an + * allocation error occurs, size is set to (size_t)-1. + * \param priv library handle + * \param providers output, list of default providers (malloc'ed array) + * \param size output, number of providers + * \return list of available font providers (user owns the returned array) + */ +void ass_get_available_font_providers(ASS_Library *priv, + ASS_DefaultFontProvider **providers, + size_t *size); + +/** * \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 dfp which font provider to use (one of ASS_DefaultFontProvider). In + * older libass version, this could be 0 or 1, where 1 enabled fontconfig. + * Newer relases also accept 0 (ASS_FONTPROVIDER_NONE) and 1 + * (ASS_FONTPROVIDER_AUTODETECT), which is almost backward-compatible. + * If the requested fontprovider does not exist or fails to initialize, the + * behavior is the same as when ASS_FONTPROVIDER_NONE was passed. * \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 @@ -396,8 +433,8 @@ * 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); + const char *default_family, int dfp, + const char *config, int update); /** * \brief Set selective style override mode. @@ -426,8 +463,8 @@ void ass_set_selective_style_override(ASS_Renderer *priv, ASS_Style *style); /** - * \brief Update/build font cache. This needs to be called if it was - * disabled when ass_set_fonts was set. + * \brief This is a stub and does nothing. Old documentation: 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 diff -Nru libass-0.12.2/libass/ass_library.c libass-0.13.0/libass/ass_library.c --- libass-0.12.2/libass/ass_library.c 2014-11-16 16:01:37.000000000 +0000 +++ libass-0.13.0/libass/ass_library.c 2015-09-24 08:34:34.000000000 +0000 @@ -17,6 +17,7 @@ */ #include "config.h" +#include "ass_compat.h" #include #include @@ -27,6 +28,7 @@ #include "ass.h" #include "ass_library.h" #include "ass_utils.h" +#include "ass_string.h" static void ass_msg_handler(int level, const char *fmt, va_list va, void *data) { diff -Nru libass-0.12.2/libass/ass_library.h libass-0.13.0/libass/ass_library.h --- libass-0.12.2/libass/ass_library.h 2014-05-31 20:46:46.000000000 +0000 +++ libass-0.13.0/libass/ass_library.h 2015-09-07 09:44:16.000000000 +0000 @@ -38,4 +38,6 @@ void *msg_callback_data; }; +char *read_file(struct ass_library *library, char *fname, size_t *bufsize); + #endif /* LIBASS_LIBRARY_H */ diff -Nru libass-0.12.2/libass/ass_parse.c libass-0.13.0/libass/ass_parse.c --- libass-0.12.2/libass/ass_parse.c 2015-03-06 12:23:04.000000000 +0000 +++ libass-0.13.0/libass/ass_parse.c 2015-09-24 08:34:34.000000000 +0000 @@ -17,6 +17,7 @@ */ #include "config.h" +#include "ass_compat.h" #include #include @@ -102,7 +103,6 @@ { 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; @@ -114,22 +114,22 @@ val = render_priv->state.bold; // 0 = normal, 1 = bold, >1 = exact weight - if (val == 1) - val = 200; // bold + if (val == 1 || val == -1) + val = 700; // bold else if (val <= 0) - val = 80; // normal + val = 400; // normal desc.bold = val; val = render_priv->state.italic; if (val == 1) - val = 110; // italic + val = 100; // 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, + render_priv->ftlibrary, render_priv->fontselect, &desc); free(desc.family); @@ -178,17 +178,15 @@ */ 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); + (*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) +inline void change_alpha(uint32_t *var, int32_t new, double pwr) { - *var = - (_r(*var) << 24) + (_g(*var) << 16) + (_b(*var) << 8) + - (uint32_t) (_a(*var) * (1 - pwr) + _a(new) * pwr); + *var = (*var & 0xFFFFFF00) | (uint8_t) (_a(*var) * (1 - pwr) + new * pwr); } /** @@ -207,11 +205,11 @@ * \brief Calculate alpha value by piecewise linear function * Used for \fad, \fade implementation. */ -static unsigned +static int interpolate_alpha(long long now, long long t1, long long t2, long long t3, - long long t4, unsigned a1, unsigned a2, unsigned a3) + long long t4, int a1, int a2, int a3) { - unsigned a; + int a; double cf; if (now < t1) { @@ -240,22 +238,23 @@ { int scale = 1; ASS_Drawing *drawing = render_priv->state.clip_drawing; - struct arg text; if (nargs != 1 && nargs != 2) return 0; + if (nargs == 2) + scale = argtoi(args[0]); + struct arg text = args[nargs - 1]; ass_drawing_free(drawing); render_priv->state.clip_drawing = ass_drawing_new(render_priv->library, render_priv->ftlibrary); drawing = render_priv->state.clip_drawing; - if (nargs == 2) - scale = argtoi(args[0]); - drawing->scale = scale; - drawing->scale_x = render_priv->font_scale_x * render_priv->font_scale; - drawing->scale_y = render_priv->font_scale; - text = args[nargs - 1]; - ass_drawing_set_text(drawing, text.start, text.end - text.start); + if (drawing) { + drawing->scale = scale; + drawing->scale_x = render_priv->font_scale_x * render_priv->font_scale; + drawing->scale_y = render_priv->font_scale; + ass_drawing_set_text(drawing, text.start, text.end - text.start); + } return 1; } @@ -545,23 +544,20 @@ render_priv->state.family = family; update_font(render_priv); } else if (tag("alpha")) { - uint32_t val; int i; - int hex = render_priv->track->track_type == TRACK_TYPE_ASS; if (nargs) { - val = string2color(render_priv->library, args->start, hex); - unsigned char a = val >> 24; + int32_t a = parse_alpha_tag(args->start); 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, 1); + _a(render_priv->state.style->PrimaryColour), 1); change_alpha(&render_priv->state.c[1], - render_priv->state.style->SecondaryColour, 1); + _a(render_priv->state.style->SecondaryColour), 1); change_alpha(&render_priv->state.c[2], - render_priv->state.style->OutlineColour, 1); + _a(render_priv->state.style->OutlineColour), 1); change_alpha(&render_priv->state.c[3], - render_priv->state.style->BackColour, 1); + _a(render_priv->state.style->BackColour), 1); } // FIXME: simplify } else if (tag("an")) { @@ -714,59 +710,62 @@ if (parse_vector_clip(render_priv, args, nargs)) render_priv->state.clip_drawing_mode = 0; } - } else if (tag("c")) { - uint32_t val; - int hex = render_priv->track->track_type == TRACK_TYPE_ASS; + } else if (tag("c") || tag("1c")) { if (nargs) { - val = string2color(render_priv->library, args->start, hex); + uint32_t val = parse_color_tag(args->start); change_color(&render_priv->state.c[0], val, pwr); } else change_color(&render_priv->state.c[0], render_priv->state.style->PrimaryColour, 1); - } else if ((*p >= '1') && (*p <= '4') && (++p) - && (tag("c") || tag("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 (nargs) - val = string2color(render_priv->library, args->start, hex); - else { - 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 - } - if (cmd == 'a') - val <<= 24; - pwr = 1; - } - switch (cmd) { - case 'c': - change_color(render_priv->state.c + cidx, val, pwr); - break; - case 'a': - change_alpha(render_priv->state.c + cidx, val >> 24, pwr); - break; - default: - ass_msg(render_priv->library, MSGL_WARN, "Bad command: %c%c", - n, cmd); - break; - } + } else if (tag("2c")) { + if (nargs) { + uint32_t val = parse_color_tag(args->start); + change_color(&render_priv->state.c[1], val, pwr); + } else + change_color(&render_priv->state.c[1], + render_priv->state.style->SecondaryColour, 1); + } else if (tag("3c")) { + if (nargs) { + uint32_t val = parse_color_tag(args->start); + change_color(&render_priv->state.c[2], val, pwr); + } else + change_color(&render_priv->state.c[2], + render_priv->state.style->OutlineColour, 1); + } else if (tag("4c")) { + if (nargs) { + uint32_t val = parse_color_tag(args->start); + change_color(&render_priv->state.c[3], val, pwr); + } else + change_color(&render_priv->state.c[3], + render_priv->state.style->BackColour, 1); + } else if (tag("1a")) { + if (nargs) { + uint32_t val = parse_alpha_tag(args->start); + change_alpha(&render_priv->state.c[0], val, pwr); + } else + change_alpha(&render_priv->state.c[0], + _a(render_priv->state.style->PrimaryColour), 1); + } else if (tag("2a")) { + if (nargs) { + uint32_t val = parse_alpha_tag(args->start); + change_alpha(&render_priv->state.c[1], val, pwr); + } else + change_alpha(&render_priv->state.c[1], + _a(render_priv->state.style->SecondaryColour), 1); + } else if (tag("3a")) { + if (nargs) { + uint32_t val = parse_alpha_tag(args->start); + change_alpha(&render_priv->state.c[2], val, pwr); + } else + change_alpha(&render_priv->state.c[2], + _a(render_priv->state.style->OutlineColour), 1); + } else if (tag("4a")) { + if (nargs) { + uint32_t val = parse_alpha_tag(args->start); + change_alpha(&render_priv->state.c[3], val, pwr); + } else + change_alpha(&render_priv->state.c[3], + _a(render_priv->state.style->BackColour), 1); } else if (tag("r")) { if (nargs) { int len = args->end - args->start; diff -Nru libass-0.12.2/libass/ass_parse.h libass-0.13.0/libass/ass_parse.h --- libass-0.12.2/libass/ass_parse.h 2015-03-06 12:23:04.000000000 +0000 +++ libass-0.13.0/libass/ass_parse.h 2015-07-07 18:28:03.000000000 +0000 @@ -36,7 +36,7 @@ unsigned get_next_char(ASS_Renderer *render_priv, char **str); char *parse_tag(ASS_Renderer *render_priv, char *p, char *end, double pwr); int event_has_hard_overrides(char *str); -extern void change_alpha(uint32_t *var, uint32_t new, double pwr); +extern void change_alpha(uint32_t *var, int32_t new, double pwr); extern uint32_t mult_alpha(uint32_t a, uint32_t b); diff -Nru libass-0.12.2/libass/ass_rasterizer.c libass-0.13.0/libass/ass_rasterizer.c --- libass-0.12.2/libass/ass_rasterizer.c 2015-03-06 12:23:04.000000000 +0000 +++ libass-0.13.0/libass/ass_rasterizer.c 2015-09-24 08:34:34.000000000 +0000 @@ -16,6 +16,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "config.h" +#include "ass_compat.h" + #include "ass_utils.h" #include "ass_rasterizer.h" #include @@ -47,8 +50,9 @@ } -void rasterizer_init(ASS_Rasterizer *rst) +void rasterizer_init(RasterizerData *rst, int outline_error) { + rst->outline_error = outline_error; rst->linebuf[0] = rst->linebuf[1] = NULL; rst->size[0] = rst->capacity[0] = 0; rst->size[1] = rst->capacity[1] = 0; @@ -60,7 +64,7 @@ * \param delta requested size increase * \return zero on error */ -static inline int check_capacity(ASS_Rasterizer *rst, int index, size_t delta) +static inline int check_capacity(RasterizerData *rst, int index, size_t delta) { delta += rst->size[index]; if (rst->capacity[index] >= delta) @@ -78,13 +82,34 @@ return 1; } -void rasterizer_done(ASS_Rasterizer *rst) +void rasterizer_done(RasterizerData *rst) { free(rst->linebuf[0]); free(rst->linebuf[1]); } +/* + * Tiled Rasterization Algorithm + * + * 1) Convert splines into polylines using recursive subdivision. + * + * 2) Determine which segments of resulting polylines fall into each tile. + * That's done through recursive splitting of segment array with horizontal or vertical lines. + * Each individual segment can lie fully left(top) or right(bottom) from the splitting line or cross it. + * In the latter case copies of such segment go to both output arrays. Also winding count + * of the top-left corner of the second result rectangle gets calculated simultaneously with splitting. + * Winding count of the first result rectangle is the same as of the source rectangle. + * + * 3) When the splitting is done to the tile level, there are 3 possible outcome: + * - Tile doesn't have segments at all--fill it with solid color in accordance with winding count. + * - Tile have only 1 segment--use simple half-plane filling algorithm. + * - Generic case with 2 or more segments. + * In the latter case each segment gets rasterized as right trapezoid into buffer + * with additive or subtractive blending. + */ + + typedef struct { int32_t x, y; } OutlinePoint; @@ -124,7 +149,7 @@ /** * \brief Add new segment to polyline */ -static inline int add_line(ASS_Rasterizer *rst, OutlinePoint pt0, OutlinePoint pt1) +static inline int add_line(RasterizerData *rst, OutlinePoint pt0, OutlinePoint pt1) { int32_t x = pt1.x - pt0.x; int32_t y = pt1.y - pt0.y; @@ -169,9 +194,9 @@ /** * \brief Add quadratic spline to polyline - * Preforms recursive subdivision if necessary. + * Performs recursive subdivision if necessary. */ -static int add_quadratic(ASS_Rasterizer *rst, +static int add_quadratic(RasterizerData *rst, OutlinePoint pt0, OutlinePoint pt1, OutlinePoint pt2) { OutlineSegment seg; @@ -195,9 +220,9 @@ /** * \brief Add cubic spline to polyline - * Preforms recursive subdivision if necessary. + * Performs recursive subdivision if necessary. */ -static int add_cubic(ASS_Rasterizer *rst, +static int add_cubic(RasterizerData *rst, OutlinePoint pt0, OutlinePoint pt1, OutlinePoint pt2, OutlinePoint pt3) { OutlineSegment seg; @@ -230,7 +255,7 @@ } -int rasterizer_set_outline(ASS_Rasterizer *rst, const ASS_Outline *path) +int rasterizer_set_outline(RasterizerData *rst, const ASS_Outline *path) { enum Status { S_ON, S_Q, S_C1, S_C2 @@ -591,56 +616,56 @@ } -static inline void rasterizer_fill_solid(ASS_Rasterizer *rst, +static inline void rasterizer_fill_solid(const BitmapEngine *engine, uint8_t *buf, int width, int height, ptrdiff_t stride, int set) { - assert(!(width & ((1 << rst->tile_order) - 1))); - assert(!(height & ((1 << rst->tile_order) - 1))); + assert(!(width & ((1 << engine->tile_order) - 1))); + assert(!(height & ((1 << engine->tile_order) - 1))); int i, j; - ptrdiff_t step = 1 << rst->tile_order; - ptrdiff_t tile_stride = stride * (1 << rst->tile_order); - width >>= rst->tile_order; - height >>= rst->tile_order; + ptrdiff_t step = 1 << engine->tile_order; + ptrdiff_t tile_stride = stride * (1 << engine->tile_order); + width >>= engine->tile_order; + height >>= engine->tile_order; for (j = 0; j < height; ++j) { for (i = 0; i < width; ++i) - rst->fill_solid(buf + i * step, stride, set); + engine->fill_solid(buf + i * step, stride, set); buf += tile_stride; } } -static inline void rasterizer_fill_halfplane(ASS_Rasterizer *rst, +static inline void rasterizer_fill_halfplane(const BitmapEngine *engine, uint8_t *buf, int width, int height, ptrdiff_t stride, int32_t a, int32_t b, int64_t c, int32_t scale) { - assert(!(width & ((1 << rst->tile_order) - 1))); - assert(!(height & ((1 << rst->tile_order) - 1))); - if (width == 1 << rst->tile_order && height == 1 << rst->tile_order) { - rst->fill_halfplane(buf, stride, a, b, c, scale); + assert(!(width & ((1 << engine->tile_order) - 1))); + assert(!(height & ((1 << engine->tile_order) - 1))); + if (width == 1 << engine->tile_order && height == 1 << engine->tile_order) { + engine->fill_halfplane(buf, stride, a, b, c, scale); return; } uint32_t abs_a = a < 0 ? -a : a; uint32_t abs_b = b < 0 ? -b : b; - int64_t size = (int64_t)(abs_a + abs_b) << (rst->tile_order + 5); - int64_t offs = ((int64_t)a + b) * (1 << (rst->tile_order + 5)); + int64_t size = (int64_t)(abs_a + abs_b) << (engine->tile_order + 5); + int64_t offs = ((int64_t)a + b) * (1 << (engine->tile_order + 5)); int i, j; - ptrdiff_t step = 1 << rst->tile_order; - ptrdiff_t tile_stride = stride * (1 << rst->tile_order); - width >>= rst->tile_order; - height >>= rst->tile_order; + ptrdiff_t step = 1 << engine->tile_order; + ptrdiff_t tile_stride = stride * (1 << engine->tile_order); + width >>= engine->tile_order; + height >>= engine->tile_order; for (j = 0; j < height; ++j) { for (i = 0; i < width; ++i) { - int64_t cc = c - (a * (int64_t)i + b * (int64_t)j) * (1 << (rst->tile_order + 6)); + int64_t cc = c - (a * (int64_t)i + b * (int64_t)j) * (1 << (engine->tile_order + 6)); int64_t offs_c = offs - cc; int64_t abs_c = offs_c < 0 ? -offs_c : offs_c; if (abs_c < size) - rst->fill_halfplane(buf + i * step, stride, a, b, cc, scale); + engine->fill_halfplane(buf + i * step, stride, a, b, cc, scale); else - rst->fill_solid(buf + i * step, stride, - ((uint32_t)(offs_c >> 32) ^ scale) & 0x80000000); + engine->fill_solid(buf + i * step, stride, + ((uint32_t)(offs_c >> 32) ^ scale) & 0x80000000); } buf += tile_stride; } @@ -655,18 +680,19 @@ * Rasterizes (possibly recursive) one quad-tree level. * Truncates used input buffer. */ -static int rasterizer_fill_level(ASS_Rasterizer *rst, - uint8_t *buf, int width, int height, ptrdiff_t stride, int index, size_t offs, int winding) +static int rasterizer_fill_level(const BitmapEngine *engine, RasterizerData *rst, + uint8_t *buf, int width, int height, ptrdiff_t stride, + int index, size_t offs, int winding) { assert(width > 0 && height > 0); assert((unsigned)index < 2u && offs <= rst->size[index]); - assert(!(width & ((1 << rst->tile_order) - 1))); - assert(!(height & ((1 << rst->tile_order) - 1))); + assert(!(width & ((1 << engine->tile_order) - 1))); + assert(!(height & ((1 << engine->tile_order) - 1))); size_t n = rst->size[index] - offs; struct segment *line = rst->linebuf[index] + offs; if (!n) { - rasterizer_fill_solid(rst, buf, width, height, stride, winding); + rasterizer_fill_solid(engine, buf, width, height, stride, winding); return 1; } if (n == 1) { @@ -680,16 +706,16 @@ if (winding - 1) flag ^= 3; if (flag & 1) - rasterizer_fill_halfplane(rst, buf, width, height, stride, + rasterizer_fill_halfplane(engine, buf, width, height, stride, line->a, line->b, line->c, flag & 2 ? -line->scale : line->scale); else - rasterizer_fill_solid(rst, buf, width, height, stride, flag & 2); + rasterizer_fill_solid(engine, buf, width, height, stride, flag & 2); rst->size[index] = offs; return 1; } - if (width == 1 << rst->tile_order && height == 1 << rst->tile_order) { - rst->fill_generic(buf, stride, line, rst->size[index] - offs, winding); + if (width == 1 << engine->tile_order && height == 1 << engine->tile_order) { + engine->fill_generic(buf, stride, line, rst->size[index] - offs, winding); rst->size[index] = offs; return 1; } @@ -718,21 +744,21 @@ rst->size[index ^ 0] = dst0 - rst->linebuf[index ^ 0]; rst->size[index ^ 1] = dst1 - rst->linebuf[index ^ 1]; - if (!rasterizer_fill_level(rst, buf, width, height, stride, index ^ 0, offs, winding)) + if (!rasterizer_fill_level(engine, rst, buf, width, height, stride, index ^ 0, offs, winding)) return 0; assert(rst->size[index ^ 0] == offs); - if (!rasterizer_fill_level(rst, buf1, width1, height1, stride, index ^ 1, offs1, winding1)) + if (!rasterizer_fill_level(engine, rst, buf1, width1, height1, stride, index ^ 1, offs1, winding1)) return 0; assert(rst->size[index ^ 1] == offs1); return 1; } -int rasterizer_fill(ASS_Rasterizer *rst, +int rasterizer_fill(const BitmapEngine *engine, RasterizerData *rst, uint8_t *buf, int x0, int y0, int width, int height, ptrdiff_t stride) { assert(width > 0 && height > 0); - assert(!(width & ((1 << rst->tile_order) - 1))); - assert(!(height & ((1 << rst->tile_order) - 1))); + assert(!(width & ((1 << engine->tile_order) - 1))); + assert(!(height & ((1 << engine->tile_order) - 1))); x0 *= 1 << 6; y0 *= 1 << 6; size_t n = rst->size[0]; @@ -784,6 +810,6 @@ } rst->size[index] = n; rst->size[index ^ 1] = 0; - return rasterizer_fill_level(rst, buf, width, height, stride, + return rasterizer_fill_level(engine, rst, buf, width, height, stride, index, 0, winding); } diff -Nru libass-0.12.2/libass/ass_rasterizer_c.c libass-0.13.0/libass/ass_rasterizer_c.c --- libass-0.12.2/libass/ass_rasterizer_c.c 2015-03-06 12:23:04.000000000 +0000 +++ libass-0.13.0/libass/ass_rasterizer_c.c 2015-09-24 08:34:34.000000000 +0000 @@ -16,6 +16,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "config.h" +#include "ass_compat.h" + #include "ass_utils.h" #include "ass_rasterizer.h" #include @@ -138,12 +141,12 @@ * Generic Filling Functions * * Used Algorithm - * Construct trapezium from each polyline segment and its projection into left side of tile. - * Render that trapezium into internal buffer with additive blending and correct sign. + * Construct trapeziod from each polyline segment and its projection into left side of tile. + * Render that trapeziod into internal buffer with additive blending and correct sign. * Store clamped absolute value from internal buffer into result buffer. */ -// Render top/bottom line of the trapezium with antialiasing +// Render top/bottom line of the trapeziod with antialiasing static inline void update_border_line16(int16_t res[16], int16_t abs_a, const int16_t va[16], int16_t b, int16_t abs_b, @@ -262,7 +265,7 @@ } } -// Render top/bottom line of the trapezium with antialiasing +// Render top/bottom line of the trapeziod with antialiasing static inline void update_border_line32(int16_t res[32], int16_t abs_a, const int16_t va[32], int16_t b, int16_t abs_b, diff -Nru libass-0.12.2/libass/ass_rasterizer.h libass-0.13.0/libass/ass_rasterizer.h --- libass-0.12.2/libass/ass_rasterizer.h 2015-03-06 12:23:04.000000000 +0000 +++ libass-0.13.0/libass/ass_rasterizer.h 2015-07-07 18:28:03.000000000 +0000 @@ -22,7 +22,7 @@ #include #include -#include "ass.h" +#include "ass_bitmap.h" #include "ass_font.h" @@ -42,48 +42,25 @@ int32_t x_min, x_max, y_min, y_max; }; - -typedef void (*FillSolidTileFunc)(uint8_t *buf, ptrdiff_t stride, int set); -typedef void (*FillHalfplaneTileFunc)(uint8_t *buf, ptrdiff_t stride, - int32_t a, int32_t b, int64_t c, int32_t scale); -typedef void (*FillGenericTileFunc)(uint8_t *buf, ptrdiff_t stride, - const struct segment *line, size_t n_lines, - int winding); - -void ass_fill_solid_tile16_c(uint8_t *buf, ptrdiff_t stride, int set); -void ass_fill_solid_tile32_c(uint8_t *buf, ptrdiff_t stride, int set); -void ass_fill_halfplane_tile16_c(uint8_t *buf, ptrdiff_t stride, - int32_t a, int32_t b, int64_t c, int32_t scale); -void ass_fill_halfplane_tile32_c(uint8_t *buf, ptrdiff_t stride, - int32_t a, int32_t b, int64_t c, int32_t scale); -void ass_fill_generic_tile16_c(uint8_t *buf, ptrdiff_t stride, - const struct segment *line, size_t n_lines, - int winding); -void ass_fill_generic_tile32_c(uint8_t *buf, ptrdiff_t stride, - const struct segment *line, size_t n_lines, - int winding); - -typedef struct ass_rasterizer { +typedef struct { int outline_error; // acceptable error (in 1/64 pixel units) - int tile_order; // log2(tile_size) - FillSolidTileFunc fill_solid; - FillHalfplaneTileFunc fill_halfplane; - FillGenericTileFunc fill_generic; - - int32_t x_min, x_max, y_min, y_max; // usable after rasterizer_set_outline + // usable after rasterizer_set_outline + int32_t x_min, x_max, y_min, y_max; // internal buffers struct segment *linebuf[2]; size_t size[2], capacity[2]; -} ASS_Rasterizer; +} RasterizerData; + +void rasterizer_init(RasterizerData *rst, int outline_error); +void rasterizer_done(RasterizerData *rst); -void rasterizer_init(ASS_Rasterizer *rst); -void rasterizer_done(ASS_Rasterizer *rst); /** * \brief Convert FreeType outline to polyline and calculate exact bounds */ -int rasterizer_set_outline(ASS_Rasterizer *rst, const ASS_Outline *path); +int rasterizer_set_outline(RasterizerData *rst, const ASS_Outline *path); + /** * \brief Polyline rasterization function * \param x0, y0, width, height in: source window (full pixel units) @@ -92,7 +69,8 @@ * \return zero on error * Deletes preprocessed polyline after work. */ -int rasterizer_fill(ASS_Rasterizer *rst, uint8_t *buf, int x0, int y0, +int rasterizer_fill(const BitmapEngine *engine, RasterizerData *rst, + uint8_t *buf, int x0, int y0, int width, int height, ptrdiff_t stride); diff -Nru libass-0.12.2/libass/ass_render_api.c libass-0.13.0/libass/ass_render_api.c --- libass-0.12.2/libass/ass_render_api.c 2015-03-06 12:23:04.000000000 +0000 +++ libass-0.13.0/libass/ass_render_api.c 2015-09-24 08:34:34.000000000 +0000 @@ -18,6 +18,8 @@ */ #include "config.h" +#include "ass_compat.h" + #include "ass_render.h" static void ass_reconfigure(ASS_Renderer *priv) @@ -135,8 +137,8 @@ } void ass_set_fonts(ASS_Renderer *priv, const char *default_font, - const char *default_family, int fc, const char *config, - int update) + const char *default_family, int dfp, + const char *config, int update) { free(priv->settings.default_font); free(priv->settings.default_family); @@ -144,11 +146,12 @@ 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); + ass_reconfigure(priv); + + if (priv->fontselect) + ass_fontselect_free(priv->fontselect); + priv->fontselect = ass_fontselect_init(priv->library, priv->ftlibrary, + default_family, default_font, config, dfp); } void ass_set_selective_style_override_enabled(ASS_Renderer *priv, int bits) @@ -169,7 +172,8 @@ int ass_fonts_update(ASS_Renderer *render_priv) { - return fontconfig_update(render_priv->fontconfig_priv); + // This is just a stub now! + return 1; } void ass_set_cache_limits(ASS_Renderer *render_priv, int glyph_max, @@ -179,3 +183,10 @@ render_priv->cache.bitmap_max_size = bitmap_max ? 1048576 * bitmap_max : BITMAP_CACHE_MAX_SIZE; } + +ASS_FontProvider * +ass_create_font_provider(ASS_Renderer *priv, ASS_FontProviderFuncs *funcs, + void *data) +{ + return ass_font_provider_new(priv->fontselect, funcs, data); +} diff -Nru libass-0.12.2/libass/ass_render.c libass-0.13.0/libass/ass_render.c --- libass-0.12.2/libass/ass_render.c 2015-03-16 20:00:58.000000000 +0000 +++ libass-0.13.0/libass/ass_render.c 2015-09-24 08:34:34.000000000 +0000 @@ -17,6 +17,7 @@ */ #include "config.h" +#include "ass_compat.h" #include #include @@ -34,12 +35,6 @@ #define SUBPIXEL_MASK 63 #define SUBPIXEL_ACCURACY 7 -#if (defined(__i386__) || defined(__x86_64__)) && CONFIG_ASM - -#include "x86/blend_bitmaps.h" -#include "x86/rasterizer.h" - -#endif // ASM ASS_Renderer *ass_renderer_init(ASS_Library *library) { @@ -64,62 +59,23 @@ 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 - #if (defined(__i386__) || defined(__x86_64__)) && CONFIG_ASM - int sse2 = has_sse2(); - int avx2 = has_avx2(); - priv->add_bitmaps_func = avx2 ? ass_add_bitmaps_avx2 : - (sse2 ? ass_add_bitmaps_sse2 : ass_add_bitmaps_x86); - #ifdef __x86_64__ - priv->mul_bitmaps_func = avx2 ? ass_mul_bitmaps_avx2 : ass_mul_bitmaps_sse2; - priv->sub_bitmaps_func = avx2 ? ass_sub_bitmaps_avx2 : ass_sub_bitmaps_sse2; - #else - priv->mul_bitmaps_func = mul_bitmaps_c; - priv->sub_bitmaps_func = ass_sub_bitmaps_x86; - #endif - #else - priv->add_bitmaps_func = add_bitmaps_c; - priv->sub_bitmaps_func = sub_bitmaps_c; - priv->mul_bitmaps_func = mul_bitmaps_c; - #endif - -#if CONFIG_RASTERIZER -#if CONFIG_LARGE_TILES - priv->rasterizer.tile_order = 5; - #if (defined(__i386__) || defined(__x86_64__)) && CONFIG_ASM - priv->rasterizer.fill_solid = avx2 ? ass_fill_solid_tile32_avx2 : - (sse2 ? ass_fill_solid_tile32_sse2 : ass_fill_solid_tile32_c); - priv->rasterizer.fill_halfplane = avx2 ? ass_fill_halfplane_tile32_avx2 : - (sse2 ? ass_fill_halfplane_tile32_sse2 : ass_fill_halfplane_tile32_c); - priv->rasterizer.fill_generic = avx2 ? ass_fill_generic_tile32_avx2 : - (sse2 ? ass_fill_generic_tile32_sse2 : ass_fill_generic_tile32_c); - #else - priv->rasterizer.fill_solid = ass_fill_solid_tile32_c; - priv->rasterizer.fill_halfplane = ass_fill_halfplane_tile32_c; - priv->rasterizer.fill_generic = ass_fill_generic_tile32_c; - #endif +#if (defined(__i386__) || defined(__x86_64__)) && CONFIG_ASM + if (has_avx2()) + priv->engine = &ass_bitmap_engine_avx2; + else if (has_sse2()) + priv->engine = &ass_bitmap_engine_sse2; + else + priv->engine = &ass_bitmap_engine_c; #else - priv->rasterizer.tile_order = 4; - #if (defined(__i386__) || defined(__x86_64__)) && CONFIG_ASM - priv->rasterizer.fill_solid = avx2 ? ass_fill_solid_tile16_avx2 : - (sse2 ? ass_fill_solid_tile16_sse2 : ass_fill_solid_tile16_c); - priv->rasterizer.fill_halfplane = avx2 ? ass_fill_halfplane_tile16_avx2 : - (sse2 ? ass_fill_halfplane_tile16_sse2 : ass_fill_halfplane_tile16_c); - priv->rasterizer.fill_generic = avx2 ? ass_fill_generic_tile16_avx2 : - (sse2 ? ass_fill_generic_tile16_sse2 : ass_fill_generic_tile16_c); - #else - priv->rasterizer.fill_solid = ass_fill_solid_tile16_c; - priv->rasterizer.fill_halfplane = ass_fill_halfplane_tile16_c; - priv->rasterizer.fill_generic = ass_fill_generic_tile16_c; - #endif + priv->engine = &ass_bitmap_engine_c; #endif - priv->rasterizer.outline_error = 16; - rasterizer_init(&priv->rasterizer); + +#if CONFIG_RASTERIZER + rasterizer_init(&priv->rasterizer, 16); #endif priv->cache.font_cache = ass_font_cache_create(); @@ -190,13 +146,11 @@ FT_Stroker_Done(render_priv->state.stroker); render_priv->state.stroker = 0; } + if (render_priv->fontselect) + ass_fontselect_free(render_priv->fontselect); + ass_shaper_free(render_priv->shaper); 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); @@ -633,9 +587,9 @@ // Blend together memcpy(nbuffer, abuffer, ((ah - 1) * as) + aw); - render_priv->sub_bitmaps_func(nbuffer + atop * as + aleft, as, - bbuffer + btop * bs + bleft, bs, - h, w); + render_priv->engine->sub_bitmaps(nbuffer + atop * as + aleft, as, + bbuffer + btop * bs + bleft, bs, + h, w); } else { // Regular clip if (ax + aw < bx || ay + ah < by || ax > bx + bw || @@ -654,10 +608,10 @@ } // Blend together - render_priv->mul_bitmaps_func(nbuffer, ns, - abuffer + atop * as + aleft, as, - bbuffer + btop * bs + bleft, bs, - w, h); + render_priv->engine->mul_bitmaps(nbuffer, ns, + abuffer + atop * as + aleft, as, + bbuffer + btop * bs + bleft, bs, + w, h); cur->dst_x += aleft; cur->dst_y += atop; cur->w = w; @@ -961,9 +915,6 @@ render_priv->state.effect_type = EF_NONE; render_priv->state.effect_timing = 0; render_priv->state.effect_skip_timing = 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); } @@ -971,12 +922,15 @@ static void free_render_context(ASS_Renderer *render_priv) { free(render_priv->state.family); - ass_drawing_free(render_priv->state.drawing); ass_drawing_free(render_priv->state.clip_drawing); render_priv->state.family = NULL; - render_priv->state.drawing = NULL; render_priv->state.clip_drawing = NULL; + + TextInfo *text_info = &render_priv->text_info; + for (int n = 0; n < text_info->length; n++) + ass_drawing_free(text_info->glyphs[n].drawing); + text_info->length = 0; } /* @@ -1102,7 +1056,7 @@ outline->n_points = n_points; outline->n_contours = n_contours; for (size_t i = 0; i < n_contours; ++i) - outline->contours[i] = contours[i]; + outline->contours[i] = (unsigned short) contours[i]; // "Stroke" with the outline emboldener (in two passes if needed). // The outlines look uglier, but the emboldening never adds any points @@ -1228,7 +1182,7 @@ ass_font_set_transform(info->font, info->scale_x, info->scale_y, NULL); FT_Glyph glyph = - ass_font_get_glyph(priv->fontconfig_priv, info->font, + ass_font_get_glyph(info->font, info->symbol, info->face_index, info->glyph_index, priv->settings.hinting, info->flags); if (glyph != NULL) { @@ -1528,7 +1482,7 @@ } // A break itself can contain a whitespace, too cur = ti->glyphs + i; - if (cur->symbol == ' ') { + if (cur->symbol == ' ' || cur->symbol == '\n') { cur->skip++; // Mark whitespace after j = i + 1; @@ -1559,7 +1513,7 @@ wrap_lines_smart(ASS_Renderer *render_priv, double max_text_width) { int i; - GlyphInfo *cur, *s1, *e1, *s2, *s3, *w; + GlyphInfo *cur, *s1, *e1, *s2, *s3; int last_space; int break_type; int exit; @@ -1611,7 +1565,6 @@ 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++; } } @@ -1620,7 +1573,7 @@ exit = 0; while (!exit && render_priv->state.wrap_style != 1) { exit = 1; - w = s3 = text_info->glyphs; + s3 = text_info->glyphs; s1 = s2 = 0; for (i = 0; i <= text_info->length; ++i) { cur = text_info->glyphs + i; @@ -1630,8 +1583,8 @@ s3 = cur; if (s1 && (s2->linebreak == 1)) { // have at least 2 lines, and linebreak is 'soft' double l1, l2, l1_new, l2_new; + GlyphInfo *w = s2; - w = s2; do { --w; } while ((w > s1) && (w->symbol == ' ')); @@ -1674,8 +1627,6 @@ measure_text(render_priv); trim_whitespace(render_priv); - pen_shift_x = 0.; - pen_shift_y = 0.; cur_line = 1; run_offset = 0; @@ -1684,6 +1635,7 @@ while (i < text_info->length && cur->skip) cur = text_info->glyphs + ++i; pen_shift_x = d6_to_double(-cur->pos.x); + pen_shift_y = 0.; for (i = 0; i < text_info->length; ++i) { cur = text_info->glyphs + i; @@ -1834,7 +1786,7 @@ static void make_shadow_bitmap(CombinedBitmapInfo *info, ASS_Renderer *render_priv) { if (!(info->filter.flags & FILTER_NONZERO_SHADOW)) { - if (info->bm_o && !(info->filter.flags & FILTER_BORDER_STYLE_3)) { + if (info->bm && info->bm_o && !(info->filter.flags & FILTER_BORDER_STYLE_3)) { fix_outline(info->bm, info->bm_o); } else if (info->bm_o && !(info->filter.flags & FILTER_NONZERO_BORDER)) { ass_free_bitmap(info->bm_o); @@ -1844,16 +1796,16 @@ } // Create shadow and fix outline as needed - if (info->bm_o && !(info->filter.flags & FILTER_BORDER_STYLE_3)) { - info->bm_s = copy_bitmap(info->bm_o); + if (info->bm && info->bm_o && !(info->filter.flags & FILTER_BORDER_STYLE_3)) { + info->bm_s = copy_bitmap(render_priv->engine, info->bm_o); fix_outline(info->bm, info->bm_o); } else if (info->bm_o && (info->filter.flags & FILTER_NONZERO_BORDER)) { - info->bm_s = copy_bitmap(info->bm_o); + info->bm_s = copy_bitmap(render_priv->engine, info->bm_o); } else if (info->bm_o) { info->bm_s = info->bm_o; info->bm_o = 0; - } else - info->bm_s = copy_bitmap(info->bm); + } else if (info->bm) + info->bm_s = copy_bitmap(render_priv->engine, info->bm); if (!info->bm_s) return; @@ -1870,12 +1822,11 @@ static int parse_events(ASS_Renderer *render_priv, ASS_Event *event) { TextInfo *text_info = &render_priv->text_info; - ASS_Drawing *drawing; + ASS_Drawing *drawing = NULL; unsigned code; char *p, *q; int i; - drawing = render_priv->state.drawing; p = event->Text; // Event parsing. @@ -1895,6 +1846,12 @@ q++; while ((*q != '{') && (*q != 0)) q++; + if (!drawing) { + drawing = ass_drawing_new(render_priv->library, + render_priv->ftlibrary); + if (!drawing) + return 1; + } ass_drawing_set_text(drawing, p, q - p); code = 0xfffc; // object replacement character p = q; @@ -1908,6 +1865,13 @@ if (code == 0) break; + // face could have been changed in get_next_char + if (!render_priv->state.font) { + free_render_context(render_priv); + ass_drawing_free(drawing); + return 1; + } + if (text_info->length >= text_info->max_glyphs) { // Raise maximum number of glyphs text_info->max_glyphs *= 2; @@ -1922,7 +1886,7 @@ memset(info, 0, sizeof(GlyphInfo)); // Parse drawing - if (drawing->text) { + if (drawing && drawing->text) { drawing->scale_x = render_priv->state.scale_x * render_priv->font_scale; drawing->scale_y = render_priv->state.scale_y * @@ -1930,12 +1894,7 @@ drawing->scale = render_priv->state.drawing_scale; drawing->pbo = render_priv->state.pbo; info->drawing = drawing; - } - - // face could have been changed in get_next_char - if (!render_priv->state.font) { - free_render_context(render_priv); - return 1; + drawing = NULL; } // Fill glyph information @@ -1943,8 +1902,10 @@ info->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.); + // VSFilter compatibility: apply fade only when it's positive + if (render_priv->state.fade > 0) + change_alpha(&clr, + mult_alpha(_a(clr), render_priv->state.fade), 1.); info->c[i] = clr; } @@ -1972,12 +1933,8 @@ info->fax = render_priv->state.fax; info->fay = render_priv->state.fay; - if (info->drawing) { - drawing = render_priv->state.drawing = - ass_drawing_new(render_priv->library, render_priv->ftlibrary); - } else { + if (!info->drawing) fix_glyph_scaling(render_priv, info); - } text_info->length++; @@ -1986,6 +1943,8 @@ render_priv->state.effect_skip_timing = 0; } + ass_drawing_free(drawing); + return 0; } @@ -2268,7 +2227,7 @@ } last_info = info; - if (!info->image) + if (!info->image || !current_info) continue; if (current_info->bitmap_count >= current_info->max_bitmap_count) { @@ -2315,15 +2274,12 @@ continue; } - int bbord = info->filter.be > 0 ? sqrt(2 * info->filter.be) : 0; - int gbord = info->filter.blur > 0.0 ? FFMIN(info->filter.blur + 1, INT_MAX) : 0; - int bord = FFMAX(bbord, gbord); - + int bord = be_padding(info->filter.be); if (!bord && info->n_bm == 1) { for (int j = 0; j < info->bitmap_count; ++j) { if (!info->bitmaps[j].image->bm) continue; - info->bm = copy_bitmap(info->bitmaps[j].image->bm); + info->bm = copy_bitmap(render_priv->engine, info->bitmaps[j].image->bm); if (info->bm) { info->bm->left += info->bitmaps[j].x; info->bm->top += info->bitmaps[j].y; @@ -2331,7 +2287,8 @@ break; } } else if (info->n_bm) { - info->bm = alloc_bitmap(info->rect.x_max - info->rect.x_min + 2 * bord, + info->bm = alloc_bitmap(render_priv->engine, + info->rect.x_max - info->rect.x_min + 2 * bord, info->rect.y_max - info->rect.y_min + 2 * bord); Bitmap *dst = info->bm; if (dst) { @@ -2346,9 +2303,9 @@ assert(x >= 0 && x + src->w <= dst->w); assert(y >= 0 && y + src->h <= dst->h); unsigned char *buf = dst->buffer + y * dst->stride + x; - render_priv->add_bitmaps_func(buf, dst->stride, - src->buffer, src->stride, - src->h, src->w); + render_priv->engine->add_bitmaps(buf, dst->stride, + src->buffer, src->stride, + src->h, src->w); } } } @@ -2356,7 +2313,7 @@ for (int j = 0; j < info->bitmap_count; ++j) { if (!info->bitmaps[j].image->bm_o) continue; - info->bm_o = copy_bitmap(info->bitmaps[j].image->bm_o); + info->bm_o = copy_bitmap(render_priv->engine, info->bitmaps[j].image->bm_o); if (info->bm_o) { info->bm_o->left += info->bitmaps[j].x; info->bm_o->top += info->bitmaps[j].y; @@ -2364,7 +2321,8 @@ break; } } else if (info->n_bm_o) { - info->bm_o = alloc_bitmap(info->rect_o.x_max - info->rect_o.x_min + 2 * bord, + info->bm_o = alloc_bitmap(render_priv->engine, + info->rect_o.x_max - info->rect_o.x_min + 2 * bord, info->rect_o.y_max - info->rect_o.y_min + 2 * bord); Bitmap *dst = info->bm_o; if (dst) { @@ -2379,15 +2337,15 @@ assert(x >= 0 && x + src->w <= dst->w); assert(y >= 0 && y + src->h <= dst->h); unsigned char *buf = dst->buffer + y * dst->stride + x; - render_priv->add_bitmaps_func(buf, dst->stride, - src->buffer, src->stride, - src->h, src->w); + render_priv->engine->add_bitmaps(buf, dst->stride, + src->buffer, src->stride, + src->h, src->w); } } } if(info->bm || info->bm_o){ - ass_synth_blur(render_priv->synth_priv, info->filter.flags & FILTER_BORDER_STYLE_3, + ass_synth_blur(render_priv->engine, info->filter.flags & FILTER_BORDER_STYLE_3, info->filter.be, info->filter.blur, info->bm, info->bm_o); if (info->filter.flags & FILTER_DRAW_SHADOW) make_shadow_bitmap(info, render_priv); @@ -2450,8 +2408,8 @@ return 1; } + free_render_context(render_priv); init_render_context(render_priv, event); - text_info->length = 0; if (parse_events(render_priv, event)) return 1; @@ -2544,6 +2502,8 @@ y2scr(render_priv, render_priv->track->PlayResY / 2.0); device_y = scr_y - (bbox.yMax + bbox.yMin) / 2.0; } else { // subtitle + double line_pos = render_priv->state.explicit ? + 0 : render_priv->settings.line_position; double scr_top, scr_bottom, scr_y0; if (valign != VALIGN_SUB) ass_msg(render_priv->library, MSGL_V, @@ -2552,15 +2512,14 @@ y2scr_sub(render_priv, render_priv->track->PlayResY - MarginV); scr_top = y2scr_top(render_priv, 0); //xxx not always 0? - device_y = scr_bottom + (scr_top - scr_bottom) * - render_priv->settings.line_position / 100.0; + device_y = scr_bottom + (scr_top - scr_bottom) * line_pos / 100.0; device_y -= text_info->height; device_y += text_info->lines[0].asc; // clip to top to avoid confusion if line_position is very high, // turning the subtitle into a toptitle // also, don't change behavior if line_position is not used scr_y0 = scr_top + text_info->lines[0].asc; - if (device_y < scr_y0 && render_priv->settings.line_position > 0) { + if (device_y < scr_y0 && line_pos > 0) { device_y = scr_y0; } } @@ -2624,6 +2583,19 @@ y2scr_pos(render_priv, render_priv->state.clip_y1); } + if (render_priv->state.explicit) { + // we still need to clip against screen boundaries + double zx = x2scr_pos_scaled(render_priv, 0); + double zy = y2scr_pos(render_priv, 0); + double sx = x2scr_pos_scaled(render_priv, render_priv->track->PlayResX); + double sy = y2scr_pos(render_priv, render_priv->track->PlayResY); + + render_priv->state.clip_x0 = render_priv->state.clip_x0 < zx ? zx : render_priv->state.clip_x0; + render_priv->state.clip_y0 = render_priv->state.clip_y0 < zy ? zy : render_priv->state.clip_y0; + render_priv->state.clip_x1 = render_priv->state.clip_x1 > sx ? sx : render_priv->state.clip_x1; + render_priv->state.clip_y1 = render_priv->state.clip_y1 > sy ? sy : render_priv->state.clip_y1; + } + calculate_rotation_params(render_priv, &bbox, device_x, device_y); render_and_combine_glyphs(render_priv, device_x, device_y); @@ -2700,7 +2672,10 @@ && !render_priv->settings.frame_height) return 1; // library not initialized - if (!render_priv->fontconfig_priv) + if (!render_priv->fontselect) + return 1; + + if (render_priv->library != track->library) return 1; free_list_clear(render_priv); diff -Nru libass-0.12.2/libass/ass_render.h libass-0.13.0/libass/ass_render.h --- libass-0.12.2/libass/ass_render.h 2015-03-16 19:53:46.000000000 +0000 +++ libass-0.13.0/libass/ass_render.h 2015-09-24 08:34:34.000000000 +0000 @@ -30,15 +30,12 @@ #include "hb.h" #endif -// 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_fontselect.h" #include "ass_library.h" #include "ass_drawing.h" #include "ass_bitmap.h" @@ -240,14 +237,13 @@ int clip_x0, clip_y0, clip_x1, clip_y1; char clip_mode; // 1 = iclip char detect_collisions; - uint32_t fade; // alpha from \fad + int fade; // alpha from \fad char be; // blur edges double blur; // gaussian blur double shadow_x; double shadow_y; int drawing_scale; // currently reading: regular text if 0, drawing otherwise double pbo; // drawing baseline offset - ASS_Drawing *drawing; // current drawing ASS_Drawing *clip_drawing; // clip vector int clip_drawing_mode; // 0 = regular clip, 1 = inverse clip @@ -292,24 +288,14 @@ size_t composite_max_size; } CacheStore; -typedef void (*BitmapBlendFunc)(uint8_t *dst, intptr_t dst_stride, - uint8_t *src, intptr_t src_stride, - intptr_t height, intptr_t width); -typedef void (*BitmapMulFunc)(uint8_t *dst, intptr_t dst_stride, - uint8_t *src1, intptr_t src1_stride, - uint8_t *src2, intptr_t src2_stride, - intptr_t width, intptr_t height); -typedef void (*BEBlurFunc)(uint8_t *buf, intptr_t w, - intptr_t h, intptr_t stride, - uint16_t *tmp); +#include "ass_shaper.h" struct ass_renderer { ASS_Library *library; FT_Library ftlibrary; - FCInstance *fontconfig_priv; + ASS_FontSelector *fontselect; ASS_Settings settings; int render_id; - ASS_SynthPriv *synth_priv; ASS_Shaper *shaper; ASS_Image *images_root; // rendering result is stored here @@ -336,12 +322,10 @@ TextInfo text_info; CacheStore cache; + const BitmapEngine *engine; #if CONFIG_RASTERIZER - ASS_Rasterizer rasterizer; + RasterizerData rasterizer; #endif - BitmapBlendFunc add_bitmaps_func; - BitmapBlendFunc sub_bitmaps_func; - BitmapMulFunc mul_bitmaps_func; FreeList *free_head; FreeList *free_tail; diff -Nru libass-0.12.2/libass/ass_shaper.c libass-0.13.0/libass/ass_shaper.c --- libass-0.12.2/libass/ass_shaper.c 2014-11-20 21:03:56.000000000 +0000 +++ libass-0.13.0/libass/ass_shaper.c 2015-09-24 08:34:34.000000000 +0000 @@ -17,6 +17,7 @@ */ #include "config.h" +#include "ass_compat.h" #include "ass_shaper.h" #include "ass_render.h" @@ -79,7 +80,7 @@ */ void ass_shaper_info(ASS_Library *lib) { - ass_msg(lib, MSGL_V, "Shaper: FriBidi " + ass_msg(lib, MSGL_INFO, "Shaper: FriBidi " FRIBIDI_VERSION " (SIMPLE)" #ifdef CONFIG_HARFBUZZ " HarfBuzz-ng %s (COMPLEX)", hb_version_string() @@ -702,8 +703,8 @@ /** * \brief Toggle kerning for HarfBuzz shaping. - * NOTE: currently only works with OpenType fonts, the TrueType fallback *always* - * kerns. It's a bug in HarfBuzz. + * \param shaper shaper instance + * \param kern toggle kerning */ void ass_shaper_set_kerning(ASS_Shaper *shaper, int kern) { @@ -733,7 +734,7 @@ if (info->symbol == 0xfffc) continue; // set size and get glyph index - ass_font_get_index(render_priv->fontconfig_priv, info->font, + ass_font_get_index(render_priv->fontselect, info->font, info->symbol, &info->face_index, &info->glyph_index); // shape runs break on: xbord, ybord, xshad, yshad, // all four colors, all four alphas, be, blur, fn, fs, diff -Nru libass-0.12.2/libass/ass_shaper.h libass-0.13.0/libass/ass_shaper.h --- libass-0.12.2/libass/ass_shaper.h 2014-08-14 02:11:03.000000000 +0000 +++ libass-0.13.0/libass/ass_shaper.h 2015-09-24 08:34:34.000000000 +0000 @@ -19,7 +19,7 @@ #ifndef LIBASS_SHAPER_H #define LIBASS_SHAPER_H -#include "config.h" +typedef struct ass_shaper ASS_Shaper; #include #include "ass_render.h" diff -Nru libass-0.12.2/libass/ass_string.c libass-0.13.0/libass/ass_string.c --- libass-0.12.2/libass/ass_string.c 1970-01-01 00:00:00.000000000 +0000 +++ libass-0.13.0/libass/ass_string.c 2015-09-24 08:34:34.000000000 +0000 @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2015 Grigori Goronzy + * + * 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_compat.h" + +#include "ass_string.h" + +static const char lowertab[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, + 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, + 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, + 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, + 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, + 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, + 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, + 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, + 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, + 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, + 0xfd, 0xfe, 0xff +}; + +int ass_strcasecmp(const char *s1, const char *s2) +{ + unsigned char a, b; + + do { + a = lowertab[(unsigned char)*s1++]; + b = lowertab[(unsigned char)*s2++]; + } while (a && a == b); + + return a - b; +} + +int ass_strncasecmp(const char *s1, const char *s2, size_t n) +{ + unsigned char a, b; + const char *last = s1 + n; + + do { + a = lowertab[(unsigned char)*s1++]; + b = lowertab[(unsigned char)*s2++]; + } while (s1 < last && a && a == b); + + return a - b; +} + diff -Nru libass-0.12.2/libass/ass_string.h libass-0.13.0/libass/ass_string.h --- libass-0.12.2/libass/ass_string.h 1970-01-01 00:00:00.000000000 +0000 +++ libass-0.13.0/libass/ass_string.h 2015-09-24 08:34:34.000000000 +0000 @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 Grigori Goronzy + * + * 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 + +#ifndef ASS_STRING_H +#define ASS_STRING_H + +int ass_strcasecmp(const char *s1, const char *s2); +int ass_strncasecmp(const char *s1, const char *s2, size_t n); + +static inline int ass_isspace(int c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || + c == '\f' || c == '\r'; +} + +static inline int ass_isdigit(int c) +{ + return c >= '0' && c <= '9'; +} + +#endif diff -Nru libass-0.12.2/libass/ass_strtod.c libass-0.13.0/libass/ass_strtod.c --- libass-0.12.2/libass/ass_strtod.c 2014-02-25 17:26:10.000000000 +0000 +++ libass-0.13.0/libass/ass_strtod.c 2015-09-24 08:34:34.000000000 +0000 @@ -12,9 +12,12 @@ * */ +#include "config.h" +#include "ass_compat.h" + #include -#include #include +#include "ass_string.h" static const int maxExponent = 511; /* Largest possible base 10 exponent. Any @@ -100,7 +103,7 @@ */ p = string; - while (isspace(*p)) { + while (ass_isspace(*p)) { p += 1; } if (*p == '-') { @@ -122,7 +125,7 @@ for (mantSize = 0; ; mantSize += 1) { c = *p; - if (!isdigit(c)) { + if (!ass_isdigit(c)) { if ((c != '.') || (decPt >= 0)) { break; } @@ -198,7 +201,7 @@ } expSign = 0; } - while (isdigit(*p)) { + while (ass_isdigit(*p)) { exp = exp * 10 + (*p - '0'); p += 1; } diff -Nru libass-0.12.2/libass/ass_types.h libass-0.13.0/libass/ass_types.h --- libass-0.12.2/libass/ass_types.h 2014-04-27 19:28:46.000000000 +0000 +++ libass-0.13.0/libass/ass_types.h 2015-09-07 09:44:16.000000000 +0000 @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 Evgeniy Stepanov + * Copyright (C) 2011 Grigori Goronzy * * This file is part of libass. * @@ -28,6 +29,17 @@ #define HALIGN_CENTER 2 #define HALIGN_RIGHT 3 +#define FONT_WEIGHT_LIGHT 300 +#define FONT_WEIGHT_MEDIUM 400 +#define FONT_WEIGHT_BOLD 700 +#define FONT_SLANT_NONE 0 +#define FONT_SLANT_ITALIC 100 +#define FONT_SLANT_OBLIQUE 110 +#define FONT_WIDTH_CONDENSED 75 +#define FONT_WIDTH_NORMAL 100 +#define FONT_WIDTH_EXPANDED 125 + + /* Opaque objects internally used by libass. Contents are private. */ typedef struct ass_renderer ASS_Renderer; typedef struct render_priv ASS_RenderPriv; @@ -63,6 +75,7 @@ double Blur; } ASS_Style; + /* * ASS_Event corresponds to a single Dialogue line; * text is stored as-is, style overrides will be parsed later. diff -Nru libass-0.12.2/libass/ass_utils.c libass-0.13.0/libass/ass_utils.c --- libass-0.12.2/libass/ass_utils.c 2014-11-17 20:19:46.000000000 +0000 +++ libass-0.13.0/libass/ass_utils.c 2015-09-24 08:34:34.000000000 +0000 @@ -17,18 +17,18 @@ */ #include "config.h" +#include "ass_compat.h" #include #include #include #include #include -#include -#include #include "ass_library.h" #include "ass.h" #include "ass_utils.h" +#include "ass_string.h" #if (defined(__i386__) || defined(__x86_64__)) && CONFIG_ASM @@ -48,6 +48,9 @@ if(!(ecx & (1 << 27))) // not OSXSAVE return 0; uint32_t misc = ecx; + ass_get_xgetbv(0, &eax, &edx); + if((eax & 0x6) != 0x6) + return 0; eax = 0; ass_get_cpuid(&eax, &ebx, &ecx, &edx); return (ecx & 0x6) == 0x6 ? (misc >> 28) & 0x1 : 0; // check high bits are relevant, then AVX support @@ -165,57 +168,124 @@ return *p != start; } -int mystrtou32(char **p, int base, uint32_t *res) +int mystrtod(char **p, double *res) { char *start = *p; - *res = strtoll(*p, p, base); + *res = ass_strtod(*p, p); return *p != start; } -int mystrtod(char **p, double *res) +int mystrtoi32(char **p, int base, int32_t *res) { char *start = *p; - *res = ass_strtod(*p, p); + long long temp_res = strtoll(*p, p, base); + *res = FFMINMAX(temp_res, INT32_MIN, INT32_MAX); return *p != start; } -uint32_t string2color(ASS_Library *library, char *p, int hex) +static int read_digits(char **str, int base, uint32_t *res) { - uint32_t color = 0; - int base = hex ? 16 : 10; - - if (*p == '&') - while (*p == '&') - ++p; - else - ass_msg(library, MSGL_DBG2, "suspicious color format: \"%s\"\n", p); + char *p = *str; + char *start = p; + uint32_t val = 0; - if (*p == 'H' || *p == 'h') { + while (1) { + int digit; + if (*p >= '0' && *p < base + '0') + digit = *p - '0'; + else if (*p >= 'a' && *p < base - 10 + 'a') + digit = *p - 'a' + 10; + else if (*p >= 'A' && *p < base - 10 + 'A') + digit = *p - 'A' + 10; + else + break; + val = val * base + digit; ++p; - mystrtou32(&p, 16, &color); - } else - mystrtou32(&p, base, &color); + } - while (*p == '&' || *p == 'H') - ++p; + *res = val; + *str = p; + return p != start; +} + +/** + * \brief Convert a string to an integer reduced modulo 2**32 + * Follows the rules for strtoul but reduces the number modulo 2**32 + * instead of saturating it to 2**32 - 1. + */ +static int mystrtou32_modulo(char **p, int base, uint32_t *res) +{ + // This emulates scanf with %d or %x format as it works on + // Windows, because that's what is used by VSFilter. In practice, + // scanf works the same way on other platforms too, but + // the standard leaves its behavior on overflow undefined. + + // Unlike scanf and like strtoul, produce 0 for invalid inputs. + + char *start = *p; + int sign = 1; + + skip_spaces(p); + + if (**p == '+') + ++*p; + else if (**p == '-') + sign = -1, ++*p; - 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 (base == 16 && !ass_strncasecmp(*p, "0x", 2)) + *p += 2; - return color; + if (read_digits(p, base, res)) { + *res *= sign; + return 1; + } else { + *p = start; + return 0; + } +} + +int32_t parse_alpha_tag(char *str) +{ + int32_t alpha = 0; + + while (*str == '&' || *str == 'H') + ++str; + + mystrtoi32(&str, 16, &alpha); + return alpha; +} + +uint32_t parse_color_tag(char *str) +{ + int32_t color = 0; + + while (*str == '&' || *str == 'H') + ++str; + + mystrtoi32(&str, 16, &color); + return ass_bswap32((uint32_t) color); +} + +uint32_t parse_color_header(char *str) +{ + uint32_t color = 0; + int base; + + if (!ass_strncasecmp(str, "&h", 2) || !ass_strncasecmp(str, "0x", 2)) { + str += 2; + base = 16; + } else + base = 10; + + mystrtou32_modulo(&str, base, &color); + return ass_bswap32(color); } // Return a boolean value for a string char parse_bool(char *str) { skip_spaces(&str); - return !strncasecmp(str, "yes", 3) || strtol(str, NULL, 10) > 0; + return !ass_strncasecmp(str, "yes", 3) || strtol(str, NULL, 10) > 0; } int parse_ycbcr_matrix(char *str) @@ -235,28 +305,28 @@ memcpy(buffer, str, n); buffer[n] = '\0'; - if (!strcasecmp(buffer, "none")) + if (!ass_strcasecmp(buffer, "none")) return YCBCR_NONE; - if (!strcasecmp(buffer, "tv.601")) + if (!ass_strcasecmp(buffer, "tv.601")) return YCBCR_BT601_TV; - if (!strcasecmp(buffer, "pc.601")) + if (!ass_strcasecmp(buffer, "pc.601")) return YCBCR_BT601_PC; - if (!strcasecmp(buffer, "tv.709")) + if (!ass_strcasecmp(buffer, "tv.709")) return YCBCR_BT709_TV; - if (!strcasecmp(buffer, "pc.709")) + if (!ass_strcasecmp(buffer, "pc.709")) return YCBCR_BT709_PC; - if (!strcasecmp(buffer, "tv.240m")) + if (!ass_strcasecmp(buffer, "tv.240m")) return YCBCR_SMPTE240M_TV; - if (!strcasecmp(buffer, "pc.240m")) + if (!ass_strcasecmp(buffer, "pc.240m")) return YCBCR_SMPTE240M_PC; - if (!strcasecmp(buffer, "tv.fcc")) + if (!ass_strcasecmp(buffer, "tv.fcc")) return YCBCR_FCC_TV; - if (!strcasecmp(buffer, "pc.fcc")) + if (!ass_strcasecmp(buffer, "pc.fcc")) return YCBCR_FCC_PC; return YCBCR_UNKNOWN; } -void ass_msg(ASS_Library *priv, int lvl, char *fmt, ...) +void ass_msg(ASS_Library *priv, int lvl, const char *fmt, ...) { va_list va; va_start(va, fmt); @@ -264,6 +334,28 @@ va_end(va); } +/** + * Return a string with spaces trimmed at start and end. + * \param str input string + * \return output string, can be released with free() + */ +char *strdup_trimmed(const char *str) +{ + int left = 0; + int right = strlen(str) - 1; + char *out = NULL; + + while (ass_isspace(str[left])) left++; + while (right > left && ass_isspace(str[right])) right--; + + out = calloc(1, right-left+2); + + if (out) + memcpy(out, str + left, right-left+1); + + return out; +} + unsigned ass_utf8_get_char(char **str) { uint8_t *strp = (uint8_t *) * str; @@ -327,6 +419,64 @@ } /** + * \brief Parse UTF-16 and return the code point of the sequence starting at src. + * \param src pointer to a pointer to the start of the UTF-16 data + * (will be set to the start of the next code point) + * \return the code point + */ +static uint32_t ass_read_utf16be(uint8_t **src, size_t bytes) +{ + if (bytes < 2) + goto too_short; + + uint32_t cp = ((*src)[0] << 8) | (*src)[1]; + *src += 2; + bytes -= 2; + + if (cp >= 0xD800 && cp <= 0xDBFF) { + if (bytes < 2) + goto too_short; + + uint32_t cp2 = ((*src)[0] << 8) | (*src)[1]; + + if (cp2 < 0xDC00 || cp2 > 0xDFFF) + return 0xFFFD; + + *src += 2; + + cp = 0x10000 + ((cp - 0xD800) << 10) + (cp2 - 0xDC00); + } + + if (cp >= 0xDC00 && cp <= 0xDFFF) + return 0xFFFD; + + return cp; + +too_short: + *src += bytes; + return 0xFFFD; +} + +void ass_utf16be_to_utf8(char *dst, size_t dst_size, uint8_t *src, size_t src_size) +{ + uint8_t *end = src + src_size; + + if (!dst_size) + return; + + while (src < end) { + uint32_t cp = ass_read_utf16be(&src, end - src); + if (dst_size < 5) + break; + unsigned s = ass_utf8_put_char(dst, cp); + dst += s; + dst_size -= s; + } + + *dst = '\0'; +} + +/** * \brief find style by name * \param track track * \param name style name @@ -343,7 +493,7 @@ ++name; // VSFilter then normalizes the case of "Default" // (only in contexts where this function is called) - if (strcasecmp(name, "Default") == 0) + if (ass_strcasecmp(name, "Default") == 0) name = "Default"; for (i = track->n_styles - 1; i >= 0; --i) { if (strcmp(track->styles[i].Name, name) == 0) @@ -378,47 +528,3 @@ return NULL; } -#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 -Nru libass-0.12.2/libass/ass_utils.h libass-0.13.0/libass/ass_utils.h --- libass-0.12.2/libass/ass_utils.h 2015-03-15 21:38:00.000000000 +0000 +++ libass-0.13.0/libass/ass_utils.h 2015-09-24 08:34:34.000000000 +0000 @@ -28,12 +28,6 @@ #include #include -#include "config.h" - -#ifdef CONFIG_ENCA -#include -#endif - #include "ass.h" #ifndef SIZE_MAX @@ -85,21 +79,21 @@ void rskip_spaces(char **str, char *limit); 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); -uint32_t string2color(ASS_Library *library, char *p, int hex); +int mystrtoi32(char **p, int base, int32_t *res); +int32_t parse_alpha_tag(char *str); +uint32_t parse_color_tag(char *str); +uint32_t parse_color_header(char *str); +char *trim_space(char *str); +char *strdup_trimmed(const char *str); char parse_bool(char *str); int parse_ycbcr_matrix(char *str); unsigned ass_utf8_get_char(char **str); unsigned ass_utf8_put_char(char *dest, uint32_t ch); -void ass_msg(ASS_Library *priv, int lvl, char *fmt, ...); +void ass_utf16be_to_utf8(char *dst, size_t dst_size, uint8_t *src, size_t src_size); +void ass_msg(ASS_Library *priv, int lvl, const char *fmt, ...); int lookup_style(ASS_Track *track, char *name); ASS_Style *lookup_style_strict(ASS_Track *track, char *name, size_t len); -#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); @@ -111,6 +105,16 @@ return (s + (alignment - 1)) & ~(alignment - 1); } +static inline uint32_t ass_bswap32(uint32_t x) +{ +#ifdef _MSC_VER + return _byteswap_ulong(x); +#else + return (x & 0x000000FF) << 24 | (x & 0x0000FF00) << 8 | + (x & 0x00FF0000) >> 8 | (x & 0xFF000000) >> 24; +#endif +} + static inline int d6_to_int(int x) { return (x + 32) >> 6; @@ -160,7 +164,7 @@ return (int) (x * 0x400000); } -// Calculate cache key for a rotational angle in degrees +// Calculate cache key for a rotational angle in radians static inline int rot_key(double a) { return double_to_d22(remainder(a, 2 * M_PI)); @@ -171,7 +175,7 @@ static inline unsigned fnv_32a_buf(void *buf, size_t len, unsigned hval) { - unsigned char *bp = buf; + unsigned char *bp = (unsigned char*)buf; size_t n = (len + 3) / 4; switch (len % 4) { diff -Nru libass-0.12.2/libass/dwrite_c.h libass-0.13.0/libass/dwrite_c.h --- libass-0.12.2/libass/dwrite_c.h 1970-01-01 00:00:00.000000000 +0000 +++ libass-0.13.0/libass/dwrite_c.h 2015-09-20 16:34:39.000000000 +0000 @@ -0,0 +1,673 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ +/** + * Stripped version. Only definitions needed by libass. Contains fixes to + * make it compile with C. Also needed on MSVC. + */ +#ifndef __INC_DWRITE__ +#define __INC_DWRITE__ + +#define DWRITEAPI DECLSPEC_IMPORT + +#include + +typedef struct IDWriteFactory IDWriteFactory; +typedef struct IDWriteFont IDWriteFont; +typedef struct IDWriteFontCollection IDWriteFontCollection; +typedef struct IDWriteFontFace IDWriteFontFace; +typedef struct IDWriteFontFamily IDWriteFontFamily; +typedef struct IDWriteFontList IDWriteFontList; +typedef struct IDWriteFontFile IDWriteFontFile; +typedef struct IDWriteFontFileLoader IDWriteFontFileLoader; +typedef struct IDWriteFontFileStream IDWriteFontFileStream; +typedef struct IDWriteInlineObject IDWriteInlineObject; +typedef struct IDWriteLocalizedStrings IDWriteLocalizedStrings; +typedef struct IDWritePixelSnapping IDWritePixelSnapping; +typedef struct IDWriteTextFormat IDWriteTextFormat; +typedef struct IDWriteTextLayout IDWriteTextLayout; +typedef struct IDWriteTextRenderer IDWriteTextRenderer; + +#include + +typedef enum DWRITE_INFORMATIONAL_STRING_ID { + DWRITE_INFORMATIONAL_STRING_NONE = 0, + DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE, + DWRITE_INFORMATIONAL_STRING_VERSION_STRINGS, + DWRITE_INFORMATIONAL_STRING_TRADEMARK, + DWRITE_INFORMATIONAL_STRING_MANUFACTURER, + DWRITE_INFORMATIONAL_STRING_DESIGNER, + DWRITE_INFORMATIONAL_STRING_DESIGNER_URL, + DWRITE_INFORMATIONAL_STRING_DESCRIPTION, + DWRITE_INFORMATIONAL_STRING_FONT_VENDOR_URL, + DWRITE_INFORMATIONAL_STRING_LICENSE_DESCRIPTION, + DWRITE_INFORMATIONAL_STRING_LICENSE_INFO_URL, + DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, + DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES, + DWRITE_INFORMATIONAL_STRING_PREFERRED_FAMILY_NAMES, + DWRITE_INFORMATIONAL_STRING_PREFERRED_SUBFAMILY_NAMES, + DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT, + DWRITE_INFORMATIONAL_STRING_FULL_NAME, + DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, + DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME +} DWRITE_INFORMATIONAL_STRING_ID; + +typedef enum DWRITE_FACTORY_TYPE { + DWRITE_FACTORY_TYPE_SHARED = 0, + DWRITE_FACTORY_TYPE_ISOLATED +} DWRITE_FACTORY_TYPE; + + +typedef enum DWRITE_FONT_SIMULATIONS { + DWRITE_FONT_SIMULATIONS_NONE = 0x0000, + DWRITE_FONT_SIMULATIONS_BOLD = 0x0001, + DWRITE_FONT_SIMULATIONS_OBLIQUE = 0x0002 +} DWRITE_FONT_SIMULATIONS; + +typedef enum DWRITE_FONT_STRETCH { + DWRITE_FONT_STRETCH_UNDEFINED = 0, + DWRITE_FONT_STRETCH_ULTRA_CONDENSED = 1, + DWRITE_FONT_STRETCH_EXTRA_CONDENSED = 2, + DWRITE_FONT_STRETCH_CONDENSED = 3, + DWRITE_FONT_STRETCH_SEMI_CONDENSED = 4, + DWRITE_FONT_STRETCH_NORMAL = 5, + DWRITE_FONT_STRETCH_MEDIUM = 5, + DWRITE_FONT_STRETCH_SEMI_EXPANDED = 6, + DWRITE_FONT_STRETCH_EXPANDED = 7, + DWRITE_FONT_STRETCH_EXTRA_EXPANDED = 8, + DWRITE_FONT_STRETCH_ULTRA_EXPANDED = 9 +} DWRITE_FONT_STRETCH; + +typedef enum DWRITE_FONT_STYLE { + DWRITE_FONT_STYLE_NORMAL = 0, + DWRITE_FONT_STYLE_OBLIQUE, + DWRITE_FONT_STYLE_ITALIC +} DWRITE_FONT_STYLE; + +typedef enum DWRITE_FONT_WEIGHT { + DWRITE_FONT_WEIGHT_MEDIUM = 500, + /* rest dropped */ +} DWRITE_FONT_WEIGHT; + +typedef struct DWRITE_FONT_METRICS { + UINT16 designUnitsPerEm; + UINT16 ascent; + UINT16 descent; + INT16 lineGap; + UINT16 capHeight; + UINT16 xHeight; + INT16 underlinePosition; + UINT16 underlineThickness; + INT16 strikethroughPosition; + UINT16 strikethroughThickness; +} DWRITE_FONT_METRICS; + +typedef struct DWRITE_GLYPH_OFFSET DWRITE_GLYPH_OFFSET; + +typedef struct DWRITE_GLYPH_RUN { + IDWriteFontFace *fontFace; + FLOAT fontEmSize; + UINT32 glyphCount; + const UINT16 *glyphIndices; + const FLOAT *glyphAdvances; + const DWRITE_GLYPH_OFFSET *glyphOffsets; + BOOL isSideways; + UINT32 bidiLevel; +} DWRITE_GLYPH_RUN; + +typedef struct DWRITE_GLYPH_RUN_DESCRIPTION DWRITE_GLYPH_RUN_DESCRIPTION; +typedef struct DWRITE_HIT_TEST_METRICS DWRITE_HIT_TEST_METRICS; +typedef struct DWRITE_LINE_METRICS DWRITE_LINE_METRICS; +typedef struct DWRITE_MATRIX DWRITE_MATRIX; +typedef struct DWRITE_STRIKETHROUGH DWRITE_STRIKETHROUGH; +typedef struct DWRITE_TEXT_METRICS DWRITE_TEXT_METRICS; + +typedef struct DWRITE_TEXT_RANGE { + UINT32 startPosition; + UINT32 length; +} DWRITE_TEXT_RANGE; + +typedef struct DWRITE_TRIMMING DWRITE_TRIMMING; +typedef struct DWRITE_UNDERLINE DWRITE_UNDERLINE; + +#ifndef __MINGW_DEF_ARG_VAL +#ifdef __cplusplus +#define __MINGW_DEF_ARG_VAL(x) = x +#else +#define __MINGW_DEF_ARG_VAL(x) +#endif +#endif + +#undef INTERFACE +#define INTERFACE IDWriteFactory +DECLARE_INTERFACE_(IDWriteFactory,IUnknown) +{ + BEGIN_INTERFACE + +#ifndef __cplusplus + /* IUnknown methods */ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; +#endif + + /* IDWriteFactory methods */ + STDMETHOD(GetSystemFontCollection)(THIS_ + IDWriteFontCollection **fontCollection, + BOOL checkForUpdates __MINGW_DEF_ARG_VAL(FALSE)) PURE; + + STDMETHOD(dummy1)(THIS); + STDMETHOD(dummy2)(THIS); + STDMETHOD(dummy3)(THIS); + STDMETHOD(dummy4)(THIS); + STDMETHOD(dummy5)(THIS); + STDMETHOD(dummy6)(THIS); + STDMETHOD(dummy7)(THIS); + STDMETHOD(dummy8)(THIS); + STDMETHOD(dummy9)(THIS); + STDMETHOD(dummy10)(THIS); + STDMETHOD(dummy11)(THIS); + + STDMETHOD(CreateTextFormat)(THIS_ + WCHAR const *fontFamilyName, + IDWriteFontCollection *fontCollection, + DWRITE_FONT_WEIGHT fontWeight, + DWRITE_FONT_STYLE fontStyle, + DWRITE_FONT_STRETCH fontStretch, + FLOAT fontSize, + WCHAR const *localeName, + IDWriteTextFormat **textFormat) PURE; + + STDMETHOD(dummy12)(THIS); + STDMETHOD(dummy13)(THIS); + + STDMETHOD(CreateTextLayout)(THIS_ + WCHAR const *string, + UINT32 stringLength, + IDWriteTextFormat *textFormat, + FLOAT maxWidth, + FLOAT maxHeight, + IDWriteTextLayout **textLayout) PURE; + + /* remainder dropped */ + END_INTERFACE +}; +#ifdef COBJMACROS +#define IDWriteFactory_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFactory_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFactory_Release(This) (This)->lpVtbl->Release(This) +#define IDWriteFactory_GetSystemFontCollection(This,fontCollection,checkForUpdates) (This)->lpVtbl->GetSystemFontCollection(This,fontCollection,checkForUpdates) +#define IDWriteFactory_CreateTextFormat(This,fontFamilyName,fontCollection,fontWeight,fontStyle,fontStretch,fontSize,localeName,textFormat) (This)->lpVtbl->CreateTextFormat(This,fontFamilyName,fontCollection,fontWeight,fontStyle,fontStretch,fontSize,localeName,textFormat) +#define IDWriteFactory_CreateTextLayout(This,string,stringLength,textFormat,maxWidth,maxHeight,textLayout) (This)->lpVtbl->CreateTextLayout(This,string,stringLength,textFormat,maxWidth,maxHeight,textLayout) +#endif /*COBJMACROS*/ + +#undef INTERFACE +#define INTERFACE IDWriteFont +DECLARE_INTERFACE_(IDWriteFont,IUnknown) +{ + BEGIN_INTERFACE + +#ifndef __cplusplus + /* IUnknown methods */ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; +#endif + + /* IDWriteFont methods */ + STDMETHOD(GetFontFamily)(THIS_ + IDWriteFontFamily **fontFamily) PURE; + + STDMETHOD_(DWRITE_FONT_WEIGHT, GetWeight)(THIS) PURE; + STDMETHOD_(DWRITE_FONT_STRETCH, GetStretch)(THIS) PURE; + STDMETHOD_(DWRITE_FONT_STYLE, GetStyle)(THIS) PURE; + STDMETHOD_(BOOL, IsSymbolFont)(THIS) PURE; + + STDMETHOD(GetFaceNames)(THIS_ + IDWriteLocalizedStrings **names) PURE; + + STDMETHOD(GetInformationalStrings)(THIS_ + DWRITE_INFORMATIONAL_STRING_ID informationalStringID, + IDWriteLocalizedStrings **informationalStrings, + BOOL *exists) PURE; + + STDMETHOD_(DWRITE_FONT_SIMULATIONS, GetSimulations)(THIS) PURE; + + STDMETHOD_(void, GetMetrics)(THIS_ + DWRITE_FONT_METRICS *fontMetrics) PURE; + + STDMETHOD(HasCharacter)(THIS_ + UINT32 unicodeValue, + BOOL *exists) PURE; + + STDMETHOD(CreateFontFace)(THIS_ + IDWriteFontFace **fontFace) PURE; + + END_INTERFACE +}; +#ifdef COBJMACROS +#define IDWriteFont_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFont_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFont_Release(This) (This)->lpVtbl->Release(This) +#define IDWriteFont_CreateFontFace(This,fontFace) (This)->lpVtbl->CreateFontFace(This,fontFace) +#define IDWriteFont_GetFaceNames(This,names) (This)->lpVtbl->GetFaceNames(This,names) +#define IDWriteFont_GetFontFamily(This,fontFamily) (This)->lpVtbl->GetFontFamily(This,fontFamily) +#define IDWriteFont_GetInformationalStrings(This,informationalStringID,informationalStrings,exists) (This)->lpVtbl->GetInformationalStrings(This,informationalStringID,informationalStrings,exists) +#define IDWriteFont_GetMetrics(This,fontMetrics) (This)->lpVtbl->GetMetrics(This,fontMetrics) +#define IDWriteFont_GetSimulations(This) (This)->lpVtbl->GetSimulations(This) +#define IDWriteFont_GetStretch(This) (This)->lpVtbl->GetStretch(This) +#define IDWriteFont_GetStyle(This) (This)->lpVtbl->GetStyle(This) +#define IDWriteFont_GetWeight(This) (This)->lpVtbl->GetWeight(This) +#define IDWriteFont_HasCharacter(This,unicodeValue,exists) (This)->lpVtbl->HasCharacter(This,unicodeValue,exists) +#define IDWriteFont_IsSymbolFont(This) (This)->lpVtbl->IsSymbolFont(This) +#endif /*COBJMACROS*/ + +#undef INTERFACE +#define INTERFACE IDWriteFontCollection +DECLARE_INTERFACE_(IDWriteFontCollection,IUnknown) +{ + BEGIN_INTERFACE + +#ifndef __cplusplus + /* IUnknown methods */ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; +#endif + + /* IDWriteFontCollection methods */ + STDMETHOD_(UINT32, GetFontFamilyCount)(THIS) PURE; + + STDMETHOD(GetFontFamily)(THIS_ + UINT32 index, + IDWriteFontFamily **fontFamily) PURE; + + STDMETHOD(FindFamilyName)(THIS_ + WCHAR const *familyName, + UINT32 *index, + BOOL *exists) PURE; + + STDMETHOD(GetFontFromFontFace)(THIS_ + IDWriteFontFace* fontFace, + IDWriteFont **font) PURE; + + END_INTERFACE +}; +#ifdef COBJMACROS +#define IDWriteFontCollection_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontCollection_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontCollection_Release(This) (This)->lpVtbl->Release(This) +#define IDWriteFontCollection_FindFamilyName(This,familyName,index,exists) (This)->lpVtbl->FindFamilyName(This,familyName,index,exists) +#define IDWriteFontCollection_GetFontFamily(This,index,fontFamily) (This)->lpVtbl->GetFontFamily(This,index,fontFamily) +#define IDWriteFontCollection_GetFontFamilyCount(This) (This)->lpVtbl->GetFontFamilyCount(This) +#define IDWriteFontCollection_GetFontFromFontFace(This,fontFace,font) (This)->lpVtbl->GetFontFromFontFace(This,fontFace,font) +#endif /*COBJMACROS*/ + +#undef INTERFACE +#define INTERFACE IDWriteFontFace +DECLARE_INTERFACE_(IDWriteFontFace,IUnknown) +{ + BEGIN_INTERFACE + +#ifndef __cplusplus + /* IUnknown methods */ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; +#endif + + /* IDWriteFontFace methods */ + STDMETHOD(dummy1)(THIS); + + STDMETHOD(GetFiles)(THIS_ + UINT32 *numberOfFiles, + IDWriteFontFile **fontFiles) PURE; + + /* rest dropped */ + END_INTERFACE +}; +#ifdef COBJMACROS +#define IDWriteFontFace_Release(This) (This)->lpVtbl->Release(This) +#define IDWriteFontFace_GetFiles(This,fontFiles,b) (This)->lpVtbl->GetFiles(This,fontFiles,b) +#endif /*COBJMACROS*/ + +#undef INTERFACE +#define INTERFACE IDWriteFontFamily +DECLARE_INTERFACE_(IDWriteFontFamily,IDWriteFontList) +{ + BEGIN_INTERFACE + +#ifndef __cplusplus + /* IUnknown methods */ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + /* IDWriteFontList methods */ + STDMETHOD(GetFontCollection)(THIS_ + IDWriteFontCollection** fontCollection) PURE; + + STDMETHOD_(UINT32, GetFontCount)(THIS) PURE; + + STDMETHOD(GetFont)(THIS_ + UINT32 index, + IDWriteFont **font) PURE; +#endif + + /* IDWriteFontFamily methods */ + STDMETHOD(GetFamilyNames)(THIS_ + IDWriteLocalizedStrings **names) PURE; + + /* rest dropped */ + END_INTERFACE +}; +#ifdef COBJMACROS +#define IDWriteFontFamily_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontFamily_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontFamily_Release(This) (This)->lpVtbl->Release(This) +#define IDWriteFontFamily_GetFont(This,index,font) (This)->lpVtbl->GetFont(This,index,font) +#define IDWriteFontFamily_GetFontCount(This) (This)->lpVtbl->GetFontCount(This) +#define IDWriteFontFamily_GetFamilyNames(This,names) (This)->lpVtbl->GetFamilyNames(This,names) +#endif /*COBJMACROS*/ + +#undef INTERFACE +#define INTERFACE IDWriteFontFile +DECLARE_INTERFACE_(IDWriteFontFile,IUnknown) +{ + BEGIN_INTERFACE + +#ifndef __cplusplus + /* IUnknown methods */ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; +#endif + + /* IDWriteFontFile methods */ + STDMETHOD(GetReferenceKey)(THIS_ + void const **fontFileReferenceKey, + UINT32 *fontFileReferenceKeySize) PURE; + + STDMETHOD(GetLoader)(THIS_ + IDWriteFontFileLoader **fontFileLoader) PURE; + + /* rest dropped */ + END_INTERFACE +}; +#ifdef COBJMACROS +#define IDWriteFontFile_Release(This) (This)->lpVtbl->Release(This) +#define IDWriteFontFile_GetLoader(This,fontFileLoader) (This)->lpVtbl->GetLoader(This,fontFileLoader) +#define IDWriteFontFile_GetReferenceKey(This,fontFileReferenceKey,fontFileReferenceKeySize) (This)->lpVtbl->GetReferenceKey(This,fontFileReferenceKey,fontFileReferenceKeySize) +#endif /*COBJMACROS*/ + +#undef INTERFACE +#define INTERFACE IDWriteFontFileLoader +DECLARE_INTERFACE_(IDWriteFontFileLoader,IUnknown) +{ + BEGIN_INTERFACE + +#ifndef __cplusplus + /* IUnknown methods */ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; +#endif + + /* IDWriteFontFileLoader methods */ + STDMETHOD(CreateStreamFromKey)(THIS_ + void const *fontFileReferenceKey, + UINT32 fontFileReferenceKeySize, + IDWriteFontFileStream **fontFileStream) PURE; + + END_INTERFACE +}; +#ifdef COBJMACROS +#define IDWriteFontFileLoader_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontFileLoader_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontFileLoader_Release(This) (This)->lpVtbl->Release(This) +#define IDWriteFontFileLoader_CreateStreamFromKey(This,fontFileReferenceKey,fontFileReferenceKeySize,fontFileStream) (This)->lpVtbl->CreateStreamFromKey(This,fontFileReferenceKey,fontFileReferenceKeySize,fontFileStream) +#endif /*COBJMACROS*/ + +#undef INTERFACE +#define INTERFACE IDWriteFontFileStream +DECLARE_INTERFACE_(IDWriteFontFileStream,IUnknown) +{ + BEGIN_INTERFACE + +#ifndef __cplusplus + /* IUnknown methods */ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; +#endif + + /* IDWriteFontFileStream methods */ + STDMETHOD(ReadFileFragment)(THIS_ + void const **fragmentStart, + UINT64 fileOffset, + UINT64 fragmentSize, + void** fragmentContext) PURE; + + STDMETHOD_(void, ReleaseFileFragment)(THIS_ + void *fragmentContext) PURE; + + STDMETHOD(GetFileSize)(THIS_ + UINT64 *fileSize) PURE; + + STDMETHOD(GetLastWriteTime)(THIS_ + UINT64 *lastWriteTime) PURE; + + END_INTERFACE +}; +#ifdef COBJMACROS +#define IDWriteFontFileStream_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontFileStream_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontFileStream_Release(This) (This)->lpVtbl->Release(This) +#define IDWriteFontFileStream_GetFileSize(This,fileSize) (This)->lpVtbl->GetFileSize(This,fileSize) +#define IDWriteFontFileStream_ReadFileFragment(This,fragmentStart,fileOffset,fragmentSize,fragmentContext) (This)->lpVtbl->ReadFileFragment(This,fragmentStart,fileOffset,fragmentSize,fragmentContext) +#define IDWriteFontFileStream_ReleaseFileFragment(This,fragmentContext) (This)->lpVtbl->ReleaseFileFragment(This,fragmentContext) +#endif /*COBJMACROS*/ + +#undef INTERFACE +#define INTERFACE IDWriteLocalizedStrings +DECLARE_INTERFACE_(IDWriteLocalizedStrings,IUnknown) +{ + BEGIN_INTERFACE + +#ifndef __cplusplus + /* IUnknown methods */ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; +#endif + + /* IDWriteLocalizedStrings methods */ + STDMETHOD_(UINT32, GetCount)(THIS) PURE; + + STDMETHOD(dummy1)(THIS); + STDMETHOD(dummy2)(THIS); + STDMETHOD(dummy3)(THIS); + STDMETHOD(dummy4)(THIS); + + STDMETHOD(GetString)(THIS_ + UINT32 index, + WCHAR *stringBuffer, + UINT32 size) PURE; + + END_INTERFACE +}; +#ifdef COBJMACROS +#define IDWriteLocalizedStrings_Release(This) (This)->lpVtbl->Release(This) +#define IDWriteLocalizedStrings_GetCount(This) (This)->lpVtbl->GetCount(This) +#define IDWriteLocalizedStrings_GetString(This,index,stringBuffer,size) (This)->lpVtbl->GetString(This,index,stringBuffer,size) +#endif /*COBJMACROS*/ + +#undef INTERFACE +#define INTERFACE IDWriteTextFormat +DECLARE_INTERFACE_(IDWriteTextFormat,IUnknown) +{ + BEGIN_INTERFACE + +#ifndef __cplusplus + /* IUnknown methods */ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; +#endif + + /* IDWriteTextFormat methods */ + /* rest dropped */ + END_INTERFACE +}; +#ifdef COBJMACROS +#define IDWriteTextFormat_Release(This) (This)->lpVtbl->Release(This) +#endif /*COBJMACROS*/ + +#undef INTERFACE +#define INTERFACE IDWriteTextLayout +DECLARE_INTERFACE_(IDWriteTextLayout,IDWriteTextFormat) +{ + BEGIN_INTERFACE + +#ifndef __cplusplus + /* IUnknown methods */ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + /* IDWriteTextFormat methods */ + STDMETHOD(dummy1)(THIS); + STDMETHOD(dummy2)(THIS); + STDMETHOD(dummy3)(THIS); + STDMETHOD(dummy4)(THIS); + STDMETHOD(dummy5)(THIS); + STDMETHOD(dummy6)(THIS); + STDMETHOD(dummy7)(THIS); + STDMETHOD(dummy8)(THIS); + STDMETHOD(dummy9)(THIS); + STDMETHOD(dummy10)(THIS); + STDMETHOD(dummy11)(THIS); + STDMETHOD(dummy12)(THIS); + STDMETHOD(dummy13)(THIS); + STDMETHOD(dummy14)(THIS); + STDMETHOD(dummy15)(THIS); + STDMETHOD(dummy16)(THIS); + STDMETHOD(dummy17)(THIS); + STDMETHOD(dummy18)(THIS); + STDMETHOD(dummy19)(THIS); + STDMETHOD(dummy20)(THIS); + STDMETHOD(dummy21)(THIS); + STDMETHOD(dummy22)(THIS); + STDMETHOD(dummy23)(THIS); + STDMETHOD(dummy24)(THIS); + STDMETHOD(dummy25)(THIS); +#endif + + /* IDWriteTextLayout methods */ + STDMETHOD(dummy26)(THIS); + STDMETHOD(dummy27)(THIS); + STDMETHOD(dummy28)(THIS); + STDMETHOD(dummy29)(THIS); + STDMETHOD(dummy30)(THIS); + STDMETHOD(dummy31)(THIS); + STDMETHOD(dummy32)(THIS); + STDMETHOD(dummy33)(THIS); + STDMETHOD(dummy34)(THIS); + STDMETHOD(dummy35)(THIS); + STDMETHOD(dummy36)(THIS); + STDMETHOD(dummy37)(THIS); + STDMETHOD(dummy38)(THIS); + STDMETHOD(dummy39)(THIS); + STDMETHOD(dummy40)(THIS); + STDMETHOD(dummy41)(THIS); + STDMETHOD(dummy42)(THIS); + STDMETHOD(dummy43)(THIS); + STDMETHOD(dummy44)(THIS); + STDMETHOD(dummy45)(THIS); + STDMETHOD(dummy46)(THIS); + STDMETHOD(dummy47)(THIS); + STDMETHOD(dummy48)(THIS); + STDMETHOD(dummy49)(THIS); + STDMETHOD(dummy50)(THIS); + STDMETHOD(dummy51)(THIS); + STDMETHOD(dummy52)(THIS); + STDMETHOD(dummy53)(THIS); + STDMETHOD(dummy54)(THIS); + STDMETHOD(dummy55)(THIS); + STDMETHOD(Draw)(THIS_ + void *clientDrawingContext, + IDWriteTextRenderer *renderer, + FLOAT originX, + FLOAT originY) PURE; + /* rest dropped */ + END_INTERFACE +}; +#ifdef COBJMACROS +#define IDWriteTextLayout_Release(This) (This)->lpVtbl->Release(This) +#define IDWriteTextLayout_Draw(This,clientDrawingContext,renderer,originX,originY) (This)->lpVtbl->Draw(This,clientDrawingContext,renderer,originX,originY) +#endif /*COBJMACROS*/ + +#undef INTERFACE +#define INTERFACE IDWriteTextRenderer +DECLARE_INTERFACE_(IDWriteTextRenderer,IDWritePixelSnapping) +{ + BEGIN_INTERFACE + +#ifndef __cplusplus + /* IUnknown methods */ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + /* IDWritePixelSnapping methods */ + STDMETHOD(IsPixelSnappingDisabled)(THIS_ + void *clientDrawingContext, + BOOL *isDisabled) PURE; + STDMETHOD(GetCurrentTransform)(THIS_ + void *clientDrawingContext, + DWRITE_MATRIX *transform) PURE; + STDMETHOD(GetPixelsPerDip)(THIS_ + void *clientDrawingContext, + FLOAT *pixelsPerDip) PURE; +#endif + + /* IDWriteTextRenderer methods */ + STDMETHOD(DrawGlyphRun)(THIS_ + void *clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + DWRITE_MEASURING_MODE measuringMode, + DWRITE_GLYPH_RUN const *glyphRun, + DWRITE_GLYPH_RUN_DESCRIPTION const *glyphRunDescription, + IUnknown* clientDrawingEffect) PURE; + STDMETHOD(DrawUnderline)(THIS_ + void *clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + DWRITE_UNDERLINE const *underline, + IUnknown *clientDrawingEffect) PURE; + STDMETHOD(DrawStrikethrough)(THIS_ + void *clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + DWRITE_STRIKETHROUGH const *strikethrough, + IUnknown* clientDrawingEffect) PURE; + STDMETHOD(DrawInlineObject)(THIS_ + void *clientDrawingContext, + FLOAT originX, + FLOAT originY, + IDWriteInlineObject *inlineObject, + BOOL isSideways, + BOOL isRightToLeft, + IUnknown *clientDrawingEffect) PURE; + + END_INTERFACE +}; + +DEFINE_GUID(IID_IDWriteFactory, 0xb859ee5a,0xd838,0x4b5b,0xa2,0xe8,0x1a,0xdc,0x7d,0x93,0xdb,0x48); +DEFINE_GUID(IID_IDWritePixelSnapping, 0xeaf3a2da,0xecf4,0x4d24,0xb6,0x44,0xb3,0x4f,0x68,0x42,0x02,0x4b); +DEFINE_GUID(IID_IDWriteTextRenderer, 0xef8a8135,0x5cc6,0x45fe,0x88,0x25,0xc5,0xa0,0x72,0x4e,0xb8,0x19); + +#endif /* __INC_DWRITE__ */ diff -Nru libass-0.12.2/libass/libass.sym libass-0.13.0/libass/libass.sym --- libass-0.12.2/libass/libass.sym 2014-08-14 02:11:03.000000000 +0000 +++ libass-0.13.0/libass/libass.sym 2015-09-07 09:44:16.000000000 +0000 @@ -14,6 +14,7 @@ ass_set_font_scale ass_set_hinting ass_set_line_spacing +ass_get_available_font_providers ass_set_fonts ass_render_frame ass_new_track diff -Nru libass-0.12.2/libass/Makefile.am libass-0.13.0/libass/Makefile.am --- libass-0.12.2/libass/Makefile.am 2015-05-07 18:57:49.000000000 +0000 +++ libass-0.13.0/libass/Makefile.am 2015-10-03 18:18:46.000000000 +0000 @@ -2,35 +2,48 @@ -Werror-implicit-function-declaration -Wstrict-prototypes \ -Wpointer-arith -Wredundant-decls -D_GNU_SOURCE -LIBASS_LT_CURRENT = 6 -LIBASS_LT_REVISION = 1 -LIBASS_LT_AGE = 1 +LIBASS_LT_CURRENT = 7 +LIBASS_LT_REVISION = 0 +LIBASS_LT_AGE = 2 yasm_verbose = $(yasm_verbose_$(V)) yasm_verbose_ = $(yasm_verbose_$(AM_DEFAULT_VERBOSITY)) yasm_verbose_0 = @echo " YASM " $@; .asm.lo: - $(yasm_verbose)$(LIBTOOL) $(AM_V_lt) --mode=compile $(AS) $(ASFLAGS) -o $@ $< -prefer-non-pic + $(yasm_verbose)$(LIBTOOL) $(AM_V_lt) --tag=CC --mode=compile $(AS) $(ASFLAGS) -o $@ $< -prefer-non-pic -SRC_INTEL = x86/blend_bitmaps.asm x86/cpuid.asm x86/blend_bitmaps.h x86/cpuid.h -SRC_INTEL64 = x86/be_blur.asm x86/be_blur.h -SRC_INTEL_RASTERIZER = x86/rasterizer.asm x86/rasterizer.h +SRC_INTEL = x86/blend_bitmaps.asm x86/blur.asm x86/cpuid.asm x86/utils.asm \ + x86/cpuid.h +SRC_INTEL64 = x86/be_blur.asm +SRC_INTEL_RASTERIZER = x86/rasterizer.asm SRC_RASTERIZER = ass_rasterizer.h ass_rasterizer.c ass_rasterizer_c.c +SRC_DIRECTWRITE = ass_directwrite.c ass_directwrite.h dwrite_c.h +SRC_CORETEXT = ass_coretext.c ass_coretext.h + 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 \ +libass_la_SOURCES = ass.c ass_cache.c ass_font.c ass_fontselect.c ass_render.c \ + ass_utils.c ass_bitmap.c ass_blur.c ass_library.c ass_bitmap.h \ + ass_cache.h ass_fontselect.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 + ass_shaper.h ass_strtod.c ass_fontconfig.c ass_fontconfig.h \ + ass_string.h ass_string.c ass_compat.h ass_func_template.h libass_la_LDFLAGS = -no-undefined -version-info $(LIBASS_LT_CURRENT):$(LIBASS_LT_REVISION):$(LIBASS_LT_AGE) libass_la_LDFLAGS += -export-symbols $(srcdir)/libass.sym +if DIRECTWRITE +libass_la_SOURCES += $(SRC_DIRECTWRITE) +endif + +if CORETEXT +libass_la_SOURCES += $(SRC_CORETEXT) +endif + if RASTERIZER libass_la_SOURCES += $(SRC_RASTERIZER) endif diff -Nru libass-0.12.2/libass/Makefile.in libass-0.13.0/libass/Makefile.in --- libass-0.12.2/libass/Makefile.in 2015-05-07 19:47:27.000000000 +0000 +++ libass-0.13.0/libass/Makefile.in 2015-10-03 18:20:38.000000000 +0000 @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -16,7 +16,17 @@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -79,13 +89,13 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -@RASTERIZER_TRUE@am__append_1 = $(SRC_RASTERIZER) -@ASM_TRUE@@INTEL_TRUE@am__append_2 = $(SRC_INTEL) -@ASM_TRUE@@INTEL_TRUE@@RASTERIZER_TRUE@am__append_3 = $(SRC_INTEL_RASTERIZER) -@ASM_TRUE@@INTEL_TRUE@@X64_TRUE@am__append_4 = $(SRC_INTEL64) +@DIRECTWRITE_TRUE@am__append_1 = $(SRC_DIRECTWRITE) +@CORETEXT_TRUE@am__append_2 = $(SRC_CORETEXT) +@RASTERIZER_TRUE@am__append_3 = $(SRC_RASTERIZER) +@ASM_TRUE@@INTEL_TRUE@am__append_4 = $(SRC_INTEL) +@ASM_TRUE@@INTEL_TRUE@@RASTERIZER_TRUE@am__append_5 = $(SRC_INTEL_RASTERIZER) +@ASM_TRUE@@INTEL_TRUE@@X64_TRUE@am__append_6 = $(SRC_INTEL64) subdir = libass -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/depcomp $(dist_assheaders_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ @@ -93,6 +103,8 @@ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(dist_assheaders_HEADERS) \ + $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -128,30 +140,40 @@ LTLIBRARIES = $(lib_LTLIBRARIES) libass_la_LIBADD = am__libass_la_SOURCES_DIST = 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 ass_rasterizer.h ass_rasterizer.c \ - ass_rasterizer_c.c x86/blend_bitmaps.asm x86/cpuid.asm \ - x86/blend_bitmaps.h x86/cpuid.h x86/rasterizer.asm \ - x86/rasterizer.h x86/be_blur.asm x86/be_blur.h -am__objects_1 = ass_rasterizer.lo ass_rasterizer_c.lo -@RASTERIZER_TRUE@am__objects_2 = $(am__objects_1) + ass_fontselect.c ass_render.c ass_utils.c ass_bitmap.c \ + ass_blur.c ass_library.c ass_bitmap.h ass_cache.h \ + ass_fontselect.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 ass_fontconfig.c \ + ass_fontconfig.h ass_string.h ass_string.c ass_compat.h \ + ass_func_template.h ass_directwrite.c ass_directwrite.h \ + dwrite_c.h ass_coretext.c ass_coretext.h ass_rasterizer.h \ + ass_rasterizer.c ass_rasterizer_c.c x86/blend_bitmaps.asm \ + x86/blur.asm x86/cpuid.asm x86/utils.asm x86/cpuid.h \ + x86/rasterizer.asm x86/be_blur.asm +am__objects_1 = ass_directwrite.lo +@DIRECTWRITE_TRUE@am__objects_2 = $(am__objects_1) +am__objects_3 = ass_coretext.lo +@CORETEXT_TRUE@am__objects_4 = $(am__objects_3) +am__objects_5 = ass_rasterizer.lo ass_rasterizer_c.lo +@RASTERIZER_TRUE@am__objects_6 = $(am__objects_5) am__dirstamp = $(am__leading_dot)dirstamp -am__objects_3 = x86/blend_bitmaps.lo x86/cpuid.lo -@ASM_TRUE@@INTEL_TRUE@am__objects_4 = $(am__objects_3) -am__objects_5 = x86/rasterizer.lo -@ASM_TRUE@@INTEL_TRUE@@RASTERIZER_TRUE@am__objects_6 = \ -@ASM_TRUE@@INTEL_TRUE@@RASTERIZER_TRUE@ $(am__objects_5) -am__objects_7 = x86/be_blur.lo -@ASM_TRUE@@INTEL_TRUE@@X64_TRUE@am__objects_8 = $(am__objects_7) +am__objects_7 = x86/blend_bitmaps.lo x86/blur.lo x86/cpuid.lo \ + x86/utils.lo +@ASM_TRUE@@INTEL_TRUE@am__objects_8 = $(am__objects_7) +am__objects_9 = x86/rasterizer.lo +@ASM_TRUE@@INTEL_TRUE@@RASTERIZER_TRUE@am__objects_10 = \ +@ASM_TRUE@@INTEL_TRUE@@RASTERIZER_TRUE@ $(am__objects_9) +am__objects_11 = x86/be_blur.lo +@ASM_TRUE@@INTEL_TRUE@@X64_TRUE@am__objects_12 = $(am__objects_11) am_libass_la_OBJECTS = ass.lo ass_cache.lo ass_font.lo \ - ass_fontconfig.lo ass_render.lo ass_utils.lo ass_bitmap.lo \ - ass_library.lo ass_drawing.lo ass_parse.lo ass_render_api.lo \ - ass_shaper.lo ass_strtod.lo $(am__objects_2) $(am__objects_4) \ - $(am__objects_6) $(am__objects_8) + ass_fontselect.lo ass_render.lo ass_utils.lo ass_bitmap.lo \ + ass_blur.lo ass_library.lo ass_drawing.lo ass_parse.lo \ + ass_render_api.lo ass_shaper.lo ass_strtod.lo \ + ass_fontconfig.lo ass_string.lo $(am__objects_2) \ + $(am__objects_4) $(am__objects_6) $(am__objects_8) \ + $(am__objects_10) $(am__objects_12) libass_la_OBJECTS = $(am_libass_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -221,6 +243,7 @@ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ @@ -250,8 +273,6 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ -ENCA_CFLAGS = @ENCA_CFLAGS@ -ENCA_LIBS = @ENCA_LIBS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@ @@ -352,6 +373,7 @@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -365,25 +387,31 @@ -Werror-implicit-function-declaration -Wstrict-prototypes \ -Wpointer-arith -Wredundant-decls -D_GNU_SOURCE -LIBASS_LT_CURRENT = 6 -LIBASS_LT_REVISION = 1 -LIBASS_LT_AGE = 1 +LIBASS_LT_CURRENT = 7 +LIBASS_LT_REVISION = 0 +LIBASS_LT_AGE = 2 yasm_verbose = $(yasm_verbose_$(V)) yasm_verbose_ = $(yasm_verbose_$(AM_DEFAULT_VERBOSITY)) yasm_verbose_0 = @echo " YASM " $@; -SRC_INTEL = x86/blend_bitmaps.asm x86/cpuid.asm x86/blend_bitmaps.h x86/cpuid.h -SRC_INTEL64 = x86/be_blur.asm x86/be_blur.h -SRC_INTEL_RASTERIZER = x86/rasterizer.asm x86/rasterizer.h +SRC_INTEL = x86/blend_bitmaps.asm x86/blur.asm x86/cpuid.asm x86/utils.asm \ + x86/cpuid.h + +SRC_INTEL64 = x86/be_blur.asm +SRC_INTEL_RASTERIZER = x86/rasterizer.asm SRC_RASTERIZER = ass_rasterizer.h ass_rasterizer.c ass_rasterizer_c.c +SRC_DIRECTWRITE = ass_directwrite.c ass_directwrite.h dwrite_c.h +SRC_CORETEXT = ass_coretext.c ass_coretext.h 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 \ +libass_la_SOURCES = ass.c ass_cache.c ass_font.c ass_fontselect.c \ + ass_render.c ass_utils.c ass_bitmap.c ass_blur.c ass_library.c \ + ass_bitmap.h ass_cache.h ass_fontselect.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 $(am__append_1) $(am__append_2) $(am__append_3) \ - $(am__append_4) + ass_strtod.c ass_fontconfig.c ass_fontconfig.h ass_string.h \ + ass_string.c ass_compat.h ass_func_template.h $(am__append_1) \ + $(am__append_2) $(am__append_3) $(am__append_4) \ + $(am__append_5) $(am__append_6) libass_la_LDFLAGS = -no-undefined -version-info \ $(LIBASS_LT_CURRENT):$(LIBASS_LT_REVISION):$(LIBASS_LT_AGE) \ -export-symbols $(srcdir)/libass.sym @@ -403,10 +431,9 @@ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libass/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libass/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu libass/Makefile -.PRECIOUS: Makefile + $(AUTOMAKE) --foreign libass/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -467,7 +494,9 @@ @: > x86/$(DEPDIR)/$(am__dirstamp) x86/blend_bitmaps.lo: x86/$(am__dirstamp) \ x86/$(DEPDIR)/$(am__dirstamp) +x86/blur.lo: x86/$(am__dirstamp) x86/$(DEPDIR)/$(am__dirstamp) x86/cpuid.lo: x86/$(am__dirstamp) x86/$(DEPDIR)/$(am__dirstamp) +x86/utils.lo: x86/$(am__dirstamp) x86/$(DEPDIR)/$(am__dirstamp) x86/rasterizer.lo: x86/$(am__dirstamp) x86/$(DEPDIR)/$(am__dirstamp) x86/be_blur.lo: x86/$(am__dirstamp) x86/$(DEPDIR)/$(am__dirstamp) @@ -484,10 +513,14 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_bitmap.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_blur.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_cache.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_coretext.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_directwrite.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_drawing.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_font.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_fontconfig.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_fontselect.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_library.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_parse.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_rasterizer.Plo@am__quote@ @@ -495,6 +528,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_render.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_render_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_shaper.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_string.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_strtod.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_utils.Plo@am__quote@ @@ -758,9 +792,11 @@ tags tags-am uninstall uninstall-am \ uninstall-dist_assheadersHEADERS uninstall-libLTLIBRARIES +.PRECIOUS: Makefile + .asm.lo: - $(yasm_verbose)$(LIBTOOL) $(AM_V_lt) --mode=compile $(AS) $(ASFLAGS) -o $@ $< -prefer-non-pic + $(yasm_verbose)$(LIBTOOL) $(AM_V_lt) --tag=CC --mode=compile $(AS) $(ASFLAGS) -o $@ $< -prefer-non-pic # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff -Nru libass-0.12.2/libass/x86/be_blur.h libass-0.13.0/libass/x86/be_blur.h --- libass-0.12.2/libass/x86/be_blur.h 2014-02-25 17:26:10.000000000 +0000 +++ libass-0.13.0/libass/x86/be_blur.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2013 Rodger Combs - * - * 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 INTEL_BE_BLUR_H -#define INTEL_BE_BLUR_H - -void ass_be_blur_sse2( uint8_t *buf, intptr_t width, - intptr_t height, intptr_t stride, - uint16_t *tmp); - -void ass_be_blur_avx2( uint8_t *buf, intptr_t width, - intptr_t height, intptr_t stride, - uint16_t *tmp); - -#endif diff -Nru libass-0.12.2/libass/x86/blend_bitmaps.h libass-0.13.0/libass/x86/blend_bitmaps.h --- libass-0.12.2/libass/x86/blend_bitmaps.h 2014-02-25 17:26:10.000000000 +0000 +++ libass-0.13.0/libass/x86/blend_bitmaps.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2013 Rodger Combs - * - * 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 INTEL_BLEND_BITMAPS_H -#define INTEL_BLEND_BITMAPS_H - -void ass_add_bitmaps_avx2( uint8_t *dst, intptr_t dst_stride, - uint8_t *src, intptr_t src_stride, - intptr_t height, intptr_t width ); - -void ass_add_bitmaps_sse2( uint8_t *dst, intptr_t dst_stride, - uint8_t *src, intptr_t src_stride, - intptr_t height, intptr_t width ); - -void ass_add_bitmaps_x86( uint8_t *dst, intptr_t dst_stride, - uint8_t *src, intptr_t src_stride, - intptr_t height, intptr_t width ); - -void ass_sub_bitmaps_avx2( uint8_t *dst, intptr_t dst_stride, - uint8_t *src, intptr_t src_stride, - intptr_t height, intptr_t width ); - -void ass_sub_bitmaps_sse2( uint8_t *dst, intptr_t dst_stride, - uint8_t *src, intptr_t src_stride, - intptr_t height, intptr_t width ); - -void ass_sub_bitmaps_x86( uint8_t *dst, intptr_t dst_stride, - uint8_t *src, intptr_t src_stride, - intptr_t height, intptr_t width ); - -void ass_mul_bitmaps_avx2( uint8_t *dst, intptr_t dst_stride, - uint8_t *src1, intptr_t src1_stride, - uint8_t *src2, intptr_t src2_stride, - intptr_t width, intptr_t height ); - -void ass_mul_bitmaps_sse2( uint8_t *dst, intptr_t dst_stride, - uint8_t *src1, intptr_t src1_stride, - uint8_t *src2, intptr_t src2_stride, - intptr_t width, intptr_t height ); - -#endif diff -Nru libass-0.12.2/libass/x86/blur.asm libass-0.13.0/libass/x86/blur.asm --- libass-0.12.2/libass/x86/blur.asm 1970-01-01 00:00:00.000000000 +0000 +++ libass-0.13.0/libass/x86/blur.asm 2015-07-07 18:25:48.000000000 +0000 @@ -0,0 +1,1423 @@ +;****************************************************************************** +;* blur.asm: SSE2/AVX2 cascade blur +;****************************************************************************** +;* Copyright (C) 2015 Vabishchevich Nikolay +;* +;* 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 "utils.asm" + +SECTION_RODATA 32 + +words_zero: times 16 dw 0 +words_one: times 16 dw 1 +words_15_6: times 8 dw 15, 6 +words_dither0: times 8 dw 8, 40 +words_dither1: times 8 dw 56, 24 +words_sign: times 16 dw 0x8000 + +dwords_two: times 8 dd 2 +dwords_32: times 8 dd 32 +dwords_round: times 8 dd 0x8000 +dwords_lomask: times 8 dd 0xFFFF + +SECTION .text + +;------------------------------------------------------------------------------ +; STRIPE_UNPACK +; void stripe_unpack(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, +; uintptr_t width, uintptr_t height); +;------------------------------------------------------------------------------ + +%macro STRIPE_UNPACK 0 +cglobal stripe_unpack, 5,6,3 + lea r3, [2 * r3 + mmsize - 1] + and r3, ~(mmsize - 1) + mov r5, r3 + imul r3, r4 + shr r5, 1 + MUL r4, mmsize + and r5, ~(mmsize - 1) + sub r3, r4 + sub r2, r5 + xor r5, r5 + mova m2, [words_one] + jmp .row_loop + +.col_loop + mova m1, [r1] +%if mmsize == 32 + vpermq m1, m1, q3120 +%endif + punpcklbw m0, m1, m1 + punpckhbw m1, m1 + psrlw m0, 1 + psrlw m1, 1 + paddw m0, m2 + paddw m1, m2 + psrlw m0, 1 + psrlw m1, 1 + mova [r0 + r5], m0 + add r5, r4 + mova [r0 + r5], m1 + add r5, r4 + add r1, mmsize +.row_loop + cmp r5, r3 + jl .col_loop + sub r5, r4 + cmp r5, r3 + jge .skip_odd + + add r5, r4 + mova m0, [r1] +%if mmsize == 32 + vpermq m0, m0, q3120 +%endif + punpcklbw m0, m0 + psrlw m0, 1 + paddw m0, m2 + psrlw m0, 1 + mova [r0 + r5], m0 + +.skip_odd + add r5, mmsize + sub r5, r3 + add r1, r2 + cmp r5, r4 + jb .row_loop + RET +%endmacro + +INIT_XMM sse2 +STRIPE_UNPACK +INIT_YMM avx2 +STRIPE_UNPACK + +;------------------------------------------------------------------------------ +; STRIPE_PACK +; void stripe_pack(uint8_t *dst, ptrdiff_t dst_stride, const int16_t *src, +; uintptr_t width, uintptr_t height); +;------------------------------------------------------------------------------ + +%macro STRIPE_PACK 0 +cglobal stripe_pack, 5,7,5 + lea r3, [2 * r3 + mmsize - 1] + mov r6, r1 + and r3, ~(mmsize - 1) + mov r5, mmsize + imul r3, r4 + imul r6, r4 + add r3, r2 + MUL r4, mmsize + sub r5, r6 + jmp .row_loop + +.col_loop + mova m0, [r2] + mova m2, m0 + psrlw m2, 8 + psubw m0, m2 + mova m1, [r2 + r4] + mova m2, m1 + psrlw m2, 8 + psubw m1, m2 + paddw m0, m3 + paddw m1, m3 + psrlw m0, 6 + psrlw m1, 6 + packuswb m0, m1 +%if mmsize == 32 + vpermq m0, m0, q3120 +%endif + mova [r0], m0 + mova m2, m3 + mova m3, m4 + mova m4, m2 + add r2, mmsize + add r0, r1 + cmp r2, r6 + jb .col_loop + add r0, r5 + add r2, r4 +.row_loop + mova m3, [words_dither0] + mova m4, [words_dither1] + lea r6, [r2 + r4] + cmp r6, r3 + jb .col_loop + cmp r2, r3 + jb .odd_stripe + RET + +.odd_stripe + mova m0, [r2] + mova m2, m0 + psrlw m2, 8 + psubw m0, m2 + pxor m1, m1 + paddw m0, m3 + psrlw m0, 6 + packuswb m0, m1 +%if mmsize == 32 + vpermq m0, m0, q3120 +%endif + mova [r0], m0 + mova m2, m3 + mova m3, m4 + mova m4, m2 + add r2, mmsize + add r0, r1 + cmp r2, r6 + jb .odd_stripe + RET +%endmacro + +INIT_XMM sse2 +STRIPE_PACK +INIT_YMM avx2 +STRIPE_PACK + +;------------------------------------------------------------------------------ +; LOAD_LINE 1:m_dst, 2:base, 3:max, 4:zero_offs, +; 5:offs(lea arg), 6:tmp, [7:left/right] +; LOAD_LINE_COMPACT 1:m_dst, 2:base, 3:max, +; 4:offs(register), 5:tmp, [6:left/right] +; Load xmm/ymm register with correct source bitmap data +;------------------------------------------------------------------------------ + +%macro LOAD_LINE 6-7 + lea %6, [%5] + cmp %6, %3 + cmovae %6, %4 +%if (mmsize != 32) || (%0 < 7) + mova m%1, [%2 + %6] +%elifidn %7, left + mova xm%1, [%2 + %6] +%elifidn %7, right + mova xm%1, [%2 + %6 + 16] +%else + %error "left/right expected" +%endif +%endmacro + +%macro LOAD_LINE_COMPACT 5-6 + lea %5, [words_zero] + sub %5, %2 + cmp %4, %3 + cmovb %5, %4 +%if (mmsize != 32) || (%0 < 6) + mova m%1, [%2 + %5] +%elifidn %6, left + mova xm%1, [%2 + %5] +%elifidn %6, right + mova xm%1, [%2 + %5 + 16] +%else + %error "left/right expected" +%endif +%endmacro + +;------------------------------------------------------------------------------ +; SHRINK_HORZ +; void shrink_horz(int16_t *dst, const int16_t *src, +; uintptr_t src_width, uintptr_t src_height); +;------------------------------------------------------------------------------ + +%macro SHRINK_HORZ 0 +%if ARCH_X86_64 +cglobal shrink_horz, 4,9,9 + DECLARE_REG_TMP 8 +%else +cglobal shrink_horz, 4,7,8 + DECLARE_REG_TMP 6 +%endif + lea t0, [r2 + mmsize + 3] + lea r2, [2 * r2 + mmsize - 1] + and t0, ~(mmsize - 1) + and r2, ~(mmsize - 1) + imul t0, r3 + imul r2, r3 + add t0, r0 + xor r4, r4 + MUL r3, mmsize + sub r4, r3 + mova m7, [dwords_lomask] +%if ARCH_X86_64 + mova m8, [dwords_two] + lea r7, [words_zero] + sub r7, r1 +%else + PUSH t0 +%endif + + lea r5, [r0 + r3] +.main_loop +%if ARCH_X86_64 + LOAD_LINE 0, r1,r2,r7, r4 + 0 * r3, r6, right + LOAD_LINE 1, r1,r2,r7, r4 + 1 * r3, r6 + LOAD_LINE 2, r1,r2,r7, r4 + 2 * r3, r6 +%else + LOAD_LINE_COMPACT 0, r1,r2,r4, r6, right + add r4, r3 + LOAD_LINE_COMPACT 1, r1,r2,r4, r6 + add r4, r3 + LOAD_LINE_COMPACT 2, r1,r2,r4, r6 + sub r4, r3 + sub r4, r3 +%endif + +%if mmsize == 32 + vperm2i128 m3, m0, m1, 0x20 + vperm2i128 m4, m1, m2, 0x21 +%else + mova m3, m0 + mova m4, m1 +%endif + psrldq m3, 10 + psrldq m4, 10 + pslldq m6, m1, 6 + por m3, m6 + pslldq m6, m2, 6 + por m4, m6 + paddw m3, m1 + paddw m4, m2 + pand m3, m7 + pand m4, m7 + + psrld xm6, xm0, 16 + paddw xm0, xm6 + psrld m6, m1, 16 + paddw m1, m6 + psrld m6, m2, 16 + paddw m2, m6 + pand xm0, xm7 + pand m1, m7 + pand m2, m7 + +%if mmsize == 32 + vperm2i128 m0, m0, m1, 0x20 +%endif + psrldq m0, 8 + pslldq m6, m1, 8 + por m0, m6 + paddd m5, m0, m1 + psrld m5, 1 + psrldq m0, 4 + pslldq m6, m1, 4 + por m0, m6 + paddd m5, m0 + psrld m5, 1 + paddd m5, m3 + psrld m5, 1 + paddd m0, m5 + +%if mmsize == 32 + vperm2i128 m1, m1, m2, 0x21 +%endif + psrldq m1, 8 + pslldq m6, m2, 8 + por m1, m6 + paddd m5, m1, m2 + psrld m5, 1 + psrldq m1, 4 + pslldq m6, m2, 4 + por m1, m6 + paddd m5, m1 + psrld m5, 1 + paddd m5, m4 + psrld m5, 1 + paddd m1, m5 + +%if ARCH_X86_64 + paddd m0, m8 + paddd m1, m8 +%else + mova m6, [dwords_two] + paddd m0, m6 + paddd m1, m6 +%endif + psrld m0, 2 + psrld m1, 2 + packssdw m0, m1 +%if mmsize == 32 + vpermq m0, m0, q3120 +%endif + + mova [r0], m0 + add r0, mmsize + add r4, mmsize + cmp r0, r5 + jb .main_loop + add r4, r3 + add r5, r3 +%if ARCH_X86_64 + cmp r0, t0 +%else + cmp r0, [rstk] +%endif + jb .main_loop +%if ARCH_X86_64 == 0 + ADD rstk, 4 +%endif + RET +%endmacro + +INIT_XMM sse2 +SHRINK_HORZ +INIT_YMM avx2 +SHRINK_HORZ + +;------------------------------------------------------------------------------ +; SHRINK_VERT +; void shrink_vert(int16_t *dst, const int16_t *src, +; uintptr_t src_width, uintptr_t src_height); +;------------------------------------------------------------------------------ + +%macro SHRINK_VERT 0 +%if ARCH_X86_64 +cglobal shrink_vert, 4,7,9 +%else +cglobal shrink_vert, 4,7,8 +%endif + lea r2, [2 * r2 + mmsize - 1] + lea r5, [r3 + 5] + and r2, ~(mmsize - 1) + shr r5, 1 + imul r2, r5 + MUL r3, mmsize + add r2, r0 + mova m7, [words_one] +%if ARCH_X86_64 + mova m8, [words_sign] +%endif + lea r6, [words_zero] + sub r6, r1 + +.col_loop + mov r4, -4 * mmsize + pxor m0, m0 + pxor m1, m1 + pxor m2, m2 + pxor m3, m3 +.row_loop + LOAD_LINE 4, r1,r3,r6, r4 + 4 * mmsize, r5 + LOAD_LINE 5, r1,r3,r6, r4 + 5 * mmsize, r5 + +%if ARCH_X86_64 + mova m6, m8 +%else + psllw m6, m7, 15 +%endif + paddw m1, m4 + paddw m4, m5 + pand m6, m0 + pand m6, m4 + paddw m0, m4 + psrlw m0, 1 + por m0, m6 + pand m6, m2 + paddw m0, m2 + psrlw m0, 1 + por m0, m6 + pand m6, m1 + paddw m0, m1 + psrlw m0, 1 + por m0, m6 + paddw m0, m2 + psrlw m0, 1 + por m0, m6 + paddw m0, m7 + psrlw m0, 1 + + mova [r0], m0 + add r4, 2 * mmsize + add r0, mmsize + mova m0, m2 + mova m1, m3 + mova m2, m4 + mova m3, m5 + cmp r4, r3 + jl .row_loop + add r1, r3 + sub r6, r3 + cmp r0, r2 + jb .col_loop + RET +%endmacro + +INIT_XMM sse2 +SHRINK_VERT +INIT_YMM avx2 +SHRINK_VERT + +;------------------------------------------------------------------------------ +; EXPAND_HORZ +; void expand_horz(int16_t *dst, const int16_t *src, +; uintptr_t src_width, uintptr_t src_height); +;------------------------------------------------------------------------------ + +%macro EXPAND_HORZ 0 +%if ARCH_X86_64 +cglobal expand_horz, 4,9,5 + DECLARE_REG_TMP 8 +%else +cglobal expand_horz, 4,7,5 + DECLARE_REG_TMP 6 +%endif + lea t0, [4 * r2 + 7] + lea r2, [2 * r2 + mmsize - 1] + and t0, ~(mmsize - 1) + and r2, ~(mmsize - 1) + imul t0, r3 + imul r2, r3 + add t0, r0 + xor r4, r4 + MUL r3, mmsize + sub r4, r3 + mova m4, [words_one] +%if ARCH_X86_64 + lea r7, [words_zero] + sub r7, r1 +%endif + + lea r5, [r0 + r3] + cmp r0, t0 + jae .odd_stripe +%if ARCH_X86_64 == 0 + PUSH t0 +%endif +.main_loop +%if ARCH_X86_64 + LOAD_LINE 0, r1,r2,r7, r4 + 0 * r3, r6, right + LOAD_LINE 1, r1,r2,r7, r4 + 1 * r3, r6 +%else + LOAD_LINE_COMPACT 0, r1,r2,r4, r6, right + add r4, r3 + LOAD_LINE_COMPACT 1, r1,r2,r4, r6 + sub r4, r3 +%endif + +%if mmsize == 32 + vperm2i128 m0, m0, m1, 0x20 +%endif + psrldq m0, 12 + pslldq m3, m1, 4 + por m0, m3 + psrldq m2, m0, 2 + pslldq m3, m1, 2 + por m2, m3 + + paddw m3, m0, m1 + psrlw m3, 1 + paddw m3, m2 + psrlw m3, 1 + paddw m0, m3 + paddw m1, m3 + psrlw m0, 1 + psrlw m1, 1 + paddw m0, m2 + paddw m1, m2 + paddw m0, m4 + paddw m1, m4 + psrlw m0, 1 + psrlw m1, 1 + +%if mmsize == 32 + vpermq m0, m0, q3120 + vpermq m1, m1, q3120 +%endif + punpcklwd m2, m0, m1 + punpckhwd m0, m1 + mova [r0], m2 + mova [r0 + r3], m0 + add r0, mmsize + add r4, mmsize + cmp r0, r5 + jb .main_loop + add r0, r3 + lea r5, [r0 + r3] +%if ARCH_X86_64 == 0 + mov t0, [rstk] +%endif + cmp r0, t0 + jb .main_loop + add t0, r3 +%if ARCH_X86_64 == 0 + ADD rstk, 4 +%endif + cmp r0, t0 + jb .odd_stripe + RET + +.odd_stripe +%if ARCH_X86_64 + LOAD_LINE 0, r1,r2,r7, r4 + 0 * r3, r6, right + LOAD_LINE 1, r1,r2,r7, r4 + 1 * r3, r6, left +%else + LOAD_LINE_COMPACT 0, r1,r2,r4, r6, right + add r4, r3 + LOAD_LINE_COMPACT 1, r1,r2,r4, r6, left + sub r4, r3 +%endif + + psrldq xm0, 12 + pslldq xm3, xm1, 4 + por xm0, xm3 + psrldq xm2, xm0, 2 + pslldq xm3, xm1, 2 + por xm2, xm3 + + paddw xm3, xm0, xm1 + psrlw xm3, 1 + paddw xm3, xm2 + psrlw xm3, 1 + paddw xm0, xm3 + paddw xm1, xm3 + psrlw xm0, 1 + psrlw xm1, 1 + paddw xm0, xm2 + paddw xm1, xm2 + paddw xm0, xm4 + paddw xm1, xm4 + psrlw xm0, 1 + psrlw xm1, 1 + +%if mmsize == 32 + vpermq m0, m0, q3120 + vpermq m1, m1, q3120 +%endif + punpcklwd m0, m1 + mova [r0], m0 + add r0, mmsize + add r4, mmsize + cmp r0, r5 + jb .odd_stripe + RET +%endmacro + +INIT_XMM sse2 +EXPAND_HORZ +INIT_YMM avx2 +EXPAND_HORZ + +;------------------------------------------------------------------------------ +; EXPAND_VERT +; void expand_vert(int16_t *dst, const int16_t *src, +; uintptr_t src_width, uintptr_t src_height); +;------------------------------------------------------------------------------ + +%macro EXPAND_VERT 0 +cglobal expand_vert, 4,7,5 + lea r2, [2 * r2 + mmsize - 1] + lea r5, [2 * r3 + 4] + and r2, ~(mmsize - 1) + imul r2, r5 + MUL r3, mmsize + add r2, r0 + mova m4, [words_one] + lea r6, [words_zero] + sub r6, r1 + +.col_loop + mov r4, -2 * mmsize + pxor m0, m0 + pxor m1, m1 +.row_loop + LOAD_LINE 2, r1,r3,r6, r4 + 2 * mmsize, r5 + + paddw m3, m0, m2 + psrlw m3, 1 + paddw m3, m1 + psrlw m3, 1 + paddw m0, m3 + paddw m3, m2 + psrlw m0, 1 + psrlw m3, 1 + paddw m0, m1 + paddw m3, m1 + paddw m0, m4 + paddw m3, m4 + psrlw m0, 1 + psrlw m3, 1 + + mova [r0], m0 + mova [r0 + mmsize], m3 + add r4, mmsize + add r0, 2 * mmsize + mova m0, m1 + mova m1, m2 + cmp r4, r3 + jl .row_loop + add r1, r3 + sub r6, r3 + cmp r0, r2 + jb .col_loop + RET +%endmacro + +INIT_XMM sse2 +EXPAND_VERT +INIT_YMM avx2 +EXPAND_VERT + +;------------------------------------------------------------------------------ +; PRE_BLUR1_HORZ +; void pre_blur1_horz(int16_t *dst, const int16_t *src, +; uintptr_t src_width, uintptr_t src_height); +;------------------------------------------------------------------------------ + +%macro PRE_BLUR1_HORZ 0 +%if ARCH_X86_64 +cglobal pre_blur1_horz, 4,8,4 +%else +cglobal pre_blur1_horz, 4,7,4 +%endif + lea r5, [2 * r2 + mmsize + 3] + lea r2, [2 * r2 + mmsize - 1] + and r5, ~(mmsize - 1) + and r2, ~(mmsize - 1) + imul r5, r3 + imul r2, r3 + add r5, r0 + xor r4, r4 + MUL r3, mmsize + sub r4, r3 + mova m3, [words_one] +%if ARCH_X86_64 + lea r7, [words_zero] + sub r7, r1 +%endif + +.main_loop +%if ARCH_X86_64 + LOAD_LINE 0, r1,r2,r7, r4 + 0 * r3, r6, right + LOAD_LINE 1, r1,r2,r7, r4 + 1 * r3, r6 +%else + LOAD_LINE_COMPACT 0, r1,r2,r4, r6, right + add r4, r3 + LOAD_LINE_COMPACT 1, r1,r2,r4, r6 + sub r4, r3 +%endif + +%if mmsize == 32 + vperm2i128 m0, m0, m1, 0x20 +%endif + psrldq m0, 12 + pslldq m2, m1, 4 + por m0, m2 + psrldq m2, m0, 2 + paddw m0, m1 + pslldq m1, 2 + psrlw m0, 1 + por m1, m2 + paddw m0, m1 + paddw m0, m3 + psrlw m0, 1 + + mova [r0], m0 + add r0, mmsize + add r4, mmsize + cmp r0, r5 + jb .main_loop + RET +%endmacro + +INIT_XMM sse2 +PRE_BLUR1_HORZ +INIT_YMM avx2 +PRE_BLUR1_HORZ + +;------------------------------------------------------------------------------ +; PRE_BLUR1_VERT +; void pre_blur1_vert(int16_t *dst, const int16_t *src, +; uintptr_t src_width, uintptr_t src_height); +;------------------------------------------------------------------------------ + +%macro PRE_BLUR1_VERT 0 +cglobal pre_blur1_vert, 4,7,4 + lea r2, [2 * r2 + mmsize - 1] + lea r5, [r3 + 2] + and r2, ~(mmsize - 1) + imul r2, r5 + MUL r3, mmsize + add r2, r0 + mova m3, [words_one] + lea r6, [words_zero] + sub r6, r1 + +.col_loop + mov r4, -2 * mmsize + pxor m0, m0 + pxor m1, m1 +.row_loop + LOAD_LINE 2, r1,r3,r6, r4 + 2 * mmsize, r5 + + paddw m0, m2 + psrlw m0, 1 + paddw m0, m1 + paddw m0, m3 + psrlw m0, 1 + + mova [r0], m0 + add r4, mmsize + add r0, mmsize + mova m0, m1 + mova m1, m2 + cmp r4, r3 + jl .row_loop + add r1, r3 + sub r6, r3 + cmp r0, r2 + jb .col_loop + RET +%endmacro + +INIT_XMM sse2 +PRE_BLUR1_VERT +INIT_YMM avx2 +PRE_BLUR1_VERT + +;------------------------------------------------------------------------------ +; PRE_BLUR2_HORZ +; void pre_blur2_horz(int16_t *dst, const int16_t *src, +; uintptr_t src_width, uintptr_t src_height); +;------------------------------------------------------------------------------ + +%macro PRE_BLUR2_HORZ 0 +%if ARCH_X86_64 +cglobal pre_blur2_horz, 4,8,7 +%else +cglobal pre_blur2_horz, 4,7,7 +%endif + lea r5, [2 * r2 + mmsize + 7] + lea r2, [2 * r2 + mmsize - 1] + and r5, ~(mmsize - 1) + and r2, ~(mmsize - 1) + imul r5, r3 + imul r2, r3 + add r5, r0 + xor r4, r4 + MUL r3, mmsize + sub r4, r3 + mova m5, [words_one] + mova m6, [words_sign] +%if ARCH_X86_64 + lea r7, [words_zero] + sub r7, r1 +%endif + +.main_loop +%if ARCH_X86_64 + LOAD_LINE 0, r1,r2,r7, r4 + 0 * r3, r6, right + LOAD_LINE 1, r1,r2,r7, r4 + 1 * r3, r6 +%else + LOAD_LINE_COMPACT 0, r1,r2,r4, r6, right + add r4, r3 + LOAD_LINE_COMPACT 1, r1,r2,r4, r6 + sub r4, r3 +%endif + +%if mmsize == 32 + vperm2i128 m0, m0, m1, 0x20 +%endif + psrldq m0, 8 + pslldq m2, m1, 8 + por m2, m0 + paddw m2, m1 + psrlw m2, 1 + psrldq m0, 2 + pslldq m3, m1, 6 + por m3, m0 + psrldq m0, 2 + pslldq m4, m1, 4 + por m4, m0 + paddw m2, m4 + psrlw m2, 1 + paddw m2, m4 + psrldq m0, 2 + pslldq m1, 2 + por m0, m1 + paddw m0, m3 + mova m1, m6 + pand m1, m0 + pand m1, m2 + paddw m0, m2 + psrlw m0, 1 + por m0, m1 + paddw m0, m5 + psrlw m0, 1 + + mova [r0], m0 + add r0, mmsize + add r4, mmsize + cmp r0, r5 + jb .main_loop + RET +%endmacro + +INIT_XMM sse2 +PRE_BLUR2_HORZ +INIT_YMM avx2 +PRE_BLUR2_HORZ + +;------------------------------------------------------------------------------ +; PRE_BLUR2_VERT +; void pre_blur2_vert(int16_t *dst, const int16_t *src, +; uintptr_t src_width, uintptr_t src_height); +;------------------------------------------------------------------------------ + +%macro PRE_BLUR2_VERT 0 +%if ARCH_X86_64 +cglobal pre_blur2_vert, 4,7,9 +%else +cglobal pre_blur2_vert, 4,7,8 +%endif + lea r2, [2 * r2 + mmsize - 1] + lea r5, [r3 + 4] + and r2, ~(mmsize - 1) + imul r2, r5 + MUL r3, mmsize + add r2, r0 + mova m7, [words_one] +%if ARCH_X86_64 + mova m8, [words_sign] +%endif + lea r6, [words_zero] + sub r6, r1 + +.col_loop + mov r4, -4 * mmsize + pxor m0, m0 + pxor m1, m1 + pxor m2, m2 + pxor m3, m3 +.row_loop + LOAD_LINE 4, r1,r3,r6, r4 + 4 * mmsize, r5 + +%if ARCH_X86_64 + mova m6, m8 +%else + psllw m6, m7, 15 +%endif + paddw m0, m4 + psrlw m0, 1 + paddw m0, m2 + psrlw m0, 1 + paddw m0, m2 + paddw m5, m1, m3 + pand m6, m0 + pand m6, m5 + paddw m0, m5 + psrlw m0, 1 + por m0, m6 + paddw m0, m7 + psrlw m0, 1 + + mova [r0], m0 + add r4, mmsize + add r0, mmsize + mova m0, m1 + mova m1, m2 + mova m2, m3 + mova m3, m4 + cmp r4, r3 + jl .row_loop + add r1, r3 + sub r6, r3 + cmp r0, r2 + jb .col_loop + RET +%endmacro + +INIT_XMM sse2 +PRE_BLUR2_VERT +INIT_YMM avx2 +PRE_BLUR2_VERT + +;------------------------------------------------------------------------------ +; ADD_LINE 1:m_acc1, 2:m_acc2, 3:m_line, 4-5:m_tmp +; Calculate acc += line +;------------------------------------------------------------------------------ + +%macro ADD_LINE 5 + psraw m%4, m%3, 15 + punpcklwd m%5, m%3, m%4 + punpckhwd m%3, m%4 +%ifidn %1, %5 + paddd m%1, m%2 +%else + paddd m%1, m%5 +%endif + paddd m%2, m%3 +%endmacro + +;------------------------------------------------------------------------------ +; FILTER_PAIR 1:m_acc1, 2:m_acc2, 3:m_line1, 4:m_line2, +; 5:m_tmp, 6:m_mul64, [7:m_mul32, 8:swizzle] +; Calculate acc += line1 * mul[odd] + line2 * mul[even] +;------------------------------------------------------------------------------ + +%macro FILTER_PAIR 6-8 + punpcklwd m%5, m%4, m%3 + punpckhwd m%4, m%3 +%if ARCH_X86_64 || (%0 < 8) + pmaddwd m%5, m%6 + pmaddwd m%4, m%6 +%else + pshufd m%3, m%7, %8 + pmaddwd m%5, m%3 + pmaddwd m%4, m%3 +%endif +%ifidn %1, %5 + paddd m%1, m%2 +%else + paddd m%1, m%5 +%endif + paddd m%2, m%4 +%endmacro + +;------------------------------------------------------------------------------ +; PRE_BLUR3_HORZ +; void pre_blur3_horz(int16_t *dst, const int16_t *src, +; uintptr_t src_width, uintptr_t src_height); +;------------------------------------------------------------------------------ + +%macro PRE_BLUR3_HORZ 0 +%if ARCH_X86_64 +cglobal pre_blur3_horz, 4,8,9 +%else +cglobal pre_blur3_horz, 4,7,8 +%endif + lea r5, [2 * r2 + mmsize + 11] + lea r2, [2 * r2 + mmsize - 1] + and r5, ~(mmsize - 1) + and r2, ~(mmsize - 1) + imul r5, r3 + imul r2, r3 + add r5, r0 + xor r4, r4 + MUL r3, mmsize + sub r4, r3 + mova m5, [words_15_6] +%if ARCH_X86_64 + mova m8, [dwords_32] + lea r7, [words_zero] + sub r7, r1 +%endif + +.main_loop +%if ARCH_X86_64 + LOAD_LINE 0, r1,r2,r7, r4 + 0 * r3, r6, right + LOAD_LINE 1, r1,r2,r7, r4 + 1 * r3, r6 +%else + LOAD_LINE_COMPACT 0, r1,r2,r4, r6, right + add r4, r3 + LOAD_LINE_COMPACT 1, r1,r2,r4, r6 + sub r4, r3 +%endif + +%if ARCH_X86_64 + mova m7, m8 +%else + mova m7, [dwords_32] +%endif +%if mmsize == 32 + vperm2i128 m0, m0, m1, 0x20 +%endif + psrldq m2, m0, 10 + pslldq m3, m1, 6 + por m2, m3 + + psrldq m0, 4 + pslldq m3, m2, 6 + por m3, m0 + psubw m3, m2 + ADD_LINE 6,7, 3,4, 6 + + psrldq m0, 2 + pslldq m3, m2, 4 + por m3, m0 + psubw m3, m2 + psrldq m0, 2 + pslldq m4, m2, 2 + por m4, m0 + psubw m4, m2 + FILTER_PAIR 6,7, 3,4, 0, 5 + + psubw m3, m1, m2 + ADD_LINE 6,7, 3,4, 0 + + pslldq m1, 2 + psrldq m3, m2, 4 + por m3, m1 + psubw m3, m2 + pslldq m1, 2 + psrldq m4, m2, 2 + por m4, m1 + psubw m4, m2 + FILTER_PAIR 6,7, 3,4, 0, 5 + + psrad m6, 6 + psrad m7, 6 + packssdw m6, m7 + paddw m2, m6 + mova [r0], m2 + add r0, mmsize + add r4, mmsize + cmp r0, r5 + jb .main_loop + RET +%endmacro + +INIT_XMM sse2 +PRE_BLUR3_HORZ +INIT_YMM avx2 +PRE_BLUR3_HORZ + +;------------------------------------------------------------------------------ +; PRE_BLUR3_VERT +; void pre_blur3_vert(int16_t *dst, const int16_t *src, +; uintptr_t src_width, uintptr_t src_height); +;------------------------------------------------------------------------------ + +%macro PRE_BLUR3_VERT 0 +%if ARCH_X86_64 +cglobal pre_blur3_vert, 4,7,8 +%else +cglobal pre_blur3_vert, 4,7,8 +%endif + lea r2, [2 * r2 + mmsize - 1] + lea r5, [r3 + 6] + and r2, ~(mmsize - 1) + imul r2, r5 + MUL r3, mmsize + add r2, r0 + mova m4, [dwords_32] + mova m5, [words_15_6] + lea r6, [words_zero] + sub r6, r1 + +.col_loop + mov r4, -6 * mmsize +.row_loop + mova m6, m4 + mova m7, m4 + LOAD_LINE 0, r1,r3,r6, r4 + 3 * mmsize, r5 + + LOAD_LINE 1, r1,r3,r6, r4 + 0 * mmsize, r5 + psubw m1, m0 + ADD_LINE 6,7, 1,2, 3 + + LOAD_LINE 1, r1,r3,r6, r4 + 1 * mmsize, r5 + LOAD_LINE 2, r1,r3,r6, r4 + 2 * mmsize, r5 + psubw m1, m0 + psubw m2, m0 + FILTER_PAIR 6,7, 1,2, 3, 5 + + LOAD_LINE 1, r1,r3,r6, r4 + 6 * mmsize, r5 + psubw m1, m0 + ADD_LINE 6,7, 1,2, 3 + + LOAD_LINE 1, r1,r3,r6, r4 + 5 * mmsize, r5 + LOAD_LINE 2, r1,r3,r6, r4 + 4 * mmsize, r5 + psubw m1, m0 + psubw m2, m0 + FILTER_PAIR 6,7, 1,2, 3, 5 + + psrad m6, 6 + psrad m7, 6 + packssdw m6, m7 + paddw m0, m6 + mova [r0], m0 + add r4, mmsize + add r0, mmsize + cmp r4, r3 + jl .row_loop + add r1, r3 + sub r6, r3 + cmp r0, r2 + jb .col_loop + RET +%endmacro + +INIT_XMM sse2 +PRE_BLUR3_VERT +INIT_YMM avx2 +PRE_BLUR3_VERT + +;------------------------------------------------------------------------------ +; LOAD_MULTIPLIER 1:m_mul1, 2:m_mul2, 3:src, 4:tmp +; Load blur parameters into xmm/ymm registers +;------------------------------------------------------------------------------ + +%macro LOAD_MULTIPLIER 4 + mov %4, [%3] + movd xm%1, %4d +%if ARCH_X86_64 + shr %4, 32 +%else + mov %4, [%3 + 4] +%endif + movd xm%2, %4d +%if ARCH_X86_64 == 0 + punpckldq xm%1, xm%2 +%if mmsize == 32 + vpbroadcastq m%1, xm%1 +%endif +%elif mmsize == 32 + vpbroadcastd m%1, xm%1 + vpbroadcastd m%2, xm%2 +%else + pshufd m%1, m%1, q0000 + pshufd m%2, m%2, q0000 +%endif +%endmacro + +;------------------------------------------------------------------------------ +; BLUR_HORZ 1:pattern +; void blurNNNN_horz(int16_t *dst, const int16_t *src, +; uintptr_t src_width, uintptr_t src_height, +; const int16_t *param); +;------------------------------------------------------------------------------ + +%macro BLUR_HORZ 1 + %assign %%i1 %1 / 1000 % 10 + %assign %%i2 %1 / 100 % 10 + %assign %%i3 %1 / 10 % 10 + %assign %%i4 %1 / 1 % 10 +%if ARCH_X86_64 +cglobal blur%1_horz, 5,8,10 +%else +cglobal blur%1_horz, 5,7,8 +%endif +%if ARCH_X86_64 + LOAD_MULTIPLIER 8,9, r4, r5 +%else + LOAD_MULTIPLIER 5,0, r4, r5 +%endif + lea r5, [2 * r2 + mmsize + 4 * %%i4 - 1] + lea r2, [2 * r2 + mmsize - 1] + and r5, ~(mmsize - 1) + and r2, ~(mmsize - 1) + imul r5, r3 + imul r2, r3 + add r5, r0 + xor r4, r4 + MUL r3, mmsize +%if (mmsize != 32) && (%%i4 > 4) + sub r4, r3 +%endif + sub r4, r3 +%if ARCH_X86_64 + mova m5, [dwords_round] + lea r7, [words_zero] + sub r7, r1 +%endif + +.main_loop +%if ARCH_X86_64 +%if %%i4 > 4 + LOAD_LINE 0, r1,r2,r7, r4 + 0 * r3, r6 +%else + LOAD_LINE 0, r1,r2,r7, r4 + 0 * r3, r6, right +%endif + LOAD_LINE 1, r1,r2,r7, r4 + 1 * r3, r6 +%if (mmsize != 32) && (%%i4 > 4) + LOAD_LINE 2, r1,r2,r7, r4 + 2 * r3, r6 + SWAP 1, 2 +%endif +%else +%if %%i4 > 4 + LOAD_LINE_COMPACT 0, r1,r2,r4, r6 +%else + LOAD_LINE_COMPACT 0, r1,r2,r4, r6, right +%endif + add r4, r3 + LOAD_LINE_COMPACT 1, r1,r2,r4, r6 +%if (mmsize != 32) && (%%i4 > 4) + add r4, r3 + LOAD_LINE_COMPACT 2, r1,r2,r4, r6 + SWAP 1, 2 + sub r4, r3 +%endif + sub r4, r3 +%endif + +%if ARCH_X86_64 + mova m7, m5 +%else + mova m7, [dwords_round] +%endif +%if %%i4 > 4 +%if mmsize == 32 + vperm2i128 m2, m0, m1, 0x21 +%endif + psrldq m0, 32 - 4 * %%i4 + pslldq m3, m2, 4 * %%i4 - 16 + por m0, m3 + psrldq m2, 16 - 2 * %%i4 +%else +%if mmsize == 32 + vperm2i128 m0, m0, m1, 0x20 +%endif + psrldq m2, m0, 16 - 2 * %%i4 +%endif + pslldq m3, m1, 2 * %%i4 + por m2, m3 + + psubw m3, m1, m2 + pslldq m1, 2 * (%%i4 - %%i3) + psrldq m4, m2, 2 * %%i3 + por m4, m1 + psubw m4, m2 + FILTER_PAIR 6,7, 3,4, 6, 9,5,q1111 + + pslldq m1, 2 * (%%i3 - %%i2) + psrldq m3, m2, 2 * %%i2 + por m3, m1 + psubw m3, m2 + pslldq m1, 2 * (%%i2 - %%i1) + psrldq m4, m2, 2 * %%i1 + por m4, m1 + psubw m4, m2 + FILTER_PAIR 6,7, 3,4, 1, 8,5,q0000 + + psubw m3, m0, m2 + psrldq m0, 2 * (%%i4 - %%i3) + pslldq m4, m2, 2 * %%i3 + por m4, m0 + psubw m4, m2 + FILTER_PAIR 6,7, 3,4, 1, 9,5,q1111 + + psrldq m0, 2 * (%%i3 - %%i2) + pslldq m3, m2, 2 * %%i2 + por m3, m0 + psubw m3, m2 + psrldq m0, 2 * (%%i2 - %%i1) + pslldq m4, m2, 2 * %%i1 + por m4, m0 + psubw m4, m2 + FILTER_PAIR 6,7, 3,4, 1, 8,5,q0000 + + psrad m6, 16 + psrad m7, 16 + packssdw m6, m7 + paddw m2, m6 + mova [r0], m2 + add r0, mmsize + add r4, mmsize + cmp r0, r5 + jb .main_loop + RET +%endmacro + +INIT_XMM sse2 +BLUR_HORZ 1234 +BLUR_HORZ 1235 +BLUR_HORZ 1246 +INIT_YMM avx2 +BLUR_HORZ 1234 +BLUR_HORZ 1235 +BLUR_HORZ 1246 + +;------------------------------------------------------------------------------ +; BLUR_VERT 1:pattern +; void blurNNNN_vert(int16_t *dst, const int16_t *src, +; uintptr_t src_width, uintptr_t src_height, +; const int16_t *param); +;------------------------------------------------------------------------------ + +%macro BLUR_VERT 1 + %assign %%i1 %1 / 1000 % 10 + %assign %%i2 %1 / 100 % 10 + %assign %%i3 %1 / 10 % 10 + %assign %%i4 %1 / 1 % 10 +%if ARCH_X86_64 +cglobal blur%1_vert, 5,7,9 +%else +cglobal blur%1_vert, 5,7,8 +%endif +%if ARCH_X86_64 + LOAD_MULTIPLIER 4,5, r4, r5 +%else + LOAD_MULTIPLIER 5,0, r4, r5 + SWAP 4, 8 +%endif + lea r2, [2 * r2 + mmsize - 1] + lea r5, [r3 + 2 * %%i4] + and r2, ~(mmsize - 1) + imul r2, r5 + MUL r3, mmsize + add r2, r0 + mova m8, [dwords_round] + lea r6, [words_zero] + sub r6, r1 + +.col_loop + mov r4, -2 * %%i4 * mmsize +.row_loop + mova m6, m8 + mova m7, m8 + LOAD_LINE 0, r1,r3,r6, r4 + %%i4 * mmsize, r5 + + LOAD_LINE 1, r1,r3,r6, r4 + (%%i4 - %%i4) * mmsize, r5 + LOAD_LINE 2, r1,r3,r6, r4 + (%%i4 - %%i3) * mmsize, r5 + psubw m1, m0 + psubw m2, m0 + FILTER_PAIR 6,7, 1,2, 3, 5,5,q1111 + + LOAD_LINE 1, r1,r3,r6, r4 + (%%i4 - %%i2) * mmsize, r5 + LOAD_LINE 2, r1,r3,r6, r4 + (%%i4 - %%i1) * mmsize, r5 + psubw m1, m0 + psubw m2, m0 + FILTER_PAIR 6,7, 1,2, 3, 4,5,q0000 + + LOAD_LINE 1, r1,r3,r6, r4 + (%%i4 + %%i4) * mmsize, r5 + LOAD_LINE 2, r1,r3,r6, r4 + (%%i4 + %%i3) * mmsize, r5 + psubw m1, m0 + psubw m2, m0 + FILTER_PAIR 6,7, 1,2, 3, 5,5,q1111 + + LOAD_LINE 1, r1,r3,r6, r4 + (%%i4 + %%i2) * mmsize, r5 + LOAD_LINE 2, r1,r3,r6, r4 + (%%i4 + %%i1) * mmsize, r5 + psubw m1, m0 + psubw m2, m0 + FILTER_PAIR 6,7, 1,2, 3, 4,5,q0000 + + psrad m6, 16 + psrad m7, 16 + packssdw m6, m7 + paddw m0, m6 + mova [r0], m0 + add r4, mmsize + add r0, mmsize + cmp r4, r3 + jl .row_loop + add r1, r3 + sub r6, r3 + cmp r0, r2 + jb .col_loop + RET +%endmacro + +INIT_XMM sse2 +BLUR_VERT 1234 +BLUR_VERT 1235 +BLUR_VERT 1246 +INIT_YMM avx2 +BLUR_VERT 1234 +BLUR_VERT 1235 +BLUR_VERT 1246 diff -Nru libass-0.12.2/libass/x86/cpuid.asm libass-0.13.0/libass/x86/cpuid.asm --- libass-0.12.2/libass/x86/cpuid.asm 2014-02-25 17:26:10.000000000 +0000 +++ libass-0.13.0/libass/x86/cpuid.asm 2015-09-07 09:44:05.000000000 +0000 @@ -46,3 +46,19 @@ mov [r4], edx pop rbx RET + +;----------------------------------------------------------------------------- +; void get_xgetbv( uint32_t op, uint32_t *eax, uint32_t *edx ) +;----------------------------------------------------------------------------- + +INIT_XMM +cglobal get_xgetbv, 3, 7, 0 + push r2 + push r1 + mov ecx, r0d + xgetbv + pop r4 + mov [r4], eax + pop r4 + mov [r4], edx + RET diff -Nru libass-0.12.2/libass/x86/cpuid.h libass-0.13.0/libass/x86/cpuid.h --- libass-0.12.2/libass/x86/cpuid.h 2014-02-25 17:26:10.000000000 +0000 +++ libass-0.13.0/libass/x86/cpuid.h 2015-09-07 09:44:05.000000000 +0000 @@ -15,10 +15,11 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - + #ifndef INTEL_CPUID_H #define INTEL_CPUID_H - + void ass_get_cpuid( uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); - +void ass_get_xgetbv( uint32_t op, uint32_t *eax, uint32_t *edx ); + #endif diff -Nru libass-0.12.2/libass/x86/rasterizer.asm libass-0.13.0/libass/x86/rasterizer.asm --- libass-0.12.2/libass/x86/rasterizer.asm 2015-03-06 12:23:04.000000000 +0000 +++ libass-0.13.0/libass/x86/rasterizer.asm 2015-07-07 18:25:48.000000000 +0000 @@ -1,5 +1,5 @@ ;****************************************************************************** -;* rasterizer.asm: SSE2 tile rasterization functions +;* rasterizer.asm: SSE2/AVX2 tile rasterization ;****************************************************************************** ;* Copyright (C) 2014 Vabishchevich Nikolay ;* @@ -18,86 +18,18 @@ ;* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ;****************************************************************************** -%include "x86inc.asm" - -%if ARCH_X86_64 -DEFAULT REL -%endif +%include "utils.asm" SECTION_RODATA 32 words_index: dw 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F -words_tile16: dw 1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024 -words_tile32: dw 512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512 +words_tile16: times 16 dw 1024 +words_tile32: times 16 dw 512 SECTION .text ;------------------------------------------------------------------------------ -; MUL reg, num -; Multiply by constant -;------------------------------------------------------------------------------ - -%macro MUL 2 -%if (%2) == 0 - xor %1, %1 -%elif (%2) == 1 -%elif (%2) == 2 - add %1, %1 ; lea %1, [%1 + %1] -%elif (%2) == 3 - lea %1, [%1 + 2 * %1] -%elif (%2) == 4 - lea %1, [4 * %1] ; shl %1, 2 -%elif (%2) == 5 - lea %1, [%1 + 4 * %1] -%elif (%2) == 8 - lea %1, [8 * %1] ; shl %1, 3 -%elif (%2) == 9 - lea %1, [%1 + 8 * %1] -%elif (%2) == 16 - shl %1, 4 -%elif (%2) == 32 - shl %1, 5 -%elif (%2) == 64 - shl %1, 6 -%elif (%2) == 128 - shl %1, 7 -%elif (%2) == 256 - shl %1, 8 -%else - imul %1, %2 -%endif -%endmacro - -;------------------------------------------------------------------------------ -; BCASTW m_dst, r_src -;------------------------------------------------------------------------------ - -%macro BCASTW 2 - movd xm%1, %2 -%if mmsize == 32 - vpbroadcastw m%1, xm%1 -%elif mmsize == 16 - punpcklwd m%1, m%1 - pshufd m%1, m%1, q0000 -%endif -%endmacro - -;------------------------------------------------------------------------------ -; PABSW m_reg, m_tmp -;------------------------------------------------------------------------------ - -%macro PABSW 2 -%if cpuflag(ssse3) - pabsw m%1, m%1 -%else - pxor m%2, m%2 - psubw m%2, m%1 - pmaxsw m%1, m%2 -%endif -%endmacro - -;------------------------------------------------------------------------------ -; FILL_LINE r_dst, src, size +; FILL_LINE 1:dst, 2:m_src, 3:size ;------------------------------------------------------------------------------ %macro FILL_LINE 3 @@ -115,7 +47,7 @@ %endmacro ;------------------------------------------------------------------------------ -; FILL_SOLID_TILE tile_order, suffix +; FILL_SOLID_TILE 1:tile_order, 2:suffix ; void fill_solid_tile%2(uint8_t *buf, ptrdiff_t stride, int set); ;------------------------------------------------------------------------------ @@ -147,7 +79,8 @@ FILL_SOLID_TILE 5,32 ;------------------------------------------------------------------------------ -; CALC_LINE tile_order, m_dst, m_src, m_delta, m_zero, m_full, m_tmp +; CALC_LINE 1:tile_order, 2:m_dst, 3:m_src, 4:m_delta, +; 5:m_zero, 6:m_full, 7:m_tmp ; Calculate line using antialiased halfplane algorithm ;------------------------------------------------------------------------------ @@ -162,7 +95,7 @@ %endmacro ;------------------------------------------------------------------------------ -; DEF_A_SHIFT tile_order +; DEF_A_SHIFT 1:tile_order ; If single mm-register is enough to store the whole line ; then sets a_shift = 0, ; else sets a_shift = log2(mmsize / sizeof(int16_t)). @@ -181,7 +114,7 @@ %endmacro ;------------------------------------------------------------------------------ -; FILL_HALFPLANE_TILE tile_order, suffix +; FILL_HALFPLANE_TILE 1:tile_order, 2:suffix ; void fill_halfplane_tile%2(uint8_t *buf, ptrdiff_t stride, ; int32_t a, int32_t b, int64_t c, int32_t scale); ;------------------------------------------------------------------------------ @@ -346,7 +279,7 @@ endstruc ;------------------------------------------------------------------------------ -; ZEROFILL dst, size, tmp1 +; ZEROFILL 1:dst, 2:size, 3:tmp ;------------------------------------------------------------------------------ %macro ZEROFILL 3 @@ -369,7 +302,7 @@ %endmacro ;------------------------------------------------------------------------------ -; CALC_DELTA_FLAG res, line, tmp1, tmp2 +; CALC_DELTA_FLAG 1:res, 2:line, 3-4:tmp ; Set bits of result register (res): ; bit 3 - for nonzero up_delta, ; bit 2 - for nonzero dn_delta. @@ -392,7 +325,7 @@ %endmacro ;------------------------------------------------------------------------------ -; UPDATE_DELTA dn/up, dst, flag, pos, tmp +; UPDATE_DELTA 1:dn/up, 2:dst, 3:flag, 4:pos, 5:tmp ; Update delta array ;------------------------------------------------------------------------------ @@ -419,7 +352,7 @@ %endmacro ;------------------------------------------------------------------------------ -; CALC_VBA tile_order, b +; CALC_VBA 1:tile_order, 2:b ; Calculate b - (tile_size - (mmsize / sizeof(int16_t))) * a ;------------------------------------------------------------------------------ @@ -431,8 +364,8 @@ %endmacro ;------------------------------------------------------------------------------ -; FILL_BORDER_LINE tile_order, res, abs_a(abs_ab), b, [abs_b], size, sum, -; tmp8, tmp9, mt10, mt11, mt12, mt13, mt14, [mt15] +; FILL_BORDER_LINE 1:tile_order, 2:res, 3:abs_a[abs_ab], 4:b, 5:[abs_b], +; 6:size, 7:sum, 8-9:tmp, 10-14:m_tmp, 15:[m_tmp] ; Render top/bottom line of the trapezium with antialiasing ;------------------------------------------------------------------------------ @@ -508,8 +441,8 @@ %endmacro ;------------------------------------------------------------------------------ -; SAVE_RESULT tile_order, buf, stride, src, delta, -; tmp6, tmp7, mt8, mt9, mt10, mt11 +; SAVE_RESULT 1:tile_order, 2:buf, 3:stride, 4:src, 5:delta, +; 6-7:tmp, 8-11:m_tmp ; Convert and store internal buffer (with delta array) in the result buffer ;------------------------------------------------------------------------------ @@ -549,8 +482,8 @@ %endmacro ;------------------------------------------------------------------------------ -; GET_RES_ADDR dst -; CALC_RES_ADDR tile_order, dst/index, tmp, [skip_calc] +; GET_RES_ADDR 1:dst +; CALC_RES_ADDR 1:tile_order, 2:dst/index, 3:tmp, 4:[skip_calc] ; Calculate position of line in the internal buffer ;------------------------------------------------------------------------------ @@ -577,7 +510,7 @@ %endmacro ;------------------------------------------------------------------------------ -; FILL_GENERIC_TILE tile_order, suffix +; FILL_GENERIC_TILE 1:tile_order, 2:suffix ; void fill_generic_tile%2(uint8_t *buf, ptrdiff_t stride, ; const struct segment *line, size_t n_lines, ; int winding); diff -Nru libass-0.12.2/libass/x86/rasterizer.h libass-0.13.0/libass/x86/rasterizer.h --- libass-0.12.2/libass/x86/rasterizer.h 2015-03-06 12:23:04.000000000 +0000 +++ libass-0.13.0/libass/x86/rasterizer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2014 Vabishchevich Nikolay - * - * 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 X86_RASTERIZER_H -#define X86_RASTERIZER_H - -#include -#include - - -struct segment; - -void ass_fill_solid_tile16_sse2(uint8_t *buf, ptrdiff_t stride, int set); -void ass_fill_solid_tile32_sse2(uint8_t *buf, ptrdiff_t stride, int set); -void ass_fill_halfplane_tile16_sse2(uint8_t *buf, ptrdiff_t stride, - int32_t a, int32_t b, int64_t c, int32_t scale); -void ass_fill_halfplane_tile32_sse2(uint8_t *buf, ptrdiff_t stride, - int32_t a, int32_t b, int64_t c, int32_t scale); -void ass_fill_generic_tile16_sse2(uint8_t *buf, ptrdiff_t stride, - const struct segment *line, size_t n_lines, - int winding); -void ass_fill_generic_tile32_sse2(uint8_t *buf, ptrdiff_t stride, - const struct segment *line, size_t n_lines, - int winding); - -void ass_fill_solid_tile16_avx2(uint8_t *buf, ptrdiff_t stride, int set); -void ass_fill_solid_tile32_avx2(uint8_t *buf, ptrdiff_t stride, int set); -void ass_fill_halfplane_tile16_avx2(uint8_t *buf, ptrdiff_t stride, - int32_t a, int32_t b, int64_t c, int32_t scale); -void ass_fill_halfplane_tile32_avx2(uint8_t *buf, ptrdiff_t stride, - int32_t a, int32_t b, int64_t c, int32_t scale); -void ass_fill_generic_tile16_avx2(uint8_t *buf, ptrdiff_t stride, - const struct segment *line, size_t n_lines, - int winding); -void ass_fill_generic_tile32_avx2(uint8_t *buf, ptrdiff_t stride, - const struct segment *line, size_t n_lines, - int winding); - - -#endif /* X86_RASTERIZER_H */ - diff -Nru libass-0.12.2/libass/x86/utils.asm libass-0.13.0/libass/x86/utils.asm --- libass-0.12.2/libass/x86/utils.asm 1970-01-01 00:00:00.000000000 +0000 +++ libass-0.13.0/libass/x86/utils.asm 2015-07-07 18:25:48.000000000 +0000 @@ -0,0 +1,86 @@ +;****************************************************************************** +;* utils.asm: helper macros +;****************************************************************************** +;* Copyright (C) 2014 Vabishchevich Nikolay +;* +;* 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. +;****************************************************************************** + +%define PIC +%include "x86inc.asm" + +;------------------------------------------------------------------------------ +; MUL 1:reg, 2:num +; Multiply by constant +;------------------------------------------------------------------------------ + +%macro MUL 2 +%if (%2) == 0 + xor %1, %1 +%elif (%2) == 1 +%elif (%2) == 2 + add %1, %1 ; lea %1, [%1 + %1] +%elif (%2) == 3 + lea %1, [%1 + 2 * %1] +%elif (%2) == 4 + lea %1, [4 * %1] ; shl %1, 2 +%elif (%2) == 5 + lea %1, [%1 + 4 * %1] +%elif (%2) == 8 + lea %1, [8 * %1] ; shl %1, 3 +%elif (%2) == 9 + lea %1, [%1 + 8 * %1] +%elif (%2) == 16 + shl %1, 4 +%elif (%2) == 32 + shl %1, 5 +%elif (%2) == 64 + shl %1, 6 +%elif (%2) == 128 + shl %1, 7 +%elif (%2) == 256 + shl %1, 8 +%else + imul %1, %2 +%endif +%endmacro + +;------------------------------------------------------------------------------ +; BCASTW 1:m_dst, 2:r_src +;------------------------------------------------------------------------------ + +%macro BCASTW 2 + movd xm%1, %2 +%if mmsize == 32 + vpbroadcastw m%1, xm%1 +%elif mmsize == 16 + punpcklwd m%1, m%1 + pshufd m%1, m%1, q0000 +%endif +%endmacro + +;------------------------------------------------------------------------------ +; PABSW 1:m_reg, 2:m_tmp +;------------------------------------------------------------------------------ + +%macro PABSW 2 +%if cpuflag(ssse3) + pabsw m%1, m%1 +%else + pxor m%2, m%2 + psubw m%2, m%1 + pmaxsw m%1, m%2 +%endif +%endmacro diff -Nru libass-0.12.2/Makefile.in libass-0.13.0/Makefile.in --- libass-0.12.2/Makefile.in 2015-05-07 19:47:27.000000000 +0000 +++ libass-0.13.0/Makefile.in 2015-10-03 18:20:38.000000000 +0000 @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -15,7 +15,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -79,10 +89,6 @@ build_triplet = @build@ host_triplet = @host@ subdir = . -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/configure $(am__configure_deps) \ - $(srcdir)/config.h.in $(srcdir)/libass.pc.in COPYING compile \ - config.guess config.sub depcomp install-sh missing ltmain.sh ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ @@ -90,6 +96,8 @@ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ + $(am__configure_deps) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d @@ -182,6 +190,9 @@ CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = libass test profile +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \ + $(srcdir)/libass.pc.in COPYING compile config.guess config.sub \ + depcomp install-sh ltmain.sh missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) @@ -252,8 +263,6 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ -ENCA_CFLAGS = @ENCA_CFLAGS@ -ENCA_LIBS = @ENCA_LIBS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@ @@ -354,6 +363,7 @@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -390,7 +400,6 @@ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -644,15 +653,15 @@ $(am__post_remove_distdir) dist-tarZ: distdir - @echo WARNING: "Support for shar distribution archives is" \ - "deprecated." >&2 + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir - @echo WARNING: "Support for distribution archives compressed with" \ - "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) @@ -688,17 +697,17 @@ esac chmod -R a-w $(distdir) chmod u+w $(distdir) - mkdir $(distdir)/_build $(distdir)/_inst + mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ - && $(am__cd) $(distdir)/_build \ - && ../configure \ + && $(am__cd) $(distdir)/_build/sub \ + && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ - --srcdir=.. --prefix="$$dc_install_base" \ + --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ @@ -878,6 +887,8 @@ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-pkgconfigDATA +.PRECIOUS: Makefile + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff -Nru libass-0.12.2/missing libass-0.13.0/missing --- libass-0.12.2/missing 2015-05-07 19:47:27.000000000 +0000 +++ libass-0.13.0/missing 2015-09-07 12:54:15.000000000 +0000 @@ -3,7 +3,7 @@ scriptversion=2013-10-28.13; # UTC -# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify diff -Nru libass-0.12.2/profile/Makefile.in libass-0.13.0/profile/Makefile.in --- libass-0.12.2/profile/Makefile.in 2015-05-07 19:47:27.000000000 +0000 +++ libass-0.13.0/profile/Makefile.in 2015-10-03 18:20:38.000000000 +0000 @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -15,7 +15,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -80,8 +90,6 @@ host_triplet = @host@ noinst_PROGRAMS = profile$(EXEEXT) subdir = profile -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ @@ -89,6 +97,7 @@ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -164,6 +173,7 @@ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ @@ -193,8 +203,6 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ -ENCA_CFLAGS = @ENCA_CFLAGS@ -ENCA_LIBS = @ENCA_LIBS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@ @@ -295,6 +303,7 @@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -322,10 +331,9 @@ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu profile/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign profile/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu profile/Makefile -.PRECIOUS: Makefile + $(AUTOMAKE) --foreign profile/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -609,6 +617,8 @@ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am +.PRECIOUS: Makefile + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff -Nru libass-0.12.2/test/Makefile.in libass-0.13.0/test/Makefile.in --- libass-0.12.2/test/Makefile.in 2015-05-07 19:47:27.000000000 +0000 +++ libass-0.13.0/test/Makefile.in 2015-10-03 18:20:38.000000000 +0000 @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -15,7 +15,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -80,8 +90,6 @@ host_triplet = @host@ noinst_PROGRAMS = test$(EXEEXT) subdir = test -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ @@ -89,6 +97,7 @@ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -164,6 +173,7 @@ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ @@ -193,8 +203,6 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ -ENCA_CFLAGS = @ENCA_CFLAGS@ -ENCA_LIBS = @ENCA_LIBS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@ @@ -295,6 +303,7 @@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -322,10 +331,9 @@ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu test/Makefile -.PRECIOUS: Makefile + $(AUTOMAKE) --foreign test/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -609,6 +617,8 @@ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am +.PRECIOUS: Makefile + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff -Nru libass-0.12.2/test/test.c libass-0.13.0/test/test.c --- libass-0.12.2/test/test.c 2014-08-14 02:11:03.000000000 +0000 +++ libass-0.13.0/test/test.c 2015-09-07 09:44:16.000000000 +0000 @@ -107,7 +107,8 @@ } ass_set_frame_size(ass_renderer, frame_w, frame_h); - ass_set_fonts(ass_renderer, NULL, "Sans", 1, NULL, 1); + ass_set_fonts(ass_renderer, NULL, "sans-serif", + ASS_FONTPROVIDER_AUTODETECT, NULL, 1); } static image_t *gen_image(int width, int height) @@ -165,6 +166,28 @@ printf("%d images blended\n", cnt); } +char *font_provider_labels[] = { + [ASS_FONTPROVIDER_NONE] = "None", + [ASS_FONTPROVIDER_AUTODETECT] = "Autodetect", + [ASS_FONTPROVIDER_CORETEXT] = "CoreText", + [ASS_FONTPROVIDER_FONTCONFIG] = "Fontconfig", + [ASS_FONTPROVIDER_DIRECTWRITE]= "DirectWrite", +}; + +static void print_font_providers(ASS_Library *ass_library) +{ + int i; + ASS_DefaultFontProvider *providers; + size_t providers_size = 0; + ass_get_available_font_providers(ass_library, &providers, &providers_size); + printf("test.c: Available font providers (%zu): ", providers_size); + for (i = 0; i < providers_size; i++) { + const char *separator = i > 0 ? ", ": ""; + printf("%s'%s'", separator, font_provider_labels[providers[i]]); + } + printf(".\n"); +} + int main(int argc, char *argv[]) { const int frame_w = 1280; @@ -178,6 +201,8 @@ char *subfile = argv[2]; double tm = strtod(argv[3], 0); + print_font_providers(ass_library); + init(frame_w, frame_h); ASS_Track *track = ass_read_file(ass_library, subfile, NULL); if (!track) {