diff -Nru libass-0.13.7/aclocal.m4 libass-0.14.0/aclocal.m4 --- libass-0.13.7/aclocal.m4 2017-06-03 17:05:59.000000000 +0000 +++ libass-0.14.0/aclocal.m4 2017-10-31 12:56:55.000000000 +0000 @@ -20,9 +20,9 @@ If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) -dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- -dnl serial 11 (pkg-config-0.29.1) -dnl +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# serial 12 (pkg-config-0.29.2) + dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson dnl @@ -63,7 +63,7 @@ dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], -[m4_define([PKG_MACROS_VERSION], [0.29.1]) +[m4_define([PKG_MACROS_VERSION], [0.29.2]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ @@ -164,7 +164,7 @@ AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no -AC_MSG_CHECKING([for $1]) +AC_MSG_CHECKING([for $2]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) @@ -174,11 +174,11 @@ See the pkg-config man page for more details.]) if test $pkg_failed = yes; then - AC_MSG_RESULT([no]) + AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` - else + else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs @@ -195,7 +195,7 @@ _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then - AC_MSG_RESULT([no]) + AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [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 diff -Nru libass-0.13.7/Changelog libass-0.14.0/Changelog --- libass-0.13.7/Changelog 2017-06-03 16:51:35.000000000 +0000 +++ libass-0.14.0/Changelog 2017-10-31 12:55:50.000000000 +0000 @@ -1,3 +1,13 @@ +libass (0.14.0) + * Brand new, faster and better outline stroker (replaces FreeType stroker) + * Remove option to use the FreeType rasterizer + * Fix spots of missing border around self-intersecting shapes + * Switch from Yasm to NASM for building hand-written assembler code + * Support Core Text font provider on Mac OS X 10.6 and 10.7 + * Clear font cache in ass_set_fonts(). This fixes potentially incorrect + font choices and an occasional crash if this function is called midway + through rendering a file. + libass (0.13.7) * Fix invalid memory accesses with BorderStyle=4 * Fix change detection bug on frame resizes diff -Nru libass-0.13.7/config.guess libass-0.14.0/config.guess --- libass-0.13.7/config.guess 2017-06-03 17:06:00.000000000 +0000 +++ libass-0.14.0/config.guess 2017-10-31 12:56:57.000000000 +0000 @@ -1,8 +1,8 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2015 Free Software Foundation, Inc. +# Copyright 1992-2014 Free Software Foundation, Inc. -timestamp='2015-08-20' +timestamp='2014-11-04' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -50,7 +50,7 @@ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2015 Free Software Foundation, Inc. +Copyright 1992-2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -168,27 +168,20 @@ # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ - /sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || \ - echo unknown)` + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; - earmv*) - arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` - endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` - machine=${arch}${endian}-unknown - ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in - arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax) + arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ @@ -204,13 +197,6 @@ os=netbsd ;; esac - # Determine ABI tags. - case "${UNAME_MACHINE_ARCH}" in - earm*) - expr='s/^earmv[0-9]/-eabi/;s/eb$//' - abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` - ;; - esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need @@ -221,13 +207,13 @@ release='-gnu' ;; *) - release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}${abi}" + echo "${machine}-${os}${release}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` @@ -249,9 +235,6 @@ *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; - *:Sortix:*:*) - echo ${UNAME_MACHINE}-unknown-sortix - exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) @@ -950,9 +933,6 @@ crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; - e2k:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; @@ -1041,7 +1021,7 @@ echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) - echo ${UNAME_MACHINE}-pc-linux-${LIBC} + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} diff -Nru libass-0.13.7/config.h.in libass-0.14.0/config.h.in --- libass-0.13.7/config.h.in 2017-06-03 17:06:00.000000000 +0000 +++ libass-0.14.0/config.h.in 2017-10-31 12:56:57.000000000 +0000 @@ -3,7 +3,7 @@ /* ASM enabled */ #undef CONFIG_ASM -/* found CoreText in System library */ +/* found CoreText framework */ #undef CONFIG_CORETEXT /* found DirectWrite */ @@ -30,9 +30,6 @@ /* found libpng via pkg-config */ #undef CONFIG_LIBPNG -/* rasterizer enabled */ -#undef CONFIG_RASTERIZER - /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H diff -Nru libass-0.13.7/config.sub libass-0.14.0/config.sub --- libass-0.13.7/config.sub 2017-06-03 17:06:00.000000000 +0000 +++ libass-0.14.0/config.sub 2017-10-31 12:56:57.000000000 +0000 @@ -1,8 +1,8 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2015 Free Software Foundation, Inc. +# Copyright 1992-2014 Free Software Foundation, Inc. -timestamp='2015-08-20' +timestamp='2014-12-03' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -68,7 +68,7 @@ version="\ GNU config.sub ($timestamp) -Copyright 1992-2015 Free Software Foundation, Inc. +Copyright 1992-2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -117,7 +117,7 @@ case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os @@ -255,13 +255,12 @@ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ - | ba \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ - | e2k | epiphany \ - | fido | fr30 | frv | ft32 \ + | epiphany \ + | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ @@ -306,7 +305,7 @@ | riscv32 | riscv64 \ | rl78 | rx \ | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ @@ -377,13 +376,12 @@ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ - | ba-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ - | e2k-* | elxsi-* \ + | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ @@ -430,13 +428,12 @@ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ - | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ @@ -521,9 +518,6 @@ basic_machine=i386-pc os=-aros ;; - asmjs) - basic_machine=asmjs-unknown - ;; aux) basic_machine=m68k-apple os=-aux @@ -1379,7 +1373,7 @@ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* | -cloudabi* | -sortix* \ + | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ diff -Nru libass-0.13.7/configure libass-0.14.0/configure --- libass-0.13.7/configure 2017-06-03 17:06:00.000000000 +0000 +++ libass-0.14.0/configure 2017-10-31 12:56:56.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.13.7. +# Generated by GNU Autoconf 2.69 for libass 0.14.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.13.7' -PACKAGE_STRING='libass 0.13.7' +PACKAGE_VERSION='0.14.0' +PACKAGE_STRING='libass 0.14.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -649,6 +649,8 @@ DIRECTWRITE_TRUE CORETEXT_FALSE CORETEXT_TRUE +FONTCONFIG_FALSE +FONTCONFIG_TRUE FONTCONFIG_LIBS FONTCONFIG_CFLAGS FRIBIDI_LIBS @@ -660,8 +662,6 @@ PKG_CONFIG ENABLE_LARGE_TILES_FALSE ENABLE_LARGE_TILES_TRUE -RASTERIZER_FALSE -RASTERIZER_TRUE X64_FALSE X64_TRUE X86_FALSE @@ -672,7 +672,7 @@ ASM_TRUE AS ASFLAGS -yasm_check +nasm_check am__fastdepCCAS_FALSE am__fastdepCCAS_TRUE CCASDEPMODE @@ -772,7 +772,6 @@ docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -813,7 +812,6 @@ enable_require_system_font_provider enable_harfbuzz enable_asm -enable_rasterizer enable_large_tiles ' ac_precious_vars='build_alias @@ -879,7 +877,6 @@ sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1132,15 +1129,6 @@ | -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=* \ @@ -1278,7 +1266,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 runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1391,7 +1379,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.13.7 to adapt to many kinds of systems. +\`configure' configures libass 0.14.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1431,7 +1419,6 @@ --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] @@ -1462,7 +1449,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of libass 0.13.7:";; + short | recursive ) echo "Configuration of libass 0.14.0:";; esac cat <<\_ACEOF @@ -1492,7 +1479,6 @@ 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] --enable-large-tiles use larger tiles in the rasterizer (better performance, slightly worse quality) [default=disabled] @@ -1613,7 +1599,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -libass configure 0.13.7 +libass configure 0.14.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2032,7 +2018,7 @@ 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.13.7, which was +It was created by libass $as_me 0.14.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2895,7 +2881,7 @@ # Define the identity of the package. PACKAGE='libass' - VERSION='0.13.7' + VERSION='0.14.0' cat >>confdefs.h <<_ACEOF @@ -5339,7 +5325,7 @@ lt_cv_deplibs_check_method=pass_all ;; -netbsd* | netbsdelf*-gnu) +netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else @@ -9032,9 +9018,6 @@ openbsd* | bitrig*) with_gnu_ld=no ;; - linux* | k*bsd*-gnu | gnu*) - link_all_deplibs=no - ;; esac ld_shlibs=yes @@ -9289,7 +9272,7 @@ fi ;; - netbsd* | netbsdelf*-gnu) + netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= @@ -9959,7 +9942,6 @@ if test yes = "$lt_cv_irix_exported_symbol"; then archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' fi - link_all_deplibs=no else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' @@ -9981,7 +9963,7 @@ esac ;; - netbsd* | netbsdelf*-gnu) + netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else @@ -11096,18 +11078,6 @@ dynamic_linker='GNU/Linux ld.so' ;; -netbsdelf*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='NetBSD ld.elf_so' - ;; - netbsd*) version_type=sunos need_lib_prefix=no @@ -13558,11 +13528,6 @@ enableval=$enable_asm; fi -# Check whether --enable-rasterizer was given. -if test "${enable_rasterizer+set}" = set; then : - enableval=$enable_rasterizer; -fi - # Check whether --enable-large-tiles was given. if test "${enable_large_tiles+set}" = set; then : enableval=$enable_large_tiles; @@ -13575,47 +13540,27 @@ i?86-*) : INTEL=true - AS=yasm + AS=nasm X86=true BITS=32 - ASFLAGS="$ASFLAGS -DARCH_X86_64=0 -m x86" ;; #( + BITTYPE=32 + ASFLAGS="$ASFLAGS -DARCH_X86_64=0" ;; #( x86_64-*-gnux32|amd64-*-gnux32) : - AS=yasm + AS=nasm INTEL=true X64=true BITS=64 - ASFLAGS="$ASFLAGS -DARCH_X86_64=1 -m x32" ;; #( + BITTYPE=x32 + ASFLAGS="$ASFLAGS -DARCH_X86_64=1 -DPIC" ;; #( x86_64-*|amd64-*) : - AS=yasm + AS=nasm INTEL=true X64=true BITS=64 - ASFLAGS="$ASFLAGS -DARCH_X86_64=1 -m amd64" ;; #( - *) : - ;; -esac - case $host in #( - *darwin*) : - - ASFLAGS="$ASFLAGS -f macho$BITS -DPREFIX -DHAVE_ALIGNED_STACK=1" ;; #( - *linux*|*dragonfly*|*bsd*|*solaris*) : - - ASFLAGS="$ASFLAGS -f elf -DHAVE_ALIGNED_STACK=1" ;; #( - *cygwin*|*mingw*) : - - ASFLAGS="$ASFLAGS -f win$BITS" - if test x$BITS = x64; then : - - ASFLAGS="$ASFLAGS -DHAVE_ALIGNED_STACK=1" - -else - - ASFLAGS="$ASFLAGS -DHAVE_ALIGNED_STACK=0 -DPREFIX" - -fi - ;; #( + BITTYPE=64 + ASFLAGS="$ASFLAGS -DARCH_X86_64=1 -DPIC" ;; #( *) : ;; esac @@ -13625,11 +13570,11 @@ set dummy $AS; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_yasm_check+:} false; then : +if ${ac_cv_prog_nasm_check+:} false; then : $as_echo_n "(cached) " >&6 else - if test -n "$yasm_check"; then - ac_cv_prog_yasm_check="$yasm_check" # Let the user override the test. + if test -n "$nasm_check"; then + ac_cv_prog_nasm_check="$nasm_check" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH @@ -13638,7 +13583,7 @@ test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_yasm_check="yes" + ac_cv_prog_nasm_check="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi @@ -13648,26 +13593,50 @@ fi fi -yasm_check=$ac_cv_prog_yasm_check -if test -n "$yasm_check"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $yasm_check" >&5 -$as_echo "$yasm_check" >&6; } +nasm_check=$ac_cv_prog_nasm_check +if test -n "$nasm_check"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $nasm_check" >&5 +$as_echo "$nasm_check" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi - if test x$yasm_check != xyes; then : + if test x$nasm_check != xyes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: yasm was not found; ASM functions are disabled." >&5 -$as_echo "$as_me: WARNING: yasm was not found; ASM functions are disabled." >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Install yasm for a significantly faster libass build." >&5 -$as_echo "$as_me: WARNING: Install yasm for a significantly faster libass build." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: nasm was not found; ASM functions are disabled." >&5 +$as_echo "$as_me: WARNING: nasm was not found; ASM functions are disabled." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Install nasm for a significantly faster libass build." >&5 +$as_echo "$as_me: WARNING: Install nasm for a significantly faster libass build." >&2;} enable_asm=no else + case $host in #( + *darwin*) : + + ASFLAGS="$ASFLAGS -f macho$BITTYPE -DPREFIX -DHAVE_ALIGNED_STACK=1" ;; #( + *linux*|*dragonfly*|*bsd*|*solaris*) : + + ASFLAGS="$ASFLAGS -f elf$BITTYPE -DHAVE_ALIGNED_STACK=1" ;; #( + *cygwin*|*mingw*) : + + ASFLAGS="$ASFLAGS -f win$BITTYPE" + if test x$BITS = x64; then : + + ASFLAGS="$ASFLAGS -DHAVE_ALIGNED_STACK=1" + +else + + ASFLAGS="$ASFLAGS -DHAVE_ALIGNED_STACK=0 -DPREFIX" + +fi + ;; #( + *) : + ;; +esac + ASFLAGS="$ASFLAGS -DHAVE_CPUNOP=0 -Dprivate_prefix=ass" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $AS supports vpmovzxwd" >&5 $as_echo_n "checking if $AS supports vpmovzxwd... " >&6; } echo "vpmovzxwd ymm0, xmm0" > conftest.asm @@ -13681,10 +13650,10 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } VER=`($AS --version || echo no assembler) 2>/dev/null | head -n 1` - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: yasm is too old (found $VER); ASM functions are disabled." >&5 -$as_echo "$as_me: WARNING: yasm is too old (found $VER); ASM functions are disabled." >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Install yasm-1.2.0 or later for a significantly faster libass build." >&5 -$as_echo "$as_me: WARNING: Install yasm-1.2.0 or later for a significantly faster libass build." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: nasm is too old (found $VER); ASM functions are disabled." >&5 +$as_echo "$as_me: WARNING: nasm is too old (found $VER); ASM functions are disabled." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Install nasm-2.10 or later for a significantly faster libass build." >&5 +$as_echo "$as_me: WARNING: Install nasm-2.10 or later for a significantly faster libass build." >&2;} enable_asm=no fi @@ -13745,26 +13714,6 @@ fi - if test x$enable_rasterizer != xno; then - RASTERIZER_TRUE= - RASTERIZER_FALSE='#' -else - RASTERIZER_TRUE='#' - RASTERIZER_FALSE= -fi - - -if test -z "$RASTERIZER_TRUE"; then : - -$as_echo "#define CONFIG_RASTERIZER 1" >>confdefs.h - -else - -$as_echo "#define CONFIG_RASTERIZER 0" >>confdefs.h - - -fi - if test x$enable_large_tiles = xyes; then ENABLE_LARGE_TILES_TRUE= ENABLE_LARGE_TILES_FALSE='#' @@ -13905,8 +13854,8 @@ fi pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for FREETYPE" >&5 -$as_echo_n "checking for FREETYPE... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype2 >= 9.10.3" >&5 +$as_echo_n "checking for freetype2 >= 9.10.3... " >&6; } if test -n "$FREETYPE_CFLAGS"; then pkg_cv_FREETYPE_CFLAGS="$FREETYPE_CFLAGS" @@ -13946,7 +13895,7 @@ if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -13973,7 +13922,7 @@ and FREETYPE_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $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;} @@ -14004,8 +13953,8 @@ pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for FRIBIDI" >&5 -$as_echo_n "checking for FRIBIDI... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fribidi >= 0.19.0" >&5 +$as_echo_n "checking for fribidi >= 0.19.0... " >&6; } if test -n "$FRIBIDI_CFLAGS"; then pkg_cv_FRIBIDI_CFLAGS="$FRIBIDI_CFLAGS" @@ -14045,7 +13994,7 @@ if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -14072,7 +14021,7 @@ and FRIBIDI_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $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;} @@ -14103,8 +14052,8 @@ if test x$enable_fontconfig != xno; then pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for FONTCONFIG" >&5 -$as_echo_n "checking for FONTCONFIG... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fontconfig >= 2.10.92" >&5 +$as_echo_n "checking for fontconfig >= 2.10.92... " >&6; } if test -n "$FONTCONFIG_CFLAGS"; then pkg_cv_FONTCONFIG_CFLAGS="$FONTCONFIG_CFLAGS" @@ -14144,7 +14093,7 @@ if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -14162,7 +14111,7 @@ fontconfig=false elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fontconfig=false else @@ -14180,30 +14129,37 @@ fi fi + if test x$fontconfig = xtrue; then + FONTCONFIG_TRUE= + FONTCONFIG_FALSE='#' +else + 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" +# Linking to CoreText directly only works from Mountain Lion and iOS. +# In earlier OS X releases CoreText was part of the ApplicationServices +# umbrella framework. { $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 + #include int main () { -CTFontCreateWithFontDescriptor(NULL, 0.0, NULL); +CTFontDescriptorCopyAttribute(NULL, kCTFontURLAttribute); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO"; then : + LIBS="$LIBS -framework ApplicationServices -framework CoreFoundation" $as_echo "#define CONFIG_CORETEXT 1" >>confdefs.h @@ -14213,14 +14169,40 @@ else - LIBS="$OLDLIBS" - coretext=false - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include +int +main () +{ +CTFontDescriptorCopyAttribute(NULL, kCTFontURLAttribute); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + LIBS="$LIBS -framework CoreText -framework CoreFoundation" + +$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 + + 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 +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test x$coretext = xtrue; then CORETEXT_TRUE= @@ -14281,8 +14263,8 @@ if test x$enable_harfbuzz != xno; then pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for HARFBUZZ" >&5 -$as_echo_n "checking for HARFBUZZ... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for harfbuzz >= 0.9.5" >&5 +$as_echo_n "checking for harfbuzz >= 0.9.5... " >&6; } if test -n "$HARFBUZZ_CFLAGS"; then pkg_cv_HARFBUZZ_CFLAGS="$HARFBUZZ_CFLAGS" @@ -14322,7 +14304,7 @@ if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -14340,7 +14322,7 @@ harfbuzz=false elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } harfbuzz=false else @@ -14363,8 +14345,8 @@ if test x$enable_test = xyes; then pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBPNG" >&5 -$as_echo_n "checking for LIBPNG... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libpng >= 1.2.0" >&5 +$as_echo_n "checking for libpng >= 1.2.0... " >&6; } if test -n "$LIBPNG_CFLAGS"; then pkg_cv_LIBPNG_CFLAGS="$LIBPNG_CFLAGS" @@ -14404,7 +14386,7 @@ if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -14431,7 +14413,7 @@ and LIBPNG_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $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;} @@ -14716,14 +14698,14 @@ as_fn_error $? "conditional \"X64\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${RASTERIZER_TRUE}" && test -z "${RASTERIZER_FALSE}"; then - as_fn_error $? "conditional \"RASTERIZER\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi if test -z "${ENABLE_LARGE_TILES_TRUE}" && test -z "${ENABLE_LARGE_TILES_FALSE}"; then 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 "${FONTCONFIG_TRUE}" && test -z "${FONTCONFIG_FALSE}"; then + as_fn_error $? "conditional \"FONTCONFIG\" 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 @@ -15137,7 +15119,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.13.7, which was +This file was extended by libass $as_me 0.14.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -15203,7 +15185,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.13.7 +libass config.status 0.14.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -Nru libass-0.13.7/configure.ac libass-0.14.0/configure.ac --- libass-0.13.7/configure.ac 2017-06-03 16:52:37.000000000 +0000 +++ libass-0.14.0/configure.ac 2017-10-31 12:55:50.000000000 +0000 @@ -1,4 +1,4 @@ -AC_INIT(libass, 0.13.7) +AC_INIT(libass, 0.14.0) AM_INIT_AUTOMAKE AC_CONFIG_MACRO_DIR([m4]) # Disable Fortran checks @@ -49,8 +49,6 @@ [disable HarfBuzz support @<:@default=check@:>@])) AC_ARG_ENABLE([asm], AS_HELP_STRING([--disable-asm], [disable compiling with ASM @<:@default=check@:>@])) -AC_ARG_ENABLE([rasterizer], AS_HELP_STRING([--disable-rasterizer], - [disable internal rasterizer @<:@default=enabled@:>@])) AC_ARG_ENABLE([large-tiles], AS_HELP_STRING([--enable-large-tiles], [use larger tiles in the rasterizer (better performance, slightly worse quality) @<:@default=disabled@:>@])) @@ -58,43 +56,47 @@ AS_CASE([$host], [i?86-*], [ INTEL=true - AS=yasm + AS=nasm X86=true BITS=32 - ASFLAGS="$ASFLAGS -DARCH_X86_64=0 -m x86" ], + BITTYPE=32 + ASFLAGS="$ASFLAGS -DARCH_X86_64=0" ], [x86_64-*-gnux32|amd64-*-gnux32], [ - AS=yasm + AS=nasm INTEL=true X64=true BITS=64 - ASFLAGS="$ASFLAGS -DARCH_X86_64=1 -m x32" ], + BITTYPE=x32 + ASFLAGS="$ASFLAGS -DARCH_X86_64=1 -DPIC" ], [x86_64-*|amd64-*], [ - AS=yasm + AS=nasm INTEL=true X64=true BITS=64 - ASFLAGS="$ASFLAGS -DARCH_X86_64=1 -m amd64" ], + BITTYPE=64 + ASFLAGS="$ASFLAGS -DARCH_X86_64=1 -DPIC" ], ) - AS_CASE([$host], - [*darwin*], [ - ASFLAGS="$ASFLAGS -f macho$BITS -DPREFIX -DHAVE_ALIGNED_STACK=1" ], - [*linux*|*dragonfly*|*bsd*|*solaris*], [ - ASFLAGS="$ASFLAGS -f elf -DHAVE_ALIGNED_STACK=1" ], - [*cygwin*|*mingw*], [ - ASFLAGS="$ASFLAGS -f win$BITS" - AS_IF([test x$BITS = x64], [ - ASFLAGS="$ASFLAGS -DHAVE_ALIGNED_STACK=1" - ], [ - ASFLAGS="$ASFLAGS -DHAVE_ALIGNED_STACK=0 -DPREFIX" - ]) - ]) AS_IF([test x$INTEL = xtrue], [ - AC_CHECK_PROG([yasm_check], [$AS], [yes]) - AS_IF([test x$yasm_check != xyes], [ - AC_MSG_WARN(yasm was not found; ASM functions are disabled.) - AC_MSG_WARN(Install yasm for a significantly faster libass build.) + AC_CHECK_PROG([nasm_check], [$AS], [yes]) + AS_IF([test x$nasm_check != xyes], [ + AC_MSG_WARN(nasm was not found; ASM functions are disabled.) + AC_MSG_WARN(Install nasm for a significantly faster libass build.) enable_asm=no ], [ + AS_CASE([$host], + [*darwin*], [ + ASFLAGS="$ASFLAGS -f macho$BITTYPE -DPREFIX -DHAVE_ALIGNED_STACK=1" ], + [*linux*|*dragonfly*|*bsd*|*solaris*], [ + ASFLAGS="$ASFLAGS -f elf$BITTYPE -DHAVE_ALIGNED_STACK=1" ], + [*cygwin*|*mingw*], [ + ASFLAGS="$ASFLAGS -f win$BITTYPE" + AS_IF([test x$BITS = x64], [ + ASFLAGS="$ASFLAGS -DHAVE_ALIGNED_STACK=1" + ], [ + ASFLAGS="$ASFLAGS -DHAVE_ALIGNED_STACK=0 -DPREFIX" + ]) + ]) + ASFLAGS="$ASFLAGS -DHAVE_CPUNOP=0 -Dprivate_prefix=ass" AC_MSG_CHECKING([if $AS supports vpmovzxwd]) echo "vpmovzxwd ymm0, xmm0" > conftest.asm AS_IF([$AS conftest.asm $ASFLAGS -o conftest.o >conftest.log 2>&1], [ @@ -102,8 +104,8 @@ ], [ AC_MSG_RESULT([no]) VER=`($AS --version || echo no assembler) 2>/dev/null | head -n 1` - AC_MSG_WARN([yasm is too old (found $VER); ASM functions are disabled.]) - AC_MSG_WARN([Install yasm-1.2.0 or later for a significantly faster libass build.]) + AC_MSG_WARN([nasm is too old (found $VER); ASM functions are disabled.]) + AC_MSG_WARN([Install nasm-2.10 or later for a significantly faster libass build.]) enable_asm=no ]) rm conftest.asm conftest.o > /dev/null 2>&1 @@ -124,13 +126,6 @@ [AC_DEFINE(CONFIG_ASM, 0, [ASM enabled])] ) -AM_CONDITIONAL([RASTERIZER], [test x$enable_rasterizer != xno]) - -AM_COND_IF([RASTERIZER], - [AC_DEFINE(CONFIG_RASTERIZER, 1, [rasterizer enabled])], - [AC_DEFINE(CONFIG_RASTERIZER, 0, [rasterizer enabled])] - ) - AM_CONDITIONAL([ENABLE_LARGE_TILES], [test x$enable_large_tiles = xyes]) AM_COND_IF([ENABLE_LARGE_TILES], @@ -159,26 +154,36 @@ fontconfig=true ], [fontconfig=false]) fi +AM_CONDITIONAL([FONTCONFIG], [test x$fontconfig = xtrue]) 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" +# Linking to CoreText directly only works from Mountain Lion and iOS. +# In earlier OS X releases CoreText was part of the ApplicationServices +# umbrella framework. AC_MSG_CHECKING([for CORETEXT]) -AC_LINK_IFELSE([ +AC_COMPILE_IFELSE([ AC_LANG_PROGRAM( - [[#include ]], - [[CTFontCreateWithFontDescriptor(NULL, 0.0, NULL);]],) + [[#include ]], + [[CTFontDescriptorCopyAttribute(NULL, kCTFontURLAttribute);]]) ], [ - AC_DEFINE(CONFIG_CORETEXT, 1, [found CoreText in System library]) + LIBS="$LIBS -framework ApplicationServices -framework CoreFoundation" + AC_DEFINE(CONFIG_CORETEXT, 1, [found CoreText in ApplicationServices framework]) coretext=true AC_MSG_RESULT([yes]) ], [ - LIBS="$OLDLIBS" - coretext=false - AC_MSG_RESULT([no]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM( + [[#include ]], + [[CTFontDescriptorCopyAttribute(NULL, kCTFontURLAttribute);]]) + ], [ + LIBS="$LIBS -framework CoreText -framework CoreFoundation" + AC_DEFINE(CONFIG_CORETEXT, 1, [found CoreText framework]) + coretext=true + AC_MSG_RESULT([yes]) + ], [ + coretext=false + AC_MSG_RESULT([no]) + ]) ]) fi AM_CONDITIONAL([CORETEXT], [test x$coretext = xtrue]) diff -Nru libass-0.13.7/debian/changelog libass-0.14.0/debian/changelog --- libass-0.13.7/debian/changelog 2017-06-26 07:50:21.000000000 +0000 +++ libass-0.14.0/debian/changelog 2017-11-06 20:00:00.000000000 +0000 @@ -1,3 +1,13 @@ +libass (1:0.14.0-1) unstable; urgency=medium + + * New upstream release. + * debian/control: + - Bump Standards-Version. + - Replace yasm with nasm. + * debian/: Bump debhelper compat to 10. + + -- Sebastian Ramacher Mon, 06 Nov 2017 21:00:00 +0100 + libass (1:0.13.7-2) unstable; urgency=medium * Upload to unstable. @@ -316,7 +326,7 @@ * New upstream version 0.9.7 + Closes: #538648 + API break. Target experimental for now - + SONAME bump + + SONAME bump + Update symbols file + Build system has been fixed no need of extra "-lm" + Reflect new home of the project (debian/{control,watch} @@ -348,7 +358,7 @@ libass (0.9.5-2) unstable; urgency=low - * Don't install .la files + * Don't install .la files -- Christophe Mutricy Thu, 06 Nov 2008 21:55:46 +0100 diff -Nru libass-0.13.7/debian/compat libass-0.14.0/debian/compat --- libass-0.13.7/debian/compat 2017-04-23 15:57:33.000000000 +0000 +++ libass-0.14.0/debian/compat 2017-11-06 19:56:54.000000000 +0000 @@ -1 +1 @@ -9 +10 diff -Nru libass-0.13.7/debian/control libass-0.14.0/debian/control --- libass-0.13.7/debian/control 2017-06-25 21:09:15.000000000 +0000 +++ libass-0.14.0/debian/control 2017-11-06 19:57:04.000000000 +0000 @@ -5,14 +5,13 @@ Christophe Mutricy , Sebastian Ramacher Build-Depends: - debhelper (>= 9), - dh-autoreconf, + debhelper (>= 10), libfontconfig1-dev, libfreetype6-dev, libfribidi-dev, libharfbuzz-dev, - yasm [any-amd64] -Standards-Version: 4.0.0 + nasm [any-amd64] +Standards-Version: 4.1.1 Section: libs Homepage: https://github.com/libass/libass Vcs-Git: https://anonscm.debian.org/git/pkg-multimedia/libass.git diff -Nru libass-0.13.7/debian/rules libass-0.14.0/debian/rules --- libass-0.13.7/debian/rules 2017-04-23 15:57:33.000000000 +0000 +++ libass-0.14.0/debian/rules 2017-11-06 19:57:09.000000000 +0000 @@ -4,7 +4,7 @@ export DEB_BUILD_MAINT_OPTIONS=hardening=+all %: - dh $@ --parallel --with autoreconf + dh $@ override_dh_auto_configure: dh_auto_configure -- \ diff -Nru libass-0.13.7/install-sh libass-0.14.0/install-sh --- libass-0.13.7/install-sh 2017-06-03 17:06:00.000000000 +0000 +++ libass-0.14.0/install-sh 2017-10-31 12:56:57.000000000 +0000 @@ -1,7 +1,7 @@ #!/bin/sh # install - install a program, script, or datafile -scriptversion=2014-09-12.12; # UTC +scriptversion=2013-12-25.23; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the @@ -324,41 +324,34 @@ # 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 + trap 'ret=$?; rmdir "$tmpdir/d" "$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 + 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. - test_tmpdir="$tmpdir/a" - ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + 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 -- "$test_tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + $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/a/b" "$tmpdir/a" "$tmpdir" + rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; diff -Nru libass-0.13.7/libass/ass_bitmap.c libass-0.14.0/libass/ass_bitmap.c --- libass-0.13.7/libass/ass_bitmap.c 2017-06-03 16:45:15.000000000 +0000 +++ libass-0.14.0/libass/ass_bitmap.c 2017-10-31 12:14:11.000000000 +0000 @@ -31,6 +31,7 @@ #include FT_OUTLINE_H #include "ass_utils.h" +#include "ass_outline.h" #include "ass_bitmap.h" #include "ass_render.h" @@ -185,35 +186,29 @@ return dst; } -#if CONFIG_RASTERIZER - Bitmap *outline_to_bitmap(ASS_Renderer *render_priv, - ASS_Outline *outline, int bord) + ASS_Outline *outline1, ASS_Outline *outline2, + int bord) { RasterizerData *rst = &render_priv->rasterizer; - if (!rasterizer_set_outline(rst, outline)) { + if (outline1 && !rasterizer_set_outline(rst, outline1, false)) { ass_msg(render_priv->library, MSGL_WARN, "Failed to process glyph outline!\n"); return NULL; } - - if (bord < 0 || bord > INT_MAX / 2) + if (outline2 && !rasterizer_set_outline(rst, outline2, !!outline1)) { + ass_msg(render_priv->library, MSGL_WARN, "Failed to process glyph outline!\n"); return NULL; - - if (rst->x_min >= rst->x_max || rst->y_min >= rst->y_max) { - Bitmap *bm = alloc_bitmap(render_priv->engine, 2 * bord, 2 * bord, true); - if (!bm) - return NULL; - bm->left = bm->top = -bord; - return bm; } - if (rst->x_max > INT_MAX - 63 || rst->y_max > INT_MAX - 63) + if (bord < 0 || bord > INT_MAX / 2) + return NULL; + if (rst->bbox.x_max > INT_MAX - 63 || rst->bbox.y_max > INT_MAX - 63) return NULL; - int x_min = rst->x_min >> 6; - int y_min = rst->y_min >> 6; - int x_max = (rst->x_max + 63) >> 6; - int y_max = (rst->y_max + 63) >> 6; + int x_min = rst->bbox.x_min >> 6; + int y_min = rst->bbox.y_min >> 6; + int x_max = (rst->bbox.x_max + 63) >> 6; + int y_max = (rst->bbox.y_max + 63) >> 6; int w = x_max - x_min; int h = y_max - y_min; @@ -245,109 +240,6 @@ return bm; } -#else - -static Bitmap *outline_to_bitmap_ft(ASS_Renderer *render_priv, - FT_Outline *outline, int bord) -{ - Bitmap *bm; - int w, h; - int error; - FT_BBox bbox; - FT_Bitmap bitmap; - - FT_Outline_Get_CBox(outline, &bbox); - if (bbox.xMin >= bbox.xMax || bbox.yMin >= bbox.yMax) { - bm = alloc_bitmap(render_priv->engine, 2 * bord, 2 * bord, true); - if (!bm) - return NULL; - bm->left = bm->top = -bord; - return bm; - } - - // move glyph to origin (0, 0) - bbox.xMin &= ~63; - bbox.yMin &= ~63; - FT_Outline_Translate(outline, -bbox.xMin, -bbox.yMin); - if (bbox.xMax > INT_MAX - 63 || bbox.yMax > INT_MAX - 63) - return NULL; - // bitmap size - bbox.xMax = (bbox.xMax + 63) & ~63; - bbox.yMax = (bbox.yMax + 63) & ~63; - w = (bbox.xMax - bbox.xMin) >> 6; - h = (bbox.yMax - bbox.yMin) >> 6; - // pen offset - bbox.xMin >>= 6; - bbox.yMax >>= 6; - - if (w < 0 || h < 0 || - w > INT_MAX - 2 * bord || h > INT_MAX - 2 * bord) { - ass_msg(render_priv->library, MSGL_WARN, "Glyph bounding box too large: %dx%dpx", - w, h); - return NULL; - } - - // allocate and set up bitmap - bm = alloc_bitmap(render_priv->engine, w + 2 * bord, h + 2 * bord, true); - if (!bm) - return NULL; - bm->left = bbox.xMin - bord; - bm->top = -bbox.yMax - bord; - bitmap.width = w; - bitmap.rows = h; - bitmap.pitch = bm->stride; - bitmap.buffer = bm->buffer + bord + bm->stride * bord; - bitmap.num_grays = 256; - bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; - - // render into target bitmap - if ((error = FT_Outline_Get_Bitmap(render_priv->ftlibrary, outline, &bitmap))) { - ass_msg(render_priv->library, MSGL_WARN, "Failed to rasterize glyph: %d\n", error); - ass_free_bitmap(bm); - return NULL; - } - - return bm; -} - -Bitmap *outline_to_bitmap(ASS_Renderer *render_priv, - ASS_Outline *outline, int bord) -{ - size_t n_points = outline->n_points; - if (n_points > SHRT_MAX) { - ass_msg(render_priv->library, MSGL_WARN, "Too many outline points: %d", - outline->n_points); - n_points = SHRT_MAX; - } - - size_t n_contours = FFMIN(outline->n_contours, SHRT_MAX); - short contours_small[EFFICIENT_CONTOUR_COUNT]; - short *contours = contours_small; - short *contours_large = NULL; - if (n_contours > EFFICIENT_CONTOUR_COUNT) { - contours_large = malloc(n_contours * sizeof(short)); - if (!contours_large) - return NULL; - contours = contours_large; - } - for (size_t i = 0; i < n_contours; ++i) - contours[i] = FFMIN(outline->contours[i], n_points - 1); - - FT_Outline ftol; - ftol.n_points = n_points; - ftol.n_contours = n_contours; - ftol.points = outline->points; - ftol.tags = outline->tags; - ftol.contours = contours; - ftol.flags = 0; - - Bitmap *bm = outline_to_bitmap_ft(render_priv, &ftol, bord); - free(contours_large); - return bm; -} - -#endif - /** * \brief fix outline bitmap * @@ -542,27 +434,34 @@ 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) +bool outline_to_bitmap2(ASS_Renderer *render_priv, ASS_Outline *outline, + ASS_Outline *border1, ASS_Outline *border2, + Bitmap **bm_g, Bitmap **bm_o) { assert(bm_g && bm_o); - *bm_g = *bm_o = NULL; - if (outline) - *bm_g = outline_to_bitmap(render_priv, outline, 1); - if (!*bm_g) - return 1; + if (outline && !outline->n_points) + outline = NULL; + if (border1 && !border1->n_points) + border1 = NULL; + if (border2 && !border2->n_points) + border2 = NULL; + + if (outline) { + *bm_g = outline_to_bitmap(render_priv, outline, NULL, 1); + if (!*bm_g) + return false; + } - if (border) { - *bm_o = outline_to_bitmap(render_priv, border, 1); + if (border1 || border2) { + *bm_o = outline_to_bitmap(render_priv, border1, border2, 1); if (!*bm_o) { - return 1; + return false; } } - return 0; + return true; } /** diff -Nru libass-0.13.7/libass/ass_bitmap.h libass-0.14.0/libass/ass_bitmap.h --- libass-0.13.7/libass/ass_bitmap.h 2016-09-24 18:48:27.000000000 +0000 +++ libass-0.14.0/libass/ass_bitmap.h 2017-10-31 12:14:11.000000000 +0000 @@ -24,6 +24,7 @@ #include FT_GLYPH_H #include "ass.h" +#include "ass_outline.h" struct segment; @@ -62,12 +63,10 @@ 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; @@ -91,16 +90,6 @@ typedef struct { - size_t n_contours, max_contours; - size_t *contours; - size_t n_points, max_points; - FT_Vector *points; - char *tags; -} ASS_Outline; - -#define EFFICIENT_CONTOUR_COUNT 8 - -typedef struct { int left, top; int w, h; // width, height int stride; @@ -113,7 +102,8 @@ void ass_free_bitmap(Bitmap *bm); Bitmap *outline_to_bitmap(ASS_Renderer *render_priv, - ASS_Outline *outline, int bord); + ASS_Outline *outline1, ASS_Outline *outline2, + int bord); void ass_synth_blur(const BitmapEngine *engine, int opaque_box, int be, double blur_radius, Bitmap *bm_g, Bitmap *bm_o); @@ -121,13 +111,14 @@ /** * \brief perform glyph rendering * \param outline original glyph - * \param border "border" glyph, produced from outline by FreeType's glyph stroker + * \param border1 inside "border" outline, produced by stroker + * \param border2 outside "border" outline, produced by stroker * \param bm_g out: pointer to the bitmap of original glyph is returned here * \param bm_o out: pointer to the bitmap of border glyph is returned here */ -int outline_to_bitmap2(ASS_Renderer *render_priv, - ASS_Outline *outline, ASS_Outline *border, - Bitmap **bm_g, Bitmap **bm_o); +bool outline_to_bitmap2(ASS_Renderer *render_priv, ASS_Outline *outline, + ASS_Outline *border1, ASS_Outline *border2, + Bitmap **bm_g, Bitmap **bm_o); int be_padding(int be); void be_blur_pre(uint8_t *buf, intptr_t w, diff -Nru libass-0.13.7/libass/ass_blur.c libass-0.14.0/libass/ass_blur.c --- libass-0.13.7/libass/ass_blur.c 2017-06-03 16:45:15.000000000 +0000 +++ libass-0.14.0/libass/ass_blur.c 2017-10-31 12:14:11.000000000 +0000 @@ -83,7 +83,7 @@ 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] = (uint16_t) (((src[x + k] << 7) | (src[x + k] >> 1)) + 1) >> 1; //ptr[k] = (0x4000 * src[x + k] + 127) / 255; ptr += STRIPE_WIDTH * height; } @@ -100,7 +100,7 @@ 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] = (uint16_t) (src[k] - (src[k] >> 8) + dither[k]) >> 6; //ptr[k] = (255 * src[k] + 0x1FFF) / 0x4000; ptr += dst_stride; src += STRIPE_WIDTH; @@ -197,9 +197,9 @@ *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; + 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, @@ -275,7 +275,7 @@ /* return (1 * p1 + 2 * z0 + 1 * n1 + 2) >> 2; */ - return (uint16_t)(((uint16_t)(p1 + n1) >> 1) + z0 + 1) >> 1; + return (uint16_t) (((uint16_t) (p1 + n1) >> 1) + z0 + 1) >> 1; } void ass_pre_blur1_horz_c(int16_t *dst, const int16_t *src, @@ -333,10 +333,10 @@ /* 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 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; + 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, @@ -396,10 +396,10 @@ /* 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; + 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, @@ -832,7 +832,7 @@ } for (int i = 1; i <= 4; ++i) - blur->coeff[i - 1] = (int)(0x10000 * mu[i] + 0.5); + blur->coeff[i - 1] = (int) (0x10000 * mu[i] + 0.5); } /** diff -Nru libass-0.13.7/libass/ass_cache.c libass-0.14.0/libass/ass_cache.c --- libass-0.13.7/libass/ass_cache.c 2016-09-24 18:48:19.000000000 +0000 +++ libass-0.14.0/libass/ass_cache.c 2017-10-31 12:14:11.000000000 +0000 @@ -27,6 +27,7 @@ #include "ass_utils.h" #include "ass_font.h" +#include "ass_outline.h" #include "ass_cache.h" // type-specific functions @@ -258,10 +259,9 @@ { OutlineHashValue *v = value; OutlineHashKey *k = key; - outline_free(v->outline); - free(v->outline); - outline_free(v->border); - free(v->border); + outline_free(&v->outline); + outline_free(&v->border[0]); + outline_free(&v->border[1]); switch (k->type) { case OUTLINE_GLYPH: ass_cache_dec_ref(k->u.glyph.font); break; case OUTLINE_DRAWING: free(k->u.drawing.text); break; diff -Nru libass-0.13.7/libass/ass_cache.h libass-0.14.0/libass/ass_cache.h --- libass-0.13.7/libass/ass_cache.h 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/ass_cache.h 2017-10-31 12:14:11.000000000 +0000 @@ -22,6 +22,7 @@ #include "ass.h" #include "ass_font.h" +#include "ass_outline.h" #include "ass_bitmap.h" typedef struct cache Cache; @@ -29,6 +30,7 @@ // cache values typedef struct { + bool valid; Bitmap *bm; // the actual bitmaps Bitmap *bm_o; } BitmapHashValue; @@ -40,10 +42,11 @@ } CompositeHashValue; typedef struct { - ASS_Outline *outline; - ASS_Outline *border; - FT_BBox bbox_scaled; // bbox after scaling, but before rotation - FT_Vector advance; // 26.6, advance distance to the next outline in line + bool valid; + ASS_Outline outline; + ASS_Outline border[2]; + ASS_Rect bbox_scaled; // bbox after scaling, but before rotation + ASS_Vector advance; // 26.6, advance distance to the next outline in line int asc, desc; // ascender/descender } OutlineHashValue; diff -Nru libass-0.13.7/libass/ass_cache_template.h libass-0.14.0/libass/ass_cache_template.h --- libass-0.13.7/libass/ass_cache_template.h 2017-06-03 16:45:15.000000000 +0000 +++ libass-0.14.0/libass/ass_cache_template.h 2017-10-31 12:14:11.000000000 +0000 @@ -6,8 +6,8 @@ type member; #define STRING(member) \ char *member; -#define FTVECTOR(member) \ - FT_Vector member; +#define VECTOR(member) \ + ASS_Vector member; #define BITMAPHASHKEY(member) \ BitmapHashKey member; #define END(typedefnamename) \ @@ -25,7 +25,7 @@ a->member == b->member && #define STRING(member) \ strcmp(a->member, b->member) == 0 && -#define FTVECTOR(member) \ +#define VECTOR(member) \ a->member.x == b->member.x && a->member.y == b->member.y && #define BITMAPHASHKEY(member) \ bitmap_compare(&a->member, &b->member, sizeof(a->member)) && @@ -44,7 +44,7 @@ hval = fnv_32a_buf(&p->member, sizeof(p->member), hval); #define STRING(member) \ hval = fnv_32a_str(p->member, hval); -#define FTVECTOR(member) GENERIC(, member.x); GENERIC(, member.y); +#define VECTOR(member) GENERIC(, member.x); GENERIC(, member.y); #define BITMAPHASHKEY(member) { \ unsigned temp = bitmap_hash(&p->member, sizeof(p->member)); \ hval = fnv_32a_buf(&temp, sizeof(temp), hval); \ @@ -72,7 +72,7 @@ // = (glyph base point) - (rotation origin), otherwise GENERIC(int, shift_x) GENERIC(int, shift_y) - FTVECTOR(advance) // subpixel shift vector + VECTOR(advance) // subpixel shift vector END(OutlineBitmapHashKey) // describe a clip mask bitmap @@ -90,7 +90,7 @@ GENERIC(int, italic) GENERIC(unsigned, scale_x) // 16.16 GENERIC(unsigned, scale_y) // 16.16 - FTVECTOR(outline) // border width, 26.6 + VECTOR(outline) // border width, 26.6 GENERIC(unsigned, flags) // glyph decoration flags GENERIC(unsigned, border_style) GENERIC(int, hspacing) // 16.16 @@ -110,7 +110,7 @@ GENERIC(unsigned, scale_x) GENERIC(unsigned, scale_y) GENERIC(int, pbo) - FTVECTOR(outline) + VECTOR(outline) GENERIC(unsigned, border_style) GENERIC(int, hspacing) GENERIC(int, scale) @@ -123,12 +123,12 @@ GENERIC(int, flags) GENERIC(int, be) GENERIC(double, blur) - FTVECTOR(shadow) + VECTOR(shadow) END(FilterDesc) #undef START #undef GENERIC #undef STRING -#undef FTVECTOR +#undef VECTOR #undef BITMAPHASHKEY #undef END diff -Nru libass-0.13.7/libass/ass_coretext.c libass-0.14.0/libass/ass_coretext.c --- libass-0.13.7/libass/ass_coretext.c 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/ass_coretext.c 2017-10-31 12:14:11.000000000 +0000 @@ -20,7 +20,12 @@ #include "ass_compat.h" #include +#include +#if TARGET_OS_IPHONE #include +#else +#include +#endif #include "ass_coretext.h" @@ -232,7 +237,7 @@ static void match_fonts(ASS_Library *lib, ASS_FontProvider *provider, char *name) { - const size_t attributes_n = 3; + enum { attributes_n = 3 }; CTFontDescriptorRef ctdescrs[attributes_n]; CFMutableDictionaryRef cfattrs[attributes_n]; CFStringRef attributes[attributes_n] = { diff -Nru libass-0.13.7/libass/ass_drawing.c libass-0.14.0/libass/ass_drawing.c --- libass-0.13.7/libass/ass_drawing.c 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/ass_drawing.c 2017-10-31 12:14:11.000000000 +0000 @@ -21,7 +21,6 @@ #include #include FT_OUTLINE_H -#include FT_BBOX_H #include #include #include @@ -30,50 +29,8 @@ #include "ass_drawing.h" #include "ass_font.h" -#define CURVE_ACCURACY 64.0 #define GLYPH_INITIAL_POINTS 100 -#define GLYPH_INITIAL_CONTOURS 5 - -/* - * \brief Add a single point to a contour. - */ -static inline bool drawing_add_point(ASS_Drawing *drawing, - const FT_Vector *point, char tags) -{ - ASS_Outline *ol = &drawing->outline; - if (ol->n_points >= ol->max_points) { - size_t new_size = 2 * ol->max_points; - if (!ASS_REALLOC_ARRAY(ol->points, new_size)) - return false; - if (!ASS_REALLOC_ARRAY(ol->tags, new_size)) - return false; - ol->max_points = new_size; - } - - ol->points[ol->n_points].x = point->x; - ol->points[ol->n_points].y = point->y; - ol->tags[ol->n_points] = tags; - ol->n_points++; - return true; -} - -/* - * \brief Close a contour and check outline size overflow. - */ -static inline bool drawing_close_shape(ASS_Drawing *drawing) -{ - ASS_Outline *ol = &drawing->outline; - if (ol->n_contours >= ol->max_contours) { - size_t new_size = 2 * ol->max_contours; - if (!ASS_REALLOC_ARRAY(ol->contours, new_size)) - return false; - ol->max_contours = new_size; - } - - ol->contours[ol->n_contours] = ol->n_points - 1; - ol->n_contours++; - return true; -} +#define GLYPH_INITIAL_SEGMENTS 100 /* * \brief Prepare drawing for parsing. This just sets a few parameters. @@ -89,30 +46,28 @@ * \brief Finish a drawing. This only sets the horizontal advance according * to the outline's bbox at the moment. */ -static void drawing_finish(ASS_Drawing *drawing, int raw_mode) +static void drawing_finish(ASS_Drawing *drawing, bool raw_mode) { - int i; - double pbo; - FT_BBox bbox = drawing->cbox; + ASS_Rect bbox = drawing->cbox; ASS_Outline *ol = &drawing->outline; if (drawing->library) ass_msg(drawing->library, MSGL_V, - "Parsed drawing with %d points and %d contours", ol->n_points, - ol->n_contours); + "Parsed drawing with %d points and %d segments", + ol->n_points, ol->n_segments); if (raw_mode) return; - drawing->advance.x = bbox.xMax - bbox.xMin; + drawing->advance.x = bbox.x_max - bbox.x_min; - pbo = drawing->pbo / (1 << (drawing->scale - 1)); + double pbo = drawing->pbo / (1 << (drawing->scale - 1)); drawing->desc = double_to_d6(pbo * drawing->scale_y); - drawing->asc = bbox.yMax - bbox.yMin - drawing->desc; + drawing->asc = bbox.y_max - bbox.y_min - drawing->desc; // Place it onto the baseline - for (i = 0; i < ol->n_points; i++) - ol->points[i].y += drawing->asc; + for (size_t i = 0; i < ol->n_points; i++) + ol->points[i].y -= drawing->asc; } /* @@ -120,8 +75,7 @@ */ static int token_check_values(ASS_DrawingToken *token, int i, int type) { - int j; - for (j = 0; j < i; j++) { + for (int j = 0; j < i; j++) { if (!token || token->type != type) return 0; token = token->next; } @@ -136,9 +90,9 @@ static ASS_DrawingToken *drawing_tokenize(char *str) { char *p = str; - int i, type = -1, is_set = 0; + int type = -1, is_set = 0; double val; - FT_Vector point = {0, 0}; + ASS_Vector point = {0, 0}; ASS_DrawingToken *root = NULL, *tail = NULL, *spline_start = NULL; @@ -148,7 +102,7 @@ // Close b-splines: add the first three points of the b-spline // back to the end if (token_check_values(spline_start->next, 2, TOKEN_B_SPLINE)) { - for (i = 0; i < 3; i++) { + for (int i = 0; i < 3; i++) { tail->next = calloc(1, sizeof(ASS_DrawingToken)); tail->next->prev = tail; tail = tail->next; @@ -220,40 +174,24 @@ } /* - * \brief Update drawing cbox - */ -static inline void update_cbox(ASS_Drawing *drawing, FT_Vector *point) -{ - FT_BBox *box = &drawing->cbox; - - box->xMin = FFMIN(box->xMin, point->x); - box->xMax = FFMAX(box->xMax, point->x); - box->yMin = FFMIN(box->yMin, point->y); - box->yMax = FFMAX(box->yMax, point->y); -} - -/* * \brief Translate and scale a point coordinate according to baseline * offset and scale. */ -static inline void translate_point(ASS_Drawing *drawing, FT_Vector *point) +static inline void translate_point(ASS_Drawing *drawing, ASS_Vector *point) { - point->x = drawing->point_scale_x * point->x; - point->y = drawing->point_scale_y * -point->y; + point->x = lrint(drawing->point_scale_x * point->x); + point->y = lrint(drawing->point_scale_y * point->y); - update_cbox(drawing, point); + rectangle_update(&drawing->cbox, point->x, point->y, point->x, point->y); } /* - * \brief Evaluate a curve into lines - * This curve evaluator is also used in VSFilter (RTS.cpp); it's a simple - * implementation of the De Casteljau algorithm. + * \brief Add curve to drawing */ -static bool drawing_evaluate_curve(ASS_Drawing *drawing, - ASS_DrawingToken *token, char spline, - int started) +static bool drawing_add_curve(ASS_Drawing *drawing, ASS_DrawingToken *token, + bool spline, int started) { - FT_Vector p[4]; + ASS_Vector p[4]; for (int i = 0; i < 4; ++i) { p[i] = token->point; translate_point(drawing, &p[i]); @@ -278,27 +216,27 @@ p[2].y -= y12; } - return (started || drawing_add_point(drawing, &p[0], FT_CURVE_TAG_ON)) && - drawing_add_point(drawing, &p[1], FT_CURVE_TAG_CUBIC) && - drawing_add_point(drawing, &p[2], FT_CURVE_TAG_CUBIC) && - drawing_add_point(drawing, &p[3], FT_CURVE_TAG_ON); + return (started || + outline_add_point(&drawing->outline, p[0], 0)) && + outline_add_point(&drawing->outline, p[1], 0) && + outline_add_point(&drawing->outline, p[2], 0) && + outline_add_point(&drawing->outline, p[3], OUTLINE_CUBIC_SPLINE); } /* * \brief Create and initialize a new drawing and return it */ -ASS_Drawing *ass_drawing_new(ASS_Library *lib, FT_Library ftlib) +ASS_Drawing *ass_drawing_new(ASS_Library *lib) { ASS_Drawing *drawing = calloc(1, sizeof(*drawing)); if (!drawing) return NULL; - drawing->cbox.xMin = drawing->cbox.yMin = INT_MAX; - drawing->cbox.xMax = drawing->cbox.yMax = INT_MIN; - drawing->library = lib; + rectangle_reset(&drawing->cbox); + drawing->library = lib; drawing->scale_x = 1.; drawing->scale_y = 1.; - if (!outline_alloc(&drawing->outline, GLYPH_INITIAL_POINTS, GLYPH_INITIAL_CONTOURS)) { + if (!outline_alloc(&drawing->outline, GLYPH_INITIAL_POINTS, GLYPH_INITIAL_SEGMENTS)) { free(drawing); return NULL; } @@ -308,7 +246,7 @@ /* * \brief Free a drawing */ -void ass_drawing_free(ASS_Drawing* drawing) +void ass_drawing_free(ASS_Drawing *drawing) { if (drawing) { free(drawing->text); @@ -320,7 +258,7 @@ /* * \brief Copy an ASCII string to the drawing text buffer */ -void ass_drawing_set_text(ASS_Drawing* drawing, char *str, size_t len) +void ass_drawing_set_text(ASS_Drawing *drawing, char *str, size_t len) { free(drawing->text); drawing->text = strndup(str, len); @@ -330,7 +268,7 @@ * \brief Create a hashcode for the drawing * XXX: To avoid collisions a better hash algorithm might be useful. */ -void ass_drawing_hash(ASS_Drawing* drawing) +void ass_drawing_hash(ASS_Drawing *drawing) { if (!drawing->text) return; @@ -340,11 +278,11 @@ /* * \brief Convert token list to outline. Calls the line and curve evaluators. */ -ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode) +ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, bool raw_mode) { - int started = 0; + bool started = false; ASS_DrawingToken *token; - FT_Vector pen = {0, 0}; + ASS_Vector pen = {0, 0}; drawing->tokens = drawing_tokenize(drawing->text); drawing_prepare(drawing); @@ -362,43 +300,44 @@ pen = token->point; translate_point(drawing, &pen); if (started) { - if (!drawing_close_shape(drawing)) + if (!outline_add_segment(&drawing->outline, OUTLINE_LINE_SEGMENT)) + goto error; + if (!outline_close_contour(&drawing->outline)) goto error; - started = 0; + started = false; } token = token->next; break; case TOKEN_LINE: { - FT_Vector to; - to = token->point; + ASS_Vector to = token->point; translate_point(drawing, &to); - if (!started && !drawing_add_point(drawing, &pen, FT_CURVE_TAG_ON)) + if (!started && !outline_add_point(&drawing->outline, pen, 0)) goto error; - if (!drawing_add_point(drawing, &to, FT_CURVE_TAG_ON)) + if (!outline_add_point(&drawing->outline, to, OUTLINE_LINE_SEGMENT)) goto error; - started = 1; + started = true; token = token->next; break; } case TOKEN_CUBIC_BEZIER: if (token_check_values(token, 3, TOKEN_CUBIC_BEZIER) && token->prev) { - if (!drawing_evaluate_curve(drawing, token->prev, 0, started)) + if (!drawing_add_curve(drawing, token->prev, false, started)) goto error; token = token->next; token = token->next; token = token->next; - started = 1; + started = true; } else token = token->next; break; case TOKEN_B_SPLINE: if (token_check_values(token, 3, TOKEN_B_SPLINE) && token->prev) { - if (!drawing_evaluate_curve(drawing, token->prev, 1, started)) + if (!drawing_add_curve(drawing, token->prev, true, started)) goto error; token = token->next; - started = 1; + started = true; } else token = token->next; break; @@ -409,8 +348,12 @@ } // Close the last contour - if (started && !drawing_close_shape(drawing)) - goto error; + if (started) { + if (!outline_add_segment(&drawing->outline, OUTLINE_LINE_SEGMENT)) + goto error; + if (!outline_close_contour(&drawing->outline)) + goto error; + } drawing_finish(drawing, raw_mode); drawing_free_tokens(drawing->tokens); diff -Nru libass-0.13.7/libass/ass_drawing.h libass-0.14.0/libass/ass_drawing.h --- libass-0.13.7/libass/ass_drawing.h 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/ass_drawing.h 2017-10-31 12:14:11.000000000 +0000 @@ -19,10 +19,8 @@ #ifndef LIBASS_DRAWING_H #define LIBASS_DRAWING_H -#include -#include FT_OUTLINE_H - #include "ass.h" +#include "ass_outline.h" #include "ass_bitmap.h" typedef enum { @@ -38,7 +36,7 @@ typedef struct ass_drawing_token { ASS_TokenType type; - FT_Vector point; + ASS_Vector point; struct ass_drawing_token *next; struct ass_drawing_token *prev; } ASS_DrawingToken; @@ -47,26 +45,26 @@ char *text; // drawing string int scale; // scale (1-64) for subpixel accuracy double pbo; // drawing will be shifted in y direction by this amount - double scale_x; // FontScaleX - double scale_y; // FontScaleY - int asc; // ascender - int desc; // descender + double scale_x; // FontScaleX + double scale_y; // FontScaleY + int asc; // ascender + int desc; // descender ASS_Outline outline; // target outline - FT_Vector advance; // advance (from cbox) - int hash; // hash value (for caching) + ASS_Vector advance; // advance (from cbox) + int hash; // hash value (for caching) // private ASS_Library *library; ASS_DrawingToken *tokens; // tokenized drawing double point_scale_x; double point_scale_y; - FT_BBox cbox; // bounding box, or let's say... VSFilter's idea of it + ASS_Rect cbox; // bounding box, or let's say... VSFilter's idea of it } ASS_Drawing; -ASS_Drawing *ass_drawing_new(ASS_Library *lib, FT_Library ftlib); -void ass_drawing_free(ASS_Drawing* drawing); -void ass_drawing_set_text(ASS_Drawing* drawing, char *str, size_t n); -void ass_drawing_hash(ASS_Drawing* drawing); -ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode); +ASS_Drawing *ass_drawing_new(ASS_Library *lib); +void ass_drawing_free(ASS_Drawing *drawing); +void ass_drawing_set_text(ASS_Drawing *drawing, char *str, size_t n); +void ass_drawing_hash(ASS_Drawing *drawing); +ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, bool raw_mode); #endif /* LIBASS_DRAWING_H */ diff -Nru libass-0.13.7/libass/ass_font.c libass-0.14.0/libass/ass_font.c --- libass-0.13.7/libass/ass_font.c 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/ass_font.c 2017-10-31 12:14:11.000000000 +0000 @@ -436,77 +436,6 @@ return 0; } - -int outline_alloc(ASS_Outline *outline, size_t n_points, size_t n_contours) -{ - outline->contours = malloc(sizeof(size_t) * n_contours); - outline->points = malloc(sizeof(FT_Vector) * n_points); - outline->tags = malloc(n_points); - if (!outline->contours || !outline->points || !outline->tags) - return 0; - - outline->max_contours = n_contours; - outline->max_points = n_points; - return 1; -} - -ASS_Outline *outline_convert(const FT_Outline *source) -{ - if (!source) - return NULL; - - ASS_Outline *ol = calloc(1, sizeof(*ol)); - if (!ol) - return NULL; - - if (!outline_alloc(ol, source->n_points, source->n_contours)) { - outline_free(ol); - free(ol); - return NULL; - } - - for (int i = 0; i < source->n_contours; ++i) - ol->contours[i] = source->contours[i]; - memcpy(ol->points, source->points, sizeof(FT_Vector) * source->n_points); - memcpy(ol->tags, source->tags, source->n_points); - ol->n_contours = source->n_contours; - ol->n_points = source->n_points; - return ol; -} - -ASS_Outline *outline_copy(const ASS_Outline *source) -{ - if (!source) - return NULL; - - ASS_Outline *ol = calloc(1, sizeof(*ol)); - if (!ol) - return NULL; - - if (!outline_alloc(ol, source->n_points, source->n_contours)) { - outline_free(ol); - free(ol); - return NULL; - } - - memcpy(ol->contours, source->contours, sizeof(size_t) * source->n_contours); - memcpy(ol->points, source->points, sizeof(FT_Vector) * source->n_points); - memcpy(ol->tags, source->tags, source->n_points); - ol->n_contours = source->n_contours; - ol->n_points = source->n_points; - return ol; -} - -void outline_free(ASS_Outline *outline) -{ - if (!outline) - return; - - free(outline->contours); - free(outline->points); - free(outline->tags); -} - /** * Slightly embold a glyph without touching its metrics */ @@ -693,183 +622,3 @@ } free(font->desc.family); } - -/** - * \brief Calculate the cbox of a series of points - */ -static void -get_contour_cbox(FT_BBox *box, FT_Vector *points, int start, int end) -{ - box->xMin = box->yMin = INT_MAX; - box->xMax = box->yMax = INT_MIN; - int i; - - for (i = start; i <= end; i++) { - box->xMin = (points[i].x < box->xMin) ? points[i].x : box->xMin; - box->xMax = (points[i].x > box->xMax) ? points[i].x : box->xMax; - box->yMin = (points[i].y < box->yMin) ? points[i].y : box->yMin; - box->yMax = (points[i].y > box->yMax) ? points[i].y : box->yMax; - } -} - -/** - * \brief Determine signed area of a contour - * \return area doubled - */ -static long long get_contour_area(FT_Vector *points, int start, int end) -{ - long long area = 0; - int x = points[end].x; - int y = points[end].y; - for (int i = start; i <= end; i++) { - area += (long long)(points[i].x + x) * (points[i].y - y); - x = points[i].x; - y = points[i].y; - } - return area; -} - -void outline_translate(const ASS_Outline *outline, FT_Pos dx, FT_Pos dy) -{ - for (size_t i = 0; i < outline->n_points; ++i) { - outline->points[i].x += dx; - outline->points[i].y += dy; - } -} - -void outline_transform(const ASS_Outline *outline, const FT_Matrix *matrix) -{ - for (size_t i = 0; i < outline->n_points; ++i) { - FT_Pos x = FT_MulFix(outline->points[i].x, matrix->xx) + - FT_MulFix(outline->points[i].y, matrix->xy); - FT_Pos y = FT_MulFix(outline->points[i].x, matrix->yx) + - FT_MulFix(outline->points[i].y, matrix->yy); - outline->points[i].x = x; - outline->points[i].y = y; - } -} - -void outline_get_cbox(const ASS_Outline *outline, FT_BBox *cbox) -{ - if (!outline->n_points) { - cbox->xMin = cbox->xMax = 0; - cbox->yMin = cbox->yMax = 0; - return; - } - cbox->xMin = cbox->xMax = outline->points[0].x; - cbox->yMin = cbox->yMax = outline->points[0].y; - for (size_t i = 1; i < outline->n_points; ++i) { - cbox->xMin = FFMIN(cbox->xMin, outline->points[i].x); - cbox->xMax = FFMAX(cbox->xMax, outline->points[i].x); - cbox->yMin = FFMIN(cbox->yMin, outline->points[i].y); - cbox->yMax = FFMAX(cbox->yMax, outline->points[i].y); - } -} - -/** - * \brief Apply fixups to please the FreeType stroker and improve the - * rendering result, especially in case the outline has some anomalies. - * At the moment, the following fixes are done: - * - * 1. Reverse contours that have "inside" winding direction but are not - * contained in any other contours' cbox. - * 2. Remove "inside" contours depending on border size, so that large - * borders do not reverse the winding direction, which leads to "holes" - * inside the border. The inside will be filled by the border of the - * outside contour anyway in this case. - * - * \param outline FreeType outline, modified in-place - * \param border_x border size, x direction, d6 format - * \param border_x border size, y direction, d6 format - */ -void fix_freetype_stroker(ASS_Outline *outline, int border_x, int border_y) -{ - int nc = outline->n_contours; - int begin, stop; - char modified = 0; - char *valid_cont = malloc(nc); - int start = 0; - int end = -1; - FT_BBox *boxes = malloc(nc * sizeof(FT_BBox)); - int i, j; - - long long area = 0; - // create a list of cboxes of the contours - for (i = 0; i < nc; i++) { - start = end + 1; - end = outline->contours[i]; - get_contour_cbox(&boxes[i], outline->points, start, end); - area += get_contour_area(outline->points, start, end); - } - int inside_direction = area < 0; - - // for each contour, check direction and whether it's "outside" - // or contained in another contour - end = -1; - for (i = 0; i < nc; i++) { - start = end + 1; - end = outline->contours[i]; - int dir = get_contour_area(outline->points, start, end) > 0; - valid_cont[i] = 1; - if (dir == inside_direction) { - for (j = 0; j < nc; j++) { - if (i == j) - continue; - if (boxes[i].xMin >= boxes[j].xMin && - boxes[i].xMax <= boxes[j].xMax && - boxes[i].yMin >= boxes[j].yMin && - boxes[i].yMax <= boxes[j].yMax) - goto check_inside; - } - /* "inside" contour but we can't find anything it could be - * inside of - assume the font is buggy and it should be - * an "outside" contour, and reverse it */ - for (j = 0; j < (end - start) / 2; j++) { - FT_Vector temp = outline->points[start + 1 + j]; - char temp2 = outline->tags[start + 1 + j]; - outline->points[start + 1 + j] = outline->points[end - j]; - outline->points[end - j] = temp; - outline->tags[start + 1 + j] = outline->tags[end - j]; - outline->tags[end - j] = temp2; - } - dir ^= 1; - } - check_inside: - if (dir == inside_direction) { - FT_BBox box; - get_contour_cbox(&box, outline->points, start, end); - int width = box.xMax - box.xMin; - int height = box.yMax - box.yMin; - if (width < border_x * 2 || height < border_y * 2) { - valid_cont[i] = 0; - modified = 1; - } - } - } - - // if we need to modify the outline, rewrite it and skip - // the contours that we determined should be removed. - if (modified) { - int p = 0, c = 0; - for (i = 0; i < nc; i++) { - if (!valid_cont[i]) - continue; - begin = (i == 0) ? 0 : outline->contours[i - 1] + 1; - stop = outline->contours[i]; - for (j = begin; j <= stop; j++) { - outline->points[p].x = outline->points[j].x; - outline->points[p].y = outline->points[j].y; - outline->tags[p] = outline->tags[j]; - p++; - } - outline->contours[c] = p - 1; - c++; - } - outline->n_points = p; - outline->n_contours = c; - } - - free(boxes); - free(valid_cont); -} - diff -Nru libass-0.13.7/libass/ass_fontconfig.c libass-0.14.0/libass/ass_fontconfig.c --- libass-0.13.7/libass/ass_fontconfig.c 2017-06-03 16:45:15.000000000 +0000 +++ libass-0.14.0/libass/ass_fontconfig.c 2017-10-31 12:14:11.000000000 +0000 @@ -19,8 +19,6 @@ #include "config.h" #include "ass_compat.h" -#ifdef CONFIG_FONTCONFIG - #include #include #include @@ -322,5 +320,3 @@ return provider; } - -#endif diff -Nru libass-0.13.7/libass/ass_font.h libass-0.14.0/libass/ass_font.h --- libass-0.13.7/libass/ass_font.h 2017-06-03 16:45:15.000000000 +0000 +++ libass-0.14.0/libass/ass_font.h 2017-10-31 12:14:11.000000000 +0000 @@ -76,13 +76,4 @@ ASS_Hinting hinting, int deco); void ass_font_clear(ASS_Font *font); -void outline_translate(const ASS_Outline *outline, FT_Pos dx, FT_Pos dy); -void outline_transform(const ASS_Outline *outline, const FT_Matrix *matrix); -void outline_get_cbox(const ASS_Outline *outline, FT_BBox *cbox); -void fix_freetype_stroker(ASS_Outline *outline, int border_x, int border_y); -int outline_alloc(ASS_Outline *outline, size_t n_points, size_t n_contours); -ASS_Outline *outline_convert(const FT_Outline *source); -ASS_Outline *outline_copy(const ASS_Outline *source); -void outline_free(ASS_Outline *outline); - #endif /* LIBASS_FONT_H */ diff -Nru libass-0.13.7/libass/ass_fontselect.h libass-0.14.0/libass/ass_fontselect.h --- libass-0.13.7/libass/ass_fontselect.h 2017-06-03 16:45:15.000000000 +0000 +++ libass-0.14.0/libass/ass_fontselect.h 2017-10-31 12:14:11.000000000 +0000 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef LIBASS_FONTCONFIG_H -#define LIBASS_FONTCONFIG_H +#ifndef LIBASS_FONTSELECT_H +#define LIBASS_FONTSELECT_H #include #include @@ -273,4 +273,4 @@ */ void ass_font_provider_free(ASS_FontProvider *provider); -#endif /* LIBASS_FONTCONFIG_H */ +#endif /* LIBASS_FONTSELECT_H */ diff -Nru libass-0.13.7/libass/ass_func_template.h libass-0.14.0/libass/ass_func_template.h --- libass-0.13.7/libass/ass_func_template.h 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/ass_func_template.h 2017-10-31 12:14:11.000000000 +0000 @@ -92,7 +92,6 @@ const BitmapEngine DECORATE(bitmap_engine) = { .align_order = ALIGN, -#if CONFIG_RASTERIZER #if CONFIG_LARGE_TILES .tile_order = 5, .fill_solid = DECORATE(fill_solid_tile32), @@ -104,7 +103,6 @@ .fill_halfplane = DECORATE(fill_halfplane_tile16), .fill_generic = DECORATE(fill_generic_tile16), #endif -#endif .add_bitmaps = DECORATE(add_bitmaps), #ifdef __x86_64__ diff -Nru libass-0.13.7/libass/ass.h libass-0.14.0/libass/ass.h --- libass-0.13.7/libass/ass.h 2017-06-03 16:52:24.000000000 +0000 +++ libass-0.14.0/libass/ass.h 2017-10-31 12:55:50.000000000 +0000 @@ -24,7 +24,7 @@ #include #include "ass_types.h" -#define LIBASS_VERSION 0x01307000 +#define LIBASS_VERSION 0x01400000 #ifdef __cplusplus extern "C" { diff -Nru libass-0.13.7/libass/ass_outline.c libass-0.14.0/libass/ass_outline.c --- libass-0.13.7/libass/ass_outline.c 1970-01-01 00:00:00.000000000 +0000 +++ libass-0.14.0/libass/ass_outline.c 2017-10-31 12:14:11.000000000 +0000 @@ -0,0 +1,1382 @@ +/* + * Copyright (C) 2016 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 "ass_utils.h" +#include "ass_outline.h" + + + +bool outline_alloc(ASS_Outline *outline, size_t n_points, size_t n_segments) +{ + outline->points = malloc(sizeof(ASS_Vector) * n_points); + outline->segments = malloc(n_segments); + if (!outline->points || !outline->segments) { + outline_free(outline); + return false; + } + + outline->max_points = n_points; + outline->max_segments = n_segments; + return true; +} + +static void outline_clear(ASS_Outline *outline) +{ + outline->points = NULL; + outline->segments = NULL; + + outline->n_points = outline->max_points = 0; + outline->n_segments = outline->max_segments = 0; +} + +bool outline_convert(ASS_Outline *outline, const FT_Outline *source) +{ + if (!source || !source->n_points) { + outline_clear(outline); + return true; + } + + if (!outline_alloc(outline, 2 * source->n_points, source->n_points)) + return false; + + enum Status { + S_ON, S_Q, S_C1, S_C2 + }; + + outline->n_points = outline->n_segments = 0; + for (size_t i = 0, j = 0; i < source->n_contours; i++) { + ASS_Vector pt; + bool skip_last = false; + enum Status st; + + int last = source->contours[i]; + if (j > last || last >= source->n_points) + goto fail; + + // skip degenerate 2-point contours from broken fonts + if (last - j < 2) { + j = last + 1; + continue; + } + + switch (FT_CURVE_TAG(source->tags[j])) { + case FT_CURVE_TAG_ON: + st = S_ON; + break; + + case FT_CURVE_TAG_CONIC: + pt.x = source->points[last].x; + pt.y = -source->points[last].y; + switch (FT_CURVE_TAG(source->tags[last])) { + case FT_CURVE_TAG_ON: + skip_last = true; + break; + + case FT_CURVE_TAG_CONIC: + pt.x = (pt.x + source->points[j].x) >> 1; + pt.y = (pt.y - source->points[j].y) >> 1; + break; + + default: + goto fail; + } + outline->points[outline->n_points++] = pt; + st = S_Q; + break; + + default: + goto fail; + } + pt.x = source->points[j].x; + pt.y = -source->points[j].y; + outline->points[outline->n_points++] = pt; + + for (j++; j <= last; j++) { + switch (FT_CURVE_TAG(source->tags[j])) { + case FT_CURVE_TAG_ON: + switch (st) { + case S_ON: + outline->segments[outline->n_segments++] = OUTLINE_LINE_SEGMENT; + break; + + case S_Q: + outline->segments[outline->n_segments++] = OUTLINE_QUADRATIC_SPLINE; + break; + + case S_C2: + outline->segments[outline->n_segments++] = OUTLINE_CUBIC_SPLINE; + break; + + default: + goto fail; + } + st = S_ON; + break; + + case FT_CURVE_TAG_CONIC: + switch (st) { + case S_ON: + st = S_Q; + break; + + case S_Q: + outline->segments[outline->n_segments++] = OUTLINE_QUADRATIC_SPLINE; + pt.x = (pt.x + source->points[j].x) >> 1; + pt.y = (pt.y - source->points[j].y) >> 1; + outline->points[outline->n_points++] = pt; + break; + + default: + goto fail; + } + break; + + case FT_CURVE_TAG_CUBIC: + switch (st) { + case S_ON: + st = S_C1; + break; + + case S_C1: + st = S_C2; + break; + + default: + goto fail; + } + break; + + default: + goto fail; + } + pt.x = source->points[j].x; + pt.y = -source->points[j].y; + outline->points[outline->n_points++] = pt; + } + + switch (st) { + case S_ON: + if (skip_last) { + outline->n_points--; + break; + } + outline->segments[outline->n_segments++] = OUTLINE_LINE_SEGMENT; + break; + + case S_Q: + outline->segments[outline->n_segments++] = OUTLINE_QUADRATIC_SPLINE; + break; + + case S_C2: + outline->segments[outline->n_segments++] = OUTLINE_CUBIC_SPLINE; + break; + + default: + goto fail; + } + outline->segments[outline->n_segments - 1] |= OUTLINE_CONTOUR_END; + } + return true; + +fail: + outline_free(outline); + return false; +} + +bool outline_copy(ASS_Outline *outline, const ASS_Outline *source) +{ + if (!source || !source->n_points) { + outline_clear(outline); + return true; + } + + if (!outline_alloc(outline, source->n_points, source->n_segments)) + return false; + + memcpy(outline->points, source->points, sizeof(ASS_Vector) * source->n_points); + memcpy(outline->segments, source->segments, source->n_segments); + outline->n_points = source->n_points; + outline->n_segments = source->n_segments; + return true; +} + +void outline_free(ASS_Outline *outline) +{ + if (!outline) + return; + + free(outline->points); + free(outline->segments); + + outline_clear(outline); +} + + +/* + * \brief Add a single point to a contour. + * Also adds outline segment if segment parameter is nonzero. + */ +bool outline_add_point(ASS_Outline *outline, ASS_Vector pt, char segment) +{ + if (outline->n_points >= outline->max_points) { + size_t new_size = 2 * outline->max_points; + if (!ASS_REALLOC_ARRAY(outline->points, new_size)) + return false; + outline->max_points = new_size; + } + outline->points[outline->n_points] = pt; + outline->n_points++; + + return !segment || outline_add_segment(outline, segment); +} + +/* + * \brief Add a segment to a contour. + */ +bool outline_add_segment(ASS_Outline *outline, char segment) +{ + if (outline->n_segments >= outline->max_segments) { + size_t new_size = 2 * outline->max_segments; + if (!ASS_REALLOC_ARRAY(outline->segments, new_size)) + return false; + outline->max_segments = new_size; + } + outline->segments[outline->n_segments] = segment; + outline->n_segments++; + return true; +} + +/* + * \brief Close a contour. + */ +bool outline_close_contour(ASS_Outline *outline) +{ + assert(outline->n_segments); + assert(!(outline->segments[outline->n_segments - 1] & ~OUTLINE_COUNT_MASK)); + outline->segments[outline->n_segments - 1] |= OUTLINE_CONTOUR_END; + return true; +} + + +void outline_translate(const ASS_Outline *outline, int32_t dx, int32_t dy) +{ + for (size_t i = 0; i < outline->n_points; i++) { + outline->points[i].x += dx; + outline->points[i].y += dy; + } +} + +void outline_adjust(const ASS_Outline *outline, double scale_x, int32_t dx, int32_t dy) +{ + int32_t mul = lrint(scale_x * 0x10000); + if (mul == 0x10000) { + outline_translate(outline, dx, dy); + return; + } + for (size_t i = 0; i < outline->n_points; i++) { + int32_t x = (int64_t) outline->points[i].x * mul >> 16; + outline->points[i].x = x + dx; + outline->points[i].y += dy; + } +} + +void outline_get_cbox(const ASS_Outline *outline, ASS_Rect *cbox) +{ + if (!outline->n_points) { + cbox->x_min = cbox->x_max = 0; + cbox->y_min = cbox->y_max = 0; + return; + } + cbox->x_min = cbox->x_max = outline->points[0].x; + cbox->y_min = cbox->y_max = outline->points[0].y; + for (size_t i = 1; i < outline->n_points; i++) { + cbox->x_min = FFMIN(cbox->x_min, outline->points[i].x); + cbox->x_max = FFMAX(cbox->x_max, outline->points[i].x); + cbox->y_min = FFMIN(cbox->y_min, outline->points[i].y); + cbox->y_max = FFMAX(cbox->y_max, outline->points[i].y); + } +} + + +/* + * Outline Stroke Algorithm + * + * Goal: + * Given source outline, construct two border outlines, such as that + * for any point inside any border outline (nonzero winding rule) + * minimal distance to points of source outline (same rule) + * is less than 1 with given precision, and for any point outside + * both border outlines minimal distance is more than approximately 1. + * Distance here is defined in normal space that is scaled by [1 / xbord, 1 / ybord]. + * Correspondingly distance is equal to hypot(dx / xbord, dy / ybord) and + * approximate allowable error is eps / max(xbord, ybord). + * + * Two border outlines correspond to ±1 offset curves and + * are required in case of self-intersecting source outline. + * + * Each of source segment that can be line segment, quadratic or cubic spline, + * and also connection between them is stroked mostly independently. + * Line segments can be offset quite straightforwardly. + * For splines algorithm first tries to offset individual points, + * then estimates error of such approximation and subdivide recursively if necessary. + * + * List of border cases handled by this algorithm: + * 1) Too close points lead to random derivatives or even division by zero. + * Algorithm solves that by merging such points into one. + * 2) Degenerate cases--near zero derivative at some spline points. + * Algorithm adds circular cap in such cases. + * 3) Negative curvature--offset amount is larger than radius of curvature. + * Algorithm checks if produced splines can potentially have self-intersection + * and handles them accordingly. It's mostly done by skipping + * problematic spline and replacing it with polyline that covers only + * positive winging part of mathematical offset curve. + * + * Error estimation for splines is done by analyzing offset spline. + * Offset spline is the difference between result and source spline in normal space. + * Such spline should consist of vectors with length 1 and orthogonal to source spline. + * Correspondingly error estimator have radial and angular part. + * + * Useful facts about B-splines. + * 1) Derivative of B-spline of order N is B-spline of order N-1. + * 2) Multiplication of B-splines of order N and M is B-spline of order N+M. + * 3) B-spline is fully contained inside convex hull of its control points. + * + * So, for radial error it's possible to check only control points of + * offset spline multiplication by itself. And for angular error it's + * possible to check control points of cross and dot product between + * offset spline and derivative spline. + */ + + +typedef struct { + ASS_DVector v; + double len; +} Normal; + +typedef struct { + ASS_Outline *result[2]; // result outlines + size_t contour_first[2]; // start position of last contours + double xbord, ybord; // border sizes + double xscale, yscale; // inverse border sizes + int eps; // allowable error in coordinate space + + // true if where are points in current contour + bool contour_start; + // skip flags for first and last point + int first_skip, last_skip; + // normal at first and last point + ASS_DVector first_normal, last_normal; + // first point of current contour + ASS_Vector first_point; + + // cosinus of maximal angle that do not require cap + double merge_cos; + // cosinus of maximal angle of circular arc that can be approximated with quadratic spline + double split_cos; + // maximal distance between control points in normal space that triggers handling of degenerates + double min_len; + // constant that used in exact radial error checking in quadratic case + double err_q; + // constant that used in approximate radial error checking in cubic case + double err_c; + // tangent of maximal angular error + double err_a; +} StrokerState; + +/** + * \brief 2D vector dot product + */ +static inline double vec_dot(ASS_DVector vec1, ASS_DVector vec2) +{ + return vec1.x * vec2.x + vec1.y * vec2.y; +} + +/** + * \brief 2D vector cross product + */ +static inline double vec_crs(ASS_DVector vec1, ASS_DVector vec2) +{ + return vec1.x * vec2.y - vec1.y * vec2.x; +} + +/** + * \brief 2D vector length + */ +static inline double vec_len(ASS_DVector vec) +{ + return sqrt(vec.x * vec.x + vec.y * vec.y); +} + + +/** + * \brief Add point to one or two border outlines + * \param str stroker state + * \param pt source point + * \param offs offset in normal space + * \param segment outline segment type + * \param dir destination outline flags + * \return false on allocation failure + */ +static bool emit_point(StrokerState *str, ASS_Vector pt, + ASS_DVector offs, char segment, int dir) +{ + int32_t dx = (int32_t) (str->xbord * offs.x); + int32_t dy = (int32_t) (str->ybord * offs.y); + + if (dir & 1) { + ASS_Vector res = { pt.x + dx, pt.y + dy }; + if (!outline_add_point(str->result[0], res, segment)) + return false; + } + if (dir & 2) { + ASS_Vector res = { pt.x - dx, pt.y - dy }; + if (!outline_add_point(str->result[1], res, segment)) + return false; + } + return true; +} + +/** + * \brief Replace first point of current contour + * \param str stroker state + * \param pt source point + * \param offs offset in normal space + * \param dir destination outline flags + */ +static void fix_first_point(StrokerState *str, ASS_Vector pt, + ASS_DVector offs, int dir) +{ + int32_t dx = (int32_t) (str->xbord * offs.x); + int32_t dy = (int32_t) (str->ybord * offs.y); + + if (dir & 1) { + ASS_Vector res = { pt.x + dx, pt.y + dy }; + ASS_Outline *ol = str->result[0]; + ol->points[str->contour_first[0]] = res; + } + if (dir & 2) { + ASS_Vector res = { pt.x - dx, pt.y - dy }; + ASS_Outline *ol = str->result[1]; + ol->points[str->contour_first[1]] = res; + } +} + +/** + * \brief Helper function for circular arc construction + * \param str stroker state + * \param pt center point + * \param normal0 first normal + * \param normal1 last normal + * \param mul precalculated coefficients + * \param level subdivision level + * \param dir destination outline flags + * \return false on allocation failure + */ +static bool process_arc(StrokerState *str, ASS_Vector pt, + ASS_DVector normal0, ASS_DVector normal1, + const double *mul, int level, int dir) +{ + ASS_DVector center; + center.x = (normal0.x + normal1.x) * mul[level]; + center.y = (normal0.y + normal1.y) * mul[level]; + if (level) + return process_arc(str, pt, normal0, center, mul, level - 1, dir) && + process_arc(str, pt, center, normal1, mul, level - 1, dir); + return emit_point(str, pt, normal0, OUTLINE_QUADRATIC_SPLINE, dir) && + emit_point(str, pt, center, 0, dir); +} + +/** + * \brief Construct circular arc + * \param str stroker state + * \param pt center point + * \param normal0 first normal + * \param normal1 last normal + * \param c dot product between normal0 and normal1 + * \param dir destination outline flags + * \return false on allocation failure + */ +static bool draw_arc(StrokerState *str, ASS_Vector pt, + ASS_DVector normal0, ASS_DVector normal1, double c, int dir) +{ + const int max_subdiv = 15; + double mul[max_subdiv + 1]; + + ASS_DVector center; + bool small_angle = true; + if (c < 0) { + double mul = dir & 2 ? -sqrt(0.5) : sqrt(0.5); + mul /= sqrt(1 - c); + center.x = (normal1.y - normal0.y) * mul; + center.y = (normal0.x - normal1.x) * mul; + c = sqrt(FFMAX(0, 0.5 + 0.5 * c)); + small_angle = false; + } + + int pos = max_subdiv; + while (c < str->split_cos && pos) { + mul[pos] = sqrt(0.5) / sqrt(1 + c); + c = (1 + c) * mul[pos]; + pos--; + } + mul[pos] = 1 / (1 + c); + return small_angle ? + process_arc(str, pt, normal0, normal1, mul + pos, max_subdiv - pos, dir) : + process_arc(str, pt, normal0, center, mul + pos, max_subdiv - pos, dir) && + process_arc(str, pt, center, normal1, mul + pos, max_subdiv - pos, dir); +} + +/** + * \brief Construct full circle + * \param str stroker state + * \param pt center point + * \param dir destination outline flags + * \return false on allocation failure + */ +static bool draw_circle(StrokerState *str, ASS_Vector pt, int dir) +{ + const int max_subdiv = 15; + double mul[max_subdiv + 1], c = 0; + + int pos = max_subdiv; + while (c < str->split_cos && pos) { + mul[pos] = sqrt(0.5) / sqrt(1 + c); + c = (1 + c) * mul[pos]; + pos--; + } + mul[pos] = 1 / (1 + c); + + ASS_DVector normal[4] = { + { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } + }; + return process_arc(str, pt, normal[0], normal[1], mul + pos, max_subdiv - pos, dir) && + process_arc(str, pt, normal[1], normal[2], mul + pos, max_subdiv - pos, dir) && + process_arc(str, pt, normal[2], normal[3], mul + pos, max_subdiv - pos, dir) && + process_arc(str, pt, normal[3], normal[0], mul + pos, max_subdiv - pos, dir); +} + +/** + * \brief Start new segment and add circular cap if necessary + * \param str stroker state + * \param pt start point of the new segment + * \param normal normal at start of the new segment + * \param dir destination outline flags + * \return false on allocation failure + */ +static bool start_segment(StrokerState *str, ASS_Vector pt, + ASS_DVector normal, int dir) +{ + if (str->contour_start) { + str->contour_start = false; + str->first_skip = str->last_skip = 0; + str->first_normal = str->last_normal = normal; + str->first_point = pt; + return true; + } + + ASS_DVector prev = str->last_normal; + double c = vec_dot(prev, normal); + if (c > str->merge_cos) { // merge without cap + double mul = 1 / (1 + c); + str->last_normal.x = (str->last_normal.x + normal.x) * mul; + str->last_normal.y = (str->last_normal.y + normal.y) * mul; + return true; + } + str->last_normal = normal; + + // check for negative curvature + double s = vec_crs(prev, normal); + int skip_dir = s < 0 ? 1 : 2; + if (dir & skip_dir) { + if (!emit_point(str, pt, prev, OUTLINE_LINE_SEGMENT, ~str->last_skip & skip_dir)) + return false; + ASS_DVector zero_normal = {0, 0}; + if (!emit_point(str, pt, zero_normal, OUTLINE_LINE_SEGMENT, skip_dir)) + return false; + } + str->last_skip = skip_dir; + + dir &= ~skip_dir; + return !dir || draw_arc(str, pt, prev, normal, c, dir); +} + +/** + * \brief Same as emit_point() but also updates skip flags + */ +static bool emit_first_point(StrokerState *str, ASS_Vector pt, char segment, int dir) +{ + str->last_skip &= ~dir; + return emit_point(str, pt, str->last_normal, segment, dir); +} + +/** + * \brief Prepare to skip part of curve + * \param str stroker state + * \param pt start point of the skipped part + * \param dir destination outline flags + * \param first true if the skipped part is at start of the segment + * \return false on allocation failure + */ +static bool prepare_skip(StrokerState *str, ASS_Vector pt, int dir, bool first) +{ + if (first) + str->first_skip |= dir; + else if (!emit_point(str, pt, str->last_normal, OUTLINE_LINE_SEGMENT, ~str->last_skip & dir)) + return false; + str->last_skip |= dir; + return true; +} + +/** + * \brief Process source line segment + * \param str stroker state + * \param pt0 start point of the line segment + * \param pt1 end point of the line segment + * \param dir destination outline flags + * \return false on allocation failure + */ +static bool add_line(StrokerState *str, ASS_Vector pt0, ASS_Vector pt1, int dir) +{ + int32_t dx = pt1.x - pt0.x; + int32_t dy = pt1.y - pt0.y; + if (dx > -str->eps && dx < str->eps && dy > -str->eps && dy < str->eps) + return true; + + ASS_DVector deriv = { dy * str->yscale, -dx * str->xscale }; + double scale = 1 / vec_len(deriv); + ASS_DVector normal = { deriv.x * scale, deriv.y * scale }; + if (!start_segment(str, pt0, normal, dir)) + return false; + if (!emit_first_point(str, pt0, OUTLINE_LINE_SEGMENT, dir)) + return false; + str->last_normal = normal; + return true; +} + + +/** + * \brief Estimate error for quadratic spline + * \param str stroker state + * \param c dot product between normal[0] and normal[1] + * \param s cross product between normal[0] and normal[1] + * \param normal first and last spline normal + * \param result best offset for central spline point + * \return false if error is too large + */ +static bool estimate_quadratic_error(StrokerState *str, double c, double s, + const Normal *normal, ASS_DVector *result) +{ + // check radial error + if (!((3 + c) * (3 + c) < str->err_q * (1 + c))) + return false; + + double mul = 1 / (1 + c); + double l0 = 2 * normal[0].len, l1 = 2 * normal[1].len; + double dot0 = l0 + normal[1].len * c, crs0 = (l0 * mul - normal[1].len) * s; + double dot1 = l1 + normal[0].len * c, crs1 = (l1 * mul - normal[0].len) * s; + // check angular error + if (!(fabs(crs0) < str->err_a * dot0 && fabs(crs1) < str->err_a * dot1)) + return false; + + result->x = (normal[0].v.x + normal[1].v.x) * mul; + result->y = (normal[0].v.y + normal[1].v.y) * mul; + return true; +} + +/** + * \brief Helper function for quadratic spline construction + * \param str stroker state + * \param pt array of 3 source spline points + * \param deriv array of 2 differences between adjacent points in normal space + * \param normal first and last spline normal + * \param dir destination outline flags + * \param first true if the current part is at start of the segment + * \return false on allocation failure + */ +static bool process_quadratic(StrokerState *str, const ASS_Vector *pt, + const ASS_DVector *deriv, const Normal *normal, + int dir, bool first) +{ + double c = vec_dot(normal[0].v, normal[1].v); + double s = vec_crs(normal[0].v, normal[1].v); + int check_dir = dir, skip_dir = s < 0 ? 1 : 2; + if (dir & skip_dir) { + double abs_s = fabs(s); + double f0 = normal[0].len * c + normal[1].len; + double f1 = normal[1].len * c + normal[0].len; + double g0 = normal[0].len * abs_s; + double g1 = normal[1].len * abs_s; + // check for self-intersection + if (f0 < abs_s && f1 < abs_s) { + double d2 = (f0 * normal[1].len + f1 * normal[0].len) / 2; + if (d2 < g0 && d2 < g1) { + if (!prepare_skip(str, pt[0], skip_dir, first)) + return false; + if (f0 < 0 || f1 < 0) { + ASS_DVector zero_normal = {0, 0}; + if (!emit_point(str, pt[0], zero_normal, OUTLINE_LINE_SEGMENT, skip_dir) || + !emit_point(str, pt[2], zero_normal, OUTLINE_LINE_SEGMENT, skip_dir)) + return false; + } else { + double mul = f0 / abs_s; + ASS_DVector offs = { normal[0].v.x * mul, normal[0].v.y * mul }; + if (!emit_point(str, pt[0], offs, OUTLINE_LINE_SEGMENT, skip_dir)) + return false; + } + dir &= ~skip_dir; + if (!dir) { + str->last_normal = normal[1].v; + return true; + } + } + check_dir ^= skip_dir; + } else if (c + g0 < 1 && c + g1 < 1) + check_dir ^= skip_dir; + } + + ASS_DVector result; + if (check_dir && estimate_quadratic_error(str, c, s, normal, &result)) { + if (!emit_first_point(str, pt[0], OUTLINE_QUADRATIC_SPLINE, check_dir)) + return false; + if (!emit_point(str, pt[1], result, 0, check_dir)) + return false; + dir &= ~check_dir; + if (!dir) { + str->last_normal = normal[1].v; + return true; + } + } + + ASS_Vector next[5]; + next[1].x = pt[0].x + pt[1].x; + next[1].y = pt[0].y + pt[1].y; + next[3].x = pt[1].x + pt[2].x; + next[3].y = pt[1].y + pt[2].y; + next[2].x = (next[1].x + next[3].x + 2) >> 2; + next[2].y = (next[1].y + next[3].y + 2) >> 2; + next[1].x >>= 1; + next[1].y >>= 1; + next[3].x >>= 1; + next[3].y >>= 1; + next[0] = pt[0]; + next[4] = pt[2]; + + ASS_DVector next_deriv[3]; + next_deriv[0].x = deriv[0].x / 2; + next_deriv[0].y = deriv[0].y / 2; + next_deriv[2].x = deriv[1].x / 2; + next_deriv[2].y = deriv[1].y / 2; + next_deriv[1].x = (next_deriv[0].x + next_deriv[2].x) / 2; + next_deriv[1].y = (next_deriv[0].y + next_deriv[2].y) / 2; + + double len = vec_len(next_deriv[1]); + if (len < str->min_len) { // check degenerate case + if (!emit_first_point(str, next[0], OUTLINE_LINE_SEGMENT, dir)) + return false; + if (!start_segment(str, next[2], normal[1].v, dir)) + return false; + str->last_skip &= ~dir; + return emit_point(str, next[2], normal[1].v, OUTLINE_LINE_SEGMENT, dir); + } + + double scale = 1 / len; + Normal next_normal[3] = { + { normal[0].v, normal[0].len / 2 }, + { { next_deriv[1].x * scale, next_deriv[1].y * scale }, len }, + { normal[1].v, normal[1].len / 2 } + }; + return process_quadratic(str, next + 0, next_deriv + 0, next_normal + 0, dir, first) && + process_quadratic(str, next + 2, next_deriv + 1, next_normal + 1, dir, false); +} + +/** + * \brief Process source quadratic spline + * \param str stroker state + * \param pt array of 3 source spline points + * \param dir destination outline flags + * \return false on allocation failure + */ +static bool add_quadratic(StrokerState *str, const ASS_Vector *pt, int dir) +{ + int32_t dx0 = pt[1].x - pt[0].x; + int32_t dy0 = pt[1].y - pt[0].y; + if (dx0 > -str->eps && dx0 < str->eps && dy0 > -str->eps && dy0 < str->eps) + return add_line(str, pt[0], pt[2], dir); + + int32_t dx1 = pt[2].x - pt[1].x; + int32_t dy1 = pt[2].y - pt[1].y; + if (dx1 > -str->eps && dx1 < str->eps && dy1 > -str->eps && dy1 < str->eps) + return add_line(str, pt[0], pt[2], dir); + + ASS_DVector deriv[2] = { + { dy0 * str->yscale, -dx0 * str->xscale }, + { dy1 * str->yscale, -dx1 * str->xscale } + }; + double len0 = vec_len(deriv[0]), scale0 = 1 / len0; + double len1 = vec_len(deriv[1]), scale1 = 1 / len1; + Normal normal[2] = { + { { deriv[0].x * scale0, deriv[0].y * scale0 }, len0 }, + { { deriv[1].x * scale1, deriv[1].y * scale1 }, len1 } + }; + + bool first = str->contour_start; + return start_segment(str, pt[0], normal[0].v, dir) && + process_quadratic(str, pt, deriv, normal, dir, first); +} + + +enum { + FLAG_INTERSECTION = 1, + FLAG_ZERO_0 = 2, + FLAG_ZERO_1 = 4, + FLAG_CLIP_0 = 8, + FLAG_CLIP_1 = 16, + FLAG_DIR_2 = 32, + + FLAG_COUNT = 6, + + MASK_INTERSECTION = FLAG_INTERSECTION << FLAG_COUNT, + MASK_ZERO_0 = FLAG_ZERO_0 << FLAG_COUNT, + MASK_ZERO_1 = FLAG_ZERO_1 << FLAG_COUNT, + MASK_CLIP_0 = FLAG_CLIP_0 << FLAG_COUNT, + MASK_CLIP_1 = FLAG_CLIP_1 << FLAG_COUNT, +}; + +/** + * \brief Estimate error for cubic spline + * \param str stroker state + * \param c dot product between normal[0] and normal[1] + * \param s cross product between normal[0] and normal[1] + * \param dc dot products between normals and central points difference in normal space + * \param dc cross products between normals and central points difference in normal space + * \param normal first and last spline normal + * \param result best offsets for central spline points (second & third) + * \return flags for destination outlines that do not require subdivision + */ +static int estimate_cubic_error(StrokerState *str, double c, double s, + const double *dc, const double *ds, + const Normal *normal, ASS_DVector *result, + int check_flags, int dir) +{ + double t = (ds[0] + ds[1]) / (dc[0] + dc[1]), c1 = 1 + c, ss = s * s; + double ts = t * s, tt = t * t, ttc = tt * c1, ttcc = ttc * c1; + + const double w = 0.4; + double f0[] = { + 10 * w * (c - 1) + 9 * w * tt * c, + 2 * (c - 1) + 3 * tt + 2 * ts, + 2 * (c - 1) + 3 * tt - 2 * ts, + }; + double f1[] = { + 18 * w * (ss - ttc * c), + 2 * ss - 6 * ttc - 2 * ts * (c + 4), + 2 * ss - 6 * ttc + 2 * ts * (c + 4), + }; + double f2[] = { + 9 * w * (ttcc - ss) * c, + 3 * ss + 3 * ttcc + 6 * ts * c1, + 3 * ss + 3 * ttcc - 6 * ts * c1, + }; + + double aa = 0, ab = 0; + double ch = sqrt(c1 / 2); + double inv_ro0 = 1.5 * ch * (ch + 1); + for (int i = 0; i < 3; i++) { + double a = 2 * f2[i] + f1[i] * inv_ro0; + double b = f2[i] - f0[i] * inv_ro0 * inv_ro0; + aa += a * a; ab += a * b; + } + double ro = ab / (aa * inv_ro0 + 1e-9); // best fit + + double err2 = 0; + for (int i = 0; i < 3; i++) { + double err = f0[i] + ro * (f1[i] + ro * f2[i]); + err2 += err * err; + } + if (!(err2 < str->err_c)) // check radial error + return 0; + + double r = ro * c1 - 1; + double ro0 = t * r - ro * s; + double ro1 = t * r + ro * s; + + int check_dir = check_flags & FLAG_DIR_2 ? 2 : 1; + if (dir & check_dir) { + double test_s = s, test0 = ro0, test1 = ro1; + if (check_flags & FLAG_DIR_2) { + test_s = -test_s; + test0 = -test0; + test1 = -test1; + } + int flags = 0; + if (2 * test_s * r < dc[0] + dc[1]) flags |= FLAG_INTERSECTION; + if (normal[0].len - test0 < 0) flags |= FLAG_ZERO_0; + if (normal[1].len + test1 < 0) flags |= FLAG_ZERO_1; + if (normal[0].len + dc[0] + test_s - test1 * c < 0) flags |= FLAG_CLIP_0; + if (normal[1].len + dc[1] + test_s + test0 * c < 0) flags |= FLAG_CLIP_1; + if ((flags ^ check_flags) & (check_flags >> FLAG_COUNT)) { + dir &= ~check_dir; + if (!dir) + return 0; + } + } + + double d0c = 2 * dc[0], d0s = 2 * ds[0]; + double d1c = 2 * dc[1], d1s = 2 * ds[1]; + double dot0 = d0c + 3 * normal[0].len, crs0 = d0s + 3 * ro0 * normal[0].len; + double dot1 = d1c + 3 * normal[1].len, crs1 = d1s + 3 * ro1 * normal[1].len; + // check angular error (stage 1) + if (!(fabs(crs0) < str->err_a * dot0 && fabs(crs1) < str->err_a * dot1)) + return 0; + + double cl0 = c * normal[0].len, sl0 = +s * normal[0].len; + double cl1 = c * normal[1].len, sl1 = -s * normal[1].len; + dot0 = d0c - ro0 * d0s + cl0 + ro1 * sl0 + cl1 / 3; + dot1 = d1c - ro1 * d1s + cl1 + ro0 * sl1 + cl0 / 3; + crs0 = d0s + ro0 * d0c - sl0 + ro1 * cl0 - sl1 / 3; + crs1 = d1s + ro1 * d1c - sl1 + ro0 * cl1 - sl0 / 3; + // check angular error (stage 2) + if (!(fabs(crs0) < str->err_a * dot0 && fabs(crs1) < str->err_a * dot1)) + return 0; + + result[0].x = normal[0].v.x + normal[0].v.y * ro0; + result[0].y = normal[0].v.y - normal[0].v.x * ro0; + result[1].x = normal[1].v.x + normal[1].v.y * ro1; + result[1].y = normal[1].v.y - normal[1].v.x * ro1; + return dir; +} + +/** + * \brief Helper function for cubic spline construction + * \param str stroker state + * \param pt array of 4 source spline points + * \param deriv array of 3 differences between adjacent points in normal space + * \param normal first and last spline normal + * \param dir destination outline flags + * \param first true if the current part is at start of the segment + * \return false on allocation failure + */ +static bool process_cubic(StrokerState *str, const ASS_Vector *pt, + const ASS_DVector *deriv, const Normal *normal, + int dir, bool first) +{ + double c = vec_dot(normal[0].v, normal[1].v); + double s = vec_crs(normal[0].v, normal[1].v); + double dc[] = { vec_dot(normal[0].v, deriv[1]), vec_dot(normal[1].v, deriv[1]) }; + double ds[] = { vec_crs(normal[0].v, deriv[1]), vec_crs(normal[1].v, deriv[1]) }; + double f0 = normal[0].len * c + normal[1].len + dc[1]; + double f1 = normal[1].len * c + normal[0].len + dc[0]; + double g0 = normal[0].len * s - ds[1]; + double g1 = normal[1].len * s + ds[0]; + + double abs_s = s; + int check_dir = dir, skip_dir = 2; + int flags = FLAG_INTERSECTION | FLAG_DIR_2; + if (s < 0) { + abs_s = -s; + skip_dir = 1; + flags = 0; + g0 = -g0; + g1 = -g1; + } + + if (!(dc[0] + dc[1] > 0)) + check_dir = 0; + else if (dir & skip_dir) { + if (f0 < abs_s && f1 < abs_s) { // check for self-intersection + double d2 = (f0 + dc[1]) * normal[1].len + (f1 + dc[0]) * normal[0].len; + d2 = (d2 + vec_dot(deriv[1], deriv[1])) / 2; + if (d2 < g0 && d2 < g1) { + double q = sqrt(d2 / (2 - d2)); + double h0 = (f0 * q + g0) * normal[1].len; + double h1 = (f1 * q + g1) * normal[0].len; + q *= (4.0 / 3) * d2; + if (h0 > q && h1 > q) { + if (!prepare_skip(str, pt[0], skip_dir, first)) + return false; + if (f0 < 0 || f1 < 0) { + ASS_DVector zero_normal = {0, 0}; + if (!emit_point(str, pt[0], zero_normal, OUTLINE_LINE_SEGMENT, skip_dir) || + !emit_point(str, pt[3], zero_normal, OUTLINE_LINE_SEGMENT, skip_dir)) + return false; + } else { + double mul = f0 / abs_s; + ASS_DVector offs = { normal[0].v.x * mul, normal[0].v.y * mul }; + if (!emit_point(str, pt[0], offs, OUTLINE_LINE_SEGMENT, skip_dir)) + return false; + } + dir &= ~skip_dir; + if (!dir) { + str->last_normal = normal[1].v; + return true; + } + } + } + check_dir ^= skip_dir; + } else { + if (ds[0] < 0) + flags ^= MASK_INTERSECTION; + if (ds[1] < 0) + flags ^= MASK_INTERSECTION | FLAG_INTERSECTION; + bool parallel = flags & MASK_INTERSECTION; + int badness = parallel ? 0 : 1; + if (c + g0 < 1) { + if (parallel) { + flags ^= MASK_ZERO_0 | FLAG_ZERO_0; + if (c < 0) + flags ^= MASK_CLIP_0; + if (f0 > abs_s) + flags ^= FLAG_ZERO_0 | FLAG_CLIP_0; + } + badness++; + } else { + flags ^= MASK_INTERSECTION | FLAG_INTERSECTION; + if (!parallel) { + flags ^= MASK_ZERO_0; + if (c > 0) + flags ^= MASK_CLIP_0; + } + } + if (c + g1 < 1) { + if (parallel) { + flags ^= MASK_ZERO_1 | FLAG_ZERO_1; + if (c < 0) + flags ^= MASK_CLIP_1; + if (f1 > abs_s) + flags ^= FLAG_ZERO_1 | FLAG_CLIP_1; + } + badness++; + } else { + flags ^= MASK_INTERSECTION; + if (!parallel) { + flags ^= MASK_ZERO_1; + if (c > 0) + flags ^= MASK_CLIP_1; + } + } + if (badness > 2) + check_dir ^= skip_dir; + } + } + + ASS_DVector result[2]; + if (check_dir) + check_dir = estimate_cubic_error(str, c, s, dc, ds, + normal, result, flags, check_dir); + if (check_dir) { + if (!emit_first_point(str, pt[0], OUTLINE_CUBIC_SPLINE, check_dir)) + return false; + if (!emit_point(str, pt[1], result[0], 0, check_dir) || + !emit_point(str, pt[2], result[1], 0, check_dir)) + return false; + dir &= ~check_dir; + if (!dir) { + str->last_normal = normal[1].v; + return true; + } + } + + ASS_Vector next[7], center; + next[1].x = pt[0].x + pt[1].x; + next[1].y = pt[0].y + pt[1].y; + center.x = pt[1].x + pt[2].x + 2; + center.y = pt[1].y + pt[2].y + 2; + next[5].x = pt[2].x + pt[3].x; + next[5].y = pt[2].y + pt[3].y; + next[2].x = next[1].x + center.x; + next[2].y = next[1].y + center.y; + next[4].x = center.x + next[5].x; + next[4].y = center.y + next[5].y; + next[3].x = (next[2].x + next[4].x - 1) >> 3; + next[3].y = (next[2].y + next[4].y - 1) >> 3; + next[2].x >>= 2; + next[2].y >>= 2; + next[4].x >>= 2; + next[4].y >>= 2; + next[1].x >>= 1; + next[1].y >>= 1; + next[5].x >>= 1; + next[5].y >>= 1; + next[0] = pt[0]; + next[6] = pt[3]; + + ASS_DVector next_deriv[5], center_deriv; + next_deriv[0].x = deriv[0].x / 2; + next_deriv[0].y = deriv[0].y / 2; + center_deriv.x = deriv[1].x / 2; + center_deriv.y = deriv[1].y / 2; + next_deriv[4].x = deriv[2].x / 2; + next_deriv[4].y = deriv[2].y / 2; + next_deriv[1].x = (next_deriv[0].x + center_deriv.x) / 2; + next_deriv[1].y = (next_deriv[0].y + center_deriv.y) / 2; + next_deriv[3].x = (center_deriv.x + next_deriv[4].x) / 2; + next_deriv[3].y = (center_deriv.y + next_deriv[4].y) / 2; + next_deriv[2].x = (next_deriv[1].x + next_deriv[3].x) / 2; + next_deriv[2].y = (next_deriv[1].y + next_deriv[3].y) / 2; + + double len = vec_len(next_deriv[2]); + if (len < str->min_len) { // check degenerate case + Normal next_normal[4]; + next_normal[0].v = normal[0].v; + next_normal[0].len = normal[0].len / 2; + next_normal[3].v = normal[1].v; + next_normal[3].len = normal[1].len / 2; + + next_deriv[1].x += next_deriv[2].x; + next_deriv[1].y += next_deriv[2].y; + next_deriv[3].x += next_deriv[2].x; + next_deriv[3].y += next_deriv[2].y; + next_deriv[2].x = next_deriv[2].y = 0; + + double len1 = vec_len(next_deriv[1]); + if (len1 < str->min_len) { + next_normal[1] = normal[0]; + } else { + double scale = 1 / len1; + next_normal[1].v.x = next_deriv[1].x * scale; + next_normal[1].v.y = next_deriv[1].y * scale; + next_normal[1].len = len1; + } + + double len2 = vec_len(next_deriv[3]); + if (len2 < str->min_len) { + next_normal[2] = normal[1]; + } else { + double scale = 1 / len2; + next_normal[2].v.x = next_deriv[3].x * scale; + next_normal[2].v.y = next_deriv[3].y * scale; + next_normal[2].len = len2; + } + + if (len1 < str->min_len) { + if (!emit_first_point(str, next[0], OUTLINE_LINE_SEGMENT, dir)) + return false; + } else { + if (!process_cubic(str, next + 0, next_deriv + 0, next_normal + 0, dir, first)) + return false; + } + if (!start_segment(str, next[2], next_normal[2].v, dir)) + return false; + if (len2 < str->min_len) { + if (!emit_first_point(str, next[3], OUTLINE_LINE_SEGMENT, dir)) + return false; + } else { + if (!process_cubic(str, next + 3, next_deriv + 2, next_normal + 2, dir, false)) + return false; + } + return true; + } + + double scale = 1 / len; + Normal next_normal[3] = { + { normal[0].v, normal[0].len / 2 }, + { { next_deriv[2].x * scale, next_deriv[2].y * scale }, len }, + { normal[1].v, normal[1].len / 2 } + }; + return process_cubic(str, next + 0, next_deriv + 0, next_normal + 0, dir, first) && + process_cubic(str, next + 3, next_deriv + 2, next_normal + 1, dir, false); +} + +/** + * \brief Process source cubic spline + * \param str stroker state + * \param pt array of 4 source spline points + * \param dir destination outline flags + * \return false on allocation failure + */ +static bool add_cubic(StrokerState *str, const ASS_Vector *pt, int dir) +{ + int flags = 9; + + int32_t dx0 = pt[1].x - pt[0].x; + int32_t dy0 = pt[1].y - pt[0].y; + if (dx0 > -str->eps && dx0 < str->eps && dy0 > -str->eps && dy0 < str->eps) { + dx0 = pt[2].x - pt[0].x; + dy0 = pt[2].y - pt[0].y; + if (dx0 > -str->eps && dx0 < str->eps && dy0 > -str->eps && dy0 < str->eps) + return add_line(str, pt[0], pt[3], dir); + flags ^= 1; + } + + int32_t dx2 = pt[3].x - pt[2].x; + int32_t dy2 = pt[3].y - pt[2].y; + if (dx2 > -str->eps && dx2 < str->eps && dy2 > -str->eps && dy2 < str->eps) { + dx2 = pt[3].x - pt[1].x; + dy2 = pt[3].y - pt[1].y; + if (dx2 > -str->eps && dx2 < str->eps && dy2 > -str->eps && dy2 < str->eps) + return add_line(str, pt[0], pt[3], dir); + flags ^= 4; + } + + if (flags == 12) + return add_line(str, pt[0], pt[3], dir); + + int32_t dx1 = pt[flags >> 2].x - pt[flags & 3].x; + int32_t dy1 = pt[flags >> 2].y - pt[flags & 3].y; + + ASS_DVector deriv[3] = { + { dy0 * str->yscale, -dx0 * str->xscale }, + { dy1 * str->yscale, -dx1 * str->xscale }, + { dy2 * str->yscale, -dx2 * str->xscale } + }; + double len0 = vec_len(deriv[0]), scale0 = 1 / len0; + double len2 = vec_len(deriv[2]), scale2 = 1 / len2; + Normal normal[2] = { + { { deriv[0].x * scale0, deriv[0].y * scale0 }, len0 }, + { { deriv[2].x * scale2, deriv[2].y * scale2 }, len2 } + }; + + bool first = str->contour_start; + return start_segment(str, pt[0], normal[0].v, dir) && + process_cubic(str, pt, deriv, normal, dir, first); +} + + +/** + * \brief Process contour closing + * \param str stroker state + * \param last_point last contour point + * \param dir destination outline flags + * \return false on allocation failure + */ +static bool close_contour(StrokerState *str, ASS_Vector last_point, int dir) +{ + if (str->contour_start) { + if ((dir & 3) == 3) + dir = 1; + if (!draw_circle(str, last_point, dir)) + return false; + } else { + if (!add_line(str, last_point, str->first_point, dir)) + return false; + if (!start_segment(str, str->first_point, str->first_normal, dir)) + return false; + if (!emit_point(str, str->first_point, str->first_normal, OUTLINE_LINE_SEGMENT, + ~str->last_skip & dir & str->first_skip)) + return false; + if (str->last_normal.x != str->first_normal.x || + str->last_normal.y != str->first_normal.y) + fix_first_point(str, str->first_point, str->last_normal, + ~str->last_skip & dir & ~str->first_skip); + str->contour_start = true; + } + if ((dir & 1) && !outline_close_contour(str->result[0])) + return false; + if ((dir & 2) && !outline_close_contour(str->result[1])) + return false; + str->contour_first[0] = str->result[0]->n_points; + str->contour_first[1] = str->result[1]->n_points; + return true; +} + + +/* + * Stroke an outline glyph in x/y direction. + * \param result first result outline + * \param result1 second result outline + * \param path source outline + * \param xbord border size in X direction + * \param ybord border size in Y direction + * \param eps approximate allowable error + * \return false on allocation failure + */ +bool outline_stroke(ASS_Outline *result, ASS_Outline *result1, + const ASS_Outline *path, int xbord, int ybord, int eps) +{ + const int dir = 3; + int rad = FFMAX(xbord, ybord); + assert(rad >= eps); + + result->n_points = result->n_segments = 0; + result1->n_points = result1->n_segments = 0; + + StrokerState str; + str.result[0] = result; + str.result[1] = result1; + str.contour_first[0] = 0; + str.contour_first[1] = 0; + str.xbord = xbord; + str.ybord = ybord; + str.xscale = 1.0 / FFMAX(eps, xbord); + str.yscale = 1.0 / FFMAX(eps, ybord); + str.eps = eps; + + str.contour_start = true; + double rel_err = (double) eps / rad; + str.merge_cos = 1 - rel_err; + double e = sqrt(2 * rel_err); + str.split_cos = 1 + 8 * rel_err - 4 * (1 + rel_err) * e; + str.min_len = rel_err / 4; + str.err_q = 8 * (1 + rel_err) * (1 + rel_err); + str.err_c = 390 * rel_err * rel_err; + str.err_a = e; + + for (size_t i = 0; i < path->n_points; i++) { + if (path->points[i].x < OUTLINE_MIN || path->points[i].x > OUTLINE_MAX) + return false; + if (path->points[i].y < OUTLINE_MIN || path->points[i].y > OUTLINE_MAX) + return false; + } + + ASS_Vector *start = path->points, *cur = start; + for (size_t i = 0; i < path->n_segments; i++) { + int n = path->segments[i] & OUTLINE_COUNT_MASK; + cur += n; + + ASS_Vector *end = cur, p[4]; + if (path->segments[i] & OUTLINE_CONTOUR_END) { + end = start; + start = cur; + } + + switch (n) { + case OUTLINE_LINE_SEGMENT: + if (!add_line(&str, cur[-1], *end, dir)) + return false; + break; + + case OUTLINE_QUADRATIC_SPLINE: + p[0] = cur[-2]; + p[1] = cur[-1]; + p[2] = *end; + if (!add_quadratic(&str, p, dir)) + return false; + break; + + case OUTLINE_CUBIC_SPLINE: + p[0] = cur[-3]; + p[1] = cur[-2]; + p[2] = cur[-1]; + p[3] = *end; + if (!add_cubic(&str, p, dir)) + return false; + break; + + default: + return false; + } + + if (start == cur && !close_contour(&str, *end, dir)) + return false; + } + assert(start == cur && cur == path->points + path->n_points); + return true; +} diff -Nru libass-0.13.7/libass/ass_outline.h libass-0.14.0/libass/ass_outline.h --- libass-0.13.7/libass/ass_outline.h 1970-01-01 00:00:00.000000000 +0000 +++ libass-0.14.0/libass/ass_outline.h 2017-10-31 12:14:11.000000000 +0000 @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2016 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 LIBASS_OUTLINE_H +#define LIBASS_OUTLINE_H + +#include +#include FT_OUTLINE_H +#include +#include + +#include "ass_utils.h" + + +typedef struct { + int32_t x, y; +} ASS_Vector; + +typedef struct { + double x, y; +} ASS_DVector; + +typedef struct { + int32_t x_min, y_min, x_max, y_max; +} ASS_Rect; + +typedef struct { + double x_min, y_min, x_max, y_max; +} ASS_DRect; + +static inline void rectangle_reset(ASS_Rect *rect) +{ + rect->x_min = rect->y_min = INT32_MAX; + rect->x_max = rect->y_max = INT32_MIN; +} + +static inline void rectangle_update(ASS_Rect *rect, + int32_t x_min, int32_t y_min, int32_t x_max, int32_t y_max) +{ + rect->x_min = FFMIN(rect->x_min, x_min); + rect->y_min = FFMIN(rect->y_min, y_min); + rect->x_max = FFMAX(rect->x_max, x_max); + rect->y_max = FFMAX(rect->y_max, y_max); +} + +/* + * Outline represented with array of points and array of segments. + * Segment here is spline of order 1 (line), 2 (quadratic) or 3 (cubic). + * Each segment owns number of points equal to its order in point array + * and uses first point owned by the next segment as last point. + * Last segment in each contour instead of the next segment point uses + * point owned by the first segment in that contour. Correspondingly + * total number of points is equal to the sum of spline orders of all segments. + */ + +enum { + OUTLINE_LINE_SEGMENT = 1, // line segment + OUTLINE_QUADRATIC_SPLINE = 2, // quadratic spline + OUTLINE_CUBIC_SPLINE = 3, // cubic spline + OUTLINE_COUNT_MASK = 3, // spline order mask + OUTLINE_CONTOUR_END = 4 // last segment in contour flag +}; + +typedef struct { + size_t n_points, max_points; + size_t n_segments, max_segments; + ASS_Vector *points; + char *segments; +} ASS_Outline; + +#define OUTLINE_MIN (-((int32_t) 1 << 28)) +#define OUTLINE_MAX (((int32_t) 1 << 28) - 1) + +bool outline_alloc(ASS_Outline *outline, size_t n_points, size_t n_segments); +bool outline_convert(ASS_Outline *outline, const FT_Outline *source); +bool outline_copy(ASS_Outline *outline, const ASS_Outline *source); +void outline_free(ASS_Outline *outline); + +bool outline_add_point(ASS_Outline *outline, ASS_Vector pt, char segment); +bool outline_add_segment(ASS_Outline *outline, char segment); +bool outline_close_contour(ASS_Outline *outline); + +void outline_translate(const ASS_Outline *outline, int32_t dx, int32_t dy); +void outline_adjust(const ASS_Outline *outline, double scale_x, int32_t dx, int32_t dy); +void outline_get_cbox(const ASS_Outline *outline, ASS_Rect *cbox); + +bool outline_stroke(ASS_Outline *result, ASS_Outline *result1, + const ASS_Outline *path, int xbord, int ybord, int eps); + + +#endif /* LIBASS_OUTLINE_H */ diff -Nru libass-0.13.7/libass/ass_parse.c libass-0.14.0/libass/ass_parse.c --- libass-0.13.7/libass/ass_parse.c 2017-06-03 16:45:15.000000000 +0000 +++ libass-0.14.0/libass/ass_parse.c 2017-10-31 12:14:11.000000000 +0000 @@ -138,41 +138,6 @@ } /** - * \brief Change border width - * - * \param render_priv renderer state object - * \param info glyph state object - */ -void change_border(ASS_Renderer *render_priv, double border_x, double border_y) -{ - int bord = 64 * border_x * render_priv->border_scale; - - if (bord > 0 && border_x == border_y) { - if (!render_priv->state.stroker) { - int error; - error = - FT_Stroker_New(render_priv->ftlibrary, - &render_priv->state.stroker); - if (error) { - ass_msg(render_priv->library, MSGL_V, - "failed to get stroker"); - render_priv->state.stroker = 0; - } - render_priv->state.stroker_radius = -1.0; - } - if (render_priv->state.stroker && render_priv->state.stroker_radius != bord) { - FT_Stroker_Set(render_priv->state.stroker, bord, - FT_STROKER_LINECAP_ROUND, - FT_STROKER_LINEJOIN_ROUND, 0); - render_priv->state.stroker_radius = bord; - } - } else { - FT_Stroker_Done(render_priv->state.stroker); - render_priv->state.stroker = 0; - } -} - -/** * \brief Calculate a weighted average of two colors * calculates c1*(1-a) + c2*a, but separately for each component except alpha */ @@ -246,8 +211,7 @@ struct arg text = args[nargs - 1]; ass_drawing_free(drawing); - render_priv->state.clip_drawing = - ass_drawing_new(render_priv->library, render_priv->ftlibrary); + render_priv->state.clip_drawing = ass_drawing_new(render_priv->library); drawing = render_priv->state.clip_drawing; if (drawing) { drawing->scale = scale; @@ -992,8 +956,8 @@ x_start = 1000000; x_end = -1000000; for (cur2 = s1; cur2 <= e1; ++cur2) { - x_start = FFMIN(x_start, d6_to_int(cur2->bbox.xMin + cur2->pos.x)); - x_end = FFMAX(x_end, d6_to_int(cur2->bbox.xMax + cur2->pos.x)); + x_start = FFMIN(x_start, d6_to_int(cur2->bbox.x_min + cur2->pos.x)); + x_end = FFMAX(x_end, d6_to_int(cur2->bbox.x_max + cur2->pos.x)); } dt = (tm_current - tm_start); diff -Nru libass-0.13.7/libass/ass_parse.h libass-0.14.0/libass/ass_parse.h --- libass-0.13.7/libass/ass_parse.h 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/ass_parse.h 2017-10-31 12:14:11.000000000 +0000 @@ -28,9 +28,6 @@ void update_font(ASS_Renderer *render_priv); double ensure_font_size(ASS_Renderer *priv, double size); -void calc_border(ASS_Renderer *priv, double border_x, double border_y); -void change_border(ASS_Renderer *render_priv, double border_x, - double border_y); void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event); void process_karaoke_effects(ASS_Renderer *render_priv); unsigned get_next_char(ASS_Renderer *render_priv, char **str); diff -Nru libass-0.13.7/libass/ass_rasterizer.c libass-0.14.0/libass/ass_rasterizer.c --- libass-0.13.7/libass/ass_rasterizer.c 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/ass_rasterizer.c 2017-10-31 12:14:11.000000000 +0000 @@ -19,18 +19,19 @@ #include "config.h" #include "ass_compat.h" -#include "ass_utils.h" -#include "ass_rasterizer.h" #include - #ifdef _MSC_VER #include #pragma intrinsic(_BitScanReverse) #endif +#include "ass_utils.h" +#include "ass_outline.h" +#include "ass_rasterizer.h" -static inline int ilog2(uint32_t n) // XXX: different compilers + +static inline int ilog2(uint32_t n) { #ifdef __GNUC__ return __builtin_clz(n) ^ 31; @@ -41,7 +42,7 @@ #else int res = 0; for (int ord = 16; ord; ord /= 2) - if (n >= ((uint32_t)1 << ord)) { + if (n >= ((uint32_t) 1 << ord)) { res += ord; n >>= ord; } @@ -50,42 +51,48 @@ } -void rasterizer_init(RasterizerData *rst, int outline_error) +bool rasterizer_init(RasterizerData *rst, int tile_order, 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; + rst->n_first = 0; + + rst->tile = ass_aligned_alloc(32, 1 << (2 * tile_order), false); + return rst->tile; } /** * \brief Ensure sufficient buffer size (allocate if necessary) * \param index index (0 or 1) of the input segment buffer (rst->linebuf) * \param delta requested size increase - * \return zero on error + * \return false on error */ -static inline int check_capacity(RasterizerData *rst, int index, size_t delta) +static inline bool check_capacity(RasterizerData *rst, int index, size_t delta) { delta += rst->size[index]; if (rst->capacity[index] >= delta) - return 1; + return true; size_t capacity = FFMAX(2 * rst->capacity[index], 64); while (capacity < delta) capacity *= 2; void *ptr = realloc(rst->linebuf[index], sizeof(struct segment) * capacity); if (!ptr) - return 0; + return false; - rst->linebuf[index] = (struct segment *)ptr; + rst->linebuf[index] = (struct segment *) ptr; rst->capacity[index] = capacity; - return 1; + return true; } void rasterizer_done(RasterizerData *rst) { free(rst->linebuf[0]); free(rst->linebuf[1]); + + ass_aligned_free(rst->tile); } @@ -110,18 +117,14 @@ */ -typedef struct { - int32_t x, y; -} OutlinePoint; - // Helper struct for spline split decision typedef struct { - OutlinePoint r; + ASS_Vector r; int64_t r2, er; } OutlineSegment; static inline void segment_init(OutlineSegment *seg, - OutlinePoint beg, OutlinePoint end, + ASS_Vector beg, ASS_Vector end, int32_t outline_error) { int32_t x = end.x - beg.x; @@ -131,17 +134,17 @@ seg->r.x = x; seg->r.y = y; - seg->r2 = x * (int64_t)x + y * (int64_t)y; - seg->er = outline_error * (int64_t)FFMAX(abs_x, abs_y); + seg->r2 = x * (int64_t) x + y * (int64_t) y; + seg->er = outline_error * (int64_t) FFMAX(abs_x, abs_y); } -static inline int segment_subdivide(const OutlineSegment *seg, - OutlinePoint beg, OutlinePoint pt) +static inline bool segment_subdivide(const OutlineSegment *seg, + ASS_Vector beg, ASS_Vector pt) { int32_t x = pt.x - beg.x; int32_t y = pt.y - beg.y; - int64_t pdr = seg->r.x * (int64_t)x + seg->r.y * (int64_t)y; - int64_t pcr = seg->r.x * (int64_t)y - seg->r.y * (int64_t)x; + int64_t pdr = seg->r.x * (int64_t) x + seg->r.y * (int64_t) y; + int64_t pcr = seg->r.x * (int64_t) y - seg->r.y * (int64_t) x; return pdr < -seg->er || pdr > seg->r2 + seg->er || (pcr < 0 ? -pcr : pcr) > seg->er; } @@ -149,17 +152,17 @@ /** * \brief Add new segment to polyline */ -static inline int add_line(RasterizerData *rst, OutlinePoint pt0, OutlinePoint pt1) +static bool add_line(RasterizerData *rst, ASS_Vector pt0, ASS_Vector pt1) { int32_t x = pt1.x - pt0.x; int32_t y = pt1.y - pt0.y; if (!x && !y) - return 1; + return true; if (!check_capacity(rst, 0, 1)) - return 0; + return false; struct segment *line = rst->linebuf[0] + rst->size[0]; - ++rst->size[0]; + rst->size[0]++; line->flags = SEGFLAG_EXACT_LEFT | SEGFLAG_EXACT_RIGHT | SEGFLAG_EXACT_TOP | SEGFLAG_EXACT_BOTTOM; @@ -175,7 +178,7 @@ line->a = y; line->b = -x; - line->c = y * (int64_t)pt0.x - x * (int64_t)pt0.y; + line->c = y * (int64_t) pt0.x - x * (int64_t) pt0.y; // halfplane normalization int32_t abs_x = x < 0 ? -x : x; @@ -186,254 +189,142 @@ line->a *= 1 << shift; line->b *= 1 << shift; line->c *= 1 << shift; - line->scale = (uint64_t)0x53333333 * (uint32_t)(max_ab * (uint64_t)max_ab >> 32) >> 32; - line->scale += 0x8810624D - (0xBBC6A7EF * (uint64_t)max_ab >> 32); - //line->scale = ((uint64_t)1 << 61) / max_ab; - return 1; + line->scale = (uint64_t) 0x53333333 * (uint32_t) (max_ab * (uint64_t) max_ab >> 32) >> 32; + line->scale += 0x8810624D - (0xBBC6A7EF * (uint64_t) max_ab >> 32); + //line->scale = ((uint64_t) 1 << 61) / max_ab; + return true; } /** * \brief Add quadratic spline to polyline * Performs recursive subdivision if necessary. */ -static int add_quadratic(RasterizerData *rst, - OutlinePoint pt0, OutlinePoint pt1, OutlinePoint pt2) +static bool add_quadratic(RasterizerData *rst, const ASS_Vector *pt) { OutlineSegment seg; - segment_init(&seg, pt0, pt2, rst->outline_error); - if (!segment_subdivide(&seg, pt0, pt1)) - return add_line(rst, pt0, pt2); - - OutlinePoint p01, p12, c; // XXX: overflow? - p01.x = pt0.x + pt1.x; - p01.y = pt0.y + pt1.y; - p12.x = pt1.x + pt2.x; - p12.y = pt1.y + pt2.y; - c.x = (p01.x + p12.x + 2) >> 2; - c.y = (p01.y + p12.y + 2) >> 2; - p01.x >>= 1; - p01.y >>= 1; - p12.x >>= 1; - p12.y >>= 1; - return add_quadratic(rst, pt0, p01, c) && add_quadratic(rst, c, p12, pt2); + segment_init(&seg, pt[0], pt[2], rst->outline_error); + if (!segment_subdivide(&seg, pt[0], pt[1])) + return add_line(rst, pt[0], pt[2]); + + ASS_Vector next[5]; + next[1].x = pt[0].x + pt[1].x; + next[1].y = pt[0].y + pt[1].y; + next[3].x = pt[1].x + pt[2].x; + next[3].y = pt[1].y + pt[2].y; + next[2].x = (next[1].x + next[3].x + 2) >> 2; + next[2].y = (next[1].y + next[3].y + 2) >> 2; + next[1].x >>= 1; + next[1].y >>= 1; + next[3].x >>= 1; + next[3].y >>= 1; + next[0] = pt[0]; + next[4] = pt[2]; + return add_quadratic(rst, next) && add_quadratic(rst, next + 2); } /** * \brief Add cubic spline to polyline * Performs recursive subdivision if necessary. */ -static int add_cubic(RasterizerData *rst, - OutlinePoint pt0, OutlinePoint pt1, OutlinePoint pt2, OutlinePoint pt3) +static bool add_cubic(RasterizerData *rst, const ASS_Vector *pt) { OutlineSegment seg; - segment_init(&seg, pt0, pt3, rst->outline_error); - if (!segment_subdivide(&seg, pt0, pt1) && !segment_subdivide(&seg, pt0, pt2)) - return add_line(rst, pt0, pt3); - - OutlinePoint p01, p12, p23, p012, p123, c; // XXX: overflow? - p01.x = pt0.x + pt1.x; - p01.y = pt0.y + pt1.y; - p12.x = pt1.x + pt2.x + 2; - p12.y = pt1.y + pt2.y + 2; - p23.x = pt2.x + pt3.x; - p23.y = pt2.y + pt3.y; - p012.x = p01.x + p12.x; - p012.y = p01.y + p12.y; - p123.x = p12.x + p23.x; - p123.y = p12.y + p23.y; - c.x = (p012.x + p123.x - 1) >> 3; - c.y = (p012.y + p123.y - 1) >> 3; - p01.x >>= 1; - p01.y >>= 1; - p012.x >>= 2; - p012.y >>= 2; - p123.x >>= 2; - p123.y >>= 2; - p23.x >>= 1; - p23.y >>= 1; - return add_cubic(rst, pt0, p01, p012, c) && add_cubic(rst, c, p123, p23, pt3); + segment_init(&seg, pt[0], pt[3], rst->outline_error); + if (!segment_subdivide(&seg, pt[0], pt[1]) && !segment_subdivide(&seg, pt[0], pt[2])) + return add_line(rst, pt[0], pt[3]); + + ASS_Vector next[7], center; + next[1].x = pt[0].x + pt[1].x; + next[1].y = pt[0].y + pt[1].y; + center.x = pt[1].x + pt[2].x + 2; + center.y = pt[1].y + pt[2].y + 2; + next[5].x = pt[2].x + pt[3].x; + next[5].y = pt[2].y + pt[3].y; + next[2].x = next[1].x + center.x; + next[2].y = next[1].y + center.y; + next[4].x = center.x + next[5].x; + next[4].y = center.y + next[5].y; + next[3].x = (next[2].x + next[4].x - 1) >> 3; + next[3].y = (next[2].y + next[4].y - 1) >> 3; + next[2].x >>= 2; + next[2].y >>= 2; + next[4].x >>= 2; + next[4].y >>= 2; + next[1].x >>= 1; + next[1].y >>= 1; + next[5].x >>= 1; + next[5].y >>= 1; + next[0] = pt[0]; + next[6] = pt[3]; + return add_cubic(rst, next) && add_cubic(rst, next + 3); } -int rasterizer_set_outline(RasterizerData *rst, const ASS_Outline *path) -{ - enum Status { - S_ON, S_Q, S_C1, S_C2 - }; - - size_t i, j = 0; - rst->size[0] = 0; - for (i = 0; i < path->n_contours; ++i) { - OutlinePoint start, p[4]; - int process_end = 1; - enum Status st; - - int last = path->contours[i]; - if (j > last) - return 0; - - if (path->points[j].x < -(1 << 28) || path->points[j].x >= (1 << 28)) - return 0; - if (path->points[j].y <= -(1 << 28) || path->points[j].y > (1 << 28)) - return 0; - - switch (FT_CURVE_TAG(path->tags[j])) { - case FT_CURVE_TAG_ON: - p[0].x = path->points[j].x; - p[0].y = -path->points[j].y; - start = p[0]; - st = S_ON; +bool rasterizer_set_outline(RasterizerData *rst, + const ASS_Outline *path, bool extra) +{ + if (!extra) { + rectangle_reset(&rst->bbox); + rst->n_first = 0; + } + rst->size[0] = rst->n_first; + + for (size_t i = 0; i < path->n_points; i++) { + if (path->points[i].x < OUTLINE_MIN || path->points[i].x > OUTLINE_MAX) + return false; + if (path->points[i].y < OUTLINE_MIN || path->points[i].y > OUTLINE_MAX) + return false; + } + + ASS_Vector *start = path->points, *cur = start; + for (size_t i = 0; i < path->n_segments; i++) { + int n = path->segments[i] & OUTLINE_COUNT_MASK; + cur += n; + + ASS_Vector *end = cur, p[4]; + if (path->segments[i] & OUTLINE_CONTOUR_END) { + end = start; + start = cur; + } + + switch (n) { + case OUTLINE_LINE_SEGMENT: + if (!add_line(rst, cur[-1], *end)) + return false; break; - case FT_CURVE_TAG_CONIC: - switch (FT_CURVE_TAG(path->tags[last])) { - case FT_CURVE_TAG_ON: - p[0].x = path->points[last].x; - p[0].y = -path->points[last].y; - p[1].x = path->points[j].x; - p[1].y = -path->points[j].y; - process_end = 0; - st = S_Q; - break; - - case FT_CURVE_TAG_CONIC: - p[1].x = path->points[j].x; - p[1].y = -path->points[j].y; - p[0].x = (p[1].x + path->points[last].x) >> 1; - p[0].y = (p[1].y - path->points[last].y) >> 1; - start = p[0]; - st = S_Q; - break; - - default: - return 0; - } + case OUTLINE_QUADRATIC_SPLINE: + p[0] = cur[-2]; + p[1] = cur[-1]; + p[2] = *end; + if (!add_quadratic(rst, p)) + return false; break; - default: - return 0; - } + case OUTLINE_CUBIC_SPLINE: + p[0] = cur[-3]; + p[1] = cur[-2]; + p[2] = cur[-1]; + p[3] = *end; + if (!add_cubic(rst, p)) + return false; + break; - for (j++; j <= last; j++) { - if (path->points[j].x < -(1 << 28) || path->points[j].x >= (1 << 28)) - return 0; - if (path->points[j].y <= -(1 << 28) || path->points[j].y > (1 << 28)) - return 0; - - switch (FT_CURVE_TAG(path->tags[j])) { - case FT_CURVE_TAG_ON: - switch (st) { - case S_ON: - p[1].x = path->points[j].x; - p[1].y = -path->points[j].y; - if (!add_line(rst, p[0], p[1])) - return 0; - p[0] = p[1]; - break; - - case S_Q: - p[2].x = path->points[j].x; - p[2].y = -path->points[j].y; - if (!add_quadratic(rst, p[0], p[1], p[2])) - return 0; - p[0] = p[2]; - st = S_ON; - break; - - case S_C2: - p[3].x = path->points[j].x; - p[3].y = -path->points[j].y; - if (!add_cubic(rst, p[0], p[1], p[2], p[3])) - return 0; - p[0] = p[3]; - st = S_ON; - break; - - default: - return 0; - } - break; - - case FT_CURVE_TAG_CONIC: - switch (st) { - case S_ON: - p[1].x = path->points[j].x; - p[1].y = -path->points[j].y; - st = S_Q; - break; - - case S_Q: - p[3].x = path->points[j].x; - p[3].y = -path->points[j].y; - p[2].x = (p[1].x + p[3].x) >> 1; - p[2].y = (p[1].y + p[3].y) >> 1; - if (!add_quadratic(rst, p[0], p[1], p[2])) - return 0; - p[0] = p[2]; - p[1] = p[3]; - break; - - default: - return 0; - } - break; - - case FT_CURVE_TAG_CUBIC: - switch (st) { - case S_ON: - p[1].x = path->points[j].x; - p[1].y = -path->points[j].y; - st = S_C1; - break; - - case S_C1: - p[2].x = path->points[j].x; - p[2].y = -path->points[j].y; - st = S_C2; - break; - - default: - return 0; - } - break; - - default: - return 0; - } + default: + return false; } - - if (process_end) - switch (st) { - case S_ON: - if (!add_line(rst, p[0], start)) - return 0; - break; - - case S_Q: - if (!add_quadratic(rst, p[0], p[1], start)) - return 0; - break; - - case S_C2: - if (!add_cubic(rst, p[0], p[1], p[2], start)) - return 0; - break; - - default: - return 0; - } - } - - size_t k; - rst->x_min = rst->y_min = 0x7FFFFFFF; - rst->x_max = rst->y_max = 0x80000000; - for (k = 0; k < rst->size[0]; ++k) { - rst->x_min = FFMIN(rst->x_min, rst->linebuf[0][k].x_min); - rst->x_max = FFMAX(rst->x_max, rst->linebuf[0][k].x_max); - rst->y_min = FFMIN(rst->y_min, rst->linebuf[0][k].y_min); - rst->y_max = FFMAX(rst->y_max, rst->linebuf[0][k].y_max); } - return 1; + assert(start == cur && cur == path->points + path->n_points); + + for (size_t k = rst->n_first; k < rst->size[0]; k++) { + struct segment *line = &rst->linebuf[0][k]; + rectangle_update(&rst->bbox, + line->x_min, line->y_min, + line->x_max, line->y_max); + } + if (!extra) + rst->n_first = rst->size[0]; + return true; } @@ -442,7 +333,7 @@ line->x_min -= x; line->x_max -= x; line->x_min = FFMAX(line->x_min, 0); - line->c -= line->a * (int64_t)x; + line->c -= line->a * (int64_t) x; static const int test = SEGFLAG_EXACT_LEFT | SEGFLAG_UL_DR; if (!line->x_min && (line->flags & test) == test) @@ -454,7 +345,7 @@ line->y_min -= y; line->y_max -= y; line->y_min = FFMAX(line->y_min, 0); - line->c -= line->b * (int64_t)y; + line->c -= line->b * (int64_t) y; static const int test = SEGFLAG_EXACT_TOP | SEGFLAG_UL_DR; if (!line->y_min && (line->flags & test) == test) @@ -466,7 +357,7 @@ assert(x > line->x_min && x < line->x_max); *next = *line; - next->c -= line->a * (int64_t)x; + next->c -= line->a * (int64_t) x; next->x_min = 0; next->x_max -= x; line->x_max = x; @@ -487,7 +378,7 @@ assert(y > line->y_min && y < line->y_max); *next = *line; - next->c -= line->b * (int64_t)y; + next->c -= line->b * (int64_t) y; next->y_min = 0; next->y_max -= y; line->y_max = y; @@ -507,8 +398,8 @@ { if (line->flags & SEGFLAG_EXACT_LEFT) return line->x_min >= x; - int64_t cc = line->c - line->a * (int64_t)x - - line->b * (int64_t)(line->flags & SEGFLAG_UL_DR ? line->y_min : line->y_max); + int64_t cc = line->c - line->a * (int64_t) x - + line->b * (int64_t) (line->flags & SEGFLAG_UL_DR ? line->y_min : line->y_max); if (line->a < 0) cc = -cc; return cc >= 0; @@ -518,8 +409,8 @@ { if (line->flags & SEGFLAG_EXACT_RIGHT) return line->x_max <= x; - int64_t cc = line->c - line->a * (int64_t)x - - line->b * (int64_t)(line->flags & SEGFLAG_UL_DR ? line->y_max : line->y_min); + int64_t cc = line->c - line->a * (int64_t) x - + line->b * (int64_t) (line->flags & SEGFLAG_UL_DR ? line->y_max : line->y_min); if (line->a > 0) cc = -cc; return cc >= 0; @@ -529,8 +420,8 @@ { if (line->flags & SEGFLAG_EXACT_TOP) return line->y_min >= y; - int64_t cc = line->c - line->b * (int64_t)y - - line->a * (int64_t)(line->flags & SEGFLAG_UL_DR ? line->x_min : line->x_max); + int64_t cc = line->c - line->b * (int64_t) y - + line->a * (int64_t) (line->flags & SEGFLAG_UL_DR ? line->x_min : line->x_max); if (line->b < 0) cc = -cc; return cc >= 0; @@ -540,8 +431,8 @@ { if (line->flags & SEGFLAG_EXACT_BOTTOM) return line->y_max <= y; - int64_t cc = line->c - line->b * (int64_t)y - - line->a * (int64_t)(line->flags & SEGFLAG_UL_DR ? line->x_max : line->x_min); + int64_t cc = line->c - line->b * (int64_t) y - + line->a * (int64_t) (line->flags & SEGFLAG_UL_DR ? line->x_max : line->x_min); if (line->b > 0) cc = -cc; return cc >= 0; @@ -550,80 +441,99 @@ /** * \brief Split list of segments horizontally * \param src in: input array, can coincide with *dst0 or *dst1 - * \param n_src in: input array size - * \param dst0, dst1 out: pointers to output arrays of at least n_src size + * \param n_src in: numbers of input segments for both groups + * \param dst0, dst1 out: output arrays of at least n_src[0] + n_src[1] size + * \param n_dst0, n_dst1 out: numbers of output segments for both groups + * \param winding out: resulting winding of bottom-split point * \param x in: split coordinate - * \return winding difference between bottom-split and bottom-left points */ -static int polyline_split_horz(const struct segment *src, size_t n_src, - struct segment **dst0, struct segment **dst1, int32_t x) -{ - int winding = 0; - const struct segment *end = src + n_src; - for (; src != end; ++src) { +static void polyline_split_horz(const struct segment *src, const size_t n_src[2], + struct segment *dst0, size_t n_dst0[2], + struct segment *dst1, size_t n_dst1[2], + int winding[2], int32_t x) +{ + const struct segment *cmp = src + n_src[0]; + const struct segment *end = cmp + n_src[1]; + n_dst0[0] = n_dst0[1] = 0; + n_dst1[0] = n_dst1[1] = 0; + for (; src != end; src++) { + int group = src < cmp ? 0 : 1; + int delta = 0; if (!src->y_min && (src->flags & SEGFLAG_EXACT_TOP)) delta = src->a < 0 ? 1 : -1; if (segment_check_right(src, x)) { - winding += delta; + winding[group] += delta; if (src->x_min >= x) continue; - **dst0 = *src; - (*dst0)->x_max = FFMIN((*dst0)->x_max, x); - ++(*dst0); + *dst0 = *src; + dst0->x_max = FFMIN(dst0->x_max, x); + n_dst0[group]++; + dst0++; continue; } if (segment_check_left(src, x)) { - **dst1 = *src; - segment_move_x(*dst1, x); - ++(*dst1); + *dst1 = *src; + segment_move_x(dst1, x); + n_dst1[group]++; + dst1++; continue; } if (src->flags & SEGFLAG_UL_DR) - winding += delta; - **dst0 = *src; - segment_split_horz(*dst0, *dst1, x); - ++(*dst0); - ++(*dst1); + winding[group] += delta; + *dst0 = *src; + segment_split_horz(dst0, dst1, x); + n_dst0[group]++; + dst0++; + n_dst1[group]++; + dst1++; } - return winding; } /** * \brief Split list of segments vertically */ -static int polyline_split_vert(const struct segment *src, size_t n_src, - struct segment **dst0, struct segment **dst1, int32_t y) -{ - int winding = 0; - const struct segment *end = src + n_src; - for (; src != end; ++src) { +static void polyline_split_vert(const struct segment *src, const size_t n_src[2], + struct segment *dst0, size_t n_dst0[2], + struct segment *dst1, size_t n_dst1[2], + int winding[2], int32_t y) +{ + const struct segment *cmp = src + n_src[0]; + const struct segment *end = cmp + n_src[1]; + n_dst0[0] = n_dst0[1] = 0; + n_dst1[0] = n_dst1[1] = 0; + for (; src != end; src++) { + int group = src < cmp ? 0 : 1; + int delta = 0; if (!src->x_min && (src->flags & SEGFLAG_EXACT_LEFT)) delta = src->b < 0 ? 1 : -1; if (segment_check_bottom(src, y)) { - winding += delta; + winding[group] += delta; if (src->y_min >= y) continue; - **dst0 = *src; - (*dst0)->y_max = (*dst0)->y_max < y ? (*dst0)->y_max : y; - ++(*dst0); + *dst0 = *src; + dst0->y_max = dst0->y_max < y ? dst0->y_max : y; + n_dst0[group]++; + dst0++; continue; } if (segment_check_top(src, y)) { - **dst1 = *src; - segment_move_y(*dst1, y); - ++(*dst1); + *dst1 = *src; + segment_move_y(dst1, y); + n_dst1[group]++; + dst1++; continue; } if (src->flags & SEGFLAG_UL_DR) - winding += delta; - **dst0 = *src; - segment_split_vert(*dst0, *dst1, y); - ++(*dst0); - ++(*dst1); + winding[group] += delta; + *dst0 = *src; + segment_split_vert(dst0, dst1, y); + n_dst0[group]++; + dst0++; + n_dst1[group]++; + dst1++; } - return winding; } @@ -634,14 +544,13 @@ assert(!(width & ((1 << engine->tile_order) - 1))); assert(!(height & ((1 << engine->tile_order) - 1))); - int i, j; 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) - engine->fill_solid(buf + i * step, stride, set); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) + engine->fill_solid(buf + x * step, stride, set); buf += tile_stride; } } @@ -659,168 +568,219 @@ 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) << (engine->tile_order + 5); - int64_t offs = ((int64_t)a + b) * (1 << (engine->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 << 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 << (engine->tile_order + 6)); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int64_t cc = c - (a * (int64_t) x + b * (int64_t) y) * (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) - engine->fill_halfplane(buf + i * step, stride, a, b, cc, scale); + engine->fill_halfplane(buf + x * step, stride, a, b, cc, scale); else - engine->fill_solid(buf + i * step, stride, - ((uint32_t)(offs_c >> 32) ^ scale) & 0x80000000); + engine->fill_solid(buf + x * step, stride, + ((uint32_t) (offs_c >> 32) ^ scale) & 0x80000000); } buf += tile_stride; } } +enum { + FLAG_SOLID = 1, + FLAG_COMPLEX = 2, + FLAG_REVERSE = 4, + FLAG_GENERIC = 8, +}; + +static inline int get_fill_flags(struct segment *line, size_t n_lines, int winding) +{ + if (!n_lines) + return winding ? FLAG_SOLID : 0; + if (n_lines > 1) + return FLAG_COMPLEX | FLAG_GENERIC; + + static const int test = SEGFLAG_UL_DR | SEGFLAG_EXACT_LEFT; + if (((line->flags & test) != test) == !(line->flags & SEGFLAG_DN)) + winding++; + + switch (winding) { + case 0: + return FLAG_COMPLEX | FLAG_REVERSE; + case 1: + return FLAG_COMPLEX; + default: + return FLAG_SOLID; + } +} + /** * \brief Main quad-tree filling function * \param index index (0 or 1) of the input segment buffer (rst->linebuf) * \param offs current offset from the beginning of the buffer * \param winding bottom-left winding value - * \return zero on error + * \return false on error * Rasterizes (possibly recursive) one quad-tree level. * Truncates used input buffer. */ -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) +static bool rasterizer_fill_level(const BitmapEngine *engine, RasterizerData *rst, + uint8_t *buf, int width, int height, ptrdiff_t stride, + int index, const size_t n_lines[2], const int winding[2]) { assert(width > 0 && height > 0); - assert((unsigned)index < 2u && offs <= rst->size[index]); + assert((unsigned) index < 2u && n_lines[0] + n_lines[1] <= rst->size[index]); 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(engine, buf, width, height, stride, winding); - return 1; - } - if (n == 1) { - static const int test = SEGFLAG_UL_DR | SEGFLAG_EXACT_LEFT; - if (((line->flags & test) != test) == !(line->flags & SEGFLAG_DN)) - winding++; - - int flag = 0; - if (winding) - flag ^= 1; - if (winding - 1) - flag ^= 3; - if (flag & 1) - rasterizer_fill_halfplane(engine, buf, width, height, stride, - line->a, line->b, line->c, - flag & 2 ? -line->scale : line->scale); - else - rasterizer_fill_solid(engine, buf, width, height, stride, flag & 2); + size_t offs = rst->size[index] - n_lines[0] - n_lines[1]; + struct segment *line = rst->linebuf[index] + offs, *line1 = line + n_lines[0]; + int flags0 = get_fill_flags(line, n_lines[0], winding[0]); + int flags1 = get_fill_flags(line1, n_lines[1], winding[1]); + int flags = (flags0 | flags1) ^ FLAG_COMPLEX; + if (flags & (FLAG_SOLID | FLAG_COMPLEX)) { + rasterizer_fill_solid(engine, buf, width, height, stride, flags & FLAG_SOLID); + rst->size[index] = offs; + return true; + } + if (!(flags & FLAG_GENERIC) && ((flags0 ^ flags1) & FLAG_COMPLEX)) { + if (flags1 & FLAG_COMPLEX) + line = line1; + rasterizer_fill_halfplane(engine, buf, width, height, stride, + line->a, line->b, line->c, + flags & FLAG_REVERSE ? -line->scale : line->scale); rst->size[index] = offs; - return 1; + return true; } if (width == 1 << engine->tile_order && height == 1 << engine->tile_order) { - engine->fill_generic(buf, stride, line, rst->size[index] - offs, winding); + if (!(flags1 & FLAG_COMPLEX)) { + engine->fill_generic(buf, stride, line, n_lines[0], winding[0]); + rst->size[index] = offs; + return true; + } + if (!(flags0 & FLAG_COMPLEX)) { + engine->fill_generic(buf, stride, line1, n_lines[1], winding[1]); + rst->size[index] = offs; + return true; + } + if (flags0 & FLAG_GENERIC) + engine->fill_generic(buf, stride, line, n_lines[0], winding[0]); + else + engine->fill_halfplane(buf, stride, line->a, line->b, line->c, + flags0 & FLAG_REVERSE ? -line->scale : line->scale); + if (flags1 & FLAG_GENERIC) + engine->fill_generic(rst->tile, width, line1, n_lines[1], winding[1]); + else + engine->fill_halfplane(rst->tile, width, line1->a, line1->b, line1->c, + flags1 & FLAG_REVERSE ? -line1->scale : line1->scale); + // XXX: better to use max instead of add + engine->add_bitmaps(buf, stride, rst->tile, width, height, width); rst->size[index] = offs; - return 1; + return true; } size_t offs1 = rst->size[index ^ 1]; - if (!check_capacity(rst, index ^ 1, n)) - return 0; + if (!check_capacity(rst, index ^ 1, n_lines[0] + n_lines[1])) + return false; struct segment *dst0 = line; struct segment *dst1 = rst->linebuf[index ^ 1] + offs1; - int winding1 = winding; uint8_t *buf1 = buf; int width1 = width; int height1 = height; + size_t n_next0[2], n_next1[2]; + int winding1[2] = { winding[0], winding[1] }; if (width > height) { width = 1 << ilog2(width - 1); width1 -= width; buf1 += width; - winding1 += polyline_split_horz(line, n, &dst0, &dst1, (int32_t)width << 6); + polyline_split_horz(line, n_lines, + dst0, n_next0, dst1, n_next1, + winding1, (int32_t) width << 6); } else { height = 1 << ilog2(height - 1); height1 -= height; buf1 += height * stride; - winding1 += polyline_split_vert(line, n, &dst0, &dst1, (int32_t)height << 6); + polyline_split_vert(line, n_lines, + dst0, n_next0, dst1, n_next1, + winding1, (int32_t) height << 6); } - rst->size[index ^ 0] = dst0 - rst->linebuf[index ^ 0]; - rst->size[index ^ 1] = dst1 - rst->linebuf[index ^ 1]; + rst->size[index ^ 0] = offs + n_next0[0] + n_next0[1]; + rst->size[index ^ 1] = offs1 + n_next1[0] + n_next1[1]; - if (!rasterizer_fill_level(engine, rst, buf, width, height, stride, index ^ 0, offs, winding)) - return 0; + if (!rasterizer_fill_level(engine, rst, buf, width, height, stride, index ^ 0, n_next0, winding)) + return false; assert(rst->size[index ^ 0] == offs); - if (!rasterizer_fill_level(engine, rst, buf1, width1, height1, stride, index ^ 1, offs1, winding1)) - return 0; + if (!rasterizer_fill_level(engine, rst, buf1, width1, height1, stride, index ^ 1, n_next1, winding1)) + return false; assert(rst->size[index ^ 1] == offs1); - return 1; + return true; } -int rasterizer_fill(const BitmapEngine *engine, RasterizerData *rst, - uint8_t *buf, int x0, int y0, int width, int height, ptrdiff_t stride) +bool 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 << engine->tile_order) - 1))); assert(!(height & ((1 << engine->tile_order) - 1))); x0 *= 1 << 6; y0 *= 1 << 6; - size_t n = rst->size[0]; struct segment *line = rst->linebuf[0]; - struct segment *end = line + n; - for (; line != end; ++line) { + struct segment *end = line + rst->size[0]; + for (; line != end; line++) { line->x_min -= x0; line->x_max -= x0; line->y_min -= y0; line->y_max -= y0; - line->c -= line->a * (int64_t)x0 + line->b * (int64_t)y0; + line->c -= line->a * (int64_t) x0 + line->b * (int64_t) y0; } - rst->x_min -= x0; - rst->x_max -= x0; - rst->y_min -= y0; - rst->y_max -= y0; + rst->bbox.x_min -= x0; + rst->bbox.x_max -= x0; + rst->bbox.y_min -= y0; + rst->bbox.y_max -= y0; - int index = 0; - int winding = 0; if (!check_capacity(rst, 1, rst->size[0])) - return 0; - int32_t size_x = (int32_t)width << 6; - int32_t size_y = (int32_t)height << 6; - if (rst->x_max >= size_x) { - struct segment *dst0 = rst->linebuf[index]; - struct segment *dst1 = rst->linebuf[index ^ 1]; - polyline_split_horz(rst->linebuf[index], n, &dst0, &dst1, size_x); - n = dst0 - rst->linebuf[index]; - } - if (rst->y_max >= size_y) { - struct segment *dst0 = rst->linebuf[index]; - struct segment *dst1 = rst->linebuf[index ^ 1]; - polyline_split_vert(rst->linebuf[index], n, &dst0, &dst1, size_y); - n = dst0 - rst->linebuf[index]; - } - if (rst->x_min <= 0) { - struct segment *dst0 = rst->linebuf[index]; - struct segment *dst1 = rst->linebuf[index ^ 1]; - polyline_split_horz(rst->linebuf[index], n, &dst0, &dst1, 0); - index ^= 1; - n = dst1 - rst->linebuf[index]; - } - if (rst->y_min <= 0) { - struct segment *dst0 = rst->linebuf[index]; - struct segment *dst1 = rst->linebuf[index ^ 1]; - winding = polyline_split_vert(rst->linebuf[index], n, &dst0, &dst1, 0); - index ^= 1; - n = dst1 - rst->linebuf[index]; - } - rst->size[index] = n; - rst->size[index ^ 1] = 0; - return rasterizer_fill_level(engine, rst, buf, width, height, stride, - index, 0, winding); + return false; + + size_t n_unused[2]; + size_t n_lines[2] = { rst->n_first, rst->size[0] - rst->n_first }; + int winding[2] = { 0, 0 }; + + int32_t size_x = (int32_t) width << 6; + int32_t size_y = (int32_t) height << 6; + if (rst->bbox.x_max >= size_x) { + polyline_split_horz(rst->linebuf[0], n_lines, + rst->linebuf[0], n_lines, + rst->linebuf[1], n_unused, + winding, size_x); + winding[0] = winding[1] = 0; + } + if (rst->bbox.y_max >= size_y) { + polyline_split_vert(rst->linebuf[0], n_lines, + rst->linebuf[0], n_lines, + rst->linebuf[1], n_unused, + winding, size_y); + winding[0] = winding[1] = 0; + } + if (rst->bbox.x_min <= 0) { + polyline_split_horz(rst->linebuf[0], n_lines, + rst->linebuf[1], n_unused, + rst->linebuf[0], n_lines, + winding, 0); + } + if (rst->bbox.y_min <= 0) { + polyline_split_vert(rst->linebuf[0], n_lines, + rst->linebuf[1], n_unused, + rst->linebuf[0], n_lines, + winding, 0); + } + rst->size[0] = n_lines[0] + n_lines[1]; + rst->size[1] = 0; + return rasterizer_fill_level(engine, rst, + buf, width, height, stride, + 0, n_lines, winding); } diff -Nru libass-0.13.7/libass/ass_rasterizer_c.c libass-0.14.0/libass/ass_rasterizer_c.c --- libass-0.13.7/libass/ass_rasterizer_c.c 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/ass_rasterizer_c.c 2017-10-31 12:14:11.000000000 +0000 @@ -27,22 +27,20 @@ void ass_fill_solid_tile16_c(uint8_t *buf, ptrdiff_t stride, int set) { - int i, j; - int8_t value = set ? 255 : 0; - for (j = 0; j < 16; ++j) { - for (i = 0; i < 16; ++i) - buf[i] = value; + uint8_t value = set ? 255 : 0; + for (int y = 0; y < 16; y++) { + for (int x = 0; x < 16; x++) + buf[x] = value; buf += stride; } } void ass_fill_solid_tile32_c(uint8_t *buf, ptrdiff_t stride, int set) { - int i, j; - int8_t value = set ? 255 : 0; - for (j = 0; j < 32; ++j) { - for (i = 0; i < 32; ++i) - buf[i] = value; + uint8_t value = set ? 255 : 0; + for (int y = 0; y < 32; y++) { + for (int x = 0; x < 32; x++) + buf[x] = value; buf += stride; } } @@ -73,30 +71,29 @@ void ass_fill_halfplane_tile16_c(uint8_t *buf, ptrdiff_t stride, int32_t a, int32_t b, int64_t c, int32_t scale) { - int16_t aa = (a * (int64_t)scale + ((int64_t)1 << 49)) >> 50; - int16_t bb = (b * (int64_t)scale + ((int64_t)1 << 49)) >> 50; - int16_t cc = ((int32_t)(c >> 11) * (int64_t)scale + ((int64_t)1 << 44)) >> 45; + int16_t aa = (a * (int64_t) scale + ((int64_t) 1 << 49)) >> 50; + int16_t bb = (b * (int64_t) scale + ((int64_t) 1 << 49)) >> 50; + int16_t cc = ((int32_t) (c >> 11) * (int64_t) scale + ((int64_t) 1 << 44)) >> 45; cc += (1 << 9) - ((aa + bb) >> 1); int16_t abs_a = aa < 0 ? -aa : aa; int16_t abs_b = bb < 0 ? -bb : bb; int16_t delta = (FFMIN(abs_a, abs_b) + 2) >> 2; - int i, j; int16_t va1[16], va2[16]; - for (i = 0; i < 16; ++i) { - va1[i] = aa * i - delta; - va2[i] = aa * i + delta; + for (int x = 0; x < 16; x++) { + va1[x] = aa * x - delta; + va2[x] = aa * x + delta; } static const int16_t full = (1 << 10) - 1; - for (j = 0; j < 16; ++j) { - for (i = 0; i < 16; ++i) { - int16_t c1 = cc - va1[i]; - int16_t c2 = cc - va2[i]; + for (int y = 0; y < 16; y++) { + for (int x = 0; x < 16; x++) { + int16_t c1 = cc - va1[x]; + int16_t c2 = cc - va2[x]; c1 = FFMINMAX(c1, 0, full); c2 = FFMINMAX(c2, 0, full); - buf[i] = (c1 + c2) >> 3; + buf[x] = (c1 + c2) >> 3; } buf += stride; cc -= bb; @@ -106,30 +103,29 @@ void ass_fill_halfplane_tile32_c(uint8_t *buf, ptrdiff_t stride, int32_t a, int32_t b, int64_t c, int32_t scale) { - int16_t aa = (a * (int64_t)scale + ((int64_t)1 << 50)) >> 51; - int16_t bb = (b * (int64_t)scale + ((int64_t)1 << 50)) >> 51; - int16_t cc = ((int32_t)(c >> 12) * (int64_t)scale + ((int64_t)1 << 44)) >> 45; + int16_t aa = (a * (int64_t) scale + ((int64_t) 1 << 50)) >> 51; + int16_t bb = (b * (int64_t) scale + ((int64_t) 1 << 50)) >> 51; + int16_t cc = ((int32_t) (c >> 12) * (int64_t) scale + ((int64_t) 1 << 44)) >> 45; cc += (1 << 8) - ((aa + bb) >> 1); int16_t abs_a = aa < 0 ? -aa : aa; int16_t abs_b = bb < 0 ? -bb : bb; int16_t delta = (FFMIN(abs_a, abs_b) + 2) >> 2; - int i, j; int16_t va1[32], va2[32]; - for (i = 0; i < 32; ++i) { - va1[i] = aa * i - delta; - va2[i] = aa * i + delta; + for (int x = 0; x < 32; x++) { + va1[x] = aa * x - delta; + va2[x] = aa * x + delta; } static const int16_t full = (1 << 9) - 1; - for (j = 0; j < 32; ++j) { - for (i = 0; i < 32; ++i) { - int16_t c1 = cc - va1[i]; - int16_t c2 = cc - va2[i]; + for (int y = 0; y < 32; y++) { + for (int x = 0; x < 32; x++) { + int16_t c1 = cc - va1[x]; + int16_t c2 = cc - va2[x]; c1 = FFMINMAX(c1, 0, full); c2 = FFMINMAX(c2, 0, full); - buf[i] = (c1 + c2) >> 2; + buf[x] = (c1 + c2) >> 2; } buf += stride; cc -= bb; @@ -156,22 +152,21 @@ int16_t w = (1 << 10) + (size << 4) - abs_a; w = FFMIN(w, 1 << 10) << 3; - int16_t dc_b = abs_b * (int32_t)size >> 6; + int16_t dc_b = abs_b * (int32_t) size >> 6; int16_t dc = (FFMIN(abs_a, dc_b) + 2) >> 2; - int16_t base = (int32_t)b * (int16_t)(up + dn) >> 7; - int16_t offs1 = size - ((base + dc) * (int32_t)w >> 16); - int16_t offs2 = size - ((base - dc) * (int32_t)w >> 16); + int16_t base = (int32_t) b * (int16_t) (up + dn) >> 7; + int16_t offs1 = size - ((base + dc) * (int32_t) w >> 16); + int16_t offs2 = size - ((base - dc) * (int32_t) w >> 16); - int i; size <<= 1; - for (i = 0; i < 16; ++i) { - int16_t cw = (c - va[i]) * (int32_t)w >> 16; + for (int x = 0; x < 16; x++) { + int16_t cw = (c - va[x]) * (int32_t) w >> 16; int16_t c1 = cw + offs1; int16_t c2 = cw + offs2; c1 = FFMINMAX(c1, 0, size); c2 = FFMINMAX(c2, 0, size); - res[i] += c1 + c2; + res[x] += c1 + c2; } } @@ -179,13 +174,12 @@ const struct segment *line, size_t n_lines, int winding) { - int i, j; int16_t res[16][16], delta[18]; - for (j = 0; j < 16; ++j) - for (i = 0; i < 16; ++i) - res[j][i] = 0; - for (j = 0; j < 18; ++j) - delta[j] = 0; + for (int y = 0; y < 16; y++) + for (int x = 0; x < 16; x++) + res[y][x] = 0; + for (int y = 0; y < 18; y++) + delta[y] = 0; static const int16_t full = 1 << 10; const struct segment *end = line + n_lines; @@ -196,7 +190,7 @@ int16_t up_delta = line->flags & SEGFLAG_DN ? 4 : 0; int16_t dn_delta = up_delta; - if (!line->x_min && (line->flags & SEGFLAG_EXACT_LEFT))dn_delta ^= 4; + if (!line->x_min && (line->flags & SEGFLAG_EXACT_LEFT)) dn_delta ^= 4; if (line->flags & SEGFLAG_UL_DR) { int16_t tmp = up_delta; up_delta = dn_delta; @@ -215,14 +209,14 @@ if (line->y_min == line->y_max) continue; - int16_t a = (line->a * (int64_t)line->scale + ((int64_t)1 << 49)) >> 50; - int16_t b = (line->b * (int64_t)line->scale + ((int64_t)1 << 49)) >> 50; - int16_t c = ((int32_t)(line->c >> 11) * (int64_t)line->scale + ((int64_t)1 << 44)) >> 45; + int16_t a = (line->a * (int64_t) line->scale + ((int64_t) 1 << 49)) >> 50; + int16_t b = (line->b * (int64_t) line->scale + ((int64_t) 1 << 49)) >> 50; + int16_t c = ((int32_t) (line->c >> 11) * (int64_t) line->scale + ((int64_t) 1 << 44)) >> 45; c -= (a >> 1) + b * up; int16_t va[16]; - for (i = 0; i < 16; ++i) - va[i] = a * i; + for (int x = 0; x < 16; x++) + va[x] = a * x; int16_t abs_a = a < 0 ? -a : a; int16_t abs_b = b < 0 ? -b : b; int16_t dc = (FFMIN(abs_a, abs_b) + 2) >> 2; @@ -239,13 +233,13 @@ up++; c -= b; } - for (j = up; j < dn; ++j) { - for (i = 0; i < 16; ++i) { - int16_t c1 = c - va[i] + dc1; - int16_t c2 = c - va[i] + dc2; + for (int y = up; y < dn; y++) { + for (int x = 0; x < 16; x++) { + int16_t c1 = c - va[x] + dc1; + int16_t c2 = c - va[x] + dc2; c1 = FFMINMAX(c1, 0, full); c2 = FFMINMAX(c2, 0, full); - res[j][i] += (c1 + c2) >> 3; + res[y][x] += (c1 + c2) >> 3; } c -= b; } @@ -254,12 +248,12 @@ } int16_t cur = 256 * winding; - for (j = 0; j < 16; ++j) { - cur += delta[j]; - for (i = 0; i < 16; ++i) { - int16_t val = res[j][i] + cur, neg_val = -val; + for (int y = 0; y < 16; y++) { + cur += delta[y]; + for (int x = 0; x < 16; x++) { + int16_t val = res[y][x] + cur, neg_val = -val; val = (val > neg_val ? val : neg_val); - buf[i] = FFMIN(val, 255); + buf[x] = FFMIN(val, 255); } buf += stride; } @@ -275,22 +269,21 @@ int16_t w = (1 << 9) + (size << 3) - abs_a; w = FFMIN(w, 1 << 9) << 5; - int16_t dc_b = abs_b * (int32_t)size >> 6; + int16_t dc_b = abs_b * (int32_t) size >> 6; int16_t dc = (FFMIN(abs_a, dc_b) + 2) >> 2; - int16_t base = (int32_t)b * (int16_t)(up + dn) >> 7; - int16_t offs1 = size - ((base + dc) * (int32_t)w >> 16); - int16_t offs2 = size - ((base - dc) * (int32_t)w >> 16); + int16_t base = (int32_t) b * (int16_t) (up + dn) >> 7; + int16_t offs1 = size - ((base + dc) * (int32_t) w >> 16); + int16_t offs2 = size - ((base - dc) * (int32_t) w >> 16); - int i; size <<= 1; - for (i = 0; i < 32; ++i) { - int16_t cw = (c - va[i]) * (int32_t)w >> 16; + for (int x = 0; x < 32; x++) { + int16_t cw = (c - va[x]) * (int32_t) w >> 16; int16_t c1 = cw + offs1; int16_t c2 = cw + offs2; c1 = FFMINMAX(c1, 0, size); c2 = FFMINMAX(c2, 0, size); - res[i] += c1 + c2; + res[x] += c1 + c2; } } @@ -298,13 +291,12 @@ const struct segment *line, size_t n_lines, int winding) { - int i, j; int16_t res[32][32], delta[34]; - for (j = 0; j < 32; ++j) - for (i = 0; i < 32; ++i) - res[j][i] = 0; - for (j = 0; j < 34; ++j) - delta[j] = 0; + for (int y = 0; y < 32; y++) + for (int x = 0; x < 32; x++) + res[y][x] = 0; + for (int y = 0; y < 34; y++) + delta[y] = 0; static const int16_t full = 1 << 9; const struct segment *end = line + n_lines; @@ -315,7 +307,7 @@ int16_t up_delta = line->flags & SEGFLAG_DN ? 4 : 0; int16_t dn_delta = up_delta; - if (!line->x_min && (line->flags & SEGFLAG_EXACT_LEFT))dn_delta ^= 4; + if (!line->x_min && (line->flags & SEGFLAG_EXACT_LEFT)) dn_delta ^= 4; if (line->flags & SEGFLAG_UL_DR) { int16_t tmp = up_delta; up_delta = dn_delta; @@ -334,14 +326,14 @@ if (line->y_min == line->y_max) continue; - int16_t a = (line->a * (int64_t)line->scale + ((int64_t)1 << 50)) >> 51; - int16_t b = (line->b * (int64_t)line->scale + ((int64_t)1 << 50)) >> 51; - int16_t c = ((int32_t)(line->c >> 12) * (int64_t)line->scale + ((int64_t)1 << 44)) >> 45; + int16_t a = (line->a * (int64_t) line->scale + ((int64_t) 1 << 50)) >> 51; + int16_t b = (line->b * (int64_t) line->scale + ((int64_t) 1 << 50)) >> 51; + int16_t c = ((int32_t) (line->c >> 12) * (int64_t) line->scale + ((int64_t) 1 << 44)) >> 45; c -= (a >> 1) + b * up; int16_t va[32]; - for (i = 0; i < 32; ++i) - va[i] = a * i; + for (int x = 0; x < 32; x++) + va[x] = a * x; int16_t abs_a = a < 0 ? -a : a; int16_t abs_b = b < 0 ? -b : b; int16_t dc = (FFMIN(abs_a, abs_b) + 2) >> 2; @@ -358,13 +350,13 @@ up++; c -= b; } - for (j = up; j < dn; ++j) { - for (i = 0; i < 32; ++i) { - int16_t c1 = c - va[i] + dc1; - int16_t c2 = c - va[i] + dc2; + for (int y = up; y < dn; y++) { + for (int x = 0; x < 32; x++) { + int16_t c1 = c - va[x] + dc1; + int16_t c2 = c - va[x] + dc2; c1 = FFMINMAX(c1, 0, full); c2 = FFMINMAX(c2, 0, full); - res[j][i] += (c1 + c2) >> 2; + res[y][x] += (c1 + c2) >> 2; } c -= b; } @@ -373,12 +365,12 @@ } int16_t cur = 256 * winding; - for (j = 0; j < 32; ++j) { - cur += delta[j]; - for (i = 0; i < 32; ++i) { - int16_t val = res[j][i] + cur, neg_val = -val; + for (int y = 0; y < 32; y++) { + cur += delta[y]; + for (int x = 0; x < 32; x++) { + int16_t val = res[y][x] + cur, neg_val = -val; val = (val > neg_val ? val : neg_val); - buf[i] = FFMIN(val, 255); + buf[x] = FFMIN(val, 255); } buf += stride; } diff -Nru libass-0.13.7/libass/ass_rasterizer.h libass-0.14.0/libass/ass_rasterizer.h --- libass-0.13.7/libass/ass_rasterizer.h 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/ass_rasterizer.h 2017-10-31 12:14:11.000000000 +0000 @@ -21,17 +21,17 @@ #include #include +#include #include "ass_bitmap.h" -#include "ass_font.h" enum { - SEGFLAG_DN = 1, - SEGFLAG_UL_DR = 2, - SEGFLAG_EXACT_LEFT = 4, - SEGFLAG_EXACT_RIGHT = 8, - SEGFLAG_EXACT_TOP = 16, + SEGFLAG_DN = 1, + SEGFLAG_UL_DR = 2, + SEGFLAG_EXACT_LEFT = 4, + SEGFLAG_EXACT_RIGHT = 8, + SEGFLAG_EXACT_TOP = 16, SEGFLAG_EXACT_BOTTOM = 32, }; @@ -46,32 +46,39 @@ int outline_error; // acceptable error (in 1/64 pixel units) // usable after rasterizer_set_outline - int32_t x_min, x_max, y_min, y_max; + ASS_Rect bbox; // internal buffers struct segment *linebuf[2]; size_t size[2], capacity[2]; + size_t n_first; + + uint8_t *tile; } RasterizerData; -void rasterizer_init(RasterizerData *rst, int outline_error); +bool rasterizer_init(RasterizerData *rst, int tile_order, int outline_error); void rasterizer_done(RasterizerData *rst); /** - * \brief Convert FreeType outline to polyline and calculate exact bounds + * \brief Convert outline to polyline and calculate exact bounds + * \param path in: source outline + * \param extra in: true if path is second border outline + * \return false on error */ -int rasterizer_set_outline(RasterizerData *rst, const ASS_Outline *path); +bool rasterizer_set_outline(RasterizerData *rst, + const ASS_Outline *path, bool extra); /** * \brief Polyline rasterization function * \param x0, y0, width, height in: source window (full pixel units) * \param buf out: aligned output buffer (size = stride * height) * \param stride output buffer stride (aligned) - * \return zero on error + * \return false on error * Deletes preprocessed polyline after work. */ -int rasterizer_fill(const BitmapEngine *engine, RasterizerData *rst, - uint8_t *buf, int x0, int y0, - int width, int height, ptrdiff_t stride); +bool rasterizer_fill(const BitmapEngine *engine, RasterizerData *rst, + uint8_t *buf, int x0, int y0, + int width, int height, ptrdiff_t stride); -#endif /* LIBASS_RASTERIZER_H */ +#endif /* LIBASS_RASTERIZER_H */ diff -Nru libass-0.13.7/libass/ass_render_api.c libass-0.14.0/libass/ass_render_api.c --- libass-0.13.7/libass/ass_render_api.c 2017-06-03 16:45:15.000000000 +0000 +++ libass-0.14.0/libass/ass_render_api.c 2017-10-31 12:14:11.000000000 +0000 @@ -146,6 +146,10 @@ ass_reconfigure(priv); + ass_cache_empty(priv->cache.font_cache); + if (priv->shaper) + ass_shaper_empty_cache(priv->shaper); + if (priv->fontselect) ass_fontselect_free(priv->fontselect); priv->fontselect = ass_fontselect_init(priv->library, priv->ftlibrary, diff -Nru libass-0.13.7/libass/ass_render.c libass-0.14.0/libass/ass_render.c --- libass-0.13.7/libass/ass_render.c 2017-06-03 16:45:15.000000000 +0000 +++ libass-0.14.0/libass/ass_render.c 2017-10-31 12:14:11.000000000 +0000 @@ -24,6 +24,7 @@ #include #include +#include "ass_outline.h" #include "ass_render.h" #include "ass_parse.h" #include "ass_shaper.h" @@ -74,9 +75,10 @@ priv->engine = &ass_bitmap_engine_c; #endif -#if CONFIG_RASTERIZER - rasterizer_init(&priv->rasterizer, 16); -#endif + if (!rasterizer_init(&priv->rasterizer, priv->engine->tile_order, 16)) { + FT_Done_FreeType(ft); + goto ass_init_exit; + } priv->cache.font_cache = ass_font_cache_create(); priv->cache.bitmap_cache = ass_bitmap_cache_create(); @@ -125,14 +127,8 @@ ass_shaper_free(render_priv->shaper); ass_cache_done(render_priv->cache.font_cache); -#if CONFIG_RASTERIZER rasterizer_done(&render_priv->rasterizer); -#endif - if (render_priv->state.stroker) { - FT_Stroker_Done(render_priv->state.stroker); - render_priv->state.stroker = 0; - } if (render_priv->fontselect) ass_fontselect_free(render_priv->fontselect); if (render_priv->ftlibrary) @@ -477,7 +473,7 @@ val->bm = val->bm_o = NULL; // Not found in cache, parse and rasterize it - ASS_Outline *outline = ass_drawing_parse(drawing, 1); + ASS_Outline *outline = ass_drawing_parse(drawing, true); if (!outline) { ass_msg(render_priv->library, MSGL_WARN, "Clip vector parsing failed. Skipping."); @@ -489,14 +485,14 @@ // We need to translate the clip according to screen borders if (render_priv->settings.left_margin != 0 || render_priv->settings.top_margin != 0) { - FT_Vector trans = { + ASS_Vector trans = { .x = int_to_d6(render_priv->settings.left_margin), - .y = -int_to_d6(render_priv->settings.top_margin), + .y = int_to_d6(render_priv->settings.top_margin), }; outline_translate(outline, trans.x, trans.y); } - val->bm = outline_to_bitmap(render_priv, outline, 0); + val->bm = outline_to_bitmap(render_priv, outline, NULL, 1); ass_cache_commit(val, bitmap_size(val->bm) + sizeof(BitmapHashKey) + sizeof(BitmapHashValue)); } @@ -666,27 +662,24 @@ return head; } -static void compute_string_bbox(TextInfo *text, DBBox *bbox) +static void compute_string_bbox(TextInfo *text, ASS_DRect *bbox) { - int i; - if (text->length > 0) { - bbox->xMin = 32000; - bbox->xMax = -32000; - bbox->yMin = -1 * text->lines[0].asc + d6_to_double(text->glyphs[0].pos.y); - bbox->yMax = text->height - text->lines[0].asc + - d6_to_double(text->glyphs[0].pos.y); + bbox->x_min = +32000; + bbox->x_max = -32000; + bbox->y_min = d6_to_double(text->glyphs[0].pos.y) - text->lines[0].asc; + bbox->y_max = bbox->y_min + text->height; - for (i = 0; i < text->length; ++i) { + for (int i = 0; i < text->length; i++) { GlyphInfo *info = text->glyphs + i; if (info->skip) continue; double s = d6_to_double(info->pos.x); double e = s + d6_to_double(info->cluster_advance.x); - bbox->xMin = FFMIN(bbox->xMin, s); - bbox->xMax = FFMAX(bbox->xMax, e); + bbox->x_min = FFMIN(bbox->x_min, s); + bbox->x_max = FFMAX(bbox->x_max, e); } } else - bbox->xMin = bbox->xMax = bbox->yMin = bbox->yMax = 0.; + bbox->x_min = bbox->x_max = bbox->y_min = bbox->y_max = 0; } static ASS_Style *handle_selective_style_overrides(ASS_Renderer *render_priv, @@ -850,7 +843,6 @@ render_priv->state.border_style = style->BorderStyle; render_priv->state.border_x = style->Outline; render_priv->state.border_y = style->Outline; - change_border(render_priv, render_priv->state.border_x, render_priv->state.border_y); render_priv->state.scale_x = style->ScaleX; render_priv->state.scale_y = style->ScaleY; render_priv->state.hspacing = style->Spacing; @@ -922,7 +914,7 @@ */ static void draw_opaque_box(ASS_Renderer *render_priv, GlyphInfo *info, int asc, int desc, ASS_Outline *ol, - FT_Vector advance, int sx, int sy) + ASS_Vector advance, int sx, int sy) { int adv = advance.x; double scale_y = info->orig_scale_y; @@ -941,135 +933,27 @@ desc *= scale_y; desc += asc * (scale_y - 1.0); - FT_Vector points[4] = { - { .x = -sx, .y = asc + sy }, - { .x = adv + sx, .y = asc + sy }, - { .x = adv + sx, .y = -desc - sy }, - { .x = -sx, .y = -desc - sy }, + ASS_Vector points[4] = { + { .x = -sx, .y = -asc - sy }, + { .x = adv + sx, .y = -asc - sy }, + { .x = adv + sx, .y = desc + sy }, + { .x = -sx, .y = desc + sy }, }; - ol->n_points = ol->n_contours = 0; - if (!outline_alloc(ol, 4, 1)) - return; - for (int i = 0; i < 4; ++i) { - ol->points[ol->n_points] = points[i]; - ol->tags[ol->n_points++] = 1; - } - ol->contours[ol->n_contours++] = ol->n_points - 1; -} + const char segments[4] = { + OUTLINE_LINE_SEGMENT, + OUTLINE_LINE_SEGMENT, + OUTLINE_LINE_SEGMENT, + OUTLINE_LINE_SEGMENT | OUTLINE_CONTOUR_END + }; -/* - * Stroke an outline glyph in x/y direction. Applies various fixups to get - * around limitations of the FreeType stroker. - */ -static void stroke_outline(ASS_Renderer *render_priv, ASS_Outline *outline, - int sx, int sy) -{ - if (sx <= 0 && sy <= 0) + ol->n_points = ol->n_segments = 0; + if (!outline_alloc(ol, 4, 4)) return; - - fix_freetype_stroker(outline, sx, sy); - - size_t n_points = outline->n_points; - if (n_points > SHRT_MAX) { - ass_msg(render_priv->library, MSGL_WARN, "Too many outline points: %d", - outline->n_points); - n_points = SHRT_MAX; - } - - size_t n_contours = FFMIN(outline->n_contours, SHRT_MAX); - short contours_small[EFFICIENT_CONTOUR_COUNT]; - short *contours = contours_small; - short *contours_large = NULL; - if (n_contours > EFFICIENT_CONTOUR_COUNT) { - contours_large = malloc(n_contours * sizeof(short)); - if (!contours_large) - return; - contours = contours_large; + for (int i = 0; i < 4; i++) { + ol->points[ol->n_points++] = points[i]; + ol->segments[ol->n_segments++] = segments[i]; } - for (size_t i = 0; i < n_contours; ++i) - contours[i] = FFMIN(outline->contours[i], n_points - 1); - - FT_Outline ftol; - ftol.n_points = n_points; - ftol.n_contours = n_contours; - ftol.points = outline->points; - ftol.tags = outline->tags; - ftol.contours = contours; - ftol.flags = 0; - - // Borders are equal; use the regular stroker - if (sx == sy && render_priv->state.stroker) { - int error; - FT_StrokerBorder border = FT_Outline_GetOutsideBorder(&ftol); - error = FT_Stroker_ParseOutline(render_priv->state.stroker, &ftol, 0); - if (error) { - ass_msg(render_priv->library, MSGL_WARN, - "FT_Stroker_ParseOutline failed, error: %d", error); - } - unsigned new_points, new_contours; - error = FT_Stroker_GetBorderCounts(render_priv->state.stroker, border, - &new_points, &new_contours); - if (error) { - ass_msg(render_priv->library, MSGL_WARN, - "FT_Stroker_GetBorderCounts failed, error: %d", error); - } - outline_free(outline); - outline->n_points = outline->n_contours = 0; - if (new_contours > FFMAX(EFFICIENT_CONTOUR_COUNT, n_contours)) { - if (!ASS_REALLOC_ARRAY(contours_large, new_contours)) { - free(contours_large); - return; - } - } - n_points = new_points; - n_contours = new_contours; - if (!outline_alloc(outline, n_points, n_contours)) { - ass_msg(render_priv->library, MSGL_WARN, - "Not enough memory for border outline"); - free(contours_large); - return; - } - ftol.n_points = ftol.n_contours = 0; - ftol.points = outline->points; - ftol.tags = outline->tags; - - FT_Stroker_ExportBorder(render_priv->state.stroker, border, &ftol); - - outline->n_points = n_points; - outline->n_contours = n_contours; - for (size_t i = 0; i < n_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 - } else { -#if (FREETYPE_MAJOR > 2) || \ - ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR > 4)) || \ - ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR == 4) && (FREETYPE_PATCH >= 10)) - FT_Outline_EmboldenXY(&ftol, sx * 2, sy * 2); - FT_Outline_Translate(&ftol, -sx, -sy); -#else - int i; - FT_Outline nol; - - FT_Outline_New(render_priv->ftlibrary, ftol.n_points, - ftol.n_contours, &nol); - FT_Outline_Copy(&ftol, &nol); - - FT_Outline_Embolden(&ftol, sx * 2); - FT_Outline_Translate(&ftol, -sx, -sx); - FT_Outline_Embolden(&nol, sy * 2); - FT_Outline_Translate(&nol, -sy, -sy); - - for (i = 0; i < ftol.n_points; i++) - ftol.points[i].y = nol.points[i].y; - - FT_Outline_Done(render_priv->ftlibrary, &nol); -#endif - } - - free(contours_large); } /** @@ -1129,7 +1013,7 @@ * \brief Get normal and outline (border) glyphs * \param info out: struct filled with extracted data * Tries to get both glyphs from cache. - * If they can't be found, gets a glyph from font face, generates outline with FT_Stroker, + * If they can't be found, gets a glyph from font face, generates outline, * and add them to cache. * The glyphs are returned in info->glyph and info->outline_glyph */ @@ -1149,12 +1033,12 @@ if (info->drawing) { ASS_Drawing *drawing = info->drawing; ass_drawing_hash(drawing); - if(!ass_drawing_parse(drawing, 0)) { + if(!ass_drawing_parse(drawing, false) || + !outline_copy(&val->outline, &drawing->outline)) { ass_cache_commit(val, 1); ass_cache_dec_ref(val); return; } - val->outline = outline_copy(&drawing->outline); val->advance.x = drawing->advance.x; val->advance.y = drawing->advance.y; val->asc = drawing->asc; @@ -1169,7 +1053,12 @@ info->symbol, info->face_index, info->glyph_index, priv->settings.hinting, info->flags); if (glyph != NULL) { - val->outline = outline_convert(&((FT_OutlineGlyph) glyph)->outline); + FT_Outline *src = &((FT_OutlineGlyph) glyph)->outline; + if (!outline_convert(&val->outline, src)) { + ass_cache_commit(val, 1); + ass_cache_dec_ref(val); + return; + } if (priv->settings.shaper == ASS_SHAPING_SIMPLE) { val->advance.x = d16_to_d6(glyph->advance.x); val->advance.y = d16_to_d6(glyph->advance.y); @@ -1181,57 +1070,49 @@ val->desc *= info->scale_y; } } + val->valid = true; - if (!val->outline) { - ass_cache_commit(val, 1); - ass_cache_dec_ref(val); - return; - } - - outline_get_cbox(val->outline, &val->bbox_scaled); + outline_get_cbox(&val->outline, &val->bbox_scaled); if (info->border_style == 3) { - val->border = calloc(1, sizeof(ASS_Outline)); - if (!val->border) { - outline_free(val->outline); - free(val->outline); - val->outline = NULL; - ass_cache_commit(val, 1); - ass_cache_dec_ref(val); - return; - } - - FT_Vector advance; + ASS_Vector advance; if (priv->settings.shaper == ASS_SHAPING_SIMPLE || info->drawing) advance = val->advance; else advance = info->advance; - draw_opaque_box(priv, info, val->asc, val->desc, val->border, advance, - double_to_d6(info->border_x * priv->border_scale), - double_to_d6(info->border_y * priv->border_scale)); + draw_opaque_box(priv, info, val->asc, val->desc, &val->border[0], advance, + double_to_d6(info->border_x * priv->border_scale), + double_to_d6(info->border_y * priv->border_scale)); - } else if ((info->border_x > 0 || info->border_y > 0) + } else if (val->outline.n_points && (info->border_x > 0 || info->border_y > 0) && double_to_d6(info->scale_x) && double_to_d6(info->scale_y)) { - - change_border(priv, info->border_x, info->border_y); - val->border = outline_copy(val->outline); - stroke_outline(priv, val->border, - double_to_d6(info->border_x * priv->border_scale), - double_to_d6(info->border_y * priv->border_scale)); + const int eps = 16; + int xbord = double_to_d6(info->border_x * priv->border_scale); + int ybord = double_to_d6(info->border_y * priv->border_scale); + if(xbord >= eps || ybord >= eps) { + outline_alloc(&val->border[0], 2 * val->outline.n_points, 2 * val->outline.n_segments); + outline_alloc(&val->border[1], 2 * val->outline.n_points, 2 * val->outline.n_segments); + if (!val->border[0].max_points || !val->border[1].max_points || + !outline_stroke(&val->border[0], &val->border[1], + &val->outline, xbord, ybord, eps)) { + ass_msg(priv->library, MSGL_WARN, "Cannot stoke outline"); + outline_free(&val->border[0]); + outline_free(&val->border[1]); + } + } } ass_cache_commit(val, 1); - } - - if (!val->outline) { + } else if (!val->valid) { ass_cache_dec_ref(val); return; } info->hash_key.u.outline.outline = val; - info->outline = val->outline; - info->border = val->border; + info->outline = &val->outline; + info->border[0] = &val->border[0]; + info->border[1] = &val->border[1]; info->bbox = val->bbox_scaled; if (info->drawing || priv->settings.shaper == ASS_SHAPING_SIMPLE) { info->cluster_advance.x = info->advance.x = val->advance.x; @@ -1242,50 +1123,46 @@ } /** - * \brief Apply transformation to outline points of a glyph - * Applies rotations given by frx, fry and frz and projects the points back - * onto the screen plane. + * \brief Calculate transform matrix for transform_3d() */ static void -transform_3d_points(FT_Vector shift, ASS_Outline *outline, double frx, double fry, - double frz, double fax, double fay, double scale, - int yshift) -{ - double sx = sin(frx); - double sy = sin(fry); - double sz = sin(frz); - double cx = cos(frx); - double cy = cos(fry); - double cz = cos(frz); - FT_Vector *p = outline->points; - double x, y, z, xx, yy, zz; - int dist; - - dist = 20000 * scale; - for (size_t i = 0; i < outline->n_points; ++i) { - x = (double) p[i].x + shift.x + (fax * (yshift - p[i].y)); - y = (double) p[i].y + shift.y + (-fay * p[i].x); - z = 0.; - - xx = x * cz + y * sz; - yy = -(x * sz - y * cz); - zz = z; - - x = xx; - y = yy * cx + zz * sx; - z = yy * sx - zz * cx; - - xx = x * cy + z * sy; - yy = y; - zz = x * sy - z * cy; - - zz = FFMAX(zz, 1000 - dist); - - x = (xx * dist) / (zz + dist); - y = (yy * dist) / (zz + dist); - p[i].x = x - shift.x + 0.5; - p[i].y = y - shift.y + 0.5; +calc_transform_matrix(ASS_Vector shift, + double frx, double fry, double frz, + double fax, double fay, double scale, + int yshift, double m[3][3]) +{ + double sx = -sin(frx), cx = cos(frx); + double sy = sin(fry), cy = cos(fry); + double sz = -sin(frz), cz = cos(frz); + + double x1[3] = { 1, fax, shift.x + fax * yshift }; + double y1[3] = { fay, 1, shift.y }; + + double x2[3], y2[3]; + for (int i = 0; i < 3; i++) { + x2[i] = x1[i] * cz - y1[i] * sz; + y2[i] = x1[i] * sz + y1[i] * cz; + } + + double y3[3], z3[3]; + for (int i = 0; i < 3; i++) { + y3[i] = y2[i] * cx; + z3[i] = y2[i] * sx; + } + + double x4[3], z4[3]; + for (int i = 0; i < 3; i++) { + x4[i] = x2[i] * cy - z3[i] * sy; + z4[i] = x2[i] * sy + z3[i] * cy; + } + + double dist = 20000 * scale; + for (int i = 0; i < 3; i++) { + m[0][i] = x4[i] * dist; + m[1][i] = y3[i] * dist; + m[2][i] = z4[i]; } + m[2][2] += dist; } /** @@ -1299,20 +1176,27 @@ * Rotates both glyphs by frx, fry and frz. Shift vector is added before rotation and subtracted after it. */ static void -transform_3d(FT_Vector shift, ASS_Outline *outline, ASS_Outline *border, +transform_3d(ASS_Vector shift, ASS_Outline *outline, int n_outlines, double frx, double fry, double frz, double fax, double fay, double scale, int yshift) { - frx = -frx; - frz = -frz; - if (frx != 0. || fry != 0. || frz != 0. || fax != 0. || fay != 0.) { - if (outline) - transform_3d_points(shift, outline, frx, fry, frz, - fax, fay, scale, yshift); - - if (border) - transform_3d_points(shift, border, frx, fry, frz, - fax, fay, scale, yshift); + if (frx == 0 && fry == 0 && frz == 0 && fax == 0 && fay == 0) + return; + + double m[3][3]; + calc_transform_matrix(shift, frx, fry, frz, fax, fay, scale, yshift, m); + + for (int i = 0; i < n_outlines; i++) { + ASS_Vector *p = outline[i].points; + for (size_t j = 0; j < outline[i].n_points; ++j) { + double v[3]; + for (int k = 0; k < 3; k++) + v[k] = m[k][0] * p[j].x + m[k][1] * p[j].y + m[k][2]; + + double w = 1 / FFMAX(v[2], 1000); + p[j].x = lrint(v[0] * w) - shift.x; + p[j].y = lrint(v[1] * w) - shift.y; + } } } @@ -1334,56 +1218,57 @@ OutlineBitmapHashKey *key = &info->hash_key.u.outline; if (ass_cache_get(render_priv->cache.bitmap_cache, &info->hash_key, &val)) { info->image = val; + if (!val->valid) + info->symbol = 0; + return; + } + if (!val) { + info->symbol = 0; return; } - if (!val) + if (!info->outline) { + memset(val, 0, sizeof(*val)); + ass_cache_commit(val, sizeof(BitmapHashKey) + sizeof(BitmapHashValue)); + info->image = val; + info->symbol = 0; return; + } - ASS_Outline *outline = outline_copy(info->outline); - ASS_Outline *border = outline_copy(info->border); + const int n_outlines = 3; + ASS_Outline outline[n_outlines]; + outline_copy(&outline[0], info->outline); + outline_copy(&outline[1], info->border[0]); + outline_copy(&outline[2], info->border[1]); // calculating rotation shift vector (from rotation origin to the glyph basepoint) - FT_Vector shift = { key->shift_x, key->shift_y }; + ASS_Vector shift = { key->shift_x, key->shift_y }; double scale_x = render_priv->font_scale_x; double fax_scaled = info->fax / info->scale_y * info->scale_x; double fay_scaled = info->fay / info->scale_x * info->scale_y; // apply rotation // use blur_scale because, like blurs, VSFilter forgets to scale this - transform_3d(shift, outline, border, + transform_3d(shift, outline, n_outlines, info->frx, info->fry, info->frz, fax_scaled, fay_scaled, render_priv->blur_scale, info->asc); - // PAR correction scaling - FT_Matrix m = { double_to_d16(scale_x), 0, - 0, double_to_d16(1.0) }; - - // subpixel shift - if (outline) { - if (scale_x != 1.0) - outline_transform(outline, &m); - outline_translate(outline, key->advance.x, -key->advance.y); - } - if (border) { - if (scale_x != 1.0) - outline_transform(border, &m); - outline_translate(border, key->advance.x, -key->advance.y); - } + // PAR correction scaling + subpixel shift + for (int i = 0; i < n_outlines; i++) + outline_adjust(&outline[i], scale_x, key->advance.x, key->advance.y); // render glyph - int error = outline_to_bitmap2(render_priv, outline, border, - &val->bm, &val->bm_o); - if (error) + val->valid = outline_to_bitmap2(render_priv, + &outline[0], &outline[1], &outline[2], + &val->bm, &val->bm_o); + if (!val->valid) info->symbol = 0; ass_cache_commit(val, bitmap_size(val->bm) + bitmap_size(val->bm_o) + sizeof(BitmapHashKey) + sizeof(BitmapHashValue)); info->image = val; - outline_free(outline); - free(outline); - outline_free(border); - free(border); + for (int i = 0; i < n_outlines; i++) + outline_free(&outline[i]); } /** @@ -1521,8 +1406,8 @@ int break_at = -1; double s_offset, len; cur = text_info->glyphs + i; - s_offset = d6_to_double(s1->bbox.xMin + s1->pos.x); - len = d6_to_double(cur->bbox.xMax + cur->pos.x) - s_offset; + s_offset = d6_to_double(s1->bbox.x_min + s1->pos.x); + len = d6_to_double(cur->bbox.x_max + cur->pos.x) - s_offset; if (cur->symbol == '\n') { break_type = 2; @@ -1588,16 +1473,16 @@ if (w->symbol == ' ') ++w; - l1 = d6_to_double(((s2 - 1)->bbox.xMax + (s2 - 1)->pos.x) - - (s1->bbox.xMin + s1->pos.x)); - l2 = d6_to_double(((s3 - 1)->bbox.xMax + (s3 - 1)->pos.x) - - (s2->bbox.xMin + s2->pos.x)); + l1 = d6_to_double(((s2 - 1)->bbox.x_max + (s2 - 1)->pos.x) - + (s1->bbox.x_min + s1->pos.x)); + l2 = d6_to_double(((s3 - 1)->bbox.x_max + (s3 - 1)->pos.x) - + (s2->bbox.x_min + s2->pos.x)); l1_new = d6_to_double( - (e1->bbox.xMax + e1->pos.x) - - (s1->bbox.xMin + s1->pos.x)); + (e1->bbox.x_max + e1->pos.x) - + (s1->bbox.x_min + s1->pos.x)); l2_new = d6_to_double( - ((s3 - 1)->bbox.xMax + (s3 - 1)->pos.x) - - (w->bbox.xMin + w->pos.x)); + ((s3 - 1)->bbox.x_max + (s3 - 1)->pos.x) - + (w->bbox.x_min + w->pos.x)); if (DIFF(l1_new, l2_new) < DIFF(l1, l2)) { if (w->linebreak || w == text_info->glyphs) @@ -1665,32 +1550,32 @@ * \param alignment alignment * \param bx, by out: base point coordinates */ -static void get_base_point(DBBox *bbox, int alignment, double *bx, double *by) +static void get_base_point(ASS_DRect *bbox, int alignment, double *bx, double *by) { const int halign = alignment & 3; const int valign = alignment & 12; if (bx) switch (halign) { case HALIGN_LEFT: - *bx = bbox->xMin; + *bx = bbox->x_min; break; case HALIGN_CENTER: - *bx = (bbox->xMax + bbox->xMin) / 2.0; + *bx = (bbox->x_max + bbox->x_min) / 2.0; break; case HALIGN_RIGHT: - *bx = bbox->xMax; + *bx = bbox->x_max; break; } if (by) switch (valign) { case VALIGN_TOP: - *by = bbox->yMin; + *by = bbox->y_min; break; case VALIGN_CENTER: - *by = (bbox->yMax + bbox->yMin) / 2.0; + *by = (bbox->y_max + bbox->y_min) / 2.0; break; case VALIGN_SUB: - *by = bbox->yMax; + *by = bbox->y_max; break; } } @@ -1838,8 +1723,7 @@ while ((*q != '{') && (*q != 0)) q++; if (!drawing) { - drawing = ass_drawing_new(render_priv->library, - render_priv->ftlibrary); + drawing = ass_drawing_new(render_priv->library); if (!drawing) return 1; } @@ -1959,11 +1843,11 @@ if (i && glyphs[i - 1].italic && !info->italic) { int back = i - 1; GlyphInfo *og = &glyphs[back]; - while (back && og->bbox.xMax - og->bbox.xMin == 0 + while (back && og->bbox.x_max - og->bbox.x_min == 0 && og->italic) og = &glyphs[--back]; - if (og->bbox.xMax > og->cluster_advance.x) - og->cluster_advance.x = og->bbox.xMax; + if (og->bbox.x_max > og->cluster_advance.x) + og->cluster_advance.x = og->bbox.x_max; } // add horizontal letter spacing @@ -1978,14 +1862,10 @@ // Preliminary layout (for line wrapping) static void preliminary_layout(ASS_Renderer *render_priv) { - FT_Vector pen; - int i; - - pen.x = 0; - pen.y = 0; - for (i = 0; i < render_priv->text_info.length; i++) { + ASS_Vector pen = { 0, 0 }; + for (int i = 0; i < render_priv->text_info.length; i++) { GlyphInfo *info = render_priv->text_info.glyphs + i; - FT_Vector cluster_pen = pen; + ASS_Vector cluster_pen = pen; while (info) { info->pos.x = cluster_pen.x; info->pos.y = cluster_pen.y; @@ -2009,9 +1889,6 @@ static void reorder_text(ASS_Renderer *render_priv) { TextInfo *text_info = &render_priv->text_info; - FT_Vector pen; - int i; - FriBidiStrIndex *cmap = ass_shaper_reorder(render_priv->shaper, text_info); if (!cmap) { ass_msg(render_priv->library, MSGL_ERR, "Failed to reorder text"); @@ -2021,12 +1898,11 @@ } // Reposition according to the map - pen.x = 0; - pen.y = 0; + ASS_Vector pen = { 0, 0 }; int lineno = 1; double last_pen_x = 0; double last_fay = 0; - for (i = 0; i < text_info->length; i++) { + for (int i = 0; i < text_info->length; i++) { GlyphInfo *info = text_info->glyphs + cmap[i]; if (text_info->glyphs[i].linebreak) { pen.y -= (last_fay / info->scale_x * info->scale_y) * (pen.x - last_pen_x); @@ -2042,7 +1918,7 @@ } last_fay = info->fay; if (info->skip) continue; - FT_Vector cluster_pen = pen; + ASS_Vector cluster_pen = pen; while (info) { info->pos.x = info->offset.x + cluster_pen.x; info->pos.y = info->offset.y + cluster_pen.y; @@ -2125,13 +2001,10 @@ } } -static void calculate_rotation_params(ASS_Renderer *render_priv, DBBox *bbox, +static void calculate_rotation_params(ASS_Renderer *render_priv, ASS_DRect *bbox, double device_x, double device_y) { - TextInfo *text_info = &render_priv->text_info; - DVector center; - int i; - + ASS_DVector center; if (render_priv->state.have_origin) { center.x = x2scr(render_priv, render_priv->state.org_x); center.y = y2scr(render_priv, render_priv->state.org_y); @@ -2142,14 +2015,15 @@ center.y = device_y + by; } - for (i = 0; i < text_info->length; ++i) { + TextInfo *text_info = &render_priv->text_info; + for (int i = 0; i < text_info->length; i++) { GlyphInfo *info = text_info->glyphs + i; while (info) { OutlineBitmapHashKey *key = &info->hash_key.u.outline; if (key->frx || key->fry || key->frz || key->fax || key->fay) { key->shift_x = info->pos.x + double_to_d6(device_x - center.x); - key->shift_y = -(info->pos.y + double_to_d6(device_y - center.y)); + key->shift_y = info->pos.y + double_to_d6(device_y - center.y); } else { key->shift_x = 0; key->shift_y = 0; @@ -2160,18 +2034,11 @@ } -static inline void rectangle_reset(Rectangle *rect) -{ - rect->x_min = rect->y_min = INT_MAX; - rect->x_max = rect->y_max = INT_MIN; -} - -static inline void rectangle_combine(Rectangle *rect, const Bitmap *bm, int x, int y) +static inline void rectangle_combine(ASS_Rect *rect, const Bitmap *bm, int x, int y) { - rect->x_min = FFMIN(rect->x_min, x + bm->left); - rect->y_min = FFMIN(rect->y_min, y + bm->top); - rect->x_max = FFMAX(rect->x_max, x + bm->left + bm->w); - rect->y_max = FFMAX(rect->y_max, y + bm->top + bm->h); + x += bm->left; + y += bm->top; + rectangle_update(rect, x, y, x + bm->w, y + bm->h); } // Convert glyphs to bitmaps, combine them, apply blur, generate shadows. @@ -2221,7 +2088,7 @@ memcpy(¤t_info->c, &info->c, sizeof(info->c)); current_info->effect_type = info->effect_type; current_info->effect_timing = info->effect_timing; - current_info->first_pos_x = info->bbox.xMax >> 6; + current_info->first_pos_x = info->bbox.x_max >> 6; current_info->filter.flags = 0; if (info->border_style == 3) @@ -2232,7 +2099,7 @@ current_info->filter.flags |= FILTER_NONZERO_SHADOW; // VSFilter compatibility: invisible fill and no border? // In this case no shadow is supposed to be rendered. - if (info->border || (info->c[0] & 0xFF) != 0xFF) + if (info->border[0] || info->border[1] || (info->c[0] & 0xFF) != 0xFF) current_info->filter.flags |= FILTER_DRAW_SHADOW; current_info->filter.be = info->be; @@ -2440,13 +2307,6 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, EventImages *event_images) { - DBBox bbox; - int MarginL, MarginR, MarginV; - int valign; - double device_x = 0; - double device_y = 0; - TextInfo *text_info = &render_priv->text_info; - if (event->Style >= render_priv->track->n_styles) { ass_msg(render_priv->library, MSGL_WARN, "No style found"); return 1; @@ -2462,6 +2322,7 @@ if (parse_events(render_priv, event)) return 1; + TextInfo *text_info = &render_priv->text_info; if (text_info->length == 0) { // no valid symbols in the event; this can be smth like {comment} free_render_context(render_priv); @@ -2486,13 +2347,13 @@ // depends on glyph x coordinates being monotonous, so it should be done before line wrap process_karaoke_effects(render_priv); - valign = render_priv->state.alignment & 12; + int valign = render_priv->state.alignment & 12; - MarginL = + int MarginL = (event->MarginL) ? event->MarginL : render_priv->state.style->MarginL; - MarginR = + int MarginR = (event->MarginR) ? event->MarginR : render_priv->state.style->MarginR; - MarginV = + int MarginV = (event->MarginV) ? event->MarginV : render_priv->state.style->MarginV; // calculate max length of a line @@ -2517,11 +2378,13 @@ align_lines(render_priv, max_text_width); // determing text bounding box + ASS_DRect bbox; compute_string_bbox(text_info, &bbox); // determine device coordinates for text // x coordinate for everything except positioned events + double device_x = 0; if (render_priv->state.evt_type == EVENT_NORMAL || render_priv->state.evt_type == EVENT_VSCROLL) { device_x = x2scr(render_priv, MarginL); @@ -2533,12 +2396,12 @@ render_priv->state.scroll_shift); else if (render_priv->state.scroll_direction == SCROLL_LR) device_x = - x2scr(render_priv, - render_priv->state.scroll_shift) - (bbox.xMax - - bbox.xMin); + x2scr(render_priv, render_priv->state.scroll_shift) - + (bbox.x_max - bbox.x_min); } // y coordinate for everything except positioned events + double device_y = 0; if (render_priv->state.evt_type == EVENT_NORMAL || render_priv->state.evt_type == EVENT_HSCROLL) { if (valign == VALIGN_TOP) { // toptitle @@ -2548,7 +2411,7 @@ } else if (valign == VALIGN_CENTER) { // midtitle double scr_y = y2scr(render_priv, render_priv->track->PlayResY / 2.0); - device_y = scr_y - (bbox.yMax + bbox.yMin) / 2.0; + device_y = scr_y - (bbox.y_max + bbox.y_min) / 2.0; } else { // subtitle double line_pos = render_priv->state.explicit ? 0 : render_priv->settings.line_position; @@ -2576,8 +2439,8 @@ device_y = y2scr(render_priv, render_priv->state.clip_y0 + - render_priv->state.scroll_shift) - (bbox.yMax - - bbox.yMin); + render_priv->state.scroll_shift) - + (bbox.y_max - bbox.y_min); else if (render_priv->state.scroll_direction == SCROLL_BT) device_y = y2scr(render_priv, @@ -2652,9 +2515,9 @@ event_images->top = device_y - text_info->lines[0].asc; event_images->height = text_info->height; event_images->left = - (device_x + bbox.xMin * render_priv->font_scale_x) + 0.5; + (device_x + bbox.x_min * render_priv->font_scale_x) + 0.5; event_images->width = - (bbox.xMax - bbox.xMin) * render_priv->font_scale_x + 0.5; + (bbox.x_max - bbox.x_min) * render_priv->font_scale_x + 0.5; event_images->detect_collisions = render_priv->state.detect_collisions; event_images->shift_direction = (valign == VALIGN_TOP) ? 1 : -1; event_images->event = event; diff -Nru libass-0.13.7/libass/ass_render.h libass-0.14.0/libass/ass_render.h --- libass-0.13.7/libass/ass_render.h 2017-06-03 16:45:15.000000000 +0000 +++ libass-0.14.0/libass/ass_render.h 2017-10-31 12:14:11.000000000 +0000 @@ -23,7 +23,6 @@ #include #include #include FT_FREETYPE_H -#include FT_STROKER_H #include FT_GLYPH_H #include FT_SYNTHESIS_H #ifdef CONFIG_HARFBUZZ @@ -51,18 +50,6 @@ #define PARSED_A (1<<1) typedef struct { - double xMin; - double xMax; - double yMin; - double yMax; -} DBBox; - -typedef struct { - double x; - double y; -} DVector; - -typedef struct { ASS_Image result; CompositeHashValue *source; size_t ref_count; @@ -107,11 +94,6 @@ EF_KARAOKE_KO } Effect; -typedef struct -{ - int x_min, y_min, x_max, y_max; -} Rectangle; - // describes a combined bitmap typedef struct { FilterDesc filter; @@ -127,7 +109,7 @@ BitmapRef *bitmaps; int x, y; - Rectangle rect, rect_o; + ASS_Rect rect, rect_o; size_t n_bm, n_bm_o; Bitmap *bm, *bm_o, *bm_s; // glyphs, outline, shadow bitmaps @@ -150,14 +132,14 @@ double font_size; ASS_Drawing *drawing; ASS_Outline *outline; - ASS_Outline *border; - FT_BBox bbox; - FT_Vector pos; - FT_Vector offset; + ASS_Outline *border[2]; + ASS_Rect bbox; + ASS_Vector pos; + ASS_Vector offset; char linebreak; // the first (leading) glyph of some line ? uint32_t c[4]; // colors - FT_Vector advance; // 26.6 - FT_Vector cluster_advance; + ASS_Vector advance; // 26.6 + ASS_Vector cluster_advance; char effect; // the first (leading) glyph of some effect ? Effect effect_type; int effect_timing; // time duration of current karaoke word @@ -218,8 +200,6 @@ double font_size; int flags; // decoration flags (underline/strike-through) - FT_Stroker stroker; - int stroker_radius; // last stroker radius, for caching stroker objects int alignment; // alignment overrides go here; if zero, style value will be used int justify; // justify instructions double frx, fry, frz; @@ -327,9 +307,7 @@ CacheStore cache; const BitmapEngine *engine; -#if CONFIG_RASTERIZER RasterizerData rasterizer; -#endif ASS_Style user_override_style; }; diff -Nru libass-0.13.7/libass/ass_shaper.c libass-0.14.0/libass/ass_shaper.c --- libass-0.13.7/libass/ass_shaper.c 2017-06-03 16:45:15.000000000 +0000 +++ libass-0.14.0/libass/ass_shaper.c 2017-10-31 12:14:11.000000000 +0000 @@ -121,6 +121,13 @@ free(shaper); } +void ass_shaper_empty_cache(ASS_Shaper *shaper) +{ +#ifdef CONFIG_HARFBUZZ + ass_cache_empty(shaper->metrics_cache); +#endif +} + void ass_shaper_font_data_free(ASS_ShaperFontData *priv) { #ifdef CONFIG_HARFBUZZ diff -Nru libass-0.13.7/libass/ass_shaper.h libass-0.14.0/libass/ass_shaper.h --- libass-0.13.7/libass/ass_shaper.h 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/ass_shaper.h 2017-10-31 12:14:11.000000000 +0000 @@ -27,6 +27,7 @@ void ass_shaper_info(ASS_Library *lib); ASS_Shaper *ass_shaper_new(size_t prealloc); void ass_shaper_free(ASS_Shaper *shaper); +void ass_shaper_empty_cache(ASS_Shaper *shaper); void ass_shaper_set_kerning(ASS_Shaper *shaper, int kern); void ass_shaper_find_runs(ASS_Shaper *shaper, ASS_Renderer *render_priv, GlyphInfo *glyphs, size_t len); diff -Nru libass-0.13.7/libass/Makefile.am libass-0.14.0/libass/Makefile.am --- libass-0.13.7/libass/Makefile.am 2017-06-03 16:58:43.000000000 +0000 +++ libass-0.14.0/libass/Makefile.am 2017-10-31 12:55:50.000000000 +0000 @@ -1,41 +1,45 @@ AM_CFLAGS = -std=gnu99 -Wall -Wextra -Wno-sign-compare -Wno-unused-parameter \ -Werror-implicit-function-declaration -Wstrict-prototypes \ - -Wpointer-arith -Wredundant-decls -D_GNU_SOURCE + -Wpointer-arith -Wredundant-decls -Wno-missing-field-initializers\ + -D_GNU_SOURCE LIBASS_LT_CURRENT = 9 -LIBASS_LT_REVISION = 1 +LIBASS_LT_REVISION = 2 LIBASS_LT_AGE = 0 -yasm_verbose = $(yasm_verbose_$(V)) -yasm_verbose_ = $(yasm_verbose_$(AM_DEFAULT_VERBOSITY)) -yasm_verbose_0 = @echo " YASM " $@; +nasm_verbose = $(nasm_verbose_$(V)) +nasm_verbose_ = $(nasm_verbose_$(AM_DEFAULT_VERBOSITY)) +nasm_verbose_0 = @echo " NASM " $@; .asm.lo: - $(yasm_verbose)$(LIBTOOL) $(AM_V_lt) --tag=CC --mode=compile $(AS) $(ASFLAGS) -o $@ $< -prefer-non-pic + $(nasm_verbose)$(LIBTOOL) $(AM_V_lt) --tag=CC --mode=compile $(AS) $(ASFLAGS) -I$(srcdir)/ -o $@ $< -prefer-non-pic -SRC_INTEL = x86/blend_bitmaps.asm x86/blur.asm x86/cpuid.asm x86/utils.asm \ +SRC_INTEL = x86/rasterizer.asm x86/blend_bitmaps.asm x86/blur.asm x86/cpuid.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_FONTCONFIG = ass_fontconfig.c ass_fontconfig.h 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_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 +libass_la_SOURCES = ass.h ass.c ass_types.h ass_utils.h ass_utils.c \ + ass_compat.h ass_string.h ass_string.c ass_strtod.c \ + ass_library.h ass_library.c ass_cache.h ass_cache.c ass_cache_template.h \ + ass_font.h ass_font.c ass_fontselect.h ass_fontselect.c \ + ass_render.h ass_render.c ass_render_api.c \ + ass_parse.h ass_parse.c ass_shaper.h ass_shaper.c \ + ass_outline.h ass_outline.c ass_drawing.h ass_drawing.c \ + ass_rasterizer.h ass_rasterizer.c ass_rasterizer_c.c \ + ass_bitmap.h ass_bitmap.c ass_blur.c 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 FONTCONFIG +libass_la_SOURCES += $(SRC_FONTCONFIG) +endif + if DIRECTWRITE libass_la_SOURCES += $(SRC_DIRECTWRITE) endif @@ -44,16 +48,9 @@ libass_la_SOURCES += $(SRC_CORETEXT) endif -if RASTERIZER -libass_la_SOURCES += $(SRC_RASTERIZER) -endif - if ASM if INTEL libass_la_SOURCES += $(SRC_INTEL) -if RASTERIZER -libass_la_SOURCES += $(SRC_INTEL_RASTERIZER) -endif if X64 libass_la_SOURCES += $(SRC_INTEL64) endif @@ -63,4 +60,4 @@ assheadersdir = $(includedir)/ass dist_assheaders_HEADERS = ass.h ass_types.h -EXTRA_DIST = libass.sym x86/x86inc.asm +EXTRA_DIST = libass.sym x86/x86inc.asm x86/utils.asm diff -Nru libass-0.13.7/libass/Makefile.in libass-0.14.0/libass/Makefile.in --- libass-0.13.7/libass/Makefile.in 2017-06-03 17:06:00.000000000 +0000 +++ libass-0.14.0/libass/Makefile.in 2017-10-31 12:56:57.000000000 +0000 @@ -89,12 +89,11 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -@DIRECTWRITE_TRUE@am__append_1 = $(SRC_DIRECTWRITE) -@CORETEXT_TRUE@am__append_2 = $(SRC_CORETEXT) -@RASTERIZER_TRUE@am__append_3 = $(SRC_RASTERIZER) +@FONTCONFIG_TRUE@am__append_1 = $(SRC_FONTCONFIG) +@DIRECTWRITE_TRUE@am__append_2 = $(SRC_DIRECTWRITE) +@CORETEXT_TRUE@am__append_3 = $(SRC_CORETEXT) @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) +@ASM_TRUE@@INTEL_TRUE@@X64_TRUE@am__append_5 = $(SRC_INTEL64) subdir = libass ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ @@ -139,41 +138,38 @@ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(assheadersdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libass_la_LIBADD = -am__libass_la_SOURCES_DIST = 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_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__libass_la_SOURCES_DIST = ass.h ass.c ass_types.h ass_utils.h \ + ass_utils.c ass_compat.h ass_string.h ass_string.c \ + ass_strtod.c ass_library.h ass_library.c ass_cache.h \ + ass_cache.c ass_cache_template.h ass_font.h ass_font.c \ + ass_fontselect.h ass_fontselect.c ass_render.h ass_render.c \ + ass_render_api.c ass_parse.h ass_parse.c ass_shaper.h \ + ass_shaper.c ass_outline.h ass_outline.c ass_drawing.h \ + ass_drawing.c ass_rasterizer.h ass_rasterizer.c \ + ass_rasterizer_c.c ass_bitmap.h ass_bitmap.c ass_blur.c \ + ass_func_template.h ass_fontconfig.c ass_fontconfig.h \ + ass_directwrite.c ass_directwrite.h dwrite_c.h ass_coretext.c \ + ass_coretext.h x86/rasterizer.asm x86/blend_bitmaps.asm \ + x86/blur.asm x86/cpuid.asm x86/cpuid.h x86/be_blur.asm +am__objects_1 = ass_fontconfig.lo +@FONTCONFIG_TRUE@am__objects_2 = $(am__objects_1) +am__objects_3 = ass_directwrite.lo +@DIRECTWRITE_TRUE@am__objects_4 = $(am__objects_3) +am__objects_5 = ass_coretext.lo +@CORETEXT_TRUE@am__objects_6 = $(am__objects_5) am__dirstamp = $(am__leading_dot)dirstamp -am__objects_7 = x86/blend_bitmaps.lo x86/blur.lo x86/cpuid.lo \ - x86/utils.lo +am__objects_7 = x86/rasterizer.lo x86/blend_bitmaps.lo x86/blur.lo \ + x86/cpuid.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_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_9 = x86/be_blur.lo +@ASM_TRUE@@INTEL_TRUE@@X64_TRUE@am__objects_10 = $(am__objects_9) +am_libass_la_OBJECTS = ass.lo ass_utils.lo ass_string.lo ass_strtod.lo \ + ass_library.lo ass_cache.lo ass_font.lo ass_fontselect.lo \ + ass_render.lo ass_render_api.lo ass_parse.lo ass_shaper.lo \ + ass_outline.lo ass_drawing.lo ass_rasterizer.lo \ + ass_rasterizer_c.lo ass_bitmap.lo ass_blur.lo $(am__objects_2) \ $(am__objects_4) $(am__objects_6) $(am__objects_8) \ - $(am__objects_10) $(am__objects_12) + $(am__objects_10) libass_la_OBJECTS = $(am_libass_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -369,12 +365,12 @@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ +nasm_check = @nasm_check@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ -runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -383,42 +379,42 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -yasm_check = @yasm_check@ AM_CFLAGS = -std=gnu99 -Wall -Wextra -Wno-sign-compare -Wno-unused-parameter \ -Werror-implicit-function-declaration -Wstrict-prototypes \ - -Wpointer-arith -Wredundant-decls -D_GNU_SOURCE + -Wpointer-arith -Wredundant-decls -Wno-missing-field-initializers\ + -D_GNU_SOURCE LIBASS_LT_CURRENT = 9 -LIBASS_LT_REVISION = 1 +LIBASS_LT_REVISION = 2 LIBASS_LT_AGE = 0 -yasm_verbose = $(yasm_verbose_$(V)) -yasm_verbose_ = $(yasm_verbose_$(AM_DEFAULT_VERBOSITY)) -yasm_verbose_0 = @echo " YASM " $@; -SRC_INTEL = x86/blend_bitmaps.asm x86/blur.asm x86/cpuid.asm x86/utils.asm \ +nasm_verbose = $(nasm_verbose_$(V)) +nasm_verbose_ = $(nasm_verbose_$(AM_DEFAULT_VERBOSITY)) +nasm_verbose_0 = @echo " NASM " $@; +SRC_INTEL = x86/rasterizer.asm x86/blend_bitmaps.asm x86/blur.asm x86/cpuid.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_FONTCONFIG = ass_fontconfig.c ass_fontconfig.h 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_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 $(am__append_1) \ - $(am__append_2) $(am__append_3) $(am__append_4) \ - $(am__append_5) $(am__append_6) +libass_la_SOURCES = ass.h ass.c ass_types.h ass_utils.h ass_utils.c \ + ass_compat.h ass_string.h ass_string.c ass_strtod.c \ + ass_library.h ass_library.c ass_cache.h ass_cache.c \ + ass_cache_template.h ass_font.h ass_font.c ass_fontselect.h \ + ass_fontselect.c ass_render.h ass_render.c ass_render_api.c \ + ass_parse.h ass_parse.c ass_shaper.h ass_shaper.c \ + ass_outline.h ass_outline.c ass_drawing.h ass_drawing.c \ + ass_rasterizer.h ass_rasterizer.c ass_rasterizer_c.c \ + ass_bitmap.h ass_bitmap.c ass_blur.c ass_func_template.h \ + $(am__append_1) $(am__append_2) $(am__append_3) \ + $(am__append_4) $(am__append_5) libass_la_LDFLAGS = -no-undefined -version-info \ $(LIBASS_LT_CURRENT):$(LIBASS_LT_REVISION):$(LIBASS_LT_AGE) \ -export-symbols $(srcdir)/libass.sym assheadersdir = $(includedir)/ass dist_assheaders_HEADERS = ass.h ass_types.h -EXTRA_DIST = libass.sym x86/x86inc.asm +EXTRA_DIST = libass.sym x86/x86inc.asm x86/utils.asm all: all-am .SUFFIXES: @@ -493,12 +489,11 @@ x86/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) x86/$(DEPDIR) @: > x86/$(DEPDIR)/$(am__dirstamp) +x86/rasterizer.lo: x86/$(am__dirstamp) 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) libass.la: $(libass_la_OBJECTS) $(libass_la_DEPENDENCIES) $(EXTRA_libass_la_DEPENDENCIES) @@ -523,6 +518,7 @@ @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_outline.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@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_rasterizer_c.Plo@am__quote@ @@ -797,7 +793,7 @@ .asm.lo: - $(yasm_verbose)$(LIBTOOL) $(AM_V_lt) --tag=CC --mode=compile $(AS) $(ASFLAGS) -o $@ $< -prefer-non-pic + $(nasm_verbose)$(LIBTOOL) $(AM_V_lt) --tag=CC --mode=compile $(AS) $(ASFLAGS) -I$(srcdir)/ -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.13.7/libass/x86/be_blur.asm libass-0.14.0/libass/x86/be_blur.asm --- libass-0.13.7/libass/x86/be_blur.asm 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/x86/be_blur.asm 2017-10-31 12:14:11.000000000 +0000 @@ -18,7 +18,7 @@ ;* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ;****************************************************************************** -%include "x86inc.asm" +%include "x86/x86inc.asm" SECTION_RODATA 32 low_word_zero: dd 0xFFFF0000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF @@ -43,7 +43,7 @@ lea r12, [r4 + r3 * 2] ; unsigned char *col_sum_buf = tmp + stride * 2; lea r14, [r1 - 2] ; tmpreg = (w-2); and r14, -8 ; tmpreg &= (~7); -.first_loop +.first_loop: movzx r10, byte [r7 + r6] ; int temp1 = src[x]; lea r11, [r8 + r10] ; int temp2 = old_pix + temp1; mov r8, r10 ; old_pix = temp1; @@ -58,7 +58,7 @@ movzx r8, byte [r7 + 1] ; int old_pix = src[1]; movzx r9, byte [r7] ; int old_sum = src[0]; add r9, r8 ; old_sum += old_pix -.second_loop +.second_loop: movzx r10, byte [r7 + r6] ; int temp1 = src[x]; lea r11, [r8 + r10] ; int temp2 = old_pix + temp1; mov r8, r10 ; old_pix = temp1; @@ -72,7 +72,7 @@ cmp r6, r1 ; x < w jl .second_loop mov r5, 2 ; int y = 2; -.height_loop +.height_loop: mov r10, r5; int tmpreg = y; imul r10, r3; tmpreg *= stride; lea r7, [r0 + r10] ; unsigned char *src=buf+y*stride; @@ -82,9 +82,9 @@ movzx r10, byte [r7] ; temp1 = src[0]; movzx r11, byte [r7 + 1] ; temp2 = src[1]; add r10, r11; temp1 += temp2 - movd xmm0, r10; __m128i old_pix_128 = temp2; - movd xmm1, r11; __m128i old_sum_128 = temp1; -.width_loop + movd xm0, r10d; __m128i old_pix_128 = temp2; + movd xm1, r11d; __m128i old_sum_128 = temp1; +.width_loop: movq xmm2, [r7 + r6]; __m128i new_pix = (src+x); punpcklbw xmm2, xmm6 ; new_pix = _mm_unpacklo_epi8(new_pix, temp3); movdqa xmm3, xmm2 ; __m128i temp = new_pix; @@ -116,7 +116,7 @@ movzx r9, byte [r7 + r6 - 2] ; old_sum = old_pix + src[x-2]; add r9, r8 jmp .final_width_check -.final_width_loop +.final_width_loop: movzx r10, byte [r7 + r6] ; temp1 = src[x]; lea r11, [r8 + r10] ; temp2 = old_pix + temp1; mov r8, r10 ; old_pix = temp1; @@ -131,7 +131,7 @@ mov byte [r13 + r6 - 1], r10b ; dst[x-1] = temp1 mov [r12 + r6 * 2], r11w ; col_sum_buf[x] = temp2; inc r6 ; x++ -.final_width_check +.final_width_check: cmp r6, r1 ; x < w jl .final_width_loop inc r5 ; y++; @@ -152,8 +152,8 @@ lea r12, [r4 + r3 * 2] ; unsigned char *col_sum_buf = tmp + stride * 2; lea r14, [r1 - 2] ; tmpreg = (w-2); and r14, -16 ; tmpreg &= (~15); - vmovdqa ymm7, [low_word_zero wrt rip] -.first_loop + vmovdqa ymm7, [low_word_zero] +.first_loop: movzx r10, byte [r7 + r6] ; int temp1 = src[x]; lea r11, [r8 + r10] ; int temp2 = old_pix + temp1; mov r8, r10 ; old_pix = temp1; @@ -168,7 +168,7 @@ movzx r8, byte [r7 + 1] ; int old_pix = src[1]; movzx r9, byte [r7] ; int old_sum = src[0]; add r9, r8 ; old_sum += old_pix -.second_loop +.second_loop: movzx r10, byte [r7 + r6] ; int temp1 = src[x]; lea r11, [r8 + r10] ; int temp2 = old_pix + temp1; mov r8, r10 ; old_pix = temp1; @@ -182,7 +182,7 @@ cmp r6, r1 ; x < w jl .second_loop mov r5, 2 ; int y = 2; -.height_loop +.height_loop: mov r10, r5; int tmpreg = y; imul r10, r3; tmpreg *= stride; lea r7, [r0 + r10] ; unsigned char *src=buf+y*stride; @@ -194,7 +194,7 @@ add r10, r11; temp1 += temp2 vmovd xmm0, r10d; __m128i old_pix_128 = temp2; vmovd xmm1, r11d; __m128i old_sum_128 = temp1; -.width_loop +.width_loop: vpermq ymm2, [r7 + r6], 0x10 vpunpcklbw ymm2, ymm2, ymm6 ; new_pix = _mm_unpacklo_epi8(new_pix, temp3); vpermq ymm8, ymm2, 0x4e @@ -229,7 +229,7 @@ movzx r9, byte [r7 + r6 - 2] ; old_sum = old_pix + src[x-2]; add r9, r8 jmp .final_width_check -.final_width_loop +.final_width_loop: movzx r10, byte [r7 + r6] ; temp1 = src[x]; lea r11, [r8 + r10] ; temp2 = old_pix + temp1; mov r8, r10 ; old_pix = temp1; @@ -244,7 +244,7 @@ mov byte [r13 + r6 - 1], r10b ; dst[x-1] = temp1 mov [r12 + r6 * 2], r11w ; col_sum_buf[x] = temp2; inc r6 ; x++ -.final_width_check +.final_width_check: cmp r6, r1 ; x < w jl .final_width_loop inc r5 ; y++; diff -Nru libass-0.13.7/libass/x86/blend_bitmaps.asm libass-0.14.0/libass/x86/blend_bitmaps.asm --- libass-0.13.7/libass/x86/blend_bitmaps.asm 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/x86/blend_bitmaps.asm 2017-10-31 12:14:11.000000000 +0000 @@ -18,7 +18,7 @@ ;* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ;****************************************************************************** -%include "x86inc.asm" +%include "x86/x86inc.asm" SECTION_RODATA 32 @@ -154,7 +154,7 @@ add r6, mmsize cmp r6, r7 jl .stride_loop ; still in scan line - .stride_loop2 + .stride_loop2: cmp r6, r5 jge .finish movzx r8, byte [r0 + r6] @@ -163,7 +163,7 @@ mov byte [r0 + r6], r8b inc r6 jmp .stride_loop2 - .finish + .finish: add r0, r1 add r2, r3 cmp r2, r4 @@ -215,7 +215,7 @@ imul r7, r3 add r7, r2 ; last address pxor xmm2, xmm2 - movdqa xmm3, [words_255 wrt rip] + movdqa xmm3, [words_255] mov r9, r6 and r9, -8 ; &= (~8); .height_loop: @@ -233,7 +233,7 @@ add r8, 8 cmp r8, r9 jl .stride_loop ; still in scan line -.stride_loop2 +.stride_loop2: cmp r8, r6 jge .finish movzx r10, byte [r2 + r8] @@ -262,7 +262,7 @@ imul r7, r3 add r7, r2 ; last address vpxor ymm2, ymm2 - vmovdqa ymm3, [words_255 wrt rip] + vmovdqa ymm3, [words_255] mov r9, r6 and r9, -16 ; &= (~16); .height_loop: @@ -283,7 +283,7 @@ add r8, 16 cmp r8, r9 jl .stride_loop ; still in scan line -.stride_loop2 +.stride_loop2: cmp r8, r6 jge .finish movzx r10, byte [r2 + r8] diff -Nru libass-0.13.7/libass/x86/blur.asm libass-0.14.0/libass/x86/blur.asm --- libass-0.13.7/libass/x86/blur.asm 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/x86/blur.asm 2017-10-31 12:14:11.000000000 +0000 @@ -18,7 +18,7 @@ ;* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ;****************************************************************************** -%include "utils.asm" +%include "x86/utils.asm" SECTION_RODATA 32 @@ -57,7 +57,7 @@ mova m2, [words_one] jmp .row_loop -.col_loop +.col_loop: mova m1, [r1] %if mmsize == 32 vpermq m1, m1, q3120 @@ -75,7 +75,7 @@ mova [r0 + r5], m1 add r5, r4 add r1, mmsize -.row_loop +.row_loop: cmp r5, r3 jl .col_loop sub r5, r4 @@ -93,7 +93,7 @@ psrlw m0, 1 mova [r0 + r5], m0 -.skip_odd +.skip_odd: add r5, mmsize sub r5, r3 add r1, r2 @@ -126,7 +126,7 @@ sub r5, r6 jmp .row_loop -.col_loop +.col_loop: mova m0, [r2] mova m2, m0 psrlw m2, 8 @@ -153,7 +153,7 @@ jb .col_loop add r0, r5 add r2, r4 -.row_loop +.row_loop: mova m3, [words_dither0] mova m4, [words_dither1] lea r6, [r2 + r4] @@ -163,7 +163,7 @@ jb .odd_stripe RET -.odd_stripe +.odd_stripe: mova m0, [r2] mova m2, m0 psrlw m2, 8 @@ -264,7 +264,7 @@ %endif lea r5, [r0 + r3] -.main_loop +.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 @@ -406,13 +406,13 @@ lea r6, [words_zero] sub r6, r1 -.col_loop +.col_loop: mov r4, -4 * mmsize pxor m0, m0 pxor m1, m1 pxor m2, m2 pxor m3, m3 -.row_loop +.row_loop: LOAD_LINE 4, r1,r3,r6, r4 + 4 * mmsize, r5 LOAD_LINE 5, r1,r3,r6, r4 + 5 * mmsize, r5 @@ -499,7 +499,7 @@ %if ARCH_X86_64 == 0 PUSH t0 %endif -.main_loop +.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 @@ -562,7 +562,7 @@ jb .odd_stripe RET -.odd_stripe +.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 @@ -631,11 +631,11 @@ lea r6, [words_zero] sub r6, r1 -.col_loop +.col_loop: mov r4, -2 * mmsize pxor m0, m0 pxor m1, m1 -.row_loop +.row_loop: LOAD_LINE 2, r1,r3,r6, r4 + 2 * mmsize, r5 paddw m3, m0, m2 @@ -701,7 +701,7 @@ sub r7, r1 %endif -.main_loop +.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 @@ -758,11 +758,11 @@ lea r6, [words_zero] sub r6, r1 -.col_loop +.col_loop: mov r4, -2 * mmsize pxor m0, m0 pxor m1, m1 -.row_loop +.row_loop: LOAD_LINE 2, r1,r3,r6, r4 + 2 * mmsize, r5 paddw m0, m2 @@ -819,7 +819,7 @@ sub r7, r1 %endif -.main_loop +.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 @@ -898,13 +898,13 @@ lea r6, [words_zero] sub r6, r1 -.col_loop +.col_loop: mov r4, -4 * mmsize pxor m0, m0 pxor m1, m1 pxor m2, m2 pxor m3, m3 -.row_loop +.row_loop: LOAD_LINE 4, r1,r3,r6, r4 + 4 * mmsize, r5 %if ARCH_X86_64 @@ -1018,7 +1018,7 @@ sub r7, r1 %endif -.main_loop +.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 @@ -1110,9 +1110,9 @@ lea r6, [words_zero] sub r6, r1 -.col_loop +.col_loop: mov r4, -6 * mmsize -.row_loop +.row_loop: mova m6, m4 mova m7, m4 LOAD_LINE 0, r1,r3,r6, r4 + 3 * mmsize, r5 @@ -1227,7 +1227,7 @@ sub r7, r1 %endif -.main_loop +.main_loop: %if ARCH_X86_64 %if %%i4 > 4 LOAD_LINE 0, r1,r2,r7, r4 + 0 * r3, r6 @@ -1366,9 +1366,9 @@ lea r6, [words_zero] sub r6, r1 -.col_loop +.col_loop: mov r4, -2 * %%i4 * mmsize -.row_loop +.row_loop: mova m6, m8 mova m7, m8 LOAD_LINE 0, r1,r3,r6, r4 + %%i4 * mmsize, r5 diff -Nru libass-0.13.7/libass/x86/cpuid.asm libass-0.14.0/libass/x86/cpuid.asm --- libass-0.13.7/libass/x86/cpuid.asm 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/x86/cpuid.asm 2017-10-31 12:14:11.000000000 +0000 @@ -18,7 +18,7 @@ ;* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ;****************************************************************************** -%include "x86inc.asm" +%include "x86/x86inc.asm" SECTION .text diff -Nru libass-0.13.7/libass/x86/rasterizer.asm libass-0.14.0/libass/x86/rasterizer.asm --- libass-0.13.7/libass/x86/rasterizer.asm 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/x86/rasterizer.asm 2017-10-31 12:14:11.000000000 +0000 @@ -18,7 +18,7 @@ ;* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ;****************************************************************************** -%include "utils.asm" +%include "x86/utils.asm" SECTION_RODATA 32 @@ -216,7 +216,7 @@ mov r2d, (1 << %1) jmp .loop_entry -.loop_start +.loop_start: add r0, r1 %if ARCH_X86_64 || a_shift == 0 psubw m1, m8 @@ -224,7 +224,7 @@ BCASTW 7, r3d psubw m1, m7 %endif -.loop_entry +.loop_entry: %assign i 0 %rep (1 << %1) / mmsize %if i @@ -597,7 +597,7 @@ %define dn_pos [rstk + delta_offs + 2 * tile_size + 8] %endif -.line_loop +.line_loop: %if ARCH_X86_64 == 0 mov t3, r2m lea t0, [t3 + line_size] @@ -743,7 +743,7 @@ jmp .bulk_fill %endif -.generic_fist +.generic_fist: %if ARCH_X86_64 == 0 mov t5, dn_addr %if a_shift @@ -751,7 +751,7 @@ %endif %endif -.bulk_fill +.bulk_fill: mov t2d, 1 << (13 - %1) mov t0d, t9d ; b sar t0d, 1 @@ -785,7 +785,7 @@ mova mm_full, [words_tile%2] %endif -.internal_loop +.internal_loop: %assign i 0 %rep (2 << %1) / mmsize %if i @@ -807,7 +807,7 @@ psubw mm_c, m0 %endif -.end_loop +.end_loop: %if ARCH_X86_64 test t7d, t7d jz .end_line_loop @@ -820,17 +820,17 @@ jmp .last_line %endif -.single_line +.single_line: %if ARCH_X86_64 == 0 mov t7d, dn_pos %endif mov t2d, t7d sub t2d, t6d ; dn_pos - up_pos add t6d, t7d ; dn_pos + up_pos -.last_line +.last_line: FILL_BORDER_LINE %1, t4,t8,t9,t10,t2,t6, t0,t1, 0,1,2,3,4,5 -.end_line_loop +.end_line_loop: %if ARCH_X86_64 add r2, line_size sub r3, 1 diff -Nru libass-0.13.7/libass/x86/utils.asm libass-0.14.0/libass/x86/utils.asm --- libass-0.13.7/libass/x86/utils.asm 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/x86/utils.asm 2017-10-31 12:14:11.000000000 +0000 @@ -18,8 +18,7 @@ ;* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ;****************************************************************************** -%define PIC -%include "x86inc.asm" +%include "x86/x86inc.asm" ;------------------------------------------------------------------------------ ; MUL 1:reg, 2:num diff -Nru libass-0.13.7/libass/x86/x86inc.asm libass-0.14.0/libass/x86/x86inc.asm --- libass-0.13.7/libass/x86/x86inc.asm 2016-09-24 18:42:55.000000000 +0000 +++ libass-0.14.0/libass/x86/x86inc.asm 2017-10-31 12:14:11.000000000 +0000 @@ -1,11 +1,11 @@ ;***************************************************************************** ;* x86inc.asm: x264asm abstraction layer ;***************************************************************************** -;* Copyright (C) 2005-2013 x264 project +;* Copyright (C) 2005-2016 x264 project ;* ;* Authors: Loren Merritt ;* Anton Mitrofanov -;* Jason Garrett-Glaser +;* Fiona Glaser ;* Henrik Gramner ;* ;* Permission to use, copy, modify, and/or distribute this software for any @@ -35,13 +35,24 @@ ; to x264-devel@videolan.org . %ifndef private_prefix - %define private_prefix ass + %define private_prefix x264 %endif %ifndef public_prefix %define public_prefix private_prefix %endif +%if HAVE_ALIGNED_STACK + %define STACK_ALIGNMENT 16 +%endif +%ifndef STACK_ALIGNMENT + %if ARCH_X86_64 + %define STACK_ALIGNMENT 16 + %else + %define STACK_ALIGNMENT 4 + %endif +%endif + %define WIN64 0 %define UNIX64 0 %if ARCH_X86_64 @@ -56,18 +67,30 @@ %endif %endif +%define FORMAT_ELF 0 +%ifidn __OUTPUT_FORMAT__,elf + %define FORMAT_ELF 1 +%elifidn __OUTPUT_FORMAT__,elf32 + %define FORMAT_ELF 1 +%elifidn __OUTPUT_FORMAT__,elf64 + %define FORMAT_ELF 1 +%endif + %ifdef PREFIX %define mangle(x) _ %+ x %else %define mangle(x) x %endif +; aout does not support align= +; NOTE: This section is out of sync with x264, in order to +; keep supporting OS/2. %macro SECTION_RODATA 0-1 16 - SECTION .rodata align=%1 -%endmacro - -%macro SECTION_TEXT 0-1 16 - SECTION .text align=%1 + %ifidn __OUTPUT_FORMAT__,aout + section .text + %else + SECTION .rodata align=%1 + %endif %endmacro %if WIN64 @@ -82,8 +105,11 @@ default rel %endif -; Always use long nops (reduces 0x90 spam in disassembly on x86_32) -CPU amdnop +%macro CPUNOP 1 + %if HAVE_CPUNOP + CPU %1 + %endif +%endmacro ; Macros to eliminate most code duplication between x86_32 and x86_64: ; Currently this works only for leaf functions which load all their arguments @@ -94,8 +120,9 @@ ; %1 = number of arguments. loads them from stack if needed. ; %2 = number of registers used. pushes callee-saved regs if needed. ; %3 = number of xmm registers used. pushes callee-saved xmm regs if needed. -; %4 = (optional) stack size to be allocated. If not aligned (x86-32 ICC 10.x, -; MSVC or YMM), the stack will be manually aligned (to 16 or 32 bytes), +; %4 = (optional) stack size to be allocated. The stack will be aligned before +; allocating the specified stack size. If the required stack alignment is +; larger than the known stack alignment the stack will be manually aligned ; and an extra register will be allocated to hold the original stack ; pointer (to not invalidate r0m etc.). To prevent the use of an extra ; register as stack pointer, request a negative stack size. @@ -103,8 +130,10 @@ ; PROLOGUE can also be invoked by adding the same options to cglobal ; e.g. -; cglobal foo, 2,3,0, dst, src, tmp -; declares a function (foo), taking two args (dst and src) and one local variable (tmp) +; cglobal foo, 2,3,7,0x40, dst, src, tmp +; declares a function (foo) that automatically loads two arguments (dst and +; src) into registers, uses one additional register (tmp) plus 7 vector +; registers (m0-m6) and allocates 0x40 bytes of stack space. ; TODO Some functions can use some args directly from the stack. If they're the ; last args then you can just not declare them, but if they're in the middle @@ -129,6 +158,7 @@ %define r%1w %2w %define r%1b %2b %define r%1h %2h + %define %2q %2 %if %0 == 2 %define r%1m %2d %define r%1mp %2 @@ -153,9 +183,9 @@ %define e%1h %3 %define r%1b %2 %define e%1b %2 -%if ARCH_X86_64 == 0 - %define r%1 e%1 -%endif + %if ARCH_X86_64 == 0 + %define r%1 e%1 + %endif %endmacro DECLARE_REG_SIZE ax, al, ah @@ -265,7 +295,7 @@ %macro ASSERT 1 %if (%1) == 0 - %error assert failed + %error assertion ``%1'' failed %endif %endmacro @@ -304,26 +334,28 @@ %assign n_arg_names %0 %endmacro +%define required_stack_alignment ((mmsize + 15) & ~15) + %macro ALLOC_STACK 1-2 0 ; stack_size, n_xmm_regs (for win64 only) %ifnum %1 %if %1 != 0 - %assign %%stack_alignment ((mmsize + 15) & ~15) + %assign %%pad 0 %assign stack_size %1 %if stack_size < 0 %assign stack_size -stack_size %endif - %assign stack_size_padded stack_size %if WIN64 - %assign stack_size_padded stack_size_padded + 32 ; reserve 32 bytes for shadow space + %assign %%pad %%pad + 32 ; shadow space %if mmsize != 8 %assign xmm_regs_used %2 %if xmm_regs_used > 8 - %assign stack_size_padded stack_size_padded + (xmm_regs_used-8)*16 + %assign %%pad %%pad + (xmm_regs_used-8)*16 ; callee-saved xmm registers %endif %endif %endif - %if mmsize <= 16 && HAVE_ALIGNED_STACK - %assign stack_size_padded stack_size_padded + %%stack_alignment - gprsize - (stack_offset & (%%stack_alignment - 1)) + %if required_stack_alignment <= STACK_ALIGNMENT + ; maintain the current stack alignment + %assign stack_size_padded stack_size + %%pad + ((-%%pad-stack_offset-gprsize) & (STACK_ALIGNMENT-1)) SUB rsp, stack_size_padded %else %assign %%reg_num (regs_used - 1) @@ -332,17 +364,17 @@ ; it, i.e. in [rsp+stack_size_padded], so we can restore the ; stack in a single instruction (i.e. mov rsp, rstk or mov ; rsp, [rsp+stack_size_padded]) - mov rstk, rsp %if %1 < 0 ; need to store rsp on stack - sub rsp, gprsize+stack_size_padded - and rsp, ~(%%stack_alignment-1) - %xdefine rstkm [rsp+stack_size_padded] - mov rstkm, rstk + %xdefine rstkm [rsp + stack_size + %%pad] + %assign %%pad %%pad + gprsize %else ; can keep rsp in rstk during whole function - sub rsp, stack_size_padded - and rsp, ~(%%stack_alignment-1) %xdefine rstkm rstk %endif + %assign stack_size_padded stack_size + ((%%pad + required_stack_alignment-1) & ~(required_stack_alignment-1)) + mov rstk, rsp + and rsp, ~(required_stack_alignment-1) + sub rsp, stack_size_padded + movifnidn rstkm, rstk %endif WIN64_PUSH_XMM %endif @@ -351,11 +383,21 @@ %macro SETUP_STACK_POINTER 1 %ifnum %1 - %if %1 != 0 && (HAVE_ALIGNED_STACK == 0 || mmsize == 32) + %if %1 != 0 && required_stack_alignment > STACK_ALIGNMENT %if %1 > 0 + ; Reserve an additional register for storing the original stack pointer, but avoid using + ; eax/rax for this purpose since it can potentially get overwritten as a return value. %assign regs_used (regs_used + 1) - %elif ARCH_X86_64 && regs_used == num_args && num_args <= 4 + UNIX64 * 2 - %warning "Stack pointer will overwrite register argument" + %if ARCH_X86_64 && regs_used == 7 + %assign regs_used 8 + %elif ARCH_X86_64 == 0 && regs_used == 1 + %assign regs_used 2 + %endif + %endif + %if ARCH_X86_64 && regs_used < 5 + UNIX64 * 3 + ; Ensure that we don't clobber any registers containing arguments. For UNIX64 we also preserve r6 (rax) + ; since it's used as a hidden argument in vararg functions to specify the number of vector registers used. + %assign regs_used 5 + UNIX64 * 3 %endif %endif %endif @@ -425,7 +467,9 @@ %assign xmm_regs_used %1 ASSERT xmm_regs_used <= 16 %if xmm_regs_used > 8 - %assign stack_size_padded (xmm_regs_used-8)*16 + (~stack_offset&8) + 32 + ; Allocate stack space for callee-saved xmm registers plus shadow space and align the stack. + %assign %%pad (xmm_regs_used-8)*16 + 32 + %assign stack_size_padded %%pad + ((-%%pad-stack_offset-gprsize) & (STACK_ALIGNMENT-1)) SUB rsp, stack_size_padded %endif WIN64_PUSH_XMM @@ -441,7 +485,7 @@ %endrep %endif %if stack_size_padded > 0 - %if stack_size > 0 && (mmsize == 32 || HAVE_ALIGNED_STACK == 0) + %if stack_size > 0 && required_stack_alignment > STACK_ALIGNMENT mov rsp, rstkm %else add %1, stack_size_padded @@ -467,9 +511,9 @@ %macro RET 0 WIN64_RESTORE_XMM_INTERNAL rsp POP_IF_USED 14, 13, 12, 11, 10, 9, 8, 7 -%if mmsize == 32 - vzeroupper -%endif + %if mmsize == 32 + vzeroupper + %endif AUTO_REP_RET %endmacro @@ -506,17 +550,17 @@ %define has_epilogue regs_used > 9 || mmsize == 32 || stack_size > 0 %macro RET 0 -%if stack_size_padded > 0 -%if mmsize == 32 || HAVE_ALIGNED_STACK == 0 - mov rsp, rstkm -%else - add rsp, stack_size_padded -%endif -%endif + %if stack_size_padded > 0 + %if required_stack_alignment > STACK_ALIGNMENT + mov rsp, rstkm + %else + add rsp, stack_size_padded + %endif + %endif POP_IF_USED 14, 13, 12, 11, 10, 9 -%if mmsize == 32 - vzeroupper -%endif + %if mmsize == 32 + vzeroupper + %endif AUTO_REP_RET %endmacro @@ -562,29 +606,29 @@ %define has_epilogue regs_used > 3 || mmsize == 32 || stack_size > 0 %macro RET 0 -%if stack_size_padded > 0 -%if mmsize == 32 || HAVE_ALIGNED_STACK == 0 - mov rsp, rstkm -%else - add rsp, stack_size_padded -%endif -%endif + %if stack_size_padded > 0 + %if required_stack_alignment > STACK_ALIGNMENT + mov rsp, rstkm + %else + add rsp, stack_size_padded + %endif + %endif POP_IF_USED 6, 5, 4, 3 -%if mmsize == 32 - vzeroupper -%endif + %if mmsize == 32 + vzeroupper + %endif AUTO_REP_RET %endmacro %endif ;====================================================================== %if WIN64 == 0 -%macro WIN64_SPILL_XMM 1 -%endmacro -%macro WIN64_RESTORE_XMM 1 -%endmacro -%macro WIN64_PUSH_XMM 0 -%endmacro + %macro WIN64_SPILL_XMM 1 + %endmacro + %macro WIN64_RESTORE_XMM 1 + %endmacro + %macro WIN64_PUSH_XMM 0 + %endmacro %endif ; On AMD cpus <=K10, an ordinary ret is slow if it immediately follows either @@ -597,24 +641,26 @@ %else rep ret %endif + annotate_function_size %endmacro %define last_branch_adr $$ %macro AUTO_REP_RET 0 - %ifndef cpuflags - times ((last_branch_adr-$)>>31)+1 rep ; times 1 iff $ != last_branch_adr. - %elif notcpuflag(ssse3) - times ((last_branch_adr-$)>>31)+1 rep + %if notcpuflag(ssse3) + times ((last_branch_adr-$)>>31)+1 rep ; times 1 iff $ == last_branch_adr. %endif ret + annotate_function_size %endmacro %macro BRANCH_INSTR 0-* %rep %0 %macro %1 1-2 %1 %2 %1 - %%branch_instr: - %xdefine last_branch_adr %%branch_instr + %if notcpuflag(ssse3) + %%branch_instr equ $ + %xdefine last_branch_adr %%branch_instr + %endif %endmacro %rotate 1 %endrep @@ -629,6 +675,7 @@ %elif %2 jmp %1 %endif + annotate_function_size %endmacro ;============================================================================= @@ -650,6 +697,7 @@ cglobal_internal 0, %1 %+ SUFFIX, %2 %endmacro %macro cglobal_internal 2-3+ + annotate_function_size %if %1 %xdefine %%FUNCTION_PREFIX private_prefix %xdefine %%VISIBILITY hidden @@ -663,7 +711,8 @@ CAT_XDEFINE cglobaled_, %2, 1 %endif %xdefine current_function %2 - %ifidn __OUTPUT_FORMAT__,elf + %xdefine current_function_section __SECT__ + %if FORMAT_ELF global %2:function %%VISIBILITY %else global %2 @@ -689,14 +738,16 @@ ; like cextern, but without the prefix %macro cextern_naked 1 - %xdefine %1 mangle(%1) + %ifdef PREFIX + %xdefine %1 mangle(%1) + %endif CAT_XDEFINE cglobaled_, %1, 1 extern %1 %endmacro %macro const 1-2+ %xdefine %1 mangle(private_prefix %+ _ %+ %1) - %ifidn __OUTPUT_FORMAT__,elf + %if FORMAT_ELF global %1:data hidden %else global %1 @@ -704,12 +755,29 @@ %1: %2 %endmacro -; This is needed for ELF, otherwise the GNU linker assumes the stack is -; executable by default. -%ifidn __OUTPUT_FORMAT__,elf -SECTION .note.GNU-stack noalloc noexec nowrite progbits +; This is needed for ELF, otherwise the GNU linker assumes the stack is executable by default. +%if FORMAT_ELF + [SECTION .note.GNU-stack noalloc noexec nowrite progbits] %endif +; Tell debuggers how large the function was. +; This may be invoked multiple times per function; we rely on later instances overriding earlier ones. +; This is invoked by RET and similar macros, and also cglobal does it for the previous function, +; but if the last function in a source file doesn't use any of the standard macros for its epilogue, +; then its size might be unspecified. +%macro annotate_function_size 0 + %ifdef __YASM_VER__ + %ifdef current_function + %if FORMAT_ELF + current_function_section + %%ecf equ $ + size current_function %%ecf - current_function + __SECT__ + %endif + %endif + %endif +%endmacro + ; cpuflags %assign cpuflags_mmx (1<<0) @@ -726,8 +794,8 @@ %assign cpuflags_avx (1<<11)| cpuflags_sse42 %assign cpuflags_xop (1<<12)| cpuflags_avx %assign cpuflags_fma4 (1<<13)| cpuflags_avx -%assign cpuflags_avx2 (1<<14)| cpuflags_avx -%assign cpuflags_fma3 (1<<15)| cpuflags_avx +%assign cpuflags_fma3 (1<<14)| cpuflags_avx +%assign cpuflags_avx2 (1<<15)| cpuflags_fma3 %assign cpuflags_cache32 (1<<16) %assign cpuflags_cache64 (1<<17) @@ -737,23 +805,32 @@ %assign cpuflags_atom (1<<21) %assign cpuflags_bmi1 (1<<22)|cpuflags_lzcnt %assign cpuflags_bmi2 (1<<23)|cpuflags_bmi1 +%assign cpuflags_aesni (1<<24)|cpuflags_sse42 -%define cpuflag(x) ((cpuflags & (cpuflags_ %+ x)) == (cpuflags_ %+ x)) -%define notcpuflag(x) ((cpuflags & (cpuflags_ %+ x)) != (cpuflags_ %+ x)) +; Returns a boolean value expressing whether or not the specified cpuflag is enabled. +%define cpuflag(x) (((((cpuflags & (cpuflags_ %+ x)) ^ (cpuflags_ %+ x)) - 1) >> 31) & 1) +%define notcpuflag(x) (cpuflag(x) ^ 1) -; Takes up to 2 cpuflags from the above list. +; Takes an arbitrary number of cpuflags from the above list. ; All subsequent functions (up to the next INIT_CPUFLAGS) is built for the specified cpu. ; You shouldn't need to invoke this macro directly, it's a subroutine for INIT_MMX &co. -%macro INIT_CPUFLAGS 0-2 - CPU amdnop +%macro INIT_CPUFLAGS 0-* + %xdefine SUFFIX + %undef cpuname + %assign cpuflags 0 + %if %0 >= 1 - %xdefine cpuname %1 - %assign cpuflags cpuflags_%1 - %if %0 >= 2 - %xdefine cpuname %1_%2 - %assign cpuflags cpuflags | cpuflags_%2 - %endif + %rep %0 + %ifdef cpuname + %xdefine cpuname cpuname %+ _%1 + %else + %xdefine cpuname %1 + %endif + %assign cpuflags cpuflags | cpuflags_%1 + %rotate 1 + %endrep %xdefine SUFFIX _ %+ cpuname + %if cpuflag(avx) %assign avx_enabled 1 %endif @@ -764,16 +841,15 @@ %endif %if cpuflag(aligned) %define movu mova - %elifidn %1, sse3 + %elif cpuflag(sse3) && notcpuflag(ssse3) %define movu lddqu %endif - %if ARCH_X86_64 == 0 && notcpuflag(sse2) - CPU basicnop - %endif + %endif + + %if ARCH_X86_64 || cpuflag(sse2) + CPUNOP amdnop %else - %xdefine SUFFIX - %undef cpuname - %undef cpuflags + CPUNOP basicnop %endif %endmacro @@ -802,14 +878,14 @@ %define movnta movntq %assign %%i 0 %rep 8 - CAT_XDEFINE m, %%i, mm %+ %%i - CAT_XDEFINE nmm, %%i, %%i - %assign %%i %%i+1 + CAT_XDEFINE m, %%i, mm %+ %%i + CAT_XDEFINE nnmm, %%i, %%i + %assign %%i %%i+1 %endrep %rep 8 - CAT_UNDEF m, %%i - CAT_UNDEF nmm, %%i - %assign %%i %%i+1 + CAT_UNDEF m, %%i + CAT_UNDEF nnmm, %%i + %assign %%i %%i+1 %endrep INIT_CPUFLAGS %1 %endmacro @@ -820,7 +896,7 @@ %define mmsize 16 %define num_mmregs 8 %if ARCH_X86_64 - %define num_mmregs 16 + %define num_mmregs 16 %endif %define mova movdqa %define movu movdqu @@ -828,9 +904,9 @@ %define movnta movntdq %assign %%i 0 %rep num_mmregs - CAT_XDEFINE m, %%i, xmm %+ %%i - CAT_XDEFINE nxmm, %%i, %%i - %assign %%i %%i+1 + CAT_XDEFINE m, %%i, xmm %+ %%i + CAT_XDEFINE nnxmm, %%i, %%i + %assign %%i %%i+1 %endrep INIT_CPUFLAGS %1 %endmacro @@ -841,7 +917,7 @@ %define mmsize 32 %define num_mmregs 8 %if ARCH_X86_64 - %define num_mmregs 16 + %define num_mmregs 16 %endif %define mova movdqa %define movu movdqu @@ -849,9 +925,9 @@ %define movnta movntdq %assign %%i 0 %rep num_mmregs - CAT_XDEFINE m, %%i, ymm %+ %%i - CAT_XDEFINE nymm, %%i, %%i - %assign %%i %%i+1 + CAT_XDEFINE m, %%i, ymm %+ %%i + CAT_XDEFINE nnymm, %%i, %%i + %assign %%i %%i+1 %endrep INIT_CPUFLAGS %1 %endmacro @@ -875,7 +951,7 @@ %assign i 0 %rep 16 DECLARE_MMCAST i -%assign i i+1 + %assign i i+1 %endrep ; I often want to use macros that permute their arguments. e.g. there's no @@ -893,23 +969,23 @@ ; doesn't cost any cycles. %macro PERMUTE 2-* ; takes a list of pairs to swap -%rep %0/2 - %xdefine %%tmp%2 m%2 - %rotate 2 -%endrep -%rep %0/2 - %xdefine m%1 %%tmp%2 - CAT_XDEFINE n, m%1, %1 - %rotate 2 -%endrep + %rep %0/2 + %xdefine %%tmp%2 m%2 + %rotate 2 + %endrep + %rep %0/2 + %xdefine m%1 %%tmp%2 + CAT_XDEFINE nn, m%1, %1 + %rotate 2 + %endrep %endmacro %macro SWAP 2+ ; swaps a single chain (sometimes more concise than pairs) -%ifnum %1 ; SWAP 0, 1, ... - SWAP_INTERNAL_NUM %1, %2 -%else ; SWAP m0, m1, ... - SWAP_INTERNAL_NAME %1, %2 -%endif + %ifnum %1 ; SWAP 0, 1, ... + SWAP_INTERNAL_NUM %1, %2 + %else ; SWAP m0, m1, ... + SWAP_INTERNAL_NAME %1, %2 + %endif %endmacro %macro SWAP_INTERNAL_NUM 2-* @@ -917,17 +993,17 @@ %xdefine %%tmp m%1 %xdefine m%1 m%2 %xdefine m%2 %%tmp - CAT_XDEFINE n, m%1, %1 - CAT_XDEFINE n, m%2, %2 - %rotate 1 + CAT_XDEFINE nn, m%1, %1 + CAT_XDEFINE nn, m%2, %2 + %rotate 1 %endrep %endmacro %macro SWAP_INTERNAL_NAME 2-* - %xdefine %%args n %+ %1 + %xdefine %%args nn %+ %1 %rep %0-1 - %xdefine %%args %%args, n %+ %2 - %rotate 1 + %xdefine %%args %%args, nn %+ %2 + %rotate 1 %endrep SWAP_INTERNAL_NUM %%args %endmacro @@ -944,7 +1020,7 @@ %assign %%i 0 %rep num_mmregs CAT_XDEFINE %%f, %%i, m %+ %%i - %assign %%i %%i+1 + %assign %%i %%i+1 %endrep %endmacro @@ -953,21 +1029,21 @@ %assign %%i 0 %rep num_mmregs CAT_XDEFINE m, %%i, %1_m %+ %%i - CAT_XDEFINE n, m %+ %%i, %%i - %assign %%i %%i+1 + CAT_XDEFINE nn, m %+ %%i, %%i + %assign %%i %%i+1 %endrep %endif %endmacro ; Append cpuflags to the callee's name iff the appended name is known and the plain name isn't %macro call 1 - call_internal %1, %1 %+ SUFFIX + call_internal %1 %+ SUFFIX, %1 %endmacro %macro call_internal 2 - %xdefine %%i %1 - %ifndef cglobaled_%1 - %ifdef cglobaled_%2 - %xdefine %%i %2 + %xdefine %%i %2 + %ifndef cglobaled_%2 + %ifdef cglobaled_%1 + %xdefine %%i %1 %endif %endif call %%i @@ -1010,7 +1086,7 @@ %endif CAT_XDEFINE sizeofxmm, i, 16 CAT_XDEFINE sizeofymm, i, 32 -%assign i i+1 + %assign i i+1 %endrep %undef i @@ -1026,342 +1102,362 @@ %endmacro ;%1 == instruction -;%2 == 1 if float, 0 if int -;%3 == 1 if non-destructive or 4-operand (xmm, xmm, xmm, imm), 0 otherwise -;%4 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not -;%5+: operands -%macro RUN_AVX_INSTR 5-8+ - %ifnum sizeof%6 - %assign %%sizeofreg sizeof%6 - %elifnum sizeof%5 - %assign %%sizeofreg sizeof%5 +;%2 == minimal instruction set +;%3 == 1 if float, 0 if int +;%4 == 1 if 4-operand emulation, 0 if 3-operand emulation, 255 otherwise (no emulation) +;%5 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not +;%6+: operands +%macro RUN_AVX_INSTR 6-9+ + %ifnum sizeof%7 + %assign __sizeofreg sizeof%7 + %elifnum sizeof%6 + %assign __sizeofreg sizeof%6 %else - %assign %%sizeofreg mmsize + %assign __sizeofreg mmsize %endif - %assign %%emulate_avx 0 - %if avx_enabled && %%sizeofreg >= 16 - %xdefine %%instr v%1 + %assign __emulate_avx 0 + %if avx_enabled && __sizeofreg >= 16 + %xdefine __instr v%1 %else - %xdefine %%instr %1 - %if %0 >= 7+%3 - %assign %%emulate_avx 1 + %xdefine __instr %1 + %if %0 >= 8+%4 + %assign __emulate_avx 1 %endif %endif - - %if %%emulate_avx - %xdefine %%src1 %6 - %xdefine %%src2 %7 - %ifnidn %5, %6 - %if %0 >= 8 - CHECK_AVX_INSTR_EMU {%1 %5, %6, %7, %8}, %5, %7, %8 - %else - CHECK_AVX_INSTR_EMU {%1 %5, %6, %7}, %5, %7 + %ifnidn %2, fnord + %ifdef cpuname + %if notcpuflag(%2) + %error use of ``%1'' %2 instruction in cpuname function: current_function + %elif cpuflags_%2 < cpuflags_sse && notcpuflag(sse2) && __sizeofreg > 8 + %error use of ``%1'' sse2 instruction in cpuname function: current_function %endif - %if %4 && %3 == 0 - %ifnid %7 + %endif + %endif + + %if __emulate_avx + %xdefine __src1 %7 + %xdefine __src2 %8 + %if %5 && %4 == 0 + %ifnidn %6, %7 + %ifidn %6, %8 + %xdefine __src1 %8 + %xdefine __src2 %7 + %elifnnum sizeof%8 ; 3-operand AVX instructions with a memory arg can only have it in src2, ; whereas SSE emulation prefers to have it in src1 (i.e. the mov). ; So, if the instruction is commutative with a memory arg, swap them. - %xdefine %%src1 %7 - %xdefine %%src2 %6 + %xdefine __src1 %8 + %xdefine __src2 %7 %endif %endif - %if %%sizeofreg == 8 - MOVQ %5, %%src1 - %elif %2 - MOVAPS %5, %%src1 + %endif + %ifnidn %6, __src1 + %if %0 >= 9 + CHECK_AVX_INSTR_EMU {%1 %6, %7, %8, %9}, %6, __src2, %9 + %else + CHECK_AVX_INSTR_EMU {%1 %6, %7, %8}, %6, __src2 + %endif + %if __sizeofreg == 8 + MOVQ %6, __src1 + %elif %3 + MOVAPS %6, __src1 %else - MOVDQA %5, %%src1 + MOVDQA %6, __src1 %endif %endif - %if %0 >= 8 - %1 %5, %%src2, %8 + %if %0 >= 9 + %1 %6, __src2, %9 %else - %1 %5, %%src2 + %1 %6, __src2 %endif - %elif %0 >= 8 - %%instr %5, %6, %7, %8 + %elif %0 >= 9 + __instr %6, %7, %8, %9 + %elif %0 == 8 + __instr %6, %7, %8 %elif %0 == 7 - %%instr %5, %6, %7 - %elif %0 == 6 - %%instr %5, %6 + __instr %6, %7 %else - %%instr %5 + __instr %6 %endif %endmacro ;%1 == instruction -;%2 == 1 if float, 0 if int -;%3 == 1 if non-destructive or 4-operand (xmm, xmm, xmm, imm), 0 otherwise -;%4 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not -%macro AVX_INSTR 1-4 0, 1, 0 - %macro %1 1-9 fnord, fnord, fnord, fnord, %1, %2, %3, %4 +;%2 == minimal instruction set +;%3 == 1 if float, 0 if int +;%4 == 1 if 4-operand emulation, 0 if 3-operand emulation, 255 otherwise (no emulation) +;%5 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not +%macro AVX_INSTR 1-5 fnord, 0, 255, 0 + %macro %1 1-10 fnord, fnord, fnord, fnord, %1, %2, %3, %4, %5 %ifidn %2, fnord - RUN_AVX_INSTR %6, %7, %8, %9, %1 + RUN_AVX_INSTR %6, %7, %8, %9, %10, %1 %elifidn %3, fnord - RUN_AVX_INSTR %6, %7, %8, %9, %1, %2 + RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2 %elifidn %4, fnord - RUN_AVX_INSTR %6, %7, %8, %9, %1, %2, %3 + RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3 %elifidn %5, fnord - RUN_AVX_INSTR %6, %7, %8, %9, %1, %2, %3, %4 + RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3, %4 %else - RUN_AVX_INSTR %6, %7, %8, %9, %1, %2, %3, %4, %5 + RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3, %4, %5 %endif %endmacro %endmacro ; Instructions with both VEX and non-VEX encodings ; Non-destructive instructions are written without parameters -AVX_INSTR addpd, 1, 0, 1 -AVX_INSTR addps, 1, 0, 1 -AVX_INSTR addsd, 1, 0, 1 -AVX_INSTR addss, 1, 0, 1 -AVX_INSTR addsubpd, 1, 0, 0 -AVX_INSTR addsubps, 1, 0, 0 -AVX_INSTR aesdec, 0, 0, 0 -AVX_INSTR aesdeclast, 0, 0, 0 -AVX_INSTR aesenc, 0, 0, 0 -AVX_INSTR aesenclast, 0, 0, 0 -AVX_INSTR aesimc -AVX_INSTR aeskeygenassist -AVX_INSTR andnpd, 1, 0, 0 -AVX_INSTR andnps, 1, 0, 0 -AVX_INSTR andpd, 1, 0, 1 -AVX_INSTR andps, 1, 0, 1 -AVX_INSTR blendpd, 1, 0, 0 -AVX_INSTR blendps, 1, 0, 0 -AVX_INSTR blendvpd, 1, 0, 0 -AVX_INSTR blendvps, 1, 0, 0 -AVX_INSTR cmppd, 1, 1, 0 -AVX_INSTR cmpps, 1, 1, 0 -AVX_INSTR cmpsd, 1, 1, 0 -AVX_INSTR cmpss, 1, 1, 0 -AVX_INSTR comisd -AVX_INSTR comiss -AVX_INSTR cvtdq2pd -AVX_INSTR cvtdq2ps -AVX_INSTR cvtpd2dq -AVX_INSTR cvtpd2ps -AVX_INSTR cvtps2dq -AVX_INSTR cvtps2pd -AVX_INSTR cvtsd2si -AVX_INSTR cvtsd2ss -AVX_INSTR cvtsi2sd -AVX_INSTR cvtsi2ss -AVX_INSTR cvtss2sd -AVX_INSTR cvtss2si -AVX_INSTR cvttpd2dq -AVX_INSTR cvttps2dq -AVX_INSTR cvttsd2si -AVX_INSTR cvttss2si -AVX_INSTR divpd, 1, 0, 0 -AVX_INSTR divps, 1, 0, 0 -AVX_INSTR divsd, 1, 0, 0 -AVX_INSTR divss, 1, 0, 0 -AVX_INSTR dppd, 1, 1, 0 -AVX_INSTR dpps, 1, 1, 0 -AVX_INSTR extractps -AVX_INSTR haddpd, 1, 0, 0 -AVX_INSTR haddps, 1, 0, 0 -AVX_INSTR hsubpd, 1, 0, 0 -AVX_INSTR hsubps, 1, 0, 0 -AVX_INSTR insertps, 1, 1, 0 -AVX_INSTR lddqu -AVX_INSTR ldmxcsr -AVX_INSTR maskmovdqu -AVX_INSTR maxpd, 1, 0, 1 -AVX_INSTR maxps, 1, 0, 1 -AVX_INSTR maxsd, 1, 0, 1 -AVX_INSTR maxss, 1, 0, 1 -AVX_INSTR minpd, 1, 0, 1 -AVX_INSTR minps, 1, 0, 1 -AVX_INSTR minsd, 1, 0, 1 -AVX_INSTR minss, 1, 0, 1 -AVX_INSTR movapd -AVX_INSTR movaps -AVX_INSTR movd -AVX_INSTR movddup -AVX_INSTR movdqa -AVX_INSTR movdqu -AVX_INSTR movhlps, 1, 0, 0 -AVX_INSTR movhpd, 1, 0, 0 -AVX_INSTR movhps, 1, 0, 0 -AVX_INSTR movlhps, 1, 0, 0 -AVX_INSTR movlpd, 1, 0, 0 -AVX_INSTR movlps, 1, 0, 0 -AVX_INSTR movmskpd -AVX_INSTR movmskps -AVX_INSTR movntdq -AVX_INSTR movntdqa -AVX_INSTR movntpd -AVX_INSTR movntps -AVX_INSTR movq -AVX_INSTR movsd, 1, 0, 0 -AVX_INSTR movshdup -AVX_INSTR movsldup -AVX_INSTR movss, 1, 0, 0 -AVX_INSTR movupd -AVX_INSTR movups -AVX_INSTR mpsadbw, 0, 1, 0 -AVX_INSTR mulpd, 1, 0, 1 -AVX_INSTR mulps, 1, 0, 1 -AVX_INSTR mulsd, 1, 0, 1 -AVX_INSTR mulss, 1, 0, 1 -AVX_INSTR orpd, 1, 0, 1 -AVX_INSTR orps, 1, 0, 1 -AVX_INSTR pabsb -AVX_INSTR pabsd -AVX_INSTR pabsw -AVX_INSTR packsswb, 0, 0, 0 -AVX_INSTR packssdw, 0, 0, 0 -AVX_INSTR packuswb, 0, 0, 0 -AVX_INSTR packusdw, 0, 0, 0 -AVX_INSTR paddb, 0, 0, 1 -AVX_INSTR paddw, 0, 0, 1 -AVX_INSTR paddd, 0, 0, 1 -AVX_INSTR paddq, 0, 0, 1 -AVX_INSTR paddsb, 0, 0, 1 -AVX_INSTR paddsw, 0, 0, 1 -AVX_INSTR paddusb, 0, 0, 1 -AVX_INSTR paddusw, 0, 0, 1 -AVX_INSTR palignr, 0, 1, 0 -AVX_INSTR pand, 0, 0, 1 -AVX_INSTR pandn, 0, 0, 0 -AVX_INSTR pavgb, 0, 0, 1 -AVX_INSTR pavgw, 0, 0, 1 -AVX_INSTR pblendvb, 0, 0, 0 -AVX_INSTR pblendw, 0, 1, 0 -AVX_INSTR pclmulqdq, 0, 1, 0 -AVX_INSTR pcmpestri -AVX_INSTR pcmpestrm -AVX_INSTR pcmpistri -AVX_INSTR pcmpistrm -AVX_INSTR pcmpeqb, 0, 0, 1 -AVX_INSTR pcmpeqw, 0, 0, 1 -AVX_INSTR pcmpeqd, 0, 0, 1 -AVX_INSTR pcmpeqq, 0, 0, 1 -AVX_INSTR pcmpgtb, 0, 0, 0 -AVX_INSTR pcmpgtw, 0, 0, 0 -AVX_INSTR pcmpgtd, 0, 0, 0 -AVX_INSTR pcmpgtq, 0, 0, 0 -AVX_INSTR pextrb -AVX_INSTR pextrd -AVX_INSTR pextrq -AVX_INSTR pextrw -AVX_INSTR phaddw, 0, 0, 0 -AVX_INSTR phaddd, 0, 0, 0 -AVX_INSTR phaddsw, 0, 0, 0 -AVX_INSTR phminposuw -AVX_INSTR phsubw, 0, 0, 0 -AVX_INSTR phsubd, 0, 0, 0 -AVX_INSTR phsubsw, 0, 0, 0 -AVX_INSTR pinsrb, 0, 1, 0 -AVX_INSTR pinsrd, 0, 1, 0 -AVX_INSTR pinsrq, 0, 1, 0 -AVX_INSTR pinsrw, 0, 1, 0 -AVX_INSTR pmaddwd, 0, 0, 1 -AVX_INSTR pmaddubsw, 0, 0, 0 -AVX_INSTR pmaxsb, 0, 0, 1 -AVX_INSTR pmaxsw, 0, 0, 1 -AVX_INSTR pmaxsd, 0, 0, 1 -AVX_INSTR pmaxub, 0, 0, 1 -AVX_INSTR pmaxuw, 0, 0, 1 -AVX_INSTR pmaxud, 0, 0, 1 -AVX_INSTR pminsb, 0, 0, 1 -AVX_INSTR pminsw, 0, 0, 1 -AVX_INSTR pminsd, 0, 0, 1 -AVX_INSTR pminub, 0, 0, 1 -AVX_INSTR pminuw, 0, 0, 1 -AVX_INSTR pminud, 0, 0, 1 -AVX_INSTR pmovmskb -AVX_INSTR pmovsxbw -AVX_INSTR pmovsxbd -AVX_INSTR pmovsxbq -AVX_INSTR pmovsxwd -AVX_INSTR pmovsxwq -AVX_INSTR pmovsxdq -AVX_INSTR pmovzxbw -AVX_INSTR pmovzxbd -AVX_INSTR pmovzxbq -AVX_INSTR pmovzxwd -AVX_INSTR pmovzxwq -AVX_INSTR pmovzxdq -AVX_INSTR pmuldq, 0, 0, 1 -AVX_INSTR pmulhrsw, 0, 0, 1 -AVX_INSTR pmulhuw, 0, 0, 1 -AVX_INSTR pmulhw, 0, 0, 1 -AVX_INSTR pmullw, 0, 0, 1 -AVX_INSTR pmulld, 0, 0, 1 -AVX_INSTR pmuludq, 0, 0, 1 -AVX_INSTR por, 0, 0, 1 -AVX_INSTR psadbw, 0, 0, 1 -AVX_INSTR pshufb, 0, 0, 0 -AVX_INSTR pshufd -AVX_INSTR pshufhw -AVX_INSTR pshuflw -AVX_INSTR psignb, 0, 0, 0 -AVX_INSTR psignw, 0, 0, 0 -AVX_INSTR psignd, 0, 0, 0 -AVX_INSTR psllw, 0, 0, 0 -AVX_INSTR pslld, 0, 0, 0 -AVX_INSTR psllq, 0, 0, 0 -AVX_INSTR pslldq, 0, 0, 0 -AVX_INSTR psraw, 0, 0, 0 -AVX_INSTR psrad, 0, 0, 0 -AVX_INSTR psrlw, 0, 0, 0 -AVX_INSTR psrld, 0, 0, 0 -AVX_INSTR psrlq, 0, 0, 0 -AVX_INSTR psrldq, 0, 0, 0 -AVX_INSTR psubb, 0, 0, 0 -AVX_INSTR psubw, 0, 0, 0 -AVX_INSTR psubd, 0, 0, 0 -AVX_INSTR psubq, 0, 0, 0 -AVX_INSTR psubsb, 0, 0, 0 -AVX_INSTR psubsw, 0, 0, 0 -AVX_INSTR psubusb, 0, 0, 0 -AVX_INSTR psubusw, 0, 0, 0 -AVX_INSTR ptest -AVX_INSTR punpckhbw, 0, 0, 0 -AVX_INSTR punpckhwd, 0, 0, 0 -AVX_INSTR punpckhdq, 0, 0, 0 -AVX_INSTR punpckhqdq, 0, 0, 0 -AVX_INSTR punpcklbw, 0, 0, 0 -AVX_INSTR punpcklwd, 0, 0, 0 -AVX_INSTR punpckldq, 0, 0, 0 -AVX_INSTR punpcklqdq, 0, 0, 0 -AVX_INSTR pxor, 0, 0, 1 -AVX_INSTR rcpps, 1, 0, 0 -AVX_INSTR rcpss, 1, 0, 0 -AVX_INSTR roundpd -AVX_INSTR roundps -AVX_INSTR roundsd -AVX_INSTR roundss -AVX_INSTR rsqrtps, 1, 0, 0 -AVX_INSTR rsqrtss, 1, 0, 0 -AVX_INSTR shufpd, 1, 1, 0 -AVX_INSTR shufps, 1, 1, 0 -AVX_INSTR sqrtpd, 1, 0, 0 -AVX_INSTR sqrtps, 1, 0, 0 -AVX_INSTR sqrtsd, 1, 0, 0 -AVX_INSTR sqrtss, 1, 0, 0 -AVX_INSTR stmxcsr -AVX_INSTR subpd, 1, 0, 0 -AVX_INSTR subps, 1, 0, 0 -AVX_INSTR subsd, 1, 0, 0 -AVX_INSTR subss, 1, 0, 0 -AVX_INSTR ucomisd -AVX_INSTR ucomiss -AVX_INSTR unpckhpd, 1, 0, 0 -AVX_INSTR unpckhps, 1, 0, 0 -AVX_INSTR unpcklpd, 1, 0, 0 -AVX_INSTR unpcklps, 1, 0, 0 -AVX_INSTR xorpd, 1, 0, 1 -AVX_INSTR xorps, 1, 0, 1 +AVX_INSTR addpd, sse2, 1, 0, 1 +AVX_INSTR addps, sse, 1, 0, 1 +AVX_INSTR addsd, sse2, 1, 0, 0 +AVX_INSTR addss, sse, 1, 0, 0 +AVX_INSTR addsubpd, sse3, 1, 0, 0 +AVX_INSTR addsubps, sse3, 1, 0, 0 +AVX_INSTR aesdec, aesni, 0, 0, 0 +AVX_INSTR aesdeclast, aesni, 0, 0, 0 +AVX_INSTR aesenc, aesni, 0, 0, 0 +AVX_INSTR aesenclast, aesni, 0, 0, 0 +AVX_INSTR aesimc, aesni +AVX_INSTR aeskeygenassist, aesni +AVX_INSTR andnpd, sse2, 1, 0, 0 +AVX_INSTR andnps, sse, 1, 0, 0 +AVX_INSTR andpd, sse2, 1, 0, 1 +AVX_INSTR andps, sse, 1, 0, 1 +AVX_INSTR blendpd, sse4, 1, 1, 0 +AVX_INSTR blendps, sse4, 1, 1, 0 +AVX_INSTR blendvpd, sse4 ; can't be emulated +AVX_INSTR blendvps, sse4 ; can't be emulated +AVX_INSTR cmppd, sse2, 1, 1, 0 +AVX_INSTR cmpps, sse, 1, 1, 0 +AVX_INSTR cmpsd, sse2, 1, 1, 0 +AVX_INSTR cmpss, sse, 1, 1, 0 +AVX_INSTR comisd, sse2 +AVX_INSTR comiss, sse +AVX_INSTR cvtdq2pd, sse2 +AVX_INSTR cvtdq2ps, sse2 +AVX_INSTR cvtpd2dq, sse2 +AVX_INSTR cvtpd2ps, sse2 +AVX_INSTR cvtps2dq, sse2 +AVX_INSTR cvtps2pd, sse2 +AVX_INSTR cvtsd2si, sse2 +AVX_INSTR cvtsd2ss, sse2, 1, 0, 0 +AVX_INSTR cvtsi2sd, sse2, 1, 0, 0 +AVX_INSTR cvtsi2ss, sse, 1, 0, 0 +AVX_INSTR cvtss2sd, sse2, 1, 0, 0 +AVX_INSTR cvtss2si, sse +AVX_INSTR cvttpd2dq, sse2 +AVX_INSTR cvttps2dq, sse2 +AVX_INSTR cvttsd2si, sse2 +AVX_INSTR cvttss2si, sse +AVX_INSTR divpd, sse2, 1, 0, 0 +AVX_INSTR divps, sse, 1, 0, 0 +AVX_INSTR divsd, sse2, 1, 0, 0 +AVX_INSTR divss, sse, 1, 0, 0 +AVX_INSTR dppd, sse4, 1, 1, 0 +AVX_INSTR dpps, sse4, 1, 1, 0 +AVX_INSTR extractps, sse4 +AVX_INSTR haddpd, sse3, 1, 0, 0 +AVX_INSTR haddps, sse3, 1, 0, 0 +AVX_INSTR hsubpd, sse3, 1, 0, 0 +AVX_INSTR hsubps, sse3, 1, 0, 0 +AVX_INSTR insertps, sse4, 1, 1, 0 +AVX_INSTR lddqu, sse3 +AVX_INSTR ldmxcsr, sse +AVX_INSTR maskmovdqu, sse2 +AVX_INSTR maxpd, sse2, 1, 0, 1 +AVX_INSTR maxps, sse, 1, 0, 1 +AVX_INSTR maxsd, sse2, 1, 0, 0 +AVX_INSTR maxss, sse, 1, 0, 0 +AVX_INSTR minpd, sse2, 1, 0, 1 +AVX_INSTR minps, sse, 1, 0, 1 +AVX_INSTR minsd, sse2, 1, 0, 0 +AVX_INSTR minss, sse, 1, 0, 0 +AVX_INSTR movapd, sse2 +AVX_INSTR movaps, sse +AVX_INSTR movd, mmx +AVX_INSTR movddup, sse3 +AVX_INSTR movdqa, sse2 +AVX_INSTR movdqu, sse2 +AVX_INSTR movhlps, sse, 1, 0, 0 +AVX_INSTR movhpd, sse2, 1, 0, 0 +AVX_INSTR movhps, sse, 1, 0, 0 +AVX_INSTR movlhps, sse, 1, 0, 0 +AVX_INSTR movlpd, sse2, 1, 0, 0 +AVX_INSTR movlps, sse, 1, 0, 0 +AVX_INSTR movmskpd, sse2 +AVX_INSTR movmskps, sse +AVX_INSTR movntdq, sse2 +AVX_INSTR movntdqa, sse4 +AVX_INSTR movntpd, sse2 +AVX_INSTR movntps, sse +AVX_INSTR movq, mmx +AVX_INSTR movsd, sse2, 1, 0, 0 +AVX_INSTR movshdup, sse3 +AVX_INSTR movsldup, sse3 +AVX_INSTR movss, sse, 1, 0, 0 +AVX_INSTR movupd, sse2 +AVX_INSTR movups, sse +AVX_INSTR mpsadbw, sse4, 0, 1, 0 +AVX_INSTR mulpd, sse2, 1, 0, 1 +AVX_INSTR mulps, sse, 1, 0, 1 +AVX_INSTR mulsd, sse2, 1, 0, 0 +AVX_INSTR mulss, sse, 1, 0, 0 +AVX_INSTR orpd, sse2, 1, 0, 1 +AVX_INSTR orps, sse, 1, 0, 1 +AVX_INSTR pabsb, ssse3 +AVX_INSTR pabsd, ssse3 +AVX_INSTR pabsw, ssse3 +AVX_INSTR packsswb, mmx, 0, 0, 0 +AVX_INSTR packssdw, mmx, 0, 0, 0 +AVX_INSTR packuswb, mmx, 0, 0, 0 +AVX_INSTR packusdw, sse4, 0, 0, 0 +AVX_INSTR paddb, mmx, 0, 0, 1 +AVX_INSTR paddw, mmx, 0, 0, 1 +AVX_INSTR paddd, mmx, 0, 0, 1 +AVX_INSTR paddq, sse2, 0, 0, 1 +AVX_INSTR paddsb, mmx, 0, 0, 1 +AVX_INSTR paddsw, mmx, 0, 0, 1 +AVX_INSTR paddusb, mmx, 0, 0, 1 +AVX_INSTR paddusw, mmx, 0, 0, 1 +AVX_INSTR palignr, ssse3, 0, 1, 0 +AVX_INSTR pand, mmx, 0, 0, 1 +AVX_INSTR pandn, mmx, 0, 0, 0 +AVX_INSTR pavgb, mmx2, 0, 0, 1 +AVX_INSTR pavgw, mmx2, 0, 0, 1 +AVX_INSTR pblendvb, sse4 ; can't be emulated +AVX_INSTR pblendw, sse4, 0, 1, 0 +AVX_INSTR pclmulqdq, fnord, 0, 1, 0 +AVX_INSTR pclmulhqhqdq, fnord, 0, 0, 0 +AVX_INSTR pclmulhqlqdq, fnord, 0, 0, 0 +AVX_INSTR pclmullqhqdq, fnord, 0, 0, 0 +AVX_INSTR pclmullqlqdq, fnord, 0, 0, 0 +AVX_INSTR pcmpestri, sse42 +AVX_INSTR pcmpestrm, sse42 +AVX_INSTR pcmpistri, sse42 +AVX_INSTR pcmpistrm, sse42 +AVX_INSTR pcmpeqb, mmx, 0, 0, 1 +AVX_INSTR pcmpeqw, mmx, 0, 0, 1 +AVX_INSTR pcmpeqd, mmx, 0, 0, 1 +AVX_INSTR pcmpeqq, sse4, 0, 0, 1 +AVX_INSTR pcmpgtb, mmx, 0, 0, 0 +AVX_INSTR pcmpgtw, mmx, 0, 0, 0 +AVX_INSTR pcmpgtd, mmx, 0, 0, 0 +AVX_INSTR pcmpgtq, sse42, 0, 0, 0 +AVX_INSTR pextrb, sse4 +AVX_INSTR pextrd, sse4 +AVX_INSTR pextrq, sse4 +AVX_INSTR pextrw, mmx2 +AVX_INSTR phaddw, ssse3, 0, 0, 0 +AVX_INSTR phaddd, ssse3, 0, 0, 0 +AVX_INSTR phaddsw, ssse3, 0, 0, 0 +AVX_INSTR phminposuw, sse4 +AVX_INSTR phsubw, ssse3, 0, 0, 0 +AVX_INSTR phsubd, ssse3, 0, 0, 0 +AVX_INSTR phsubsw, ssse3, 0, 0, 0 +AVX_INSTR pinsrb, sse4, 0, 1, 0 +AVX_INSTR pinsrd, sse4, 0, 1, 0 +AVX_INSTR pinsrq, sse4, 0, 1, 0 +AVX_INSTR pinsrw, mmx2, 0, 1, 0 +AVX_INSTR pmaddwd, mmx, 0, 0, 1 +AVX_INSTR pmaddubsw, ssse3, 0, 0, 0 +AVX_INSTR pmaxsb, sse4, 0, 0, 1 +AVX_INSTR pmaxsw, mmx2, 0, 0, 1 +AVX_INSTR pmaxsd, sse4, 0, 0, 1 +AVX_INSTR pmaxub, mmx2, 0, 0, 1 +AVX_INSTR pmaxuw, sse4, 0, 0, 1 +AVX_INSTR pmaxud, sse4, 0, 0, 1 +AVX_INSTR pminsb, sse4, 0, 0, 1 +AVX_INSTR pminsw, mmx2, 0, 0, 1 +AVX_INSTR pminsd, sse4, 0, 0, 1 +AVX_INSTR pminub, mmx2, 0, 0, 1 +AVX_INSTR pminuw, sse4, 0, 0, 1 +AVX_INSTR pminud, sse4, 0, 0, 1 +AVX_INSTR pmovmskb, mmx2 +AVX_INSTR pmovsxbw, sse4 +AVX_INSTR pmovsxbd, sse4 +AVX_INSTR pmovsxbq, sse4 +AVX_INSTR pmovsxwd, sse4 +AVX_INSTR pmovsxwq, sse4 +AVX_INSTR pmovsxdq, sse4 +AVX_INSTR pmovzxbw, sse4 +AVX_INSTR pmovzxbd, sse4 +AVX_INSTR pmovzxbq, sse4 +AVX_INSTR pmovzxwd, sse4 +AVX_INSTR pmovzxwq, sse4 +AVX_INSTR pmovzxdq, sse4 +AVX_INSTR pmuldq, sse4, 0, 0, 1 +AVX_INSTR pmulhrsw, ssse3, 0, 0, 1 +AVX_INSTR pmulhuw, mmx2, 0, 0, 1 +AVX_INSTR pmulhw, mmx, 0, 0, 1 +AVX_INSTR pmullw, mmx, 0, 0, 1 +AVX_INSTR pmulld, sse4, 0, 0, 1 +AVX_INSTR pmuludq, sse2, 0, 0, 1 +AVX_INSTR por, mmx, 0, 0, 1 +AVX_INSTR psadbw, mmx2, 0, 0, 1 +AVX_INSTR pshufb, ssse3, 0, 0, 0 +AVX_INSTR pshufd, sse2 +AVX_INSTR pshufhw, sse2 +AVX_INSTR pshuflw, sse2 +AVX_INSTR psignb, ssse3, 0, 0, 0 +AVX_INSTR psignw, ssse3, 0, 0, 0 +AVX_INSTR psignd, ssse3, 0, 0, 0 +AVX_INSTR psllw, mmx, 0, 0, 0 +AVX_INSTR pslld, mmx, 0, 0, 0 +AVX_INSTR psllq, mmx, 0, 0, 0 +AVX_INSTR pslldq, sse2, 0, 0, 0 +AVX_INSTR psraw, mmx, 0, 0, 0 +AVX_INSTR psrad, mmx, 0, 0, 0 +AVX_INSTR psrlw, mmx, 0, 0, 0 +AVX_INSTR psrld, mmx, 0, 0, 0 +AVX_INSTR psrlq, mmx, 0, 0, 0 +AVX_INSTR psrldq, sse2, 0, 0, 0 +AVX_INSTR psubb, mmx, 0, 0, 0 +AVX_INSTR psubw, mmx, 0, 0, 0 +AVX_INSTR psubd, mmx, 0, 0, 0 +AVX_INSTR psubq, sse2, 0, 0, 0 +AVX_INSTR psubsb, mmx, 0, 0, 0 +AVX_INSTR psubsw, mmx, 0, 0, 0 +AVX_INSTR psubusb, mmx, 0, 0, 0 +AVX_INSTR psubusw, mmx, 0, 0, 0 +AVX_INSTR ptest, sse4 +AVX_INSTR punpckhbw, mmx, 0, 0, 0 +AVX_INSTR punpckhwd, mmx, 0, 0, 0 +AVX_INSTR punpckhdq, mmx, 0, 0, 0 +AVX_INSTR punpckhqdq, sse2, 0, 0, 0 +AVX_INSTR punpcklbw, mmx, 0, 0, 0 +AVX_INSTR punpcklwd, mmx, 0, 0, 0 +AVX_INSTR punpckldq, mmx, 0, 0, 0 +AVX_INSTR punpcklqdq, sse2, 0, 0, 0 +AVX_INSTR pxor, mmx, 0, 0, 1 +AVX_INSTR rcpps, sse +AVX_INSTR rcpss, sse, 1, 0, 0 +AVX_INSTR roundpd, sse4 +AVX_INSTR roundps, sse4 +AVX_INSTR roundsd, sse4, 1, 1, 0 +AVX_INSTR roundss, sse4, 1, 1, 0 +AVX_INSTR rsqrtps, sse +AVX_INSTR rsqrtss, sse, 1, 0, 0 +AVX_INSTR shufpd, sse2, 1, 1, 0 +AVX_INSTR shufps, sse, 1, 1, 0 +AVX_INSTR sqrtpd, sse2 +AVX_INSTR sqrtps, sse +AVX_INSTR sqrtsd, sse2, 1, 0, 0 +AVX_INSTR sqrtss, sse, 1, 0, 0 +AVX_INSTR stmxcsr, sse +AVX_INSTR subpd, sse2, 1, 0, 0 +AVX_INSTR subps, sse, 1, 0, 0 +AVX_INSTR subsd, sse2, 1, 0, 0 +AVX_INSTR subss, sse, 1, 0, 0 +AVX_INSTR ucomisd, sse2 +AVX_INSTR ucomiss, sse +AVX_INSTR unpckhpd, sse2, 1, 0, 0 +AVX_INSTR unpckhps, sse, 1, 0, 0 +AVX_INSTR unpcklpd, sse2, 1, 0, 0 +AVX_INSTR unpcklps, sse, 1, 0, 0 +AVX_INSTR xorpd, sse2, 1, 0, 1 +AVX_INSTR xorps, sse, 1, 0, 1 ; 3DNow instructions, for sharing code between AVX, SSE and 3DN -AVX_INSTR pfadd, 1, 0, 1 -AVX_INSTR pfsub, 1, 0, 0 -AVX_INSTR pfmul, 1, 0, 1 +AVX_INSTR pfadd, 3dnow, 1, 0, 1 +AVX_INSTR pfsub, 3dnow, 1, 0, 0 +AVX_INSTR pfmul, 3dnow, 1, 0, 1 ; base-4 constants for shuffles %assign i 0 @@ -1376,7 +1472,7 @@ %else CAT_XDEFINE q, j, i %endif -%assign i i+1 + %assign i i+1 %endrep %undef i %undef j @@ -1385,66 +1481,72 @@ %macro %1 4-7 %1, %2, %3 %if cpuflag(xop) v%5 %1, %2, %3, %4 - %else + %elifnidn %1, %4 %6 %1, %2, %3 %7 %1, %4 + %else + %error non-xop emulation of ``%5 %1, %2, %3, %4'' is not supported %endif %endmacro %endmacro -FMA_INSTR pmacsdd, pmulld, paddd FMA_INSTR pmacsww, pmullw, paddw +FMA_INSTR pmacsdd, pmulld, paddd ; sse4 emulation +FMA_INSTR pmacsdql, pmuldq, paddq ; sse4 emulation FMA_INSTR pmadcswd, pmaddwd, paddd -; convert FMA4 to FMA3 if possible -%macro FMA4_INSTR 4 - %macro %1 4-8 %1, %2, %3, %4 - %if cpuflag(fma4) - v%5 %1, %2, %3, %4 - %elifidn %1, %2 - v%6 %1, %4, %3 ; %1 = %1 * %3 + %4 - %elifidn %1, %3 - v%7 %1, %2, %4 ; %1 = %2 * %1 + %4 - %elifidn %1, %4 - v%8 %1, %2, %3 ; %1 = %2 * %3 + %1 - %else - %error fma3 emulation of ``%5 %1, %2, %3, %4'' is not supported - %endif - %endmacro +; tzcnt is equivalent to "rep bsf" and is backwards-compatible with bsf. +; This lets us use tzcnt without bumping the yasm version requirement yet. +%define tzcnt rep bsf + +; Macros for consolidating FMA3 and FMA4 using 4-operand (dst, src1, src2, src3) syntax. +; FMA3 is only possible if dst is the same as one of the src registers. +; Either src2 or src3 can be a memory operand. +%macro FMA4_INSTR 2-* + %push fma4_instr + %xdefine %$prefix %1 + %rep %0 - 1 + %macro %$prefix%2 4-6 %$prefix, %2 + %if notcpuflag(fma3) && notcpuflag(fma4) + %error use of ``%5%6'' fma instruction in cpuname function: current_function + %elif cpuflag(fma4) + v%5%6 %1, %2, %3, %4 + %elifidn %1, %2 + ; If %3 or %4 is a memory operand it needs to be encoded as the last operand. + %ifnum sizeof%3 + v%{5}213%6 %2, %3, %4 + %else + v%{5}132%6 %2, %4, %3 + %endif + %elifidn %1, %3 + v%{5}213%6 %3, %2, %4 + %elifidn %1, %4 + v%{5}231%6 %4, %2, %3 + %else + %error fma3 emulation of ``%5%6 %1, %2, %3, %4'' is not supported + %endif + %endmacro + %rotate 1 + %endrep + %pop %endmacro -FMA4_INSTR fmaddpd, fmadd132pd, fmadd213pd, fmadd231pd -FMA4_INSTR fmaddps, fmadd132ps, fmadd213ps, fmadd231ps -FMA4_INSTR fmaddsd, fmadd132sd, fmadd213sd, fmadd231sd -FMA4_INSTR fmaddss, fmadd132ss, fmadd213ss, fmadd231ss - -FMA4_INSTR fmaddsubpd, fmaddsub132pd, fmaddsub213pd, fmaddsub231pd -FMA4_INSTR fmaddsubps, fmaddsub132ps, fmaddsub213ps, fmaddsub231ps -FMA4_INSTR fmsubaddpd, fmsubadd132pd, fmsubadd213pd, fmsubadd231pd -FMA4_INSTR fmsubaddps, fmsubadd132ps, fmsubadd213ps, fmsubadd231ps - -FMA4_INSTR fmsubpd, fmsub132pd, fmsub213pd, fmsub231pd -FMA4_INSTR fmsubps, fmsub132ps, fmsub213ps, fmsub231ps -FMA4_INSTR fmsubsd, fmsub132sd, fmsub213sd, fmsub231sd -FMA4_INSTR fmsubss, fmsub132ss, fmsub213ss, fmsub231ss - -FMA4_INSTR fnmaddpd, fnmadd132pd, fnmadd213pd, fnmadd231pd -FMA4_INSTR fnmaddps, fnmadd132ps, fnmadd213ps, fnmadd231ps -FMA4_INSTR fnmaddsd, fnmadd132sd, fnmadd213sd, fnmadd231sd -FMA4_INSTR fnmaddss, fnmadd132ss, fnmadd213ss, fnmadd231ss - -FMA4_INSTR fnmsubpd, fnmsub132pd, fnmsub213pd, fnmsub231pd -FMA4_INSTR fnmsubps, fnmsub132ps, fnmsub213ps, fnmsub231ps -FMA4_INSTR fnmsubsd, fnmsub132sd, fnmsub213sd, fnmsub231sd -FMA4_INSTR fnmsubss, fnmsub132ss, fnmsub213ss, fnmsub231ss - -; workaround: vpbroadcastq is broken in x86_32 due to a yasm bug -%if ARCH_X86_64 == 0 -%macro vpbroadcastq 2 -%if sizeof%1 == 16 - movddup %1, %2 -%else - vbroadcastsd %1, %2 -%endif -%endmacro +FMA4_INSTR fmadd, pd, ps, sd, ss +FMA4_INSTR fmaddsub, pd, ps +FMA4_INSTR fmsub, pd, ps, sd, ss +FMA4_INSTR fmsubadd, pd, ps +FMA4_INSTR fnmadd, pd, ps, sd, ss +FMA4_INSTR fnmsub, pd, ps, sd, ss + +; workaround: vpbroadcastq is broken in x86_32 due to a yasm bug (fixed in 1.3.0) +%ifdef __YASM_VER__ + %if __YASM_VERSION_ID__ < 0x01030000 && ARCH_X86_64 == 0 + %macro vpbroadcastq 2 + %if sizeof%1 == 16 + movddup %1, %2 + %else + vbroadcastsd %1, %2 + %endif + %endmacro + %endif %endif diff -Nru libass-0.13.7/ltmain.sh libass-0.14.0/ltmain.sh --- libass-0.13.7/ltmain.sh 2017-06-03 17:05:58.000000000 +0000 +++ libass-0.14.0/ltmain.sh 2017-10-31 12:56:51.000000000 +0000 @@ -31,7 +31,7 @@ PROGRAM=libtool PACKAGE=libtool -VERSION="2.4.6 Debian-2.4.6-0.1" +VERSION=2.4.6 package_revision=2.4.6 @@ -2073,7 +2073,7 @@ autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` Report bugs to . -GNU libtool home page: . +GNU libtool home page: . General help using GNU software: ." exit 0 } @@ -7272,13 +7272,10 @@ # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization - # -specs=* GCC specs files # -stdlib=* select c++ std lib with clang - # -fsanitize=* Clang/GCC memory and address sanitizer -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ - -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \ - -specs=*|-fsanitize=*) + -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*) func_quote_for_eval "$arg" arg=$func_quote_for_eval_result func_append compile_command " $arg" @@ -7571,10 +7568,7 @@ case $pass in dlopen) libs=$dlfiles ;; dlpreopen) libs=$dlprefiles ;; - link) - libs="$deplibs %DEPLIBS%" - test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" - ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; esac fi if test lib,dlpreopen = "$linkmode,$pass"; then @@ -7893,19 +7887,19 @@ # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" - tmp_libs= - for deplib in $dependency_libs; do - deplibs="$deplib $deplibs" - if $opt_preserve_dup_deps; then - case "$tmp_libs " in - *" $deplib "*) func_append specialdeplibs " $deplib" ;; - esac - fi - func_append tmp_libs " $deplib" - done elif test prog != "$linkmode" && test lib != "$linkmode"; then func_fatal_error "'$lib' is not a convenience library" fi + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_preserve_dup_deps; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done continue fi # $pass = conv @@ -8829,9 +8823,6 @@ revision=$number_minor lt_irix_increment=no ;; - *) - func_fatal_configuration "$modename: unknown library version type '$version_type'" - ;; esac ;; no) diff -Nru libass-0.13.7/m4/libtool.m4 libass-0.14.0/m4/libtool.m4 --- libass-0.13.7/m4/libtool.m4 2017-06-03 17:05:58.000000000 +0000 +++ libass-0.14.0/m4/libtool.m4 2017-10-31 12:56:51.000000000 +0000 @@ -2887,18 +2887,6 @@ dynamic_linker='GNU/Linux ld.so' ;; -netbsdelf*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='NetBSD ld.elf_so' - ;; - netbsd*) version_type=sunos need_lib_prefix=no @@ -3558,7 +3546,7 @@ lt_cv_deplibs_check_method=pass_all ;; -netbsd* | netbsdelf*-gnu) +netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else @@ -4436,7 +4424,7 @@ ;; esac ;; - netbsd* | netbsdelf*-gnu) + netbsd*) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise @@ -4948,9 +4936,6 @@ ;; esac ;; - linux* | k*bsd*-gnu | gnu*) - _LT_TAGVAR(link_all_deplibs, $1)=no - ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; @@ -5013,9 +4998,6 @@ openbsd* | bitrig*) with_gnu_ld=no ;; - linux* | k*bsd*-gnu | gnu*) - _LT_TAGVAR(link_all_deplibs, $1)=no - ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes @@ -5270,7 +5252,7 @@ fi ;; - netbsd* | netbsdelf*-gnu) + netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= @@ -5791,7 +5773,6 @@ if test yes = "$lt_cv_irix_exported_symbol"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' fi - _LT_TAGVAR(link_all_deplibs, $1)=no else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' @@ -5813,7 +5794,7 @@ esac ;; - netbsd* | netbsdelf*-gnu) + netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else diff -Nru libass-0.13.7/Makefile.in libass-0.14.0/Makefile.in --- libass-0.13.7/Makefile.in 2017-06-03 17:06:00.000000000 +0000 +++ libass-0.14.0/Makefile.in 2017-10-31 12:56:57.000000000 +0000 @@ -359,12 +359,12 @@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ +nasm_check = @nasm_check@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ -runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -373,7 +373,6 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -yasm_check = @yasm_check@ ACLOCAL_AMFLAGS = -I m4 AUTOMAKE_OPTIONS = foreign EXTRA_DIST = libass.pc.in Changelog diff -Nru libass-0.13.7/profile/Makefile.in libass-0.14.0/profile/Makefile.in --- libass-0.13.7/profile/Makefile.in 2017-06-03 17:06:00.000000000 +0000 +++ libass-0.14.0/profile/Makefile.in 2017-10-31 12:56:57.000000000 +0000 @@ -299,12 +299,12 @@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ +nasm_check = @nasm_check@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ -runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -313,7 +313,6 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -yasm_check = @yasm_check@ AM_CFLAGS = -Wall profile_SOURCES = profile.c profile_CPPFLAGS = -I$(top_srcdir)/libass diff -Nru libass-0.13.7/test/Makefile.in libass-0.14.0/test/Makefile.in --- libass-0.13.7/test/Makefile.in 2017-06-03 17:06:00.000000000 +0000 +++ libass-0.14.0/test/Makefile.in 2017-10-31 12:56:57.000000000 +0000 @@ -299,12 +299,12 @@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ +nasm_check = @nasm_check@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ -runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -313,7 +313,6 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -yasm_check = @yasm_check@ AM_CFLAGS = -Wall test_SOURCES = test.c test_CPPFLAGS = -I$(top_srcdir)/libass