New upstream version 0.15.0
Sebastian Ramacher
3 years ago
0 | libass (0.15.0) | |
1 | * Fix backwards/VSFilter-incompatible font sizes with FreeType 2.10+ | |
2 | * Improve speed via better caching | |
3 | * Require HarfBuzz unconditionally to ensure good shaping for complex scripts | |
4 | * ass_set_use_margins(true) now simply places text on the whole | |
5 | screen instead of attempting to tie it to video positioning | |
6 | (set by the margin values) and failing in various ways when | |
7 | margins are used to implement pan & scan in a video player | |
8 | * Add ass_track_set_feature() & catch-all ASS_FEATURE_INCOMPATIBLE_EXTENSIONS | |
9 | * Add ASS_FEATURE_BIDI_BRACKETS to enable Unicode 6.3+ bracket matching | |
10 | when applying the Unicode Bidirectional Algorithm | |
11 | (incompatible with VSFilter; requires libass built with FriBidi 1.0+) | |
12 | * Fix stack overflow on deeply nested \t tags | |
13 | * Fix positioning of events with leading line breaks | |
14 | * Fix small but nonzero \bord becoming \bord0 (regression in 0.14.0) | |
15 | * Measure BorderStyle=4 box padding from glyph border, not from glyph fill | |
16 | * Scale everything from script resolution if storage size is not set | |
17 | (including borders and shadows regardless of ScaledBorderAndShadow) | |
18 | * Fix the default aspect ratio calculation when neither | |
19 | ass_set_pixel_aspect() nor ass_set_aspect_ratio() is called | |
20 | * Multiple fixes for karaoke override tags | |
21 | * Handle memory allocation failures better: | |
22 | avoid some crashes and produce images closer to truth | |
23 | * Avoid some integer overflows | |
24 | * Add internal infrastructure for regression testing | |
25 | * Improve VSFilter compatibility: | |
26 | * Treat invalid nested \t tags like VSFilter | |
27 | * Make \t(T,T,...) at time exactly T use the post-transition values | |
28 | * Make lines stack more like they do in VSFilter | |
29 | * Default ScaledBorderAndShadow to 0 (like VSFilter), | |
30 | except for subtitles that were produced by old FFmpeg/Libav | |
31 | * Make shadow positioning with 3D transforms match VSFilter's | |
32 | * Cut out glyphs from border & shadow in all the same cases as VSFilter | |
33 | * Match VSFilter on animated color tags with negative acceleration | |
34 | * Fix parsing of some files that VSFilter accepts but libass didn't | |
35 | by ignoring leading whitespace in each line of an ASS file or CodecPrivate | |
36 | * Improve font selection with CoreText | |
37 | * Stop faux-bolding fonts that are too bold to get faux bold in VSFilter | |
38 | * Ignore leading/trailing spaces when calculating height of nonblank lines | |
39 | * Match VSFilter on \fade with large alpha value arguments | |
40 | * Stop splitting bitmaps on font substitution | |
41 | * Multiple fixes for Banner and Scroll effects | |
42 | * Multiple fixes for karaoke override tags | |
43 | ||
0 | 44 | libass (0.14.0) |
1 | 45 | * Brand new, faster and better outline stroker (replaces FreeType stroker) |
2 | 46 | * Remove option to use the FreeType rasterizer |
4 | 4 | pkgconfigdir = $(libdir)/pkgconfig |
5 | 5 | pkgconfig_DATA = libass.pc |
6 | 6 | |
7 | if HAVE_LIBPNG | |
7 | if ENABLE_TEST | |
8 | 8 | test = test |
9 | endif | |
10 | ||
11 | if ENABLE_COMPARE | |
12 | compare = compare | |
9 | 13 | endif |
10 | 14 | |
11 | 15 | if ENABLE_PROFILE |
12 | 16 | profile = profile |
13 | 17 | endif |
14 | 18 | |
15 | SUBDIRS = libass $(test) $(profile) | |
19 | SUBDIRS = libass $(test) $(compare) $(profile) | |
16 | 20 |
0 | # Makefile.in generated by automake 1.15 from Makefile.am. | |
0 | # Makefile.in generated by automake 1.16.1 from Makefile.am. | |
1 | 1 | # @configure_input@ |
2 | 2 | |
3 | # Copyright (C) 1994-2014 Free Software Foundation, Inc. | |
3 | # Copyright (C) 1994-2018 Free Software Foundation, Inc. | |
4 | 4 | |
5 | 5 | # This Makefile.in is free software; the Free Software Foundation |
6 | 6 | # gives unlimited permission to copy and/or distribute it, |
166 | 166 | $(RECURSIVE_CLEAN_TARGETS) \ |
167 | 167 | $(am__extra_recursive_targets) |
168 | 168 | AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ |
169 | cscope distdir dist dist-all distcheck | |
169 | cscope distdir distdir-am dist dist-all distcheck | |
170 | 170 | am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ |
171 | 171 | $(LISP)config.h.in |
172 | 172 | # Read a list of newline-separated strings from the standard input, |
188 | 188 | ETAGS = etags |
189 | 189 | CTAGS = ctags |
190 | 190 | CSCOPE = cscope |
191 | DIST_SUBDIRS = libass test profile | |
191 | DIST_SUBDIRS = libass test compare profile | |
192 | 192 | am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \ |
193 | 193 | $(srcdir)/libass.pc.in COPYING compile config.guess config.sub \ |
194 | install-sh ltmain.sh missing | |
194 | depcomp install-sh ltmain.sh missing | |
195 | 195 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) |
196 | 196 | distdir = $(PACKAGE)-$(VERSION) |
197 | 197 | top_distdir = $(distdir) |
377 | 377 | EXTRA_DIST = libass.pc.in Changelog |
378 | 378 | pkgconfigdir = $(libdir)/pkgconfig |
379 | 379 | pkgconfig_DATA = libass.pc |
380 | @HAVE_LIBPNG_TRUE@test = test | |
380 | @ENABLE_TEST_TRUE@test = test | |
381 | @ENABLE_COMPARE_TRUE@compare = compare | |
381 | 382 | @ENABLE_PROFILE_TRUE@profile = profile |
382 | SUBDIRS = libass $(test) $(profile) | |
383 | SUBDIRS = libass $(test) $(compare) $(profile) | |
383 | 384 | all: config.h |
384 | 385 | $(MAKE) $(AM_MAKEFLAGS) all-recursive |
385 | 386 | |
405 | 406 | echo ' $(SHELL) ./config.status'; \ |
406 | 407 | $(SHELL) ./config.status;; \ |
407 | 408 | *) \ |
408 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ | |
409 | cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ | |
409 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ | |
410 | cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ | |
410 | 411 | esac; |
411 | 412 | |
412 | 413 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) |
571 | 572 | -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags |
572 | 573 | -rm -f cscope.out cscope.in.out cscope.po.out cscope.files |
573 | 574 | |
574 | distdir: $(DISTFILES) | |
575 | distdir: $(BUILT_SOURCES) | |
576 | $(MAKE) $(AM_MAKEFLAGS) distdir-am | |
577 | ||
578 | distdir-am: $(DISTFILES) | |
575 | 579 | $(am__remove_distdir) |
576 | 580 | test -d "$(distdir)" || mkdir "$(distdir)" |
577 | 581 | @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ |
636 | 640 | ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ |
637 | 641 | || chmod -R a+r "$(distdir)" |
638 | 642 | dist-gzip: distdir |
639 | tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz | |
643 | tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz | |
640 | 644 | $(am__post_remove_distdir) |
641 | 645 | |
642 | 646 | dist-bzip2: distdir |
662 | 666 | @echo WARNING: "Support for shar distribution archives is" \ |
663 | 667 | "deprecated." >&2 |
664 | 668 | @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 |
665 | shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz | |
669 | shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz | |
666 | 670 | $(am__post_remove_distdir) |
667 | 671 | |
668 | 672 | dist-zip: distdir |
680 | 684 | distcheck: dist |
681 | 685 | case '$(DIST_ARCHIVES)' in \ |
682 | 686 | *.tar.gz*) \ |
683 | GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ | |
687 | eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ | |
684 | 688 | *.tar.bz2*) \ |
685 | 689 | bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ |
686 | 690 | *.tar.lz*) \ |
690 | 694 | *.tar.Z*) \ |
691 | 695 | uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ |
692 | 696 | *.shar.gz*) \ |
693 | GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ | |
697 | eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ | |
694 | 698 | *.zip*) \ |
695 | 699 | unzip $(distdir).zip ;;\ |
696 | 700 | esac |
0 | # generated automatically by aclocal 1.15 -*- Autoconf -*- | |
1 | ||
2 | # Copyright (C) 1996-2014 Free Software Foundation, Inc. | |
0 | # generated automatically by aclocal 1.16.1 -*- Autoconf -*- | |
1 | ||
2 | # Copyright (C) 1996-2018 Free Software Foundation, Inc. | |
3 | 3 | |
4 | 4 | # This file is free software; the Free Software Foundation |
5 | 5 | # gives unlimited permission to copy and/or distribute it, |
295 | 295 | AS_VAR_IF([$1], [""], [$5], [$4])dnl |
296 | 296 | ])dnl PKG_CHECK_VAR |
297 | 297 | |
298 | # Copyright (C) 2002-2014 Free Software Foundation, Inc. | |
298 | # Copyright (C) 2002-2018 Free Software Foundation, Inc. | |
299 | 299 | # |
300 | 300 | # This file is free software; the Free Software Foundation |
301 | 301 | # gives unlimited permission to copy and/or distribute it, |
307 | 307 | # generated from the m4 files accompanying Automake X.Y. |
308 | 308 | # (This private macro should not be called outside this file.) |
309 | 309 | AC_DEFUN([AM_AUTOMAKE_VERSION], |
310 | [am__api_version='1.15' | |
310 | [am__api_version='1.16' | |
311 | 311 | dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to |
312 | 312 | dnl require some minimum version. Point them to the right macro. |
313 | m4_if([$1], [1.15], [], | |
313 | m4_if([$1], [1.16.1], [], | |
314 | 314 | [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl |
315 | 315 | ]) |
316 | 316 | |
326 | 326 | # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. |
327 | 327 | # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. |
328 | 328 | AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], |
329 | [AM_AUTOMAKE_VERSION([1.15])dnl | |
329 | [AM_AUTOMAKE_VERSION([1.16.1])dnl | |
330 | 330 | m4_ifndef([AC_AUTOCONF_VERSION], |
331 | 331 | [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl |
332 | 332 | _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) |
333 | 333 | |
334 | 334 | # Figure out how to run the assembler. -*- Autoconf -*- |
335 | 335 | |
336 | # Copyright (C) 2001-2014 Free Software Foundation, Inc. | |
336 | # Copyright (C) 2001-2018 Free Software Foundation, Inc. | |
337 | 337 | # |
338 | 338 | # This file is free software; the Free Software Foundation |
339 | 339 | # gives unlimited permission to copy and/or distribute it, |
353 | 353 | |
354 | 354 | # AM_AUX_DIR_EXPAND -*- Autoconf -*- |
355 | 355 | |
356 | # Copyright (C) 2001-2014 Free Software Foundation, Inc. | |
356 | # Copyright (C) 2001-2018 Free Software Foundation, Inc. | |
357 | 357 | # |
358 | 358 | # This file is free software; the Free Software Foundation |
359 | 359 | # gives unlimited permission to copy and/or distribute it, |
405 | 405 | |
406 | 406 | # AM_COND_IF -*- Autoconf -*- |
407 | 407 | |
408 | # Copyright (C) 2008-2014 Free Software Foundation, Inc. | |
408 | # Copyright (C) 2008-2018 Free Software Foundation, Inc. | |
409 | 409 | # |
410 | 410 | # This file is free software; the Free Software Foundation |
411 | 411 | # gives unlimited permission to copy and/or distribute it, |
442 | 442 | |
443 | 443 | # AM_CONDITIONAL -*- Autoconf -*- |
444 | 444 | |
445 | # Copyright (C) 1997-2014 Free Software Foundation, Inc. | |
445 | # Copyright (C) 1997-2018 Free Software Foundation, Inc. | |
446 | 446 | # |
447 | 447 | # This file is free software; the Free Software Foundation |
448 | 448 | # gives unlimited permission to copy and/or distribute it, |
473 | 473 | Usually this means the macro was only invoked conditionally.]]) |
474 | 474 | fi])]) |
475 | 475 | |
476 | # Copyright (C) 1999-2014 Free Software Foundation, Inc. | |
476 | # Copyright (C) 1999-2018 Free Software Foundation, Inc. | |
477 | 477 | # |
478 | 478 | # This file is free software; the Free Software Foundation |
479 | 479 | # gives unlimited permission to copy and/or distribute it, |
664 | 664 | |
665 | 665 | # Generate code to set up dependency tracking. -*- Autoconf -*- |
666 | 666 | |
667 | # Copyright (C) 1999-2014 Free Software Foundation, Inc. | |
668 | # | |
669 | # This file is free software; the Free Software Foundation | |
670 | # gives unlimited permission to copy and/or distribute it, | |
671 | # with or without modifications, as long as this notice is preserved. | |
672 | ||
667 | # Copyright (C) 1999-2018 Free Software Foundation, Inc. | |
668 | # | |
669 | # This file is free software; the Free Software Foundation | |
670 | # gives unlimited permission to copy and/or distribute it, | |
671 | # with or without modifications, as long as this notice is preserved. | |
673 | 672 | |
674 | 673 | # _AM_OUTPUT_DEPENDENCY_COMMANDS |
675 | 674 | # ------------------------------ |
678 | 677 | # Older Autoconf quotes --file arguments for eval, but not when files |
679 | 678 | # are listed without --file. Let's play safe and only enable the eval |
680 | 679 | # if we detect the quoting. |
681 | case $CONFIG_FILES in | |
682 | *\'*) eval set x "$CONFIG_FILES" ;; | |
683 | *) set x $CONFIG_FILES ;; | |
684 | esac | |
680 | # TODO: see whether this extra hack can be removed once we start | |
681 | # requiring Autoconf 2.70 or later. | |
682 | AS_CASE([$CONFIG_FILES], | |
683 | [*\'*], [eval set x "$CONFIG_FILES"], | |
684 | [*], [set x $CONFIG_FILES]) | |
685 | 685 | shift |
686 | for mf | |
686 | # Used to flag and report bootstrapping failures. | |
687 | am_rc=0 | |
688 | for am_mf | |
687 | 689 | do |
688 | 690 | # Strip MF so we end up with the name of the file. |
689 | mf=`echo "$mf" | sed -e 's/:.*$//'` | |
690 | # Check whether this is an Automake generated Makefile or not. | |
691 | # We used to match only the files named 'Makefile.in', but | |
692 | # some people rename them; so instead we look at the file content. | |
693 | # Grep'ing the first line is not enough: some people post-process | |
694 | # each Makefile.in and add a new line on top of each file to say so. | |
695 | # Grep'ing the whole file is not good either: AIX grep has a line | |
691 | am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` | |
692 | # Check whether this is an Automake generated Makefile which includes | |
693 | # dependency-tracking related rules and includes. | |
694 | # Grep'ing the whole file directly is not great: AIX grep has a line | |
696 | 695 | # limit of 2048, but all sed's we know have understand at least 4000. |
697 | if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then | |
698 | dirpart=`AS_DIRNAME("$mf")` | |
699 | else | |
700 | continue | |
701 | fi | |
702 | # Extract the definition of DEPDIR, am__include, and am__quote | |
703 | # from the Makefile without running 'make'. | |
704 | DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` | |
705 | test -z "$DEPDIR" && continue | |
706 | am__include=`sed -n 's/^am__include = //p' < "$mf"` | |
707 | test -z "$am__include" && continue | |
708 | am__quote=`sed -n 's/^am__quote = //p' < "$mf"` | |
709 | # Find all dependency output files, they are included files with | |
710 | # $(DEPDIR) in their names. We invoke sed twice because it is the | |
711 | # simplest approach to changing $(DEPDIR) to its actual value in the | |
712 | # expansion. | |
713 | for file in `sed -n " | |
714 | s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ | |
715 | sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do | |
716 | # Make sure the directory exists. | |
717 | test -f "$dirpart/$file" && continue | |
718 | fdir=`AS_DIRNAME(["$file"])` | |
719 | AS_MKDIR_P([$dirpart/$fdir]) | |
720 | # echo "creating $dirpart/$file" | |
721 | echo '# dummy' > "$dirpart/$file" | |
722 | done | |
696 | sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ | |
697 | || continue | |
698 | am_dirpart=`AS_DIRNAME(["$am_mf"])` | |
699 | am_filepart=`AS_BASENAME(["$am_mf"])` | |
700 | AM_RUN_LOG([cd "$am_dirpart" \ | |
701 | && sed -e '/# am--include-marker/d' "$am_filepart" \ | |
702 | | $MAKE -f - am--depfiles]) || am_rc=$? | |
723 | 703 | done |
704 | if test $am_rc -ne 0; then | |
705 | AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments | |
706 | for automatic dependency tracking. Try re-running configure with the | |
707 | '--disable-dependency-tracking' option to at least be able to build | |
708 | the package (albeit without support for automatic dependency tracking).]) | |
709 | fi | |
710 | AS_UNSET([am_dirpart]) | |
711 | AS_UNSET([am_filepart]) | |
712 | AS_UNSET([am_mf]) | |
713 | AS_UNSET([am_rc]) | |
714 | rm -f conftest-deps.mk | |
724 | 715 | } |
725 | 716 | ])# _AM_OUTPUT_DEPENDENCY_COMMANDS |
726 | 717 | |
729 | 720 | # ----------------------------- |
730 | 721 | # This macro should only be invoked once -- use via AC_REQUIRE. |
731 | 722 | # |
732 | # This code is only required when automatic dependency tracking | |
733 | # is enabled. FIXME. This creates each '.P' file that we will | |
734 | # need in order to bootstrap the dependency handling code. | |
723 | # This code is only required when automatic dependency tracking is enabled. | |
724 | # This creates each '.Po' and '.Plo' makefile fragment that we'll need in | |
725 | # order to bootstrap the dependency handling code. | |
735 | 726 | AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], |
736 | 727 | [AC_CONFIG_COMMANDS([depfiles], |
737 | 728 | [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], |
738 | [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) | |
739 | ]) | |
729 | [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) | |
740 | 730 | |
741 | 731 | # Do all the work for Automake. -*- Autoconf -*- |
742 | 732 | |
743 | # Copyright (C) 1996-2014 Free Software Foundation, Inc. | |
733 | # Copyright (C) 1996-2018 Free Software Foundation, Inc. | |
744 | 734 | # |
745 | 735 | # This file is free software; the Free Software Foundation |
746 | 736 | # gives unlimited permission to copy and/or distribute it, |
827 | 817 | AC_REQUIRE([AC_PROG_MKDIR_P])dnl |
828 | 818 | # For better backward compatibility. To be removed once Automake 1.9.x |
829 | 819 | # dies out for good. For more background, see: |
830 | # <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html> | |
831 | # <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html> | |
820 | # <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html> | |
821 | # <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html> | |
832 | 822 | AC_SUBST([mkdir_p], ['$(MKDIR_P)']) |
833 | 823 | # We need awk for the "check" target (and possibly the TAP driver). The |
834 | 824 | # system "awk" is bad on some platforms. |
895 | 885 | Aborting the configuration process, to ensure you take notice of the issue. |
896 | 886 | |
897 | 887 | You can download and install GNU coreutils to get an 'rm' implementation |
898 | that behaves properly: <http://www.gnu.org/software/coreutils/>. | |
888 | that behaves properly: <https://www.gnu.org/software/coreutils/>. | |
899 | 889 | |
900 | 890 | If you want to complete the configuration process using your problematic |
901 | 891 | 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM |
937 | 927 | done |
938 | 928 | echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) |
939 | 929 | |
940 | # Copyright (C) 2001-2014 Free Software Foundation, Inc. | |
930 | # Copyright (C) 2001-2018 Free Software Foundation, Inc. | |
941 | 931 | # |
942 | 932 | # This file is free software; the Free Software Foundation |
943 | 933 | # gives unlimited permission to copy and/or distribute it, |
958 | 948 | fi |
959 | 949 | AC_SUBST([install_sh])]) |
960 | 950 | |
961 | # Copyright (C) 2003-2014 Free Software Foundation, Inc. | |
951 | # Copyright (C) 2003-2018 Free Software Foundation, Inc. | |
962 | 952 | # |
963 | 953 | # This file is free software; the Free Software Foundation |
964 | 954 | # gives unlimited permission to copy and/or distribute it, |
979 | 969 | |
980 | 970 | # Check to see how 'make' treats includes. -*- Autoconf -*- |
981 | 971 | |
982 | # Copyright (C) 2001-2014 Free Software Foundation, Inc. | |
972 | # Copyright (C) 2001-2018 Free Software Foundation, Inc. | |
983 | 973 | # |
984 | 974 | # This file is free software; the Free Software Foundation |
985 | 975 | # gives unlimited permission to copy and/or distribute it, |
987 | 977 | |
988 | 978 | # AM_MAKE_INCLUDE() |
989 | 979 | # ----------------- |
990 | # Check to see how make treats includes. | |
980 | # Check whether make has an 'include' directive that can support all | |
981 | # the idioms we need for our automatic dependency tracking code. | |
991 | 982 | AC_DEFUN([AM_MAKE_INCLUDE], |
992 | [am_make=${MAKE-make} | |
993 | cat > confinc << 'END' | |
983 | [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) | |
984 | cat > confinc.mk << 'END' | |
994 | 985 | am__doit: |
995 | @echo this is the am__doit target | |
986 | @echo this is the am__doit target >confinc.out | |
996 | 987 | .PHONY: am__doit |
997 | 988 | END |
998 | # If we don't find an include directive, just comment out the code. | |
999 | AC_MSG_CHECKING([for style of include used by $am_make]) | |
1000 | 989 | am__include="#" |
1001 | 990 | am__quote= |
1002 | _am_result=none | |
1003 | # First try GNU make style include. | |
1004 | echo "include confinc" > confmf | |
1005 | # Ignore all kinds of additional output from 'make'. | |
1006 | case `$am_make -s -f confmf 2> /dev/null` in #( | |
1007 | *the\ am__doit\ target*) | |
1008 | am__include=include | |
1009 | am__quote= | |
1010 | _am_result=GNU | |
1011 | ;; | |
1012 | esac | |
1013 | # Now try BSD make style include. | |
1014 | if test "$am__include" = "#"; then | |
1015 | echo '.include "confinc"' > confmf | |
1016 | case `$am_make -s -f confmf 2> /dev/null` in #( | |
1017 | *the\ am__doit\ target*) | |
1018 | am__include=.include | |
1019 | am__quote="\"" | |
1020 | _am_result=BSD | |
1021 | ;; | |
1022 | esac | |
1023 | fi | |
1024 | AC_SUBST([am__include]) | |
1025 | AC_SUBST([am__quote]) | |
1026 | AC_MSG_RESULT([$_am_result]) | |
1027 | rm -f confinc confmf | |
1028 | ]) | |
991 | # BSD make does it like this. | |
992 | echo '.include "confinc.mk" # ignored' > confmf.BSD | |
993 | # Other make implementations (GNU, Solaris 10, AIX) do it like this. | |
994 | echo 'include confinc.mk # ignored' > confmf.GNU | |
995 | _am_result=no | |
996 | for s in GNU BSD; do | |
997 | AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) | |
998 | AS_CASE([$?:`cat confinc.out 2>/dev/null`], | |
999 | ['0:this is the am__doit target'], | |
1000 | [AS_CASE([$s], | |
1001 | [BSD], [am__include='.include' am__quote='"'], | |
1002 | [am__include='include' am__quote=''])]) | |
1003 | if test "$am__include" != "#"; then | |
1004 | _am_result="yes ($s style)" | |
1005 | break | |
1006 | fi | |
1007 | done | |
1008 | rm -f confinc.* confmf.* | |
1009 | AC_MSG_RESULT([${_am_result}]) | |
1010 | AC_SUBST([am__include])]) | |
1011 | AC_SUBST([am__quote])]) | |
1029 | 1012 | |
1030 | 1013 | # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- |
1031 | 1014 | |
1032 | # Copyright (C) 1997-2014 Free Software Foundation, Inc. | |
1015 | # Copyright (C) 1997-2018 Free Software Foundation, Inc. | |
1033 | 1016 | # |
1034 | 1017 | # This file is free software; the Free Software Foundation |
1035 | 1018 | # gives unlimited permission to copy and/or distribute it, |
1068 | 1051 | |
1069 | 1052 | # Helper functions for option handling. -*- Autoconf -*- |
1070 | 1053 | |
1071 | # Copyright (C) 2001-2014 Free Software Foundation, Inc. | |
1054 | # Copyright (C) 2001-2018 Free Software Foundation, Inc. | |
1072 | 1055 | # |
1073 | 1056 | # This file is free software; the Free Software Foundation |
1074 | 1057 | # gives unlimited permission to copy and/or distribute it, |
1097 | 1080 | AC_DEFUN([_AM_IF_OPTION], |
1098 | 1081 | [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) |
1099 | 1082 | |
1100 | # Copyright (C) 1999-2014 Free Software Foundation, Inc. | |
1083 | # Copyright (C) 1999-2018 Free Software Foundation, Inc. | |
1101 | 1084 | # |
1102 | 1085 | # This file is free software; the Free Software Foundation |
1103 | 1086 | # gives unlimited permission to copy and/or distribute it, |
1144 | 1127 | # For backward compatibility. |
1145 | 1128 | AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) |
1146 | 1129 | |
1147 | # Copyright (C) 2001-2014 Free Software Foundation, Inc. | |
1130 | # Copyright (C) 2001-2018 Free Software Foundation, Inc. | |
1148 | 1131 | # |
1149 | 1132 | # This file is free software; the Free Software Foundation |
1150 | 1133 | # gives unlimited permission to copy and/or distribute it, |
1163 | 1146 | |
1164 | 1147 | # Check to make sure that the build environment is sane. -*- Autoconf -*- |
1165 | 1148 | |
1166 | # Copyright (C) 1996-2014 Free Software Foundation, Inc. | |
1149 | # Copyright (C) 1996-2018 Free Software Foundation, Inc. | |
1167 | 1150 | # |
1168 | 1151 | # This file is free software; the Free Software Foundation |
1169 | 1152 | # gives unlimited permission to copy and/or distribute it, |
1244 | 1227 | rm -f conftest.file |
1245 | 1228 | ]) |
1246 | 1229 | |
1247 | # Copyright (C) 2009-2014 Free Software Foundation, Inc. | |
1230 | # Copyright (C) 2009-2018 Free Software Foundation, Inc. | |
1248 | 1231 | # |
1249 | 1232 | # This file is free software; the Free Software Foundation |
1250 | 1233 | # gives unlimited permission to copy and/or distribute it, |
1304 | 1287 | _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl |
1305 | 1288 | ]) |
1306 | 1289 | |
1307 | # Copyright (C) 2001-2014 Free Software Foundation, Inc. | |
1290 | # Copyright (C) 2001-2018 Free Software Foundation, Inc. | |
1308 | 1291 | # |
1309 | 1292 | # This file is free software; the Free Software Foundation |
1310 | 1293 | # gives unlimited permission to copy and/or distribute it, |
1332 | 1315 | INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" |
1333 | 1316 | AC_SUBST([INSTALL_STRIP_PROGRAM])]) |
1334 | 1317 | |
1335 | # Copyright (C) 2006-2014 Free Software Foundation, Inc. | |
1318 | # Copyright (C) 2006-2018 Free Software Foundation, Inc. | |
1336 | 1319 | # |
1337 | 1320 | # This file is free software; the Free Software Foundation |
1338 | 1321 | # gives unlimited permission to copy and/or distribute it, |
1351 | 1334 | |
1352 | 1335 | # Check how to create a tarball. -*- Autoconf -*- |
1353 | 1336 | |
1354 | # Copyright (C) 2004-2014 Free Software Foundation, Inc. | |
1337 | # Copyright (C) 2004-2018 Free Software Foundation, Inc. | |
1355 | 1338 | # |
1356 | 1339 | # This file is free software; the Free Software Foundation |
1357 | 1340 | # gives unlimited permission to copy and/or distribute it, |
0 | AM_CFLAGS = -Wall | |
1 | ||
2 | noinst_PROGRAMS = compare | |
3 | compare_SOURCES = image.h image.c compare.c | |
4 | compare_CPPFLAGS = -I$(top_srcdir)/libass | |
5 | compare_LDADD = $(top_builddir)/libass/.libs/libass.a | |
6 | compare_LDFLAGS = $(AM_LDFLAGS) $(LIBPNG_LIBS) -static |
0 | # Makefile.in generated by automake 1.16.1 from Makefile.am. | |
1 | # @configure_input@ | |
2 | ||
3 | # Copyright (C) 1994-2018 Free Software Foundation, Inc. | |
4 | ||
5 | # This Makefile.in is free software; the Free Software Foundation | |
6 | # gives unlimited permission to copy and/or distribute it, | |
7 | # with or without modifications, as long as this notice is preserved. | |
8 | ||
9 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY, to the extent permitted by law; without | |
11 | # even the implied warranty of MERCHANTABILITY or FITNESS FOR A | |
12 | # PARTICULAR PURPOSE. | |
13 | ||
14 | @SET_MAKE@ | |
15 | ||
16 | VPATH = @srcdir@ | |
17 | am__is_gnu_make = { \ | |
18 | if test -z '$(MAKELEVEL)'; then \ | |
19 | false; \ | |
20 | elif test -n '$(MAKE_HOST)'; then \ | |
21 | true; \ | |
22 | elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ | |
23 | true; \ | |
24 | else \ | |
25 | false; \ | |
26 | fi; \ | |
27 | } | |
28 | am__make_running_with_option = \ | |
29 | case $${target_option-} in \ | |
30 | ?) ;; \ | |
31 | *) echo "am__make_running_with_option: internal error: invalid" \ | |
32 | "target option '$${target_option-}' specified" >&2; \ | |
33 | exit 1;; \ | |
34 | esac; \ | |
35 | has_opt=no; \ | |
36 | sane_makeflags=$$MAKEFLAGS; \ | |
37 | if $(am__is_gnu_make); then \ | |
38 | sane_makeflags=$$MFLAGS; \ | |
39 | else \ | |
40 | case $$MAKEFLAGS in \ | |
41 | *\\[\ \ ]*) \ | |
42 | bs=\\; \ | |
43 | sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | |
44 | | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ | |
45 | esac; \ | |
46 | fi; \ | |
47 | skip_next=no; \ | |
48 | strip_trailopt () \ | |
49 | { \ | |
50 | flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ | |
51 | }; \ | |
52 | for flg in $$sane_makeflags; do \ | |
53 | test $$skip_next = yes && { skip_next=no; continue; }; \ | |
54 | case $$flg in \ | |
55 | *=*|--*) continue;; \ | |
56 | -*I) strip_trailopt 'I'; skip_next=yes;; \ | |
57 | -*I?*) strip_trailopt 'I';; \ | |
58 | -*O) strip_trailopt 'O'; skip_next=yes;; \ | |
59 | -*O?*) strip_trailopt 'O';; \ | |
60 | -*l) strip_trailopt 'l'; skip_next=yes;; \ | |
61 | -*l?*) strip_trailopt 'l';; \ | |
62 | -[dEDm]) skip_next=yes;; \ | |
63 | -[JT]) skip_next=yes;; \ | |
64 | esac; \ | |
65 | case $$flg in \ | |
66 | *$$target_option*) has_opt=yes; break;; \ | |
67 | esac; \ | |
68 | done; \ | |
69 | test $$has_opt = yes | |
70 | am__make_dryrun = (target_option=n; $(am__make_running_with_option)) | |
71 | am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) | |
72 | pkgdatadir = $(datadir)/@PACKAGE@ | |
73 | pkgincludedir = $(includedir)/@PACKAGE@ | |
74 | pkglibdir = $(libdir)/@PACKAGE@ | |
75 | pkglibexecdir = $(libexecdir)/@PACKAGE@ | |
76 | am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd | |
77 | install_sh_DATA = $(install_sh) -c -m 644 | |
78 | install_sh_PROGRAM = $(install_sh) -c | |
79 | install_sh_SCRIPT = $(install_sh) -c | |
80 | INSTALL_HEADER = $(INSTALL_DATA) | |
81 | transform = $(program_transform_name) | |
82 | NORMAL_INSTALL = : | |
83 | PRE_INSTALL = : | |
84 | POST_INSTALL = : | |
85 | NORMAL_UNINSTALL = : | |
86 | PRE_UNINSTALL = : | |
87 | POST_UNINSTALL = : | |
88 | build_triplet = @build@ | |
89 | host_triplet = @host@ | |
90 | noinst_PROGRAMS = compare$(EXEEXT) | |
91 | subdir = compare | |
92 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 | |
93 | am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ | |
94 | $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ | |
95 | $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ | |
96 | $(top_srcdir)/configure.ac | |
97 | am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ | |
98 | $(ACLOCAL_M4) | |
99 | DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) | |
100 | mkinstalldirs = $(install_sh) -d | |
101 | CONFIG_HEADER = $(top_builddir)/config.h | |
102 | CONFIG_CLEAN_FILES = | |
103 | CONFIG_CLEAN_VPATH_FILES = | |
104 | PROGRAMS = $(noinst_PROGRAMS) | |
105 | am_compare_OBJECTS = compare-image.$(OBJEXT) compare-compare.$(OBJEXT) | |
106 | compare_OBJECTS = $(am_compare_OBJECTS) | |
107 | compare_DEPENDENCIES = $(top_builddir)/libass/.libs/libass.a | |
108 | AM_V_lt = $(am__v_lt_@AM_V@) | |
109 | am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) | |
110 | am__v_lt_0 = --silent | |
111 | am__v_lt_1 = | |
112 | compare_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ | |
113 | $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ | |
114 | $(compare_LDFLAGS) $(LDFLAGS) -o $@ | |
115 | AM_V_P = $(am__v_P_@AM_V@) | |
116 | am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) | |
117 | am__v_P_0 = false | |
118 | am__v_P_1 = : | |
119 | AM_V_GEN = $(am__v_GEN_@AM_V@) | |
120 | am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) | |
121 | am__v_GEN_0 = @echo " GEN " $@; | |
122 | am__v_GEN_1 = | |
123 | AM_V_at = $(am__v_at_@AM_V@) | |
124 | am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) | |
125 | am__v_at_0 = @ | |
126 | am__v_at_1 = | |
127 | DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) | |
128 | depcomp = $(SHELL) $(top_srcdir)/depcomp | |
129 | am__maybe_remake_depfiles = depfiles | |
130 | am__depfiles_remade = ./$(DEPDIR)/compare-compare.Po \ | |
131 | ./$(DEPDIR)/compare-image.Po | |
132 | am__mv = mv -f | |
133 | COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ | |
134 | $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) | |
135 | LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ | |
136 | $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ | |
137 | $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ | |
138 | $(AM_CFLAGS) $(CFLAGS) | |
139 | AM_V_CC = $(am__v_CC_@AM_V@) | |
140 | am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) | |
141 | am__v_CC_0 = @echo " CC " $@; | |
142 | am__v_CC_1 = | |
143 | CCLD = $(CC) | |
144 | LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ | |
145 | $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ | |
146 | $(AM_LDFLAGS) $(LDFLAGS) -o $@ | |
147 | AM_V_CCLD = $(am__v_CCLD_@AM_V@) | |
148 | am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) | |
149 | am__v_CCLD_0 = @echo " CCLD " $@; | |
150 | am__v_CCLD_1 = | |
151 | SOURCES = $(compare_SOURCES) | |
152 | DIST_SOURCES = $(compare_SOURCES) | |
153 | am__can_run_installinfo = \ | |
154 | case $$AM_UPDATE_INFO_DIR in \ | |
155 | n|no|NO) false;; \ | |
156 | *) (install-info --version) >/dev/null 2>&1;; \ | |
157 | esac | |
158 | am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) | |
159 | # Read a list of newline-separated strings from the standard input, | |
160 | # and print each of them once, without duplicates. Input order is | |
161 | # *not* preserved. | |
162 | am__uniquify_input = $(AWK) '\ | |
163 | BEGIN { nonempty = 0; } \ | |
164 | { items[$$0] = 1; nonempty = 1; } \ | |
165 | END { if (nonempty) { for (i in items) print i; }; } \ | |
166 | ' | |
167 | # Make sure the list of sources is unique. This is necessary because, | |
168 | # e.g., the same source file might be shared among _SOURCES variables | |
169 | # for different programs/libraries. | |
170 | am__define_uniq_tagged_files = \ | |
171 | list='$(am__tagged_files)'; \ | |
172 | unique=`for i in $$list; do \ | |
173 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ | |
174 | done | $(am__uniquify_input)` | |
175 | ETAGS = etags | |
176 | CTAGS = ctags | |
177 | am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp | |
178 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) | |
179 | ACLOCAL = @ACLOCAL@ | |
180 | AMTAR = @AMTAR@ | |
181 | AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ | |
182 | AR = @AR@ | |
183 | AS = @AS@ | |
184 | ASFLAGS = @ASFLAGS@ | |
185 | AUTOCONF = @AUTOCONF@ | |
186 | AUTOHEADER = @AUTOHEADER@ | |
187 | AUTOMAKE = @AUTOMAKE@ | |
188 | AWK = @AWK@ | |
189 | CC = @CC@ | |
190 | CCAS = @CCAS@ | |
191 | CCASDEPMODE = @CCASDEPMODE@ | |
192 | CCASFLAGS = @CCASFLAGS@ | |
193 | CCDEPMODE = @CCDEPMODE@ | |
194 | CFLAGS = @CFLAGS@ | |
195 | CPP = @CPP@ | |
196 | CPPFLAGS = @CPPFLAGS@ | |
197 | CYGPATH_W = @CYGPATH_W@ | |
198 | DEFS = @DEFS@ | |
199 | DEPDIR = @DEPDIR@ | |
200 | DLLTOOL = @DLLTOOL@ | |
201 | DSYMUTIL = @DSYMUTIL@ | |
202 | DUMPBIN = @DUMPBIN@ | |
203 | ECHO_C = @ECHO_C@ | |
204 | ECHO_N = @ECHO_N@ | |
205 | ECHO_T = @ECHO_T@ | |
206 | EGREP = @EGREP@ | |
207 | EXEEXT = @EXEEXT@ | |
208 | FGREP = @FGREP@ | |
209 | FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@ | |
210 | FONTCONFIG_LIBS = @FONTCONFIG_LIBS@ | |
211 | FREETYPE_CFLAGS = @FREETYPE_CFLAGS@ | |
212 | FREETYPE_LIBS = @FREETYPE_LIBS@ | |
213 | FRIBIDI_CFLAGS = @FRIBIDI_CFLAGS@ | |
214 | FRIBIDI_LIBS = @FRIBIDI_LIBS@ | |
215 | GREP = @GREP@ | |
216 | HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@ | |
217 | HARFBUZZ_LIBS = @HARFBUZZ_LIBS@ | |
218 | INSTALL = @INSTALL@ | |
219 | INSTALL_DATA = @INSTALL_DATA@ | |
220 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ | |
221 | INSTALL_SCRIPT = @INSTALL_SCRIPT@ | |
222 | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ | |
223 | LD = @LD@ | |
224 | LDFLAGS = @LDFLAGS@ | |
225 | LIBOBJS = @LIBOBJS@ | |
226 | LIBPNG_CFLAGS = @LIBPNG_CFLAGS@ | |
227 | LIBPNG_LIBS = @LIBPNG_LIBS@ | |
228 | LIBS = @LIBS@ | |
229 | LIBTOOL = @LIBTOOL@ | |
230 | LIPO = @LIPO@ | |
231 | LN_S = @LN_S@ | |
232 | LTLIBOBJS = @LTLIBOBJS@ | |
233 | LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ | |
234 | MAKEINFO = @MAKEINFO@ | |
235 | MANIFEST_TOOL = @MANIFEST_TOOL@ | |
236 | MKDIR_P = @MKDIR_P@ | |
237 | NM = @NM@ | |
238 | NMEDIT = @NMEDIT@ | |
239 | OBJDUMP = @OBJDUMP@ | |
240 | OBJEXT = @OBJEXT@ | |
241 | OTOOL = @OTOOL@ | |
242 | OTOOL64 = @OTOOL64@ | |
243 | PACKAGE = @PACKAGE@ | |
244 | PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ | |
245 | PACKAGE_NAME = @PACKAGE_NAME@ | |
246 | PACKAGE_STRING = @PACKAGE_STRING@ | |
247 | PACKAGE_TARNAME = @PACKAGE_TARNAME@ | |
248 | PACKAGE_URL = @PACKAGE_URL@ | |
249 | PACKAGE_VERSION = @PACKAGE_VERSION@ | |
250 | PATH_SEPARATOR = @PATH_SEPARATOR@ | |
251 | PKG_CONFIG = @PKG_CONFIG@ | |
252 | PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ | |
253 | PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ | |
254 | PKG_LIBS_DEFAULT = @PKG_LIBS_DEFAULT@ | |
255 | PKG_LIBS_PRIVATE = @PKG_LIBS_PRIVATE@ | |
256 | PKG_REQUIRES_DEFAULT = @PKG_REQUIRES_DEFAULT@ | |
257 | PKG_REQUIRES_PRIVATE = @PKG_REQUIRES_PRIVATE@ | |
258 | RANLIB = @RANLIB@ | |
259 | SED = @SED@ | |
260 | SET_MAKE = @SET_MAKE@ | |
261 | SHELL = @SHELL@ | |
262 | STRIP = @STRIP@ | |
263 | VERSION = @VERSION@ | |
264 | abs_builddir = @abs_builddir@ | |
265 | abs_srcdir = @abs_srcdir@ | |
266 | abs_top_builddir = @abs_top_builddir@ | |
267 | abs_top_srcdir = @abs_top_srcdir@ | |
268 | ac_ct_AR = @ac_ct_AR@ | |
269 | ac_ct_CC = @ac_ct_CC@ | |
270 | ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ | |
271 | am__include = @am__include@ | |
272 | am__leading_dot = @am__leading_dot@ | |
273 | am__quote = @am__quote@ | |
274 | am__tar = @am__tar@ | |
275 | am__untar = @am__untar@ | |
276 | bindir = @bindir@ | |
277 | build = @build@ | |
278 | build_alias = @build_alias@ | |
279 | build_cpu = @build_cpu@ | |
280 | build_os = @build_os@ | |
281 | build_vendor = @build_vendor@ | |
282 | builddir = @builddir@ | |
283 | datadir = @datadir@ | |
284 | datarootdir = @datarootdir@ | |
285 | docdir = @docdir@ | |
286 | dvidir = @dvidir@ | |
287 | exec_prefix = @exec_prefix@ | |
288 | host = @host@ | |
289 | host_alias = @host_alias@ | |
290 | host_cpu = @host_cpu@ | |
291 | host_os = @host_os@ | |
292 | host_vendor = @host_vendor@ | |
293 | htmldir = @htmldir@ | |
294 | includedir = @includedir@ | |
295 | infodir = @infodir@ | |
296 | install_sh = @install_sh@ | |
297 | libdir = @libdir@ | |
298 | libexecdir = @libexecdir@ | |
299 | localedir = @localedir@ | |
300 | localstatedir = @localstatedir@ | |
301 | mandir = @mandir@ | |
302 | mkdir_p = @mkdir_p@ | |
303 | nasm_check = @nasm_check@ | |
304 | oldincludedir = @oldincludedir@ | |
305 | pdfdir = @pdfdir@ | |
306 | prefix = @prefix@ | |
307 | program_transform_name = @program_transform_name@ | |
308 | psdir = @psdir@ | |
309 | sbindir = @sbindir@ | |
310 | sharedstatedir = @sharedstatedir@ | |
311 | srcdir = @srcdir@ | |
312 | sysconfdir = @sysconfdir@ | |
313 | target_alias = @target_alias@ | |
314 | top_build_prefix = @top_build_prefix@ | |
315 | top_builddir = @top_builddir@ | |
316 | top_srcdir = @top_srcdir@ | |
317 | AM_CFLAGS = -Wall | |
318 | compare_SOURCES = image.h image.c compare.c | |
319 | compare_CPPFLAGS = -I$(top_srcdir)/libass | |
320 | compare_LDADD = $(top_builddir)/libass/.libs/libass.a | |
321 | compare_LDFLAGS = $(AM_LDFLAGS) $(LIBPNG_LIBS) -static | |
322 | all: all-am | |
323 | ||
324 | .SUFFIXES: | |
325 | .SUFFIXES: .c .lo .o .obj | |
326 | $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) | |
327 | @for dep in $?; do \ | |
328 | case '$(am__configure_deps)' in \ | |
329 | *$$dep*) \ | |
330 | ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ | |
331 | && { if test -f $@; then exit 0; else break; fi; }; \ | |
332 | exit 1;; \ | |
333 | esac; \ | |
334 | done; \ | |
335 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign compare/Makefile'; \ | |
336 | $(am__cd) $(top_srcdir) && \ | |
337 | $(AUTOMAKE) --foreign compare/Makefile | |
338 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status | |
339 | @case '$?' in \ | |
340 | *config.status*) \ | |
341 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ | |
342 | *) \ | |
343 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ | |
344 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ | |
345 | esac; | |
346 | ||
347 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) | |
348 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | |
349 | ||
350 | $(top_srcdir)/configure: $(am__configure_deps) | |
351 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | |
352 | $(ACLOCAL_M4): $(am__aclocal_m4_deps) | |
353 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | |
354 | $(am__aclocal_m4_deps): | |
355 | ||
356 | clean-noinstPROGRAMS: | |
357 | @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ | |
358 | echo " rm -f" $$list; \ | |
359 | rm -f $$list || exit $$?; \ | |
360 | test -n "$(EXEEXT)" || exit 0; \ | |
361 | list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ | |
362 | echo " rm -f" $$list; \ | |
363 | rm -f $$list | |
364 | ||
365 | compare$(EXEEXT): $(compare_OBJECTS) $(compare_DEPENDENCIES) $(EXTRA_compare_DEPENDENCIES) | |
366 | @rm -f compare$(EXEEXT) | |
367 | $(AM_V_CCLD)$(compare_LINK) $(compare_OBJECTS) $(compare_LDADD) $(LIBS) | |
368 | ||
369 | mostlyclean-compile: | |
370 | -rm -f *.$(OBJEXT) | |
371 | ||
372 | distclean-compile: | |
373 | -rm -f *.tab.c | |
374 | ||
375 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compare-compare.Po@am__quote@ # am--include-marker | |
376 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compare-image.Po@am__quote@ # am--include-marker | |
377 | ||
378 | $(am__depfiles_remade): | |
379 | @$(MKDIR_P) $(@D) | |
380 | @echo '# dummy' >$@-t && $(am__mv) $@-t $@ | |
381 | ||
382 | am--depfiles: $(am__depfiles_remade) | |
383 | ||
384 | .c.o: | |
385 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< | |
386 | @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po | |
387 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ | |
388 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | |
389 | @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< | |
390 | ||
391 | .c.obj: | |
392 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` | |
393 | @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po | |
394 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ | |
395 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | |
396 | @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` | |
397 | ||
398 | .c.lo: | |
399 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< | |
400 | @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo | |
401 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ | |
402 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | |
403 | @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< | |
404 | ||
405 | compare-image.o: image.c | |
406 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(compare_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT compare-image.o -MD -MP -MF $(DEPDIR)/compare-image.Tpo -c -o compare-image.o `test -f 'image.c' || echo '$(srcdir)/'`image.c | |
407 | @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/compare-image.Tpo $(DEPDIR)/compare-image.Po | |
408 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='image.c' object='compare-image.o' libtool=no @AMDEPBACKSLASH@ | |
409 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | |
410 | @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(compare_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o compare-image.o `test -f 'image.c' || echo '$(srcdir)/'`image.c | |
411 | ||
412 | compare-image.obj: image.c | |
413 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(compare_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT compare-image.obj -MD -MP -MF $(DEPDIR)/compare-image.Tpo -c -o compare-image.obj `if test -f 'image.c'; then $(CYGPATH_W) 'image.c'; else $(CYGPATH_W) '$(srcdir)/image.c'; fi` | |
414 | @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/compare-image.Tpo $(DEPDIR)/compare-image.Po | |
415 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='image.c' object='compare-image.obj' libtool=no @AMDEPBACKSLASH@ | |
416 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | |
417 | @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(compare_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o compare-image.obj `if test -f 'image.c'; then $(CYGPATH_W) 'image.c'; else $(CYGPATH_W) '$(srcdir)/image.c'; fi` | |
418 | ||
419 | compare-compare.o: compare.c | |
420 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(compare_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT compare-compare.o -MD -MP -MF $(DEPDIR)/compare-compare.Tpo -c -o compare-compare.o `test -f 'compare.c' || echo '$(srcdir)/'`compare.c | |
421 | @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/compare-compare.Tpo $(DEPDIR)/compare-compare.Po | |
422 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='compare.c' object='compare-compare.o' libtool=no @AMDEPBACKSLASH@ | |
423 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | |
424 | @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(compare_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o compare-compare.o `test -f 'compare.c' || echo '$(srcdir)/'`compare.c | |
425 | ||
426 | compare-compare.obj: compare.c | |
427 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(compare_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT compare-compare.obj -MD -MP -MF $(DEPDIR)/compare-compare.Tpo -c -o compare-compare.obj `if test -f 'compare.c'; then $(CYGPATH_W) 'compare.c'; else $(CYGPATH_W) '$(srcdir)/compare.c'; fi` | |
428 | @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/compare-compare.Tpo $(DEPDIR)/compare-compare.Po | |
429 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='compare.c' object='compare-compare.obj' libtool=no @AMDEPBACKSLASH@ | |
430 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | |
431 | @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(compare_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o compare-compare.obj `if test -f 'compare.c'; then $(CYGPATH_W) 'compare.c'; else $(CYGPATH_W) '$(srcdir)/compare.c'; fi` | |
432 | ||
433 | mostlyclean-libtool: | |
434 | -rm -f *.lo | |
435 | ||
436 | clean-libtool: | |
437 | -rm -rf .libs _libs | |
438 | ||
439 | ID: $(am__tagged_files) | |
440 | $(am__define_uniq_tagged_files); mkid -fID $$unique | |
441 | tags: tags-am | |
442 | TAGS: tags | |
443 | ||
444 | tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) | |
445 | set x; \ | |
446 | here=`pwd`; \ | |
447 | $(am__define_uniq_tagged_files); \ | |
448 | shift; \ | |
449 | if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ | |
450 | test -n "$$unique" || unique=$$empty_fix; \ | |
451 | if test $$# -gt 0; then \ | |
452 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ | |
453 | "$$@" $$unique; \ | |
454 | else \ | |
455 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ | |
456 | $$unique; \ | |
457 | fi; \ | |
458 | fi | |
459 | ctags: ctags-am | |
460 | ||
461 | CTAGS: ctags | |
462 | ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) | |
463 | $(am__define_uniq_tagged_files); \ | |
464 | test -z "$(CTAGS_ARGS)$$unique" \ | |
465 | || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ | |
466 | $$unique | |
467 | ||
468 | GTAGS: | |
469 | here=`$(am__cd) $(top_builddir) && pwd` \ | |
470 | && $(am__cd) $(top_srcdir) \ | |
471 | && gtags -i $(GTAGS_ARGS) "$$here" | |
472 | cscopelist: cscopelist-am | |
473 | ||
474 | cscopelist-am: $(am__tagged_files) | |
475 | list='$(am__tagged_files)'; \ | |
476 | case "$(srcdir)" in \ | |
477 | [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ | |
478 | *) sdir=$(subdir)/$(srcdir) ;; \ | |
479 | esac; \ | |
480 | for i in $$list; do \ | |
481 | if test -f "$$i"; then \ | |
482 | echo "$(subdir)/$$i"; \ | |
483 | else \ | |
484 | echo "$$sdir/$$i"; \ | |
485 | fi; \ | |
486 | done >> $(top_builddir)/cscope.files | |
487 | ||
488 | distclean-tags: | |
489 | -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags | |
490 | ||
491 | distdir: $(BUILT_SOURCES) | |
492 | $(MAKE) $(AM_MAKEFLAGS) distdir-am | |
493 | ||
494 | distdir-am: $(DISTFILES) | |
495 | @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ | |
496 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ | |
497 | list='$(DISTFILES)'; \ | |
498 | dist_files=`for file in $$list; do echo $$file; done | \ | |
499 | sed -e "s|^$$srcdirstrip/||;t" \ | |
500 | -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ | |
501 | case $$dist_files in \ | |
502 | */*) $(MKDIR_P) `echo "$$dist_files" | \ | |
503 | sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ | |
504 | sort -u` ;; \ | |
505 | esac; \ | |
506 | for file in $$dist_files; do \ | |
507 | if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ | |
508 | if test -d $$d/$$file; then \ | |
509 | dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ | |
510 | if test -d "$(distdir)/$$file"; then \ | |
511 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ | |
512 | fi; \ | |
513 | if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ | |
514 | cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ | |
515 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ | |
516 | fi; \ | |
517 | cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ | |
518 | else \ | |
519 | test -f "$(distdir)/$$file" \ | |
520 | || cp -p $$d/$$file "$(distdir)/$$file" \ | |
521 | || exit 1; \ | |
522 | fi; \ | |
523 | done | |
524 | check-am: all-am | |
525 | check: check-am | |
526 | all-am: Makefile $(PROGRAMS) | |
527 | installdirs: | |
528 | install: install-am | |
529 | install-exec: install-exec-am | |
530 | install-data: install-data-am | |
531 | uninstall: uninstall-am | |
532 | ||
533 | install-am: all-am | |
534 | @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am | |
535 | ||
536 | installcheck: installcheck-am | |
537 | install-strip: | |
538 | if test -z '$(STRIP)'; then \ | |
539 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ | |
540 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ | |
541 | install; \ | |
542 | else \ | |
543 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ | |
544 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ | |
545 | "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ | |
546 | fi | |
547 | mostlyclean-generic: | |
548 | ||
549 | clean-generic: | |
550 | ||
551 | distclean-generic: | |
552 | -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) | |
553 | -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) | |
554 | ||
555 | maintainer-clean-generic: | |
556 | @echo "This command is intended for maintainers to use" | |
557 | @echo "it deletes files that may require special tools to rebuild." | |
558 | clean: clean-am | |
559 | ||
560 | clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ | |
561 | mostlyclean-am | |
562 | ||
563 | distclean: distclean-am | |
564 | -rm -f ./$(DEPDIR)/compare-compare.Po | |
565 | -rm -f ./$(DEPDIR)/compare-image.Po | |
566 | -rm -f Makefile | |
567 | distclean-am: clean-am distclean-compile distclean-generic \ | |
568 | distclean-tags | |
569 | ||
570 | dvi: dvi-am | |
571 | ||
572 | dvi-am: | |
573 | ||
574 | html: html-am | |
575 | ||
576 | html-am: | |
577 | ||
578 | info: info-am | |
579 | ||
580 | info-am: | |
581 | ||
582 | install-data-am: | |
583 | ||
584 | install-dvi: install-dvi-am | |
585 | ||
586 | install-dvi-am: | |
587 | ||
588 | install-exec-am: | |
589 | ||
590 | install-html: install-html-am | |
591 | ||
592 | install-html-am: | |
593 | ||
594 | install-info: install-info-am | |
595 | ||
596 | install-info-am: | |
597 | ||
598 | install-man: | |
599 | ||
600 | install-pdf: install-pdf-am | |
601 | ||
602 | install-pdf-am: | |
603 | ||
604 | install-ps: install-ps-am | |
605 | ||
606 | install-ps-am: | |
607 | ||
608 | installcheck-am: | |
609 | ||
610 | maintainer-clean: maintainer-clean-am | |
611 | -rm -f ./$(DEPDIR)/compare-compare.Po | |
612 | -rm -f ./$(DEPDIR)/compare-image.Po | |
613 | -rm -f Makefile | |
614 | maintainer-clean-am: distclean-am maintainer-clean-generic | |
615 | ||
616 | mostlyclean: mostlyclean-am | |
617 | ||
618 | mostlyclean-am: mostlyclean-compile mostlyclean-generic \ | |
619 | mostlyclean-libtool | |
620 | ||
621 | pdf: pdf-am | |
622 | ||
623 | pdf-am: | |
624 | ||
625 | ps: ps-am | |
626 | ||
627 | ps-am: | |
628 | ||
629 | uninstall-am: | |
630 | ||
631 | .MAKE: install-am install-strip | |
632 | ||
633 | .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ | |
634 | clean-generic clean-libtool clean-noinstPROGRAMS cscopelist-am \ | |
635 | ctags ctags-am distclean distclean-compile distclean-generic \ | |
636 | distclean-libtool distclean-tags distdir dvi dvi-am html \ | |
637 | html-am info info-am install install-am install-data \ | |
638 | install-data-am install-dvi install-dvi-am install-exec \ | |
639 | install-exec-am install-html install-html-am install-info \ | |
640 | install-info-am install-man install-pdf install-pdf-am \ | |
641 | install-ps install-ps-am install-strip installcheck \ | |
642 | installcheck-am installdirs maintainer-clean \ | |
643 | maintainer-clean-generic mostlyclean mostlyclean-compile \ | |
644 | mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ | |
645 | tags tags-am uninstall uninstall-am | |
646 | ||
647 | .PRECIOUS: Makefile | |
648 | ||
649 | ||
650 | # Tell versions [3.59,3.63) of GNU make to not export all variables. | |
651 | # Otherwise a system limit (for SysV at least) may be exceeded. | |
652 | .NOEXPORT: |
0 | /* | |
1 | * Copyright (C) 2017 Vabishchevich Nikolay <vabnick@gmail.com> | |
2 | * | |
3 | * This file is part of libass. | |
4 | * | |
5 | * Permission to use, copy, modify, and distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | ||
18 | #include "image.h" | |
19 | #include "../libass/ass.h" | |
20 | #include <sys/types.h> | |
21 | #include <sys/stat.h> | |
22 | #include <dirent.h> | |
23 | #include <string.h> | |
24 | ||
25 | ||
26 | #define FFMAX(a,b) ((a) > (b) ? (a) : (b)) | |
27 | #define FFMIN(a,b) ((a) > (b) ? (b) : (a)) | |
28 | ||
29 | static void blend_image(Image8 *frame, int32_t x0, int32_t y0, | |
30 | const ASS_Image *img) | |
31 | { | |
32 | int32_t x1 = img->dst_x, x_min = FFMAX(x0, x1); | |
33 | int32_t y1 = img->dst_y, y_min = FFMAX(y0, y1); | |
34 | x0 = x_min - x0; x1 = x_min - x1; | |
35 | y0 = y_min - y0; y1 = y_min - y1; | |
36 | ||
37 | int32_t w = FFMIN(x0 + frame->width, x1 + img->w); | |
38 | int32_t h = FFMIN(y0 + frame->height, y1 + img->h); | |
39 | if (w <= 0 || h <= 0) | |
40 | return; | |
41 | ||
42 | uint8_t r = img->color >> 24; | |
43 | uint8_t g = img->color >> 16; | |
44 | uint8_t b = img->color >> 8; | |
45 | uint8_t a = img->color >> 0; | |
46 | ||
47 | int32_t mul = 129 * (255 - a); | |
48 | const int32_t offs = (int32_t) 1 << 22; | |
49 | ||
50 | int32_t stride = 4 * frame->width; | |
51 | uint8_t *dst = frame->buffer + y0 * stride + 4 * x0; | |
52 | const uint8_t *src = img->bitmap + y1 * img->stride + x1; | |
53 | for (int32_t y = 0; y < h; y++) { | |
54 | for (int32_t x = 0; x < w; x++) { | |
55 | int32_t k = src[x] * mul; | |
56 | dst[4 * x + 0] -= ((dst[4 * x + 0] - r) * k + offs) >> 23; | |
57 | dst[4 * x + 1] -= ((dst[4 * x + 1] - g) * k + offs) >> 23; | |
58 | dst[4 * x + 2] -= ((dst[4 * x + 2] - b) * k + offs) >> 23; | |
59 | dst[4 * x + 3] -= ((dst[4 * x + 3] - 0) * k + offs) >> 23; | |
60 | } | |
61 | dst += stride; | |
62 | src += img->stride; | |
63 | } | |
64 | } | |
65 | ||
66 | static void blend_all(Image8 *frame, int32_t x0, int32_t y0, | |
67 | const ASS_Image *img) | |
68 | { | |
69 | uint8_t *dst = frame->buffer; | |
70 | size_t size = (size_t) frame->width * frame->height; | |
71 | for (size_t i = 0; i < size; i++) { | |
72 | dst[0] = dst[1] = dst[2] = 0; | |
73 | dst[3] = 255; | |
74 | dst += 4; | |
75 | } | |
76 | for (; img; img = img->next) | |
77 | blend_image(frame, x0, y0, img); | |
78 | } | |
79 | ||
80 | inline static uint16_t abs_diff(uint16_t a, uint16_t b) | |
81 | { | |
82 | return a > b ? a - b : b - a; | |
83 | } | |
84 | ||
85 | inline static uint16_t abs_diff4(const uint16_t a[4], const uint16_t b[4]) | |
86 | { | |
87 | uint16_t res = 0; | |
88 | for (int k = 0; k < 4; k++) { | |
89 | uint16_t diff = abs_diff(a[k], b[k]); | |
90 | res = FFMAX(res, diff); | |
91 | } | |
92 | return res; | |
93 | } | |
94 | ||
95 | // Calculate error visibility scale according to formula: | |
96 | // max_pixel_value / 255 + max(max_side_gradient / 4, max_diagonal_gradient / 8). | |
97 | static void calc_grad(const Image16 *target, uint16_t *grad) | |
98 | { | |
99 | const int base = 257; | |
100 | const int border = base + 65535 / 4; | |
101 | ||
102 | int32_t w = target->width; | |
103 | int32_t h = target->height; | |
104 | int32_t stride = 4 * target->width; | |
105 | ||
106 | for (int32_t x = 0; x < w; x++) | |
107 | *grad++ = border; | |
108 | const uint16_t *tg = target->buffer + stride + 4; | |
109 | for (int32_t y = 1; y < h - 1; y++) { | |
110 | *grad++ = border; | |
111 | for (int32_t x = 1; x < w - 1; x++) { | |
112 | uint16_t g[8]; | |
113 | g[0] = abs_diff4(tg, tg - 4) / 4; | |
114 | g[1] = abs_diff4(tg, tg + 4) / 4; | |
115 | g[2] = abs_diff4(tg, tg - stride) / 4; | |
116 | g[3] = abs_diff4(tg, tg + stride) / 4; | |
117 | g[4] = abs_diff4(tg, tg - stride - 4) / 8; | |
118 | g[5] = abs_diff4(tg, tg - stride + 4) / 8; | |
119 | g[6] = abs_diff4(tg, tg + stride - 4) / 8; | |
120 | g[7] = abs_diff4(tg, tg + stride + 4) / 8; | |
121 | uint16_t gg = g[0]; | |
122 | for (int k = 1; k < 8; k++) | |
123 | gg = FFMAX(gg, g[k]); | |
124 | *grad++ = base + gg; | |
125 | tg += 4; | |
126 | } | |
127 | *grad++ = border; | |
128 | tg += 8; | |
129 | } | |
130 | for (int32_t x = 0; x < w; x++) | |
131 | *grad++ = border; | |
132 | } | |
133 | ||
134 | static int compare1(const Image16 *target, const uint16_t *grad, | |
135 | const ASS_Image *img, const char *path, double *result) | |
136 | { | |
137 | Image8 frame; | |
138 | frame.width = target->width; | |
139 | frame.height = target->height; | |
140 | size_t size = (size_t) frame.width * frame.height; | |
141 | frame.buffer = malloc(4 * size); | |
142 | if (!frame.buffer) | |
143 | return 0; | |
144 | ||
145 | blend_all(&frame, 0, 0, img); | |
146 | ||
147 | double max_err = 0; | |
148 | const uint8_t *ptr = frame.buffer; | |
149 | const uint16_t *tg = target->buffer; | |
150 | for (size_t i = 0; i < size; i++) { | |
151 | uint16_t cmp[4]; | |
152 | for (int k = 0; k < 4; k++) | |
153 | cmp[k] = 257u * ptr[k]; | |
154 | double err = (double) abs_diff4(cmp, tg) / *grad++; | |
155 | if (max_err < err) | |
156 | max_err = err; | |
157 | ptr += 4; | |
158 | tg += 4; | |
159 | } | |
160 | int flag = path && !write_png8(path, &frame) ? -1 : 1; | |
161 | free(frame.buffer); | |
162 | *result = max_err; | |
163 | return flag; | |
164 | } | |
165 | ||
166 | static int compare(const Image16 *target, const uint16_t *grad, | |
167 | const ASS_Image *img, const char *path, | |
168 | double *result, int scale) | |
169 | { | |
170 | if (scale == 1) | |
171 | return compare1(target, grad, img, path, result); | |
172 | int scale2 = scale * scale; | |
173 | ||
174 | Image16 frame; | |
175 | frame.width = target->width; | |
176 | frame.height = target->height; | |
177 | size_t size = (size_t) frame.width * frame.height; | |
178 | frame.buffer = malloc(8 * size); | |
179 | if (!frame.buffer) | |
180 | return 0; | |
181 | ||
182 | Image8 temp; | |
183 | temp.width = scale * target->width; | |
184 | temp.height = scale * target->height; | |
185 | temp.buffer = malloc(4 * scale2 * size); | |
186 | if (!temp.buffer) { | |
187 | free(frame.buffer); | |
188 | return 0; | |
189 | } | |
190 | blend_all(&temp, 0, 0, img); | |
191 | ||
192 | uint16_t *dst = frame.buffer; | |
193 | const uint8_t *src = temp.buffer; | |
194 | int32_t stride = 4 * temp.width; | |
195 | const uint32_t offs = ((uint32_t) 1 << 18) - 1; | |
196 | uint32_t mul = ((uint32_t) 257 << 19) / scale2; | |
197 | for (int32_t y = 0; y < frame.height; y++) { | |
198 | for (int32_t x = 0; x < frame.width; x++) { | |
199 | uint16_t res[4] = {0}; | |
200 | const uint8_t *ptr = src; | |
201 | for (int i = 0; i < scale; i++) { | |
202 | for (int j = 0; j < scale; j++) | |
203 | for (int k = 0; k < 4; k++) | |
204 | res[k] += ptr[4 * j + k]; | |
205 | ptr += stride; | |
206 | } | |
207 | for (int k = 0; k < 4; k++) | |
208 | // equivalent to (257 * res[k] + (scale2 - 1) / 2) / scale2; | |
209 | *dst++ = (res[k] * (uint64_t) mul + offs) >> 19; | |
210 | src += 4 * scale; | |
211 | } | |
212 | src += (scale - 1) * stride; | |
213 | } | |
214 | ||
215 | free(temp.buffer); | |
216 | ||
217 | double max_err = 0; | |
218 | const uint16_t *ptr = frame.buffer; | |
219 | const uint16_t *tg = target->buffer; | |
220 | for (size_t i = 0; i < size; i++) { | |
221 | double err = (double) abs_diff4(ptr, tg) / *grad++; | |
222 | if (max_err < err) | |
223 | max_err = err; | |
224 | ptr += 4; | |
225 | tg += 4; | |
226 | } | |
227 | int flag = path && !write_png16(path, &frame) ? -1 : 1; | |
228 | free(frame.buffer); | |
229 | *result = max_err; | |
230 | return flag; | |
231 | } | |
232 | ||
233 | ||
234 | static bool load_font(ASS_Library *lib, const char *dir, const char *file) | |
235 | { | |
236 | char path[4096]; | |
237 | snprintf(path, sizeof(path), "%s/%s", dir, file); | |
238 | FILE *fp = fopen(path, "rb"); | |
239 | if (!fp) | |
240 | return false; | |
241 | ||
242 | if (fseek(fp, 0, SEEK_END) == -1) { | |
243 | fclose(fp); | |
244 | return false; | |
245 | } | |
246 | ||
247 | long size = ftell(fp); | |
248 | if (size <= 0 || size > (1l << 30)) { | |
249 | fclose(fp); | |
250 | return false; | |
251 | } | |
252 | rewind(fp); | |
253 | ||
254 | char *buf = malloc(size); | |
255 | if (!buf) { | |
256 | fclose(fp); | |
257 | return false; | |
258 | } | |
259 | ||
260 | long pos = 0; | |
261 | while (pos < size) { | |
262 | size_t n = fread(buf + pos, 1, size - pos, fp); | |
263 | if (!n) { | |
264 | free(buf); | |
265 | fclose(fp); | |
266 | return false; | |
267 | } | |
268 | pos += n; | |
269 | } | |
270 | fclose(fp); | |
271 | ||
272 | printf("Loading font '%s'.\n", file); | |
273 | ass_add_font(lib, (char *) file, buf, size); | |
274 | free(buf); | |
275 | return true; | |
276 | } | |
277 | ||
278 | static ASS_Track *load_track(ASS_Library *lib, | |
279 | const char *dir, const char *file) | |
280 | { | |
281 | char path[4096]; | |
282 | snprintf(path, sizeof(path), "%s/%s.ass", dir, file); | |
283 | ASS_Track *track = ass_read_file(lib, path, NULL); | |
284 | if (!track) { | |
285 | printf("Cannot load subtitle file '%s.ass'!\n", file); | |
286 | return NULL; | |
287 | } | |
288 | printf("Processing '%s.ass':\n", file); | |
289 | return track; | |
290 | } | |
291 | ||
292 | static bool out_of_memory() | |
293 | { | |
294 | printf("Not enough memory!\n"); | |
295 | return false; | |
296 | } | |
297 | ||
298 | static bool process_image(ASS_Renderer *renderer, ASS_Track *track, | |
299 | const char *input, const char *output, | |
300 | const char *file, int64_t time, int scale) | |
301 | { | |
302 | uint64_t tm = time; | |
303 | unsigned msec = tm % 1000; tm /= 1000; | |
304 | unsigned sec = tm % 60; tm /= 60; | |
305 | unsigned min = tm % 60; tm /= 60; | |
306 | printf(" Time %u:%02u:%02u.%03u - ", (unsigned) tm, min, sec, msec); | |
307 | ||
308 | char path[4096]; | |
309 | snprintf(path, sizeof(path), "%s/%s", input, file); | |
310 | ||
311 | Image16 target; | |
312 | if (!read_png(path, &target)) { | |
313 | printf("PNG reading failed!\n"); | |
314 | return false; | |
315 | } | |
316 | ||
317 | uint16_t *grad = malloc(2 * target.width * target.height); | |
318 | if (!grad) { | |
319 | free(target.buffer); | |
320 | return out_of_memory(); | |
321 | } | |
322 | calc_grad(&target, grad); | |
323 | ||
324 | ass_set_storage_size(renderer, target.width, target.height); | |
325 | ass_set_frame_size(renderer, scale * target.width, scale * target.height); | |
326 | ASS_Image *img = ass_render_frame(renderer, track, time, NULL); | |
327 | ||
328 | const char *out_file = NULL; | |
329 | if (output) { | |
330 | snprintf(path, sizeof(path), "%s/%s", output, file); | |
331 | out_file = path; | |
332 | } | |
333 | double max_err; | |
334 | int res = compare(&target, grad, img, out_file, &max_err, scale); | |
335 | free(target.buffer); | |
336 | free(grad); | |
337 | if (!res) | |
338 | return out_of_memory(); | |
339 | bool flag = max_err < 4; | |
340 | printf("%.3f %s\n", max_err, flag ? (max_err < 2 ? "OK" : "BAD") : "FAIL"); | |
341 | if (res < 0) | |
342 | printf("Cannot write PNG to file '%s'!\n", path); | |
343 | return flag; | |
344 | } | |
345 | ||
346 | ||
347 | typedef struct { | |
348 | char *name; | |
349 | int64_t time; | |
350 | } Item; | |
351 | ||
352 | typedef struct { | |
353 | size_t n_items, max_items; | |
354 | Item *items; | |
355 | } ItemList; | |
356 | ||
357 | static bool init_items(ItemList *list) | |
358 | { | |
359 | int n = 256; | |
360 | list->n_items = list->max_items = 0; | |
361 | list->items = malloc(n * sizeof(Item)); | |
362 | if (!list->items) | |
363 | return out_of_memory(); | |
364 | list->max_items = n; | |
365 | return true; | |
366 | } | |
367 | ||
368 | static bool add_item(ItemList *list) | |
369 | { | |
370 | if (list->n_items < list->max_items) | |
371 | return true; | |
372 | ||
373 | int n = 2 * list->max_items; | |
374 | Item *next = realloc(list->items, n * sizeof(Item)); | |
375 | if (!next) | |
376 | return out_of_memory(); | |
377 | list->max_items = n; | |
378 | list->items = next; | |
379 | return true; | |
380 | } | |
381 | ||
382 | static void delete_items(ItemList *list) | |
383 | { | |
384 | for (size_t i = 0; i < list->n_items; i++) | |
385 | free(list->items[i].name); | |
386 | free(list->items); | |
387 | } | |
388 | ||
389 | static int item_compare(const void *ptr1, const void *ptr2) | |
390 | { | |
391 | const Item *e1 = ptr1, *e2 = ptr2; | |
392 | int cmp = strcmp(e1->name, e2->name); | |
393 | if (cmp) | |
394 | return cmp; | |
395 | if (e1->time > e2->time) | |
396 | return +1; | |
397 | if (e1->time < e2->time) | |
398 | return -1; | |
399 | return 0; | |
400 | } | |
401 | ||
402 | ||
403 | static bool add_sub_item(ItemList *list, const char *file, int len) | |
404 | { | |
405 | if (!add_item(list)) | |
406 | return false; | |
407 | ||
408 | Item *item = &list->items[list->n_items]; | |
409 | item->name = strndup(file, len); | |
410 | if (!item->name) | |
411 | return out_of_memory(); | |
412 | item->time = -1; | |
413 | list->n_items++; | |
414 | return true; | |
415 | } | |
416 | ||
417 | static bool add_img_item(ItemList *list, const char *file, int len) | |
418 | { | |
419 | // Parse image name: | |
420 | // <subtitle_name>-<time_in_msec>.png | |
421 | ||
422 | int pos = len, first = len; | |
423 | while (true) { | |
424 | if (!pos--) | |
425 | return true; | |
426 | if (file[pos] == '-') | |
427 | break; | |
428 | if (file[pos] < '0' || file[pos] > '9') | |
429 | return true; | |
430 | if (file[pos] != '0') | |
431 | first = pos; | |
432 | } | |
433 | if (pos + 1 == len || first + 15 < len) | |
434 | return true; | |
435 | ||
436 | if (!add_item(list)) | |
437 | return false; | |
438 | ||
439 | Item *item = &list->items[list->n_items]; | |
440 | item->name = strdup(file); | |
441 | if (!item->name) | |
442 | return out_of_memory(); | |
443 | item->name[pos] = '\0'; | |
444 | item->time = 0; | |
445 | for (int i = first; i < len; i++) | |
446 | item->time = 10 * item->time + (file[i] - '0'); | |
447 | list->n_items++; | |
448 | return true; | |
449 | } | |
450 | ||
451 | ||
452 | static int print_usage(const char *program) | |
453 | { | |
454 | const char *fmt = | |
455 | "Usage: %s [-i] <input-dir> [-o <output-dir>] [-s <scale:1-8>]\n"; | |
456 | printf(fmt, program); | |
457 | return 1; | |
458 | } | |
459 | ||
460 | void msg_callback(int level, const char *fmt, va_list va, void *data) | |
461 | { | |
462 | if (level > 3) | |
463 | return; | |
464 | printf("libass: "); | |
465 | vprintf(fmt, va); | |
466 | printf("\n"); | |
467 | } | |
468 | ||
469 | int main(int argc, char *argv[]) | |
470 | { | |
471 | enum { | |
472 | INPUT, OUTPUT, SCALE | |
473 | }; | |
474 | int pos[3] = {0}; | |
475 | for (int i = 1; i < argc; i++) { | |
476 | if (argv[i][0] != '-') { | |
477 | if (pos[INPUT]) | |
478 | return print_usage(argv[0]); | |
479 | pos[INPUT] = i; | |
480 | continue; | |
481 | } | |
482 | int index; | |
483 | switch (argv[i][1]) { | |
484 | case 'i': index = INPUT; break; | |
485 | case 'o': index = OUTPUT; break; | |
486 | case 's': index = SCALE; break; | |
487 | default: return print_usage(argv[0]); | |
488 | } | |
489 | if (argv[i][2] || ++i >= argc || pos[index]) | |
490 | return print_usage(argv[0]); | |
491 | pos[index] = i; | |
492 | } | |
493 | if (!pos[INPUT]) | |
494 | return print_usage(argv[0]); | |
495 | ||
496 | int scale = 1; | |
497 | if (pos[SCALE]) { | |
498 | const char *arg = argv[pos[SCALE]]; | |
499 | if (arg[0] < '1' || arg[0] > '8' || arg[1]) { | |
500 | printf("Invalid scale value, should be 1-8!\n"); | |
501 | return 1; | |
502 | } | |
503 | scale = arg[0] - '0'; | |
504 | } | |
505 | ||
506 | const char *input = argv[pos[INPUT]]; | |
507 | DIR *dir = opendir(input); | |
508 | if (!dir) { | |
509 | printf("Cannot open input directory '%s'!\n", input); | |
510 | return 1; | |
511 | } | |
512 | ||
513 | const char *output = NULL; | |
514 | if (pos[OUTPUT]) { | |
515 | output = argv[pos[OUTPUT]]; | |
516 | struct stat st; | |
517 | if (stat(output, &st)) { | |
518 | if (mkdir(output, 0755)) { | |
519 | printf("Cannot create output directory '%s'!\n", output); | |
520 | closedir(dir); | |
521 | return 1; | |
522 | } | |
523 | } else if (!(st.st_mode & S_IFDIR)) { | |
524 | printf("Invalid output directory '%s'!\n", output); | |
525 | closedir(dir); | |
526 | return 1; | |
527 | } | |
528 | } | |
529 | ||
530 | ASS_Library *lib = ass_library_init(); | |
531 | if (!lib) { | |
532 | printf("ass_library_init failed!\n"); | |
533 | closedir(dir); | |
534 | return 1; | |
535 | } | |
536 | ass_set_message_cb(lib, msg_callback, NULL); | |
537 | ||
538 | ItemList list; | |
539 | if (!init_items(&list)) { | |
540 | ass_library_done(lib); | |
541 | closedir(dir); | |
542 | return 1; | |
543 | } | |
544 | ||
545 | while (true) { | |
546 | struct dirent *file = readdir(dir); | |
547 | if (!file) | |
548 | break; | |
549 | const char *name = file->d_name; | |
550 | if (name[0] == '.') | |
551 | continue; | |
552 | const char *ext = strrchr(name + 1, '.'); | |
553 | if (!ext) | |
554 | continue; | |
555 | ||
556 | if (!strcmp(ext, ".png")) { | |
557 | if (add_img_item(&list, name, ext - name)) | |
558 | continue; | |
559 | } else if (!strcmp(ext, ".ass")) { | |
560 | if (add_sub_item(&list, name, ext - name)) | |
561 | continue; | |
562 | } else if (!strcmp(ext, ".ttf") || !strcmp(ext, ".otf") || !strcmp(ext, ".pfb")) { | |
563 | if (load_font(lib, input, name)) | |
564 | continue; | |
565 | printf("Cannot load font '%s'!\n", name); | |
566 | } else { | |
567 | continue; | |
568 | } | |
569 | delete_items(&list); | |
570 | ass_library_done(lib); | |
571 | closedir(dir); | |
572 | return 1; | |
573 | } | |
574 | closedir(dir); | |
575 | ||
576 | ASS_Renderer *renderer = ass_renderer_init(lib); | |
577 | if (!renderer) { | |
578 | printf("ass_renderer_init failed!\n"); | |
579 | delete_items(&list); | |
580 | ass_library_done(lib); | |
581 | return 1; | |
582 | } | |
583 | ass_set_fonts(renderer, NULL, NULL, ASS_FONTPROVIDER_NONE, NULL, 0); | |
584 | ||
585 | int prefix; | |
586 | const char *prev = ""; | |
587 | ASS_Track *track = NULL; | |
588 | unsigned total = 0, good = 0; | |
589 | qsort(list.items, list.n_items, sizeof(Item), item_compare); | |
590 | for (size_t i = 0; i < list.n_items; i++) { | |
591 | if (strcmp(prev, list.items[i].name)) { | |
592 | if (track) | |
593 | ass_free_track(track); | |
594 | prev = list.items[i].name; | |
595 | prefix = strlen(prev); | |
596 | if (list.items[i].time < 0) | |
597 | track = load_track(lib, input, prev); | |
598 | else { | |
599 | printf("Missing subtitle file '%s.ass'!\n", prev); | |
600 | track = NULL; | |
601 | total++; | |
602 | } | |
603 | continue; | |
604 | } | |
605 | ||
606 | total++; | |
607 | if (!track) | |
608 | continue; | |
609 | char *name = list.items[i].name; | |
610 | name[prefix] = '-'; // restore initial filename | |
611 | if (process_image(renderer, track, input, output, | |
612 | name, list.items[i].time, scale)) | |
613 | good++; | |
614 | } | |
615 | if (track) | |
616 | ass_free_track(track); | |
617 | delete_items(&list); | |
618 | ass_renderer_done(renderer); | |
619 | ass_library_done(lib); | |
620 | ||
621 | if (good < total) { | |
622 | printf("Only %u of %u images have passed test\n", good, total); | |
623 | return 1; | |
624 | } | |
625 | printf("All %u images have passed test\n", total); | |
626 | return 0; | |
627 | } |
0 | /* | |
1 | * Copyright (C) 2017 Vabishchevich Nikolay <vabnick@gmail.com> | |
2 | * | |
3 | * This file is part of libass. | |
4 | * | |
5 | * Permission to use, copy, modify, and distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | ||
18 | #include "image.h" | |
19 | #include <png.h> | |
20 | ||
21 | ||
22 | bool read_png(const char *path, Image16 *img) | |
23 | { | |
24 | FILE *fp = fopen(path, "rb"); | |
25 | if (!fp) | |
26 | return false; | |
27 | ||
28 | png_structp png = | |
29 | png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |
30 | if (!png) { | |
31 | fclose(fp); | |
32 | return false; | |
33 | } | |
34 | ||
35 | png_infop info = png_create_info_struct(png); | |
36 | if (!info) { | |
37 | png_destroy_read_struct(&png, NULL, NULL); | |
38 | fclose(fp); | |
39 | return false; | |
40 | } | |
41 | ||
42 | png_byte *volatile buf = NULL; | |
43 | png_byte **volatile rows = NULL; | |
44 | if (setjmp(png_jmpbuf(png))) { | |
45 | free(buf); | |
46 | free(rows); | |
47 | png_destroy_read_struct(&png, &info, NULL); | |
48 | fclose(fp); | |
49 | return false; | |
50 | } | |
51 | ||
52 | png_init_io(png, fp); | |
53 | png_read_info(png, info); | |
54 | ||
55 | uint32_t w = png_get_image_width(png, info); | |
56 | uint32_t h = png_get_image_height(png, info); | |
57 | int type = png_get_color_type(png, info); | |
58 | int depth = png_get_bit_depth(png, info); | |
59 | ||
60 | if (w > 0xFFFF || h > 0xFFFF || type != PNG_COLOR_TYPE_RGBA) { | |
61 | png_destroy_read_struct(&png, &info, NULL); | |
62 | fclose(fp); | |
63 | return false; | |
64 | } | |
65 | ||
66 | ptrdiff_t stride = 8 * w; | |
67 | buf = malloc(stride * h); | |
68 | rows = malloc(h * sizeof(png_byte *)); | |
69 | if (!buf || !rows) { | |
70 | free(buf); | |
71 | free(rows); | |
72 | png_destroy_read_struct(&png, &info, NULL); | |
73 | fclose(fp); | |
74 | return false; | |
75 | } | |
76 | ||
77 | png_byte *ptr = buf; | |
78 | ptrdiff_t half = 4 * w; | |
79 | if (depth == 8) | |
80 | ptr += half; | |
81 | else | |
82 | png_set_swap(png); | |
83 | ||
84 | for (uint32_t i = 0; i < h; i++) { | |
85 | rows[i] = ptr; | |
86 | ptr += stride; | |
87 | } | |
88 | ||
89 | png_read_image(png, rows); | |
90 | png_read_end(png, NULL); | |
91 | ||
92 | free(rows); | |
93 | png_destroy_read_struct(&png, &info, NULL); | |
94 | fclose(fp); | |
95 | ||
96 | // convert to premultiplied with inverted alpha | |
97 | if (depth == 8) { | |
98 | uint8_t *ptr = (uint8_t *) buf; | |
99 | for (uint32_t y = 0; y < h; y++) { | |
100 | for (uint32_t x = 0; x < w; x++) { | |
101 | uint8_t r = ptr[half + 4 * x + 0]; | |
102 | uint8_t g = ptr[half + 4 * x + 1]; | |
103 | uint8_t b = ptr[half + 4 * x + 2]; | |
104 | uint8_t a = ptr[half + 4 * x + 3]; | |
105 | uint16_t ra = (uint16_t) r * a; | |
106 | uint16_t ga = (uint16_t) g * a; | |
107 | uint16_t ba = (uint16_t) b * a; | |
108 | ptr[8 * x + 0] = ptr[8 * x + 1] = (ra + (ra >> 8) + 128) >> 8; | |
109 | ptr[8 * x + 2] = ptr[8 * x + 3] = (ga + (ga >> 8) + 128) >> 8; | |
110 | ptr[8 * x + 4] = ptr[8 * x + 5] = (ba + (ba >> 8) + 128) >> 8; | |
111 | ptr[8 * x + 6] = ptr[8 * x + 7] = ~a; | |
112 | } | |
113 | ptr += stride; | |
114 | } | |
115 | } else { | |
116 | uint16_t *ptr = (uint16_t *) buf; | |
117 | for (uint32_t y = 0; y < h; y++) { | |
118 | for (uint32_t x = 0; x < w; x++) { | |
119 | uint16_t r = ptr[4 * x + 0]; | |
120 | uint16_t g = ptr[4 * x + 1]; | |
121 | uint16_t b = ptr[4 * x + 2]; | |
122 | uint16_t a = ptr[4 * x + 3]; | |
123 | uint32_t ra = (uint32_t) r * a; | |
124 | uint32_t ga = (uint32_t) g * a; | |
125 | uint32_t ba = (uint32_t) b * a; | |
126 | ptr[4 * x + 0] = (ra + (ra >> 16) + (1 << 15)) >> 16; | |
127 | ptr[4 * x + 1] = (ga + (ga >> 16) + (1 << 15)) >> 16; | |
128 | ptr[4 * x + 2] = (ba + (ba >> 16) + (1 << 15)) >> 16; | |
129 | ptr[4 * x + 3] = ~a; | |
130 | } | |
131 | ptr += half; | |
132 | } | |
133 | } | |
134 | ||
135 | img->width = w; | |
136 | img->height = h; | |
137 | img->buffer = (uint16_t *) buf; | |
138 | return true; | |
139 | } | |
140 | ||
141 | static bool write_png(const char *path, uint32_t width, uint32_t height, | |
142 | ptrdiff_t stride, const void *buffer, int depth) | |
143 | { | |
144 | FILE *fp = fopen(path, "wb"); | |
145 | if (!fp) | |
146 | return false; | |
147 | ||
148 | png_structp png = | |
149 | png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |
150 | if (!png) { | |
151 | fclose(fp); | |
152 | return false; | |
153 | } | |
154 | ||
155 | png_infop info = png_create_info_struct(png); | |
156 | if (!info) { | |
157 | png_destroy_write_struct(&png, NULL); | |
158 | fclose(fp); | |
159 | return false; | |
160 | } | |
161 | ||
162 | png_byte **rows = malloc(height * sizeof(png_byte *)); | |
163 | if (!rows) { | |
164 | png_destroy_write_struct(&png, &info); | |
165 | fclose(fp); | |
166 | return false; | |
167 | } | |
168 | ||
169 | png_byte *ptr = (png_byte *) buffer; | |
170 | for (uint32_t i = 0; i < height; i++) { | |
171 | rows[i] = (png_byte *) ptr; | |
172 | ptr += stride; | |
173 | } | |
174 | ||
175 | if (setjmp(png_jmpbuf(png))) { | |
176 | free(rows); | |
177 | png_destroy_write_struct(&png, &info); | |
178 | fclose(fp); | |
179 | return false; | |
180 | } | |
181 | ||
182 | png_init_io(png, fp); | |
183 | png_set_IHDR(png, info, width, height, depth, | |
184 | PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, | |
185 | PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); | |
186 | png_write_info(png, info); | |
187 | ||
188 | if (depth > 8) | |
189 | png_set_swap(png); | |
190 | png_write_image(png, rows); | |
191 | png_write_end(png, NULL); | |
192 | ||
193 | free(rows); | |
194 | png_destroy_write_struct(&png, &info); | |
195 | fclose(fp); | |
196 | return true; | |
197 | } | |
198 | ||
199 | bool write_png8(const char *path, Image8 *img) | |
200 | { | |
201 | uint8_t *ptr = img->buffer; | |
202 | size_t size = (size_t) img->width * img->height; | |
203 | for (size_t i = 0; i < size; i++) { | |
204 | uint8_t alpha = ~ptr[3]; | |
205 | if (alpha) { | |
206 | const uint32_t offs = (uint32_t) 1 << 15; | |
207 | uint32_t inv = ((uint32_t) 255 << 16) / alpha + 1; | |
208 | // equivalent to (255 * ptr[k] + alpha / 2) / alpha | |
209 | ptr[0] = (ptr[0] * inv + offs) >> 16; | |
210 | ptr[1] = (ptr[1] * inv + offs) >> 16; | |
211 | ptr[2] = (ptr[2] * inv + offs) >> 16; | |
212 | } | |
213 | ptr[3] = alpha; | |
214 | ptr += 4; | |
215 | } | |
216 | return write_png(path, img->width, img->height, | |
217 | 4 * img->width, img->buffer, 8); | |
218 | } | |
219 | ||
220 | bool write_png16(const char *path, Image16 *img) | |
221 | { | |
222 | uint16_t *ptr = img->buffer; | |
223 | size_t size = (size_t) img->width * img->height; | |
224 | for (size_t i = 0; i < size; i++) { | |
225 | uint16_t alpha = ~ptr[3]; | |
226 | if (alpha) { | |
227 | const uint64_t offs = (uint64_t) 1 << 32; | |
228 | uint64_t inv = ((uint64_t) 65535 << 33) / alpha + 1; | |
229 | // equivalent to (65535 * ptr[k] + alpha / 2) / alpha | |
230 | ptr[0] = (ptr[0] * inv + offs) >> 33; | |
231 | ptr[1] = (ptr[1] * inv + offs) >> 33; | |
232 | ptr[2] = (ptr[2] * inv + offs) >> 33; | |
233 | } | |
234 | ptr[3] = alpha; | |
235 | ptr += 4; | |
236 | } | |
237 | return write_png(path, img->width, img->height, | |
238 | 8 * img->width, img->buffer, 16); | |
239 | } |
0 | /* | |
1 | * Copyright (C) 2017 Vabishchevich Nikolay <vabnick@gmail.com> | |
2 | * | |
3 | * This file is part of libass. | |
4 | * | |
5 | * Permission to use, copy, modify, and distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | ||
18 | #ifndef COMPARE_IMAGE_H | |
19 | #define COMPARE_IMAGE_H | |
20 | ||
21 | #include <stddef.h> | |
22 | #include <stdlib.h> | |
23 | #include <stdbool.h> | |
24 | #include <stdint.h> | |
25 | ||
26 | typedef struct { | |
27 | int32_t width, height; | |
28 | uint8_t *buffer; | |
29 | } Image8; | |
30 | ||
31 | typedef struct { | |
32 | int32_t width, height; | |
33 | uint16_t *buffer; | |
34 | } Image16; | |
35 | ||
36 | bool read_png(const char *path, Image16 *img); | |
37 | bool write_png8(const char *path, Image8 *img); | |
38 | bool write_png16(const char *path, Image16 *img); | |
39 | ||
40 | #endif /* COMPARE_IMAGE_H */ |
0 | 0 | #! /bin/sh |
1 | 1 | # Wrapper for compilers which do not understand '-c -o'. |
2 | 2 | |
3 | scriptversion=2012-10-14.11; # UTC | |
4 | ||
5 | # Copyright (C) 1999-2014 Free Software Foundation, Inc. | |
3 | scriptversion=2018-03-07.03; # UTC | |
4 | ||
5 | # Copyright (C) 1999-2018 Free Software Foundation, Inc. | |
6 | 6 | # Written by Tom Tromey <tromey@cygnus.com>. |
7 | 7 | # |
8 | 8 | # This program is free software; you can redistribute it and/or modify |
16 | 16 | # GNU General Public License for more details. |
17 | 17 | # |
18 | 18 | # You should have received a copy of the GNU General Public License |
19 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | # along with this program. If not, see <https://www.gnu.org/licenses/>. | |
20 | 20 | |
21 | 21 | # As a special exception to the GNU General Public License, if you |
22 | 22 | # distribute this file as part of a program that contains a |
254 | 254 | echo "compile $scriptversion" |
255 | 255 | exit $? |
256 | 256 | ;; |
257 | cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) | |
257 | cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ | |
258 | icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) | |
258 | 259 | func_cl_wrapper "$@" # Doesn't return... |
259 | 260 | ;; |
260 | 261 | esac |
338 | 339 | # Local Variables: |
339 | 340 | # mode: shell-script |
340 | 341 | # sh-indentation: 2 |
341 | # eval: (add-hook 'write-file-hooks 'time-stamp) | |
342 | # eval: (add-hook 'before-save-hook 'time-stamp) | |
342 | 343 | # time-stamp-start: "scriptversion=" |
343 | 344 | # time-stamp-format: "%:y-%02m-%02d.%02H" |
344 | # time-stamp-time-zone: "UTC" | |
345 | # time-stamp-time-zone: "UTC0" | |
345 | 346 | # time-stamp-end: "; # UTC" |
346 | 347 | # End: |
0 | 0 | #! /bin/sh |
1 | 1 | # Attempt to guess a canonical system name. |
2 | # Copyright 1992-2014 Free Software Foundation, Inc. | |
3 | ||
4 | timestamp='2014-11-04' | |
2 | # Copyright 1992-2018 Free Software Foundation, Inc. | |
3 | ||
4 | timestamp='2018-03-08' | |
5 | 5 | |
6 | 6 | # This file is free software; you can redistribute it and/or modify it |
7 | 7 | # under the terms of the GNU General Public License as published by |
14 | 14 | # General Public License for more details. |
15 | 15 | # |
16 | 16 | # You should have received a copy of the GNU General Public License |
17 | # along with this program; if not, see <http://www.gnu.org/licenses/>. | |
17 | # along with this program; if not, see <https://www.gnu.org/licenses/>. | |
18 | 18 | # |
19 | 19 | # As a special exception to the GNU General Public License, if you |
20 | 20 | # distribute this file as part of a program that contains a |
26 | 26 | # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. |
27 | 27 | # |
28 | 28 | # You can get the latest version of this script from: |
29 | # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD | |
29 | # https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess | |
30 | 30 | # |
31 | 31 | # Please send patches to <config-patches@gnu.org>. |
32 | 32 | |
38 | 38 | |
39 | 39 | Output the configuration name of the system \`$me' is run on. |
40 | 40 | |
41 | Operation modes: | |
41 | Options: | |
42 | 42 | -h, --help print this help, then exit |
43 | 43 | -t, --time-stamp print date of last modification, then exit |
44 | 44 | -v, --version print version number, then exit |
49 | 49 | GNU config.guess ($timestamp) |
50 | 50 | |
51 | 51 | Originally written by Per Bothner. |
52 | Copyright 1992-2014 Free Software Foundation, Inc. | |
52 | Copyright 1992-2018 Free Software Foundation, Inc. | |
53 | 53 | |
54 | 54 | This is free software; see the source for copying conditions. There is NO |
55 | 55 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." |
106 | 106 | dummy=$tmp/dummy ; |
107 | 107 | tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; |
108 | 108 | case $CC_FOR_BUILD,$HOST_CC,$CC in |
109 | ,,) echo "int x;" > $dummy.c ; | |
109 | ,,) echo "int x;" > "$dummy.c" ; | |
110 | 110 | for c in cc gcc c89 c99 ; do |
111 | if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then | |
111 | if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then | |
112 | 112 | CC_FOR_BUILD="$c"; break ; |
113 | 113 | fi ; |
114 | 114 | done ; |
131 | 131 | UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown |
132 | 132 | UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown |
133 | 133 | |
134 | case "${UNAME_SYSTEM}" in | |
134 | case "$UNAME_SYSTEM" in | |
135 | 135 | Linux|GNU|GNU/*) |
136 | 136 | # If the system lacks a compiler, then just pick glibc. |
137 | 137 | # We could probably try harder. |
138 | 138 | LIBC=gnu |
139 | 139 | |
140 | eval $set_cc_for_build | |
141 | cat <<-EOF > $dummy.c | |
140 | eval "$set_cc_for_build" | |
141 | cat <<-EOF > "$dummy.c" | |
142 | 142 | #include <features.h> |
143 | 143 | #if defined(__UCLIBC__) |
144 | 144 | LIBC=uclibc |
148 | 148 | LIBC=gnu |
149 | 149 | #endif |
150 | 150 | EOF |
151 | eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` | |
151 | eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`" | |
152 | ||
153 | # If ldd exists, use it to detect musl libc. | |
154 | if command -v ldd >/dev/null && \ | |
155 | ldd --version 2>&1 | grep -q ^musl | |
156 | then | |
157 | LIBC=musl | |
158 | fi | |
152 | 159 | ;; |
153 | 160 | esac |
154 | 161 | |
155 | 162 | # Note: order is significant - the case branches are not exclusive. |
156 | 163 | |
157 | case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in | |
164 | case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in | |
158 | 165 | *:NetBSD:*:*) |
159 | 166 | # NetBSD (nbsd) targets should (where applicable) match one or |
160 | 167 | # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, |
167 | 174 | # Note: NetBSD doesn't particularly care about the vendor |
168 | 175 | # portion of the name. We always set it to "unknown". |
169 | 176 | sysctl="sysctl -n hw.machine_arch" |
170 | UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ | |
171 | /usr/sbin/$sysctl 2>/dev/null || echo unknown)` | |
172 | case "${UNAME_MACHINE_ARCH}" in | |
177 | UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ | |
178 | "/sbin/$sysctl" 2>/dev/null || \ | |
179 | "/usr/sbin/$sysctl" 2>/dev/null || \ | |
180 | echo unknown)` | |
181 | case "$UNAME_MACHINE_ARCH" in | |
173 | 182 | armeb) machine=armeb-unknown ;; |
174 | 183 | arm*) machine=arm-unknown ;; |
175 | 184 | sh3el) machine=shl-unknown ;; |
176 | 185 | sh3eb) machine=sh-unknown ;; |
177 | 186 | sh5el) machine=sh5le-unknown ;; |
178 | *) machine=${UNAME_MACHINE_ARCH}-unknown ;; | |
187 | earmv*) | |
188 | arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` | |
189 | endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` | |
190 | machine="${arch}${endian}"-unknown | |
191 | ;; | |
192 | *) machine="$UNAME_MACHINE_ARCH"-unknown ;; | |
179 | 193 | esac |
180 | 194 | # The Operating System including object format, if it has switched |
181 | # to ELF recently, or will in the future. | |
182 | case "${UNAME_MACHINE_ARCH}" in | |
195 | # to ELF recently (or will in the future) and ABI. | |
196 | case "$UNAME_MACHINE_ARCH" in | |
197 | earm*) | |
198 | os=netbsdelf | |
199 | ;; | |
183 | 200 | arm*|i386|m68k|ns32k|sh3*|sparc|vax) |
184 | eval $set_cc_for_build | |
201 | eval "$set_cc_for_build" | |
185 | 202 | if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ |
186 | 203 | | grep -q __ELF__ |
187 | 204 | then |
196 | 213 | os=netbsd |
197 | 214 | ;; |
198 | 215 | esac |
216 | # Determine ABI tags. | |
217 | case "$UNAME_MACHINE_ARCH" in | |
218 | earm*) | |
219 | expr='s/^earmv[0-9]/-eabi/;s/eb$//' | |
220 | abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` | |
221 | ;; | |
222 | esac | |
199 | 223 | # The OS release |
200 | 224 | # Debian GNU/NetBSD machines have a different userland, and |
201 | 225 | # thus, need a distinct triplet. However, they do not need |
202 | 226 | # kernel version information, so it can be replaced with a |
203 | 227 | # suitable tag, in the style of linux-gnu. |
204 | case "${UNAME_VERSION}" in | |
228 | case "$UNAME_VERSION" in | |
205 | 229 | Debian*) |
206 | 230 | release='-gnu' |
207 | 231 | ;; |
208 | 232 | *) |
209 | release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` | |
233 | release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` | |
210 | 234 | ;; |
211 | 235 | esac |
212 | 236 | # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: |
213 | 237 | # contains redundant information, the shorter form: |
214 | 238 | # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. |
215 | echo "${machine}-${os}${release}" | |
239 | echo "$machine-${os}${release}${abi}" | |
216 | 240 | exit ;; |
217 | 241 | *:Bitrig:*:*) |
218 | 242 | UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` |
219 | echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} | |
243 | echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" | |
220 | 244 | exit ;; |
221 | 245 | *:OpenBSD:*:*) |
222 | 246 | UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` |
223 | echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} | |
247 | echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" | |
248 | exit ;; | |
249 | *:LibertyBSD:*:*) | |
250 | UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` | |
251 | echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" | |
252 | exit ;; | |
253 | *:MidnightBSD:*:*) | |
254 | echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" | |
224 | 255 | exit ;; |
225 | 256 | *:ekkoBSD:*:*) |
226 | echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} | |
257 | echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" | |
227 | 258 | exit ;; |
228 | 259 | *:SolidBSD:*:*) |
229 | echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} | |
260 | echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" | |
230 | 261 | exit ;; |
231 | 262 | macppc:MirBSD:*:*) |
232 | echo powerpc-unknown-mirbsd${UNAME_RELEASE} | |
263 | echo powerpc-unknown-mirbsd"$UNAME_RELEASE" | |
233 | 264 | exit ;; |
234 | 265 | *:MirBSD:*:*) |
235 | echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} | |
236 | exit ;; | |
266 | echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" | |
267 | exit ;; | |
268 | *:Sortix:*:*) | |
269 | echo "$UNAME_MACHINE"-unknown-sortix | |
270 | exit ;; | |
271 | *:Redox:*:*) | |
272 | echo "$UNAME_MACHINE"-unknown-redox | |
273 | exit ;; | |
274 | mips:OSF1:*.*) | |
275 | echo mips-dec-osf1 | |
276 | exit ;; | |
237 | 277 | alpha:OSF1:*:*) |
238 | 278 | case $UNAME_RELEASE in |
239 | 279 | *4.0) |
250 | 290 | ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` |
251 | 291 | case "$ALPHA_CPU_TYPE" in |
252 | 292 | "EV4 (21064)") |
253 | UNAME_MACHINE="alpha" ;; | |
293 | UNAME_MACHINE=alpha ;; | |
254 | 294 | "EV4.5 (21064)") |
255 | UNAME_MACHINE="alpha" ;; | |
295 | UNAME_MACHINE=alpha ;; | |
256 | 296 | "LCA4 (21066/21068)") |
257 | UNAME_MACHINE="alpha" ;; | |
297 | UNAME_MACHINE=alpha ;; | |
258 | 298 | "EV5 (21164)") |
259 | UNAME_MACHINE="alphaev5" ;; | |
299 | UNAME_MACHINE=alphaev5 ;; | |
260 | 300 | "EV5.6 (21164A)") |
261 | UNAME_MACHINE="alphaev56" ;; | |
301 | UNAME_MACHINE=alphaev56 ;; | |
262 | 302 | "EV5.6 (21164PC)") |
263 | UNAME_MACHINE="alphapca56" ;; | |
303 | UNAME_MACHINE=alphapca56 ;; | |
264 | 304 | "EV5.7 (21164PC)") |
265 | UNAME_MACHINE="alphapca57" ;; | |
305 | UNAME_MACHINE=alphapca57 ;; | |
266 | 306 | "EV6 (21264)") |
267 | UNAME_MACHINE="alphaev6" ;; | |
307 | UNAME_MACHINE=alphaev6 ;; | |
268 | 308 | "EV6.7 (21264A)") |
269 | UNAME_MACHINE="alphaev67" ;; | |
309 | UNAME_MACHINE=alphaev67 ;; | |
270 | 310 | "EV6.8CB (21264C)") |
271 | UNAME_MACHINE="alphaev68" ;; | |
311 | UNAME_MACHINE=alphaev68 ;; | |
272 | 312 | "EV6.8AL (21264B)") |
273 | UNAME_MACHINE="alphaev68" ;; | |
313 | UNAME_MACHINE=alphaev68 ;; | |
274 | 314 | "EV6.8CX (21264D)") |
275 | UNAME_MACHINE="alphaev68" ;; | |
315 | UNAME_MACHINE=alphaev68 ;; | |
276 | 316 | "EV6.9A (21264/EV69A)") |
277 | UNAME_MACHINE="alphaev69" ;; | |
317 | UNAME_MACHINE=alphaev69 ;; | |
278 | 318 | "EV7 (21364)") |
279 | UNAME_MACHINE="alphaev7" ;; | |
319 | UNAME_MACHINE=alphaev7 ;; | |
280 | 320 | "EV7.9 (21364A)") |
281 | UNAME_MACHINE="alphaev79" ;; | |
321 | UNAME_MACHINE=alphaev79 ;; | |
282 | 322 | esac |
283 | 323 | # A Pn.n version is a patched version. |
284 | 324 | # A Vn.n version is a released version. |
285 | 325 | # A Tn.n version is a released field test version. |
286 | 326 | # A Xn.n version is an unreleased experimental baselevel. |
287 | 327 | # 1.2 uses "1.2" for uname -r. |
288 | echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` | |
328 | echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`" | |
289 | 329 | # Reset EXIT trap before exiting to avoid spurious non-zero exit code. |
290 | 330 | exitcode=$? |
291 | 331 | trap '' 0 |
292 | 332 | exit $exitcode ;; |
293 | Alpha\ *:Windows_NT*:*) | |
294 | # How do we know it's Interix rather than the generic POSIX subsystem? | |
295 | # Should we change UNAME_MACHINE based on the output of uname instead | |
296 | # of the specific Alpha model? | |
297 | echo alpha-pc-interix | |
298 | exit ;; | |
299 | 21064:Windows_NT:50:3) | |
300 | echo alpha-dec-winnt3.5 | |
301 | exit ;; | |
302 | 333 | Amiga*:UNIX_System_V:4.0:*) |
303 | 334 | echo m68k-unknown-sysv4 |
304 | 335 | exit ;; |
305 | 336 | *:[Aa]miga[Oo][Ss]:*:*) |
306 | echo ${UNAME_MACHINE}-unknown-amigaos | |
337 | echo "$UNAME_MACHINE"-unknown-amigaos | |
307 | 338 | exit ;; |
308 | 339 | *:[Mm]orph[Oo][Ss]:*:*) |
309 | echo ${UNAME_MACHINE}-unknown-morphos | |
340 | echo "$UNAME_MACHINE"-unknown-morphos | |
310 | 341 | exit ;; |
311 | 342 | *:OS/390:*:*) |
312 | 343 | echo i370-ibm-openedition |
318 | 349 | echo powerpc-ibm-os400 |
319 | 350 | exit ;; |
320 | 351 | arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) |
321 | echo arm-acorn-riscix${UNAME_RELEASE} | |
352 | echo arm-acorn-riscix"$UNAME_RELEASE" | |
322 | 353 | exit ;; |
323 | 354 | arm*:riscos:*:*|arm*:RISCOS:*:*) |
324 | 355 | echo arm-unknown-riscos |
345 | 376 | sparc) echo sparc-icl-nx7; exit ;; |
346 | 377 | esac ;; |
347 | 378 | s390x:SunOS:*:*) |
348 | echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` | |
379 | echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" | |
349 | 380 | exit ;; |
350 | 381 | sun4H:SunOS:5.*:*) |
351 | echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` | |
382 | echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" | |
352 | 383 | exit ;; |
353 | 384 | sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) |
354 | echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` | |
385 | echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" | |
355 | 386 | exit ;; |
356 | 387 | i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) |
357 | echo i386-pc-auroraux${UNAME_RELEASE} | |
388 | echo i386-pc-auroraux"$UNAME_RELEASE" | |
358 | 389 | exit ;; |
359 | 390 | i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) |
360 | eval $set_cc_for_build | |
361 | SUN_ARCH="i386" | |
391 | eval "$set_cc_for_build" | |
392 | SUN_ARCH=i386 | |
362 | 393 | # If there is a compiler, see if it is configured for 64-bit objects. |
363 | 394 | # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. |
364 | 395 | # This test works for both compilers. |
365 | if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then | |
396 | if [ "$CC_FOR_BUILD" != no_compiler_found ]; then | |
366 | 397 | if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ |
367 | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ | |
398 | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ | |
368 | 399 | grep IS_64BIT_ARCH >/dev/null |
369 | 400 | then |
370 | SUN_ARCH="x86_64" | |
401 | SUN_ARCH=x86_64 | |
371 | 402 | fi |
372 | 403 | fi |
373 | echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` | |
404 | echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" | |
374 | 405 | exit ;; |
375 | 406 | sun4*:SunOS:6*:*) |
376 | 407 | # According to config.sub, this is the proper way to canonicalize |
377 | 408 | # SunOS6. Hard to guess exactly what SunOS6 will be like, but |
378 | 409 | # it's likely to be more like Solaris than SunOS4. |
379 | echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` | |
410 | echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" | |
380 | 411 | exit ;; |
381 | 412 | sun4*:SunOS:*:*) |
382 | 413 | case "`/usr/bin/arch -k`" in |
385 | 416 | ;; |
386 | 417 | esac |
387 | 418 | # Japanese Language versions have a version number like `4.1.3-JL'. |
388 | echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` | |
419 | echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`" | |
389 | 420 | exit ;; |
390 | 421 | sun3*:SunOS:*:*) |
391 | echo m68k-sun-sunos${UNAME_RELEASE} | |
422 | echo m68k-sun-sunos"$UNAME_RELEASE" | |
392 | 423 | exit ;; |
393 | 424 | sun*:*:4.2BSD:*) |
394 | 425 | UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` |
395 | test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 | |
426 | test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 | |
396 | 427 | case "`/bin/arch`" in |
397 | 428 | sun3) |
398 | echo m68k-sun-sunos${UNAME_RELEASE} | |
429 | echo m68k-sun-sunos"$UNAME_RELEASE" | |
399 | 430 | ;; |
400 | 431 | sun4) |
401 | echo sparc-sun-sunos${UNAME_RELEASE} | |
432 | echo sparc-sun-sunos"$UNAME_RELEASE" | |
402 | 433 | ;; |
403 | 434 | esac |
404 | 435 | exit ;; |
405 | 436 | aushp:SunOS:*:*) |
406 | echo sparc-auspex-sunos${UNAME_RELEASE} | |
437 | echo sparc-auspex-sunos"$UNAME_RELEASE" | |
407 | 438 | exit ;; |
408 | 439 | # The situation for MiNT is a little confusing. The machine name |
409 | 440 | # can be virtually everything (everything which is not |
414 | 445 | # MiNT. But MiNT is downward compatible to TOS, so this should |
415 | 446 | # be no problem. |
416 | 447 | atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) |
417 | echo m68k-atari-mint${UNAME_RELEASE} | |
448 | echo m68k-atari-mint"$UNAME_RELEASE" | |
418 | 449 | exit ;; |
419 | 450 | atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) |
420 | echo m68k-atari-mint${UNAME_RELEASE} | |
451 | echo m68k-atari-mint"$UNAME_RELEASE" | |
421 | 452 | exit ;; |
422 | 453 | *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) |
423 | echo m68k-atari-mint${UNAME_RELEASE} | |
454 | echo m68k-atari-mint"$UNAME_RELEASE" | |
424 | 455 | exit ;; |
425 | 456 | milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) |
426 | echo m68k-milan-mint${UNAME_RELEASE} | |
457 | echo m68k-milan-mint"$UNAME_RELEASE" | |
427 | 458 | exit ;; |
428 | 459 | hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) |
429 | echo m68k-hades-mint${UNAME_RELEASE} | |
460 | echo m68k-hades-mint"$UNAME_RELEASE" | |
430 | 461 | exit ;; |
431 | 462 | *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) |
432 | echo m68k-unknown-mint${UNAME_RELEASE} | |
463 | echo m68k-unknown-mint"$UNAME_RELEASE" | |
433 | 464 | exit ;; |
434 | 465 | m68k:machten:*:*) |
435 | echo m68k-apple-machten${UNAME_RELEASE} | |
466 | echo m68k-apple-machten"$UNAME_RELEASE" | |
436 | 467 | exit ;; |
437 | 468 | powerpc:machten:*:*) |
438 | echo powerpc-apple-machten${UNAME_RELEASE} | |
469 | echo powerpc-apple-machten"$UNAME_RELEASE" | |
439 | 470 | exit ;; |
440 | 471 | RISC*:Mach:*:*) |
441 | 472 | echo mips-dec-mach_bsd4.3 |
442 | 473 | exit ;; |
443 | 474 | RISC*:ULTRIX:*:*) |
444 | echo mips-dec-ultrix${UNAME_RELEASE} | |
475 | echo mips-dec-ultrix"$UNAME_RELEASE" | |
445 | 476 | exit ;; |
446 | 477 | VAX*:ULTRIX*:*:*) |
447 | echo vax-dec-ultrix${UNAME_RELEASE} | |
478 | echo vax-dec-ultrix"$UNAME_RELEASE" | |
448 | 479 | exit ;; |
449 | 480 | 2020:CLIX:*:* | 2430:CLIX:*:*) |
450 | echo clipper-intergraph-clix${UNAME_RELEASE} | |
481 | echo clipper-intergraph-clix"$UNAME_RELEASE" | |
451 | 482 | exit ;; |
452 | 483 | mips:*:*:UMIPS | mips:*:*:RISCos) |
453 | eval $set_cc_for_build | |
454 | sed 's/^ //' << EOF >$dummy.c | |
484 | eval "$set_cc_for_build" | |
485 | sed 's/^ //' << EOF > "$dummy.c" | |
455 | 486 | #ifdef __cplusplus |
456 | 487 | #include <stdio.h> /* for printf() prototype */ |
457 | 488 | int main (int argc, char *argv[]) { |
460 | 491 | #endif |
461 | 492 | #if defined (host_mips) && defined (MIPSEB) |
462 | 493 | #if defined (SYSTYPE_SYSV) |
463 | printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); | |
494 | printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); | |
464 | 495 | #endif |
465 | 496 | #if defined (SYSTYPE_SVR4) |
466 | printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); | |
497 | printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); | |
467 | 498 | #endif |
468 | 499 | #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) |
469 | printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); | |
500 | printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); | |
470 | 501 | #endif |
471 | 502 | #endif |
472 | 503 | exit (-1); |
473 | 504 | } |
474 | 505 | EOF |
475 | $CC_FOR_BUILD -o $dummy $dummy.c && | |
476 | dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && | |
477 | SYSTEM_NAME=`$dummy $dummyarg` && | |
506 | $CC_FOR_BUILD -o "$dummy" "$dummy.c" && | |
507 | dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && | |
508 | SYSTEM_NAME=`"$dummy" "$dummyarg"` && | |
478 | 509 | { echo "$SYSTEM_NAME"; exit; } |
479 | echo mips-mips-riscos${UNAME_RELEASE} | |
510 | echo mips-mips-riscos"$UNAME_RELEASE" | |
480 | 511 | exit ;; |
481 | 512 | Motorola:PowerMAX_OS:*:*) |
482 | 513 | echo powerpc-motorola-powermax |
502 | 533 | AViiON:dgux:*:*) |
503 | 534 | # DG/UX returns AViiON for all architectures |
504 | 535 | UNAME_PROCESSOR=`/usr/bin/uname -p` |
505 | if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] | |
536 | if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ] | |
506 | 537 | then |
507 | if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ | |
508 | [ ${TARGET_BINARY_INTERFACE}x = x ] | |
538 | if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \ | |
539 | [ "$TARGET_BINARY_INTERFACE"x = x ] | |
509 | 540 | then |
510 | echo m88k-dg-dgux${UNAME_RELEASE} | |
541 | echo m88k-dg-dgux"$UNAME_RELEASE" | |
511 | 542 | else |
512 | echo m88k-dg-dguxbcs${UNAME_RELEASE} | |
543 | echo m88k-dg-dguxbcs"$UNAME_RELEASE" | |
513 | 544 | fi |
514 | 545 | else |
515 | echo i586-dg-dgux${UNAME_RELEASE} | |
546 | echo i586-dg-dgux"$UNAME_RELEASE" | |
516 | 547 | fi |
517 | 548 | exit ;; |
518 | 549 | M88*:DolphinOS:*:*) # DolphinOS (SVR3) |
529 | 560 | echo m68k-tektronix-bsd |
530 | 561 | exit ;; |
531 | 562 | *:IRIX*:*:*) |
532 | echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` | |
563 | echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`" | |
533 | 564 | exit ;; |
534 | 565 | ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. |
535 | 566 | echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id |
541 | 572 | if [ -x /usr/bin/oslevel ] ; then |
542 | 573 | IBM_REV=`/usr/bin/oslevel` |
543 | 574 | else |
544 | IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} | |
545 | fi | |
546 | echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} | |
575 | IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" | |
576 | fi | |
577 | echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" | |
547 | 578 | exit ;; |
548 | 579 | *:AIX:2:3) |
549 | 580 | if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then |
550 | eval $set_cc_for_build | |
551 | sed 's/^ //' << EOF >$dummy.c | |
581 | eval "$set_cc_for_build" | |
582 | sed 's/^ //' << EOF > "$dummy.c" | |
552 | 583 | #include <sys/systemcfg.h> |
553 | 584 | |
554 | 585 | main() |
559 | 590 | exit(0); |
560 | 591 | } |
561 | 592 | EOF |
562 | if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` | |
593 | if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` | |
563 | 594 | then |
564 | 595 | echo "$SYSTEM_NAME" |
565 | 596 | else |
573 | 604 | exit ;; |
574 | 605 | *:AIX:*:[4567]) |
575 | 606 | IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` |
576 | if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then | |
607 | if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then | |
577 | 608 | IBM_ARCH=rs6000 |
578 | 609 | else |
579 | 610 | IBM_ARCH=powerpc |
582 | 613 | IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | |
583 | 614 | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` |
584 | 615 | else |
585 | IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} | |
586 | fi | |
587 | echo ${IBM_ARCH}-ibm-aix${IBM_REV} | |
616 | IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" | |
617 | fi | |
618 | echo "$IBM_ARCH"-ibm-aix"$IBM_REV" | |
588 | 619 | exit ;; |
589 | 620 | *:AIX:*:*) |
590 | 621 | echo rs6000-ibm-aix |
591 | 622 | exit ;; |
592 | ibmrt:4.4BSD:*|romp-ibm:BSD:*) | |
623 | ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) | |
593 | 624 | echo romp-ibm-bsd4.4 |
594 | 625 | exit ;; |
595 | 626 | ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and |
596 | echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to | |
627 | echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to | |
597 | 628 | exit ;; # report: romp-ibm BSD 4.3 |
598 | 629 | *:BOSX:*:*) |
599 | 630 | echo rs6000-bull-bosx |
608 | 639 | echo m68k-hp-bsd4.4 |
609 | 640 | exit ;; |
610 | 641 | 9000/[34678]??:HP-UX:*:*) |
611 | HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` | |
612 | case "${UNAME_MACHINE}" in | |
613 | 9000/31? ) HP_ARCH=m68000 ;; | |
614 | 9000/[34]?? ) HP_ARCH=m68k ;; | |
642 | HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` | |
643 | case "$UNAME_MACHINE" in | |
644 | 9000/31?) HP_ARCH=m68000 ;; | |
645 | 9000/[34]??) HP_ARCH=m68k ;; | |
615 | 646 | 9000/[678][0-9][0-9]) |
616 | 647 | if [ -x /usr/bin/getconf ]; then |
617 | 648 | sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` |
618 | 649 | sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` |
619 | case "${sc_cpu_version}" in | |
620 | 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 | |
621 | 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 | |
650 | case "$sc_cpu_version" in | |
651 | 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 | |
652 | 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 | |
622 | 653 | 532) # CPU_PA_RISC2_0 |
623 | case "${sc_kernel_bits}" in | |
624 | 32) HP_ARCH="hppa2.0n" ;; | |
625 | 64) HP_ARCH="hppa2.0w" ;; | |
626 | '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 | |
654 | case "$sc_kernel_bits" in | |
655 | 32) HP_ARCH=hppa2.0n ;; | |
656 | 64) HP_ARCH=hppa2.0w ;; | |
657 | '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 | |
627 | 658 | esac ;; |
628 | 659 | esac |
629 | 660 | fi |
630 | if [ "${HP_ARCH}" = "" ]; then | |
631 | eval $set_cc_for_build | |
632 | sed 's/^ //' << EOF >$dummy.c | |
661 | if [ "$HP_ARCH" = "" ]; then | |
662 | eval "$set_cc_for_build" | |
663 | sed 's/^ //' << EOF > "$dummy.c" | |
633 | 664 | |
634 | 665 | #define _HPUX_SOURCE |
635 | 666 | #include <stdlib.h> |
662 | 693 | exit (0); |
663 | 694 | } |
664 | 695 | EOF |
665 | (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` | |
696 | (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` | |
666 | 697 | test -z "$HP_ARCH" && HP_ARCH=hppa |
667 | 698 | fi ;; |
668 | 699 | esac |
669 | if [ ${HP_ARCH} = "hppa2.0w" ] | |
700 | if [ "$HP_ARCH" = hppa2.0w ] | |
670 | 701 | then |
671 | eval $set_cc_for_build | |
702 | eval "$set_cc_for_build" | |
672 | 703 | |
673 | 704 | # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating |
674 | 705 | # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler |
679 | 710 | # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess |
680 | 711 | # => hppa64-hp-hpux11.23 |
681 | 712 | |
682 | if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | | |
713 | if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | | |
683 | 714 | grep -q __LP64__ |
684 | 715 | then |
685 | HP_ARCH="hppa2.0w" | |
716 | HP_ARCH=hppa2.0w | |
686 | 717 | else |
687 | HP_ARCH="hppa64" | |
718 | HP_ARCH=hppa64 | |
688 | 719 | fi |
689 | 720 | fi |
690 | echo ${HP_ARCH}-hp-hpux${HPUX_REV} | |
721 | echo "$HP_ARCH"-hp-hpux"$HPUX_REV" | |
691 | 722 | exit ;; |
692 | 723 | ia64:HP-UX:*:*) |
693 | HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` | |
694 | echo ia64-hp-hpux${HPUX_REV} | |
724 | HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` | |
725 | echo ia64-hp-hpux"$HPUX_REV" | |
695 | 726 | exit ;; |
696 | 727 | 3050*:HI-UX:*:*) |
697 | eval $set_cc_for_build | |
698 | sed 's/^ //' << EOF >$dummy.c | |
728 | eval "$set_cc_for_build" | |
729 | sed 's/^ //' << EOF > "$dummy.c" | |
699 | 730 | #include <unistd.h> |
700 | 731 | int |
701 | 732 | main () |
720 | 751 | exit (0); |
721 | 752 | } |
722 | 753 | EOF |
723 | $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && | |
754 | $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && | |
724 | 755 | { echo "$SYSTEM_NAME"; exit; } |
725 | 756 | echo unknown-hitachi-hiuxwe2 |
726 | 757 | exit ;; |
727 | 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) | |
758 | 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) | |
728 | 759 | echo hppa1.1-hp-bsd |
729 | 760 | exit ;; |
730 | 761 | 9000/8??:4.3bsd:*:*) |
733 | 764 | *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) |
734 | 765 | echo hppa1.0-hp-mpeix |
735 | 766 | exit ;; |
736 | hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) | |
767 | hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) | |
737 | 768 | echo hppa1.1-hp-osf |
738 | 769 | exit ;; |
739 | 770 | hp8??:OSF1:*:*) |
741 | 772 | exit ;; |
742 | 773 | i*86:OSF1:*:*) |
743 | 774 | if [ -x /usr/sbin/sysversion ] ; then |
744 | echo ${UNAME_MACHINE}-unknown-osf1mk | |
775 | echo "$UNAME_MACHINE"-unknown-osf1mk | |
745 | 776 | else |
746 | echo ${UNAME_MACHINE}-unknown-osf1 | |
777 | echo "$UNAME_MACHINE"-unknown-osf1 | |
747 | 778 | fi |
748 | 779 | exit ;; |
749 | 780 | parisc*:Lites*:*:*) |
768 | 799 | echo c4-convex-bsd |
769 | 800 | exit ;; |
770 | 801 | CRAY*Y-MP:*:*:*) |
771 | echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' | |
802 | echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' | |
772 | 803 | exit ;; |
773 | 804 | CRAY*[A-Z]90:*:*:*) |
774 | echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | |
805 | echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | |
775 | 806 | | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ |
776 | 807 | -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ |
777 | 808 | -e 's/\.[^.]*$/.X/' |
778 | 809 | exit ;; |
779 | 810 | CRAY*TS:*:*:*) |
780 | echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' | |
811 | echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' | |
781 | 812 | exit ;; |
782 | 813 | CRAY*T3E:*:*:*) |
783 | echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' | |
814 | echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' | |
784 | 815 | exit ;; |
785 | 816 | CRAY*SV1:*:*:*) |
786 | echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' | |
817 | echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' | |
787 | 818 | exit ;; |
788 | 819 | *:UNICOS/mp:*:*) |
789 | echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' | |
820 | echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' | |
790 | 821 | exit ;; |
791 | 822 | F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) |
792 | FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` | |
793 | FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` | |
794 | FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` | |
823 | FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` | |
824 | FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` | |
825 | FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` | |
795 | 826 | echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" |
796 | 827 | exit ;; |
797 | 828 | 5000:UNIX_System_V:4.*:*) |
798 | FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` | |
799 | FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` | |
829 | FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` | |
830 | FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` | |
800 | 831 | echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" |
801 | 832 | exit ;; |
802 | 833 | i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) |
803 | echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} | |
834 | echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" | |
804 | 835 | exit ;; |
805 | 836 | sparc*:BSD/OS:*:*) |
806 | echo sparc-unknown-bsdi${UNAME_RELEASE} | |
837 | echo sparc-unknown-bsdi"$UNAME_RELEASE" | |
807 | 838 | exit ;; |
808 | 839 | *:BSD/OS:*:*) |
809 | echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} | |
840 | echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" | |
810 | 841 | exit ;; |
811 | 842 | *:FreeBSD:*:*) |
812 | 843 | UNAME_PROCESSOR=`/usr/bin/uname -p` |
813 | case ${UNAME_PROCESSOR} in | |
844 | case "$UNAME_PROCESSOR" in | |
814 | 845 | amd64) |
815 | echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; | |
816 | *) | |
817 | echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; | |
846 | UNAME_PROCESSOR=x86_64 ;; | |
847 | i386) | |
848 | UNAME_PROCESSOR=i586 ;; | |
818 | 849 | esac |
850 | echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" | |
819 | 851 | exit ;; |
820 | 852 | i*:CYGWIN*:*) |
821 | echo ${UNAME_MACHINE}-pc-cygwin | |
853 | echo "$UNAME_MACHINE"-pc-cygwin | |
822 | 854 | exit ;; |
823 | 855 | *:MINGW64*:*) |
824 | echo ${UNAME_MACHINE}-pc-mingw64 | |
856 | echo "$UNAME_MACHINE"-pc-mingw64 | |
825 | 857 | exit ;; |
826 | 858 | *:MINGW*:*) |
827 | echo ${UNAME_MACHINE}-pc-mingw32 | |
859 | echo "$UNAME_MACHINE"-pc-mingw32 | |
828 | 860 | exit ;; |
829 | 861 | *:MSYS*:*) |
830 | echo ${UNAME_MACHINE}-pc-msys | |
831 | exit ;; | |
832 | i*:windows32*:*) | |
833 | # uname -m includes "-pc" on this system. | |
834 | echo ${UNAME_MACHINE}-mingw32 | |
862 | echo "$UNAME_MACHINE"-pc-msys | |
835 | 863 | exit ;; |
836 | 864 | i*:PW*:*) |
837 | echo ${UNAME_MACHINE}-pc-pw32 | |
865 | echo "$UNAME_MACHINE"-pc-pw32 | |
838 | 866 | exit ;; |
839 | 867 | *:Interix*:*) |
840 | case ${UNAME_MACHINE} in | |
868 | case "$UNAME_MACHINE" in | |
841 | 869 | x86) |
842 | echo i586-pc-interix${UNAME_RELEASE} | |
870 | echo i586-pc-interix"$UNAME_RELEASE" | |
843 | 871 | exit ;; |
844 | 872 | authenticamd | genuineintel | EM64T) |
845 | echo x86_64-unknown-interix${UNAME_RELEASE} | |
873 | echo x86_64-unknown-interix"$UNAME_RELEASE" | |
846 | 874 | exit ;; |
847 | 875 | IA64) |
848 | echo ia64-unknown-interix${UNAME_RELEASE} | |
876 | echo ia64-unknown-interix"$UNAME_RELEASE" | |
849 | 877 | exit ;; |
850 | 878 | esac ;; |
851 | [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) | |
852 | echo i${UNAME_MACHINE}-pc-mks | |
853 | exit ;; | |
854 | 8664:Windows_NT:*) | |
855 | echo x86_64-pc-mks | |
856 | exit ;; | |
857 | i*:Windows_NT*:* | Pentium*:Windows_NT*:*) | |
858 | # How do we know it's Interix rather than the generic POSIX subsystem? | |
859 | # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we | |
860 | # UNAME_MACHINE based on the output of uname instead of i386? | |
861 | echo i586-pc-interix | |
862 | exit ;; | |
863 | 879 | i*:UWIN*:*) |
864 | echo ${UNAME_MACHINE}-pc-uwin | |
880 | echo "$UNAME_MACHINE"-pc-uwin | |
865 | 881 | exit ;; |
866 | 882 | amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) |
867 | 883 | echo x86_64-unknown-cygwin |
868 | 884 | exit ;; |
869 | p*:CYGWIN*:*) | |
870 | echo powerpcle-unknown-cygwin | |
871 | exit ;; | |
872 | 885 | prep*:SunOS:5.*:*) |
873 | echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` | |
886 | echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" | |
874 | 887 | exit ;; |
875 | 888 | *:GNU:*:*) |
876 | 889 | # the GNU system |
877 | echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` | |
890 | echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`" | |
878 | 891 | exit ;; |
879 | 892 | *:GNU/*:*:*) |
880 | 893 | # other systems with GNU libc and userland |
881 | echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} | |
894 | echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" | |
882 | 895 | exit ;; |
883 | 896 | i*86:Minix:*:*) |
884 | echo ${UNAME_MACHINE}-pc-minix | |
897 | echo "$UNAME_MACHINE"-pc-minix | |
885 | 898 | exit ;; |
886 | 899 | aarch64:Linux:*:*) |
887 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
900 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
888 | 901 | exit ;; |
889 | 902 | aarch64_be:Linux:*:*) |
890 | 903 | UNAME_MACHINE=aarch64_be |
891 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
904 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
892 | 905 | exit ;; |
893 | 906 | alpha:Linux:*:*) |
894 | 907 | case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in |
901 | 914 | EV68*) UNAME_MACHINE=alphaev68 ;; |
902 | 915 | esac |
903 | 916 | objdump --private-headers /bin/sh | grep -q ld.so.1 |
904 | if test "$?" = 0 ; then LIBC="gnulibc1" ; fi | |
905 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
917 | if test "$?" = 0 ; then LIBC=gnulibc1 ; fi | |
918 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
906 | 919 | exit ;; |
907 | 920 | arc:Linux:*:* | arceb:Linux:*:*) |
908 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
921 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
909 | 922 | exit ;; |
910 | 923 | arm*:Linux:*:*) |
911 | eval $set_cc_for_build | |
924 | eval "$set_cc_for_build" | |
912 | 925 | if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ |
913 | 926 | | grep -q __ARM_EABI__ |
914 | 927 | then |
915 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
928 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
916 | 929 | else |
917 | 930 | if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ |
918 | 931 | | grep -q __ARM_PCS_VFP |
919 | 932 | then |
920 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi | |
933 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi | |
921 | 934 | else |
922 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf | |
935 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf | |
923 | 936 | fi |
924 | 937 | fi |
925 | 938 | exit ;; |
926 | 939 | avr32*:Linux:*:*) |
927 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
940 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
928 | 941 | exit ;; |
929 | 942 | cris:Linux:*:*) |
930 | echo ${UNAME_MACHINE}-axis-linux-${LIBC} | |
943 | echo "$UNAME_MACHINE"-axis-linux-"$LIBC" | |
931 | 944 | exit ;; |
932 | 945 | crisv32:Linux:*:*) |
933 | echo ${UNAME_MACHINE}-axis-linux-${LIBC} | |
946 | echo "$UNAME_MACHINE"-axis-linux-"$LIBC" | |
947 | exit ;; | |
948 | e2k:Linux:*:*) | |
949 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
934 | 950 | exit ;; |
935 | 951 | frv:Linux:*:*) |
936 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
952 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
937 | 953 | exit ;; |
938 | 954 | hexagon:Linux:*:*) |
939 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
955 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
940 | 956 | exit ;; |
941 | 957 | i*86:Linux:*:*) |
942 | echo ${UNAME_MACHINE}-pc-linux-${LIBC} | |
958 | echo "$UNAME_MACHINE"-pc-linux-"$LIBC" | |
943 | 959 | exit ;; |
944 | 960 | ia64:Linux:*:*) |
945 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
961 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
962 | exit ;; | |
963 | k1om:Linux:*:*) | |
964 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
946 | 965 | exit ;; |
947 | 966 | m32r*:Linux:*:*) |
948 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
967 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
949 | 968 | exit ;; |
950 | 969 | m68*:Linux:*:*) |
951 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
970 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
952 | 971 | exit ;; |
953 | 972 | mips:Linux:*:* | mips64:Linux:*:*) |
954 | eval $set_cc_for_build | |
955 | sed 's/^ //' << EOF >$dummy.c | |
973 | eval "$set_cc_for_build" | |
974 | sed 's/^ //' << EOF > "$dummy.c" | |
956 | 975 | #undef CPU |
957 | 976 | #undef ${UNAME_MACHINE} |
958 | 977 | #undef ${UNAME_MACHINE}el |
966 | 985 | #endif |
967 | 986 | #endif |
968 | 987 | EOF |
969 | eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` | |
970 | test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } | |
988 | eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU'`" | |
989 | test "x$CPU" != x && { echo "$CPU-unknown-linux-$LIBC"; exit; } | |
971 | 990 | ;; |
991 | mips64el:Linux:*:*) | |
992 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
993 | exit ;; | |
972 | 994 | openrisc*:Linux:*:*) |
973 | echo or1k-unknown-linux-${LIBC} | |
995 | echo or1k-unknown-linux-"$LIBC" | |
974 | 996 | exit ;; |
975 | 997 | or32:Linux:*:* | or1k*:Linux:*:*) |
976 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
998 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
977 | 999 | exit ;; |
978 | 1000 | padre:Linux:*:*) |
979 | echo sparc-unknown-linux-${LIBC} | |
1001 | echo sparc-unknown-linux-"$LIBC" | |
980 | 1002 | exit ;; |
981 | 1003 | parisc64:Linux:*:* | hppa64:Linux:*:*) |
982 | echo hppa64-unknown-linux-${LIBC} | |
1004 | echo hppa64-unknown-linux-"$LIBC" | |
983 | 1005 | exit ;; |
984 | 1006 | parisc:Linux:*:* | hppa:Linux:*:*) |
985 | 1007 | # Look for CPU level |
986 | 1008 | case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in |
987 | PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; | |
988 | PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; | |
989 | *) echo hppa-unknown-linux-${LIBC} ;; | |
1009 | PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; | |
1010 | PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; | |
1011 | *) echo hppa-unknown-linux-"$LIBC" ;; | |
990 | 1012 | esac |
991 | 1013 | exit ;; |
992 | 1014 | ppc64:Linux:*:*) |
993 | echo powerpc64-unknown-linux-${LIBC} | |
1015 | echo powerpc64-unknown-linux-"$LIBC" | |
994 | 1016 | exit ;; |
995 | 1017 | ppc:Linux:*:*) |
996 | echo powerpc-unknown-linux-${LIBC} | |
1018 | echo powerpc-unknown-linux-"$LIBC" | |
997 | 1019 | exit ;; |
998 | 1020 | ppc64le:Linux:*:*) |
999 | echo powerpc64le-unknown-linux-${LIBC} | |
1021 | echo powerpc64le-unknown-linux-"$LIBC" | |
1000 | 1022 | exit ;; |
1001 | 1023 | ppcle:Linux:*:*) |
1002 | echo powerpcle-unknown-linux-${LIBC} | |
1024 | echo powerpcle-unknown-linux-"$LIBC" | |
1025 | exit ;; | |
1026 | riscv32:Linux:*:* | riscv64:Linux:*:*) | |
1027 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
1003 | 1028 | exit ;; |
1004 | 1029 | s390:Linux:*:* | s390x:Linux:*:*) |
1005 | echo ${UNAME_MACHINE}-ibm-linux-${LIBC} | |
1030 | echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" | |
1006 | 1031 | exit ;; |
1007 | 1032 | sh64*:Linux:*:*) |
1008 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
1033 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
1009 | 1034 | exit ;; |
1010 | 1035 | sh*:Linux:*:*) |
1011 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
1036 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
1012 | 1037 | exit ;; |
1013 | 1038 | sparc:Linux:*:* | sparc64:Linux:*:*) |
1014 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
1039 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
1015 | 1040 | exit ;; |
1016 | 1041 | tile*:Linux:*:*) |
1017 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
1042 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
1018 | 1043 | exit ;; |
1019 | 1044 | vax:Linux:*:*) |
1020 | echo ${UNAME_MACHINE}-dec-linux-${LIBC} | |
1045 | echo "$UNAME_MACHINE"-dec-linux-"$LIBC" | |
1021 | 1046 | exit ;; |
1022 | 1047 | x86_64:Linux:*:*) |
1023 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
1048 | echo "$UNAME_MACHINE"-pc-linux-"$LIBC" | |
1024 | 1049 | exit ;; |
1025 | 1050 | xtensa*:Linux:*:*) |
1026 | echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | |
1051 | echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" | |
1027 | 1052 | exit ;; |
1028 | 1053 | i*86:DYNIX/ptx:4*:*) |
1029 | 1054 | # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. |
1037 | 1062 | # I am not positive that other SVR4 systems won't match this, |
1038 | 1063 | # I just have to hope. -- rms. |
1039 | 1064 | # Use sysv4.2uw... so that sysv4* matches it. |
1040 | echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} | |
1065 | echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" | |
1041 | 1066 | exit ;; |
1042 | 1067 | i*86:OS/2:*:*) |
1043 | 1068 | # If we were able to find `uname', then EMX Unix compatibility |
1044 | 1069 | # is probably installed. |
1045 | echo ${UNAME_MACHINE}-pc-os2-emx | |
1070 | echo "$UNAME_MACHINE"-pc-os2-emx | |
1046 | 1071 | exit ;; |
1047 | 1072 | i*86:XTS-300:*:STOP) |
1048 | echo ${UNAME_MACHINE}-unknown-stop | |
1073 | echo "$UNAME_MACHINE"-unknown-stop | |
1049 | 1074 | exit ;; |
1050 | 1075 | i*86:atheos:*:*) |
1051 | echo ${UNAME_MACHINE}-unknown-atheos | |
1076 | echo "$UNAME_MACHINE"-unknown-atheos | |
1052 | 1077 | exit ;; |
1053 | 1078 | i*86:syllable:*:*) |
1054 | echo ${UNAME_MACHINE}-pc-syllable | |
1079 | echo "$UNAME_MACHINE"-pc-syllable | |
1055 | 1080 | exit ;; |
1056 | 1081 | i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) |
1057 | echo i386-unknown-lynxos${UNAME_RELEASE} | |
1082 | echo i386-unknown-lynxos"$UNAME_RELEASE" | |
1058 | 1083 | exit ;; |
1059 | 1084 | i*86:*DOS:*:*) |
1060 | echo ${UNAME_MACHINE}-pc-msdosdjgpp | |
1061 | exit ;; | |
1062 | i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) | |
1063 | UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` | |
1085 | echo "$UNAME_MACHINE"-pc-msdosdjgpp | |
1086 | exit ;; | |
1087 | i*86:*:4.*:*) | |
1088 | UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` | |
1064 | 1089 | if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then |
1065 | echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} | |
1090 | echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" | |
1066 | 1091 | else |
1067 | echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} | |
1092 | echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" | |
1068 | 1093 | fi |
1069 | 1094 | exit ;; |
1070 | 1095 | i*86:*:5:[678]*) |
1074 | 1099 | *Pentium) UNAME_MACHINE=i586 ;; |
1075 | 1100 | *Pent*|*Celeron) UNAME_MACHINE=i686 ;; |
1076 | 1101 | esac |
1077 | echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} | |
1102 | echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}{$UNAME_VERSION}" | |
1078 | 1103 | exit ;; |
1079 | 1104 | i*86:*:3.2:*) |
1080 | 1105 | if test -f /usr/options/cb.name; then |
1081 | 1106 | UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` |
1082 | echo ${UNAME_MACHINE}-pc-isc$UNAME_REL | |
1107 | echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL" | |
1083 | 1108 | elif /bin/uname -X 2>/dev/null >/dev/null ; then |
1084 | 1109 | UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` |
1085 | 1110 | (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 |
1089 | 1114 | && UNAME_MACHINE=i686 |
1090 | 1115 | (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ |
1091 | 1116 | && UNAME_MACHINE=i686 |
1092 | echo ${UNAME_MACHINE}-pc-sco$UNAME_REL | |
1117 | echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" | |
1093 | 1118 | else |
1094 | echo ${UNAME_MACHINE}-pc-sysv32 | |
1119 | echo "$UNAME_MACHINE"-pc-sysv32 | |
1095 | 1120 | fi |
1096 | 1121 | exit ;; |
1097 | 1122 | pc:*:*:*) |
1099 | 1124 | # uname -m prints for DJGPP always 'pc', but it prints nothing about |
1100 | 1125 | # the processor, so we play safe by assuming i586. |
1101 | 1126 | # Note: whatever this is, it MUST be the same as what config.sub |
1102 | # prints for the "djgpp" host, or else GDB configury will decide that | |
1127 | # prints for the "djgpp" host, or else GDB configure will decide that | |
1103 | 1128 | # this is a cross-build. |
1104 | 1129 | echo i586-pc-msdosdjgpp |
1105 | 1130 | exit ;; |
1111 | 1136 | exit ;; |
1112 | 1137 | i860:*:4.*:*) # i860-SVR4 |
1113 | 1138 | if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then |
1114 | echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 | |
1139 | echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 | |
1115 | 1140 | else # Add other i860-SVR4 vendors below as they are discovered. |
1116 | echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 | |
1141 | echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 | |
1117 | 1142 | fi |
1118 | 1143 | exit ;; |
1119 | 1144 | mini*:CTIX:SYS*5:*) |
1133 | 1158 | test -r /etc/.relid \ |
1134 | 1159 | && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` |
1135 | 1160 | /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ |
1136 | && { echo i486-ncr-sysv4.3${OS_REL}; exit; } | |
1161 | && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } | |
1137 | 1162 | /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ |
1138 | && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; | |
1163 | && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; | |
1139 | 1164 | 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) |
1140 | 1165 | /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ |
1141 | 1166 | && { echo i486-ncr-sysv4; exit; } ;; |
1144 | 1169 | test -r /etc/.relid \ |
1145 | 1170 | && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` |
1146 | 1171 | /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ |
1147 | && { echo i486-ncr-sysv4.3${OS_REL}; exit; } | |
1172 | && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } | |
1148 | 1173 | /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ |
1149 | && { echo i586-ncr-sysv4.3${OS_REL}; exit; } | |
1174 | && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } | |
1150 | 1175 | /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ |
1151 | && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; | |
1176 | && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; | |
1152 | 1177 | m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) |
1153 | echo m68k-unknown-lynxos${UNAME_RELEASE} | |
1178 | echo m68k-unknown-lynxos"$UNAME_RELEASE" | |
1154 | 1179 | exit ;; |
1155 | 1180 | mc68030:UNIX_System_V:4.*:*) |
1156 | 1181 | echo m68k-atari-sysv4 |
1157 | 1182 | exit ;; |
1158 | 1183 | TSUNAMI:LynxOS:2.*:*) |
1159 | echo sparc-unknown-lynxos${UNAME_RELEASE} | |
1184 | echo sparc-unknown-lynxos"$UNAME_RELEASE" | |
1160 | 1185 | exit ;; |
1161 | 1186 | rs6000:LynxOS:2.*:*) |
1162 | echo rs6000-unknown-lynxos${UNAME_RELEASE} | |
1187 | echo rs6000-unknown-lynxos"$UNAME_RELEASE" | |
1163 | 1188 | exit ;; |
1164 | 1189 | PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) |
1165 | echo powerpc-unknown-lynxos${UNAME_RELEASE} | |
1190 | echo powerpc-unknown-lynxos"$UNAME_RELEASE" | |
1166 | 1191 | exit ;; |
1167 | 1192 | SM[BE]S:UNIX_SV:*:*) |
1168 | echo mips-dde-sysv${UNAME_RELEASE} | |
1193 | echo mips-dde-sysv"$UNAME_RELEASE" | |
1169 | 1194 | exit ;; |
1170 | 1195 | RM*:ReliantUNIX-*:*:*) |
1171 | 1196 | echo mips-sni-sysv4 |
1176 | 1201 | *:SINIX-*:*:*) |
1177 | 1202 | if uname -p 2>/dev/null >/dev/null ; then |
1178 | 1203 | UNAME_MACHINE=`(uname -p) 2>/dev/null` |
1179 | echo ${UNAME_MACHINE}-sni-sysv4 | |
1204 | echo "$UNAME_MACHINE"-sni-sysv4 | |
1180 | 1205 | else |
1181 | 1206 | echo ns32k-sni-sysv |
1182 | 1207 | fi |
1196 | 1221 | exit ;; |
1197 | 1222 | i*86:VOS:*:*) |
1198 | 1223 | # From Paul.Green@stratus.com. |
1199 | echo ${UNAME_MACHINE}-stratus-vos | |
1224 | echo "$UNAME_MACHINE"-stratus-vos | |
1200 | 1225 | exit ;; |
1201 | 1226 | *:VOS:*:*) |
1202 | 1227 | # From Paul.Green@stratus.com. |
1203 | 1228 | echo hppa1.1-stratus-vos |
1204 | 1229 | exit ;; |
1205 | 1230 | mc68*:A/UX:*:*) |
1206 | echo m68k-apple-aux${UNAME_RELEASE} | |
1231 | echo m68k-apple-aux"$UNAME_RELEASE" | |
1207 | 1232 | exit ;; |
1208 | 1233 | news*:NEWS-OS:6*:*) |
1209 | 1234 | echo mips-sony-newsos6 |
1210 | 1235 | exit ;; |
1211 | 1236 | R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) |
1212 | 1237 | if [ -d /usr/nec ]; then |
1213 | echo mips-nec-sysv${UNAME_RELEASE} | |
1238 | echo mips-nec-sysv"$UNAME_RELEASE" | |
1214 | 1239 | else |
1215 | echo mips-unknown-sysv${UNAME_RELEASE} | |
1240 | echo mips-unknown-sysv"$UNAME_RELEASE" | |
1216 | 1241 | fi |
1217 | 1242 | exit ;; |
1218 | 1243 | BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. |
1231 | 1256 | echo x86_64-unknown-haiku |
1232 | 1257 | exit ;; |
1233 | 1258 | SX-4:SUPER-UX:*:*) |
1234 | echo sx4-nec-superux${UNAME_RELEASE} | |
1259 | echo sx4-nec-superux"$UNAME_RELEASE" | |
1235 | 1260 | exit ;; |
1236 | 1261 | SX-5:SUPER-UX:*:*) |
1237 | echo sx5-nec-superux${UNAME_RELEASE} | |
1262 | echo sx5-nec-superux"$UNAME_RELEASE" | |
1238 | 1263 | exit ;; |
1239 | 1264 | SX-6:SUPER-UX:*:*) |
1240 | echo sx6-nec-superux${UNAME_RELEASE} | |
1265 | echo sx6-nec-superux"$UNAME_RELEASE" | |
1241 | 1266 | exit ;; |
1242 | 1267 | SX-7:SUPER-UX:*:*) |
1243 | echo sx7-nec-superux${UNAME_RELEASE} | |
1268 | echo sx7-nec-superux"$UNAME_RELEASE" | |
1244 | 1269 | exit ;; |
1245 | 1270 | SX-8:SUPER-UX:*:*) |
1246 | echo sx8-nec-superux${UNAME_RELEASE} | |
1271 | echo sx8-nec-superux"$UNAME_RELEASE" | |
1247 | 1272 | exit ;; |
1248 | 1273 | SX-8R:SUPER-UX:*:*) |
1249 | echo sx8r-nec-superux${UNAME_RELEASE} | |
1274 | echo sx8r-nec-superux"$UNAME_RELEASE" | |
1275 | exit ;; | |
1276 | SX-ACE:SUPER-UX:*:*) | |
1277 | echo sxace-nec-superux"$UNAME_RELEASE" | |
1250 | 1278 | exit ;; |
1251 | 1279 | Power*:Rhapsody:*:*) |
1252 | echo powerpc-apple-rhapsody${UNAME_RELEASE} | |
1280 | echo powerpc-apple-rhapsody"$UNAME_RELEASE" | |
1253 | 1281 | exit ;; |
1254 | 1282 | *:Rhapsody:*:*) |
1255 | echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} | |
1283 | echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" | |
1256 | 1284 | exit ;; |
1257 | 1285 | *:Darwin:*:*) |
1258 | 1286 | UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown |
1259 | eval $set_cc_for_build | |
1287 | eval "$set_cc_for_build" | |
1260 | 1288 | if test "$UNAME_PROCESSOR" = unknown ; then |
1261 | 1289 | UNAME_PROCESSOR=powerpc |
1262 | 1290 | fi |
1263 | if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then | |
1264 | if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then | |
1291 | if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then | |
1292 | if [ "$CC_FOR_BUILD" != no_compiler_found ]; then | |
1265 | 1293 | if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ |
1266 | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ | |
1267 | grep IS_64BIT_ARCH >/dev/null | |
1294 | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ | |
1295 | grep IS_64BIT_ARCH >/dev/null | |
1268 | 1296 | then |
1269 | 1297 | case $UNAME_PROCESSOR in |
1270 | 1298 | i386) UNAME_PROCESSOR=x86_64 ;; |
1271 | 1299 | powerpc) UNAME_PROCESSOR=powerpc64 ;; |
1272 | 1300 | esac |
1301 | fi | |
1302 | # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc | |
1303 | if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ | |
1304 | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ | |
1305 | grep IS_PPC >/dev/null | |
1306 | then | |
1307 | UNAME_PROCESSOR=powerpc | |
1273 | 1308 | fi |
1274 | 1309 | fi |
1275 | 1310 | elif test "$UNAME_PROCESSOR" = i386 ; then |
1281 | 1316 | # that Apple uses in portable devices. |
1282 | 1317 | UNAME_PROCESSOR=x86_64 |
1283 | 1318 | fi |
1284 | echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} | |
1319 | echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" | |
1285 | 1320 | exit ;; |
1286 | 1321 | *:procnto*:*:* | *:QNX:[0123456789]*:*) |
1287 | 1322 | UNAME_PROCESSOR=`uname -p` |
1288 | if test "$UNAME_PROCESSOR" = "x86"; then | |
1323 | if test "$UNAME_PROCESSOR" = x86; then | |
1289 | 1324 | UNAME_PROCESSOR=i386 |
1290 | 1325 | UNAME_MACHINE=pc |
1291 | 1326 | fi |
1292 | echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} | |
1327 | echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" | |
1293 | 1328 | exit ;; |
1294 | 1329 | *:QNX:*:4*) |
1295 | 1330 | echo i386-pc-qnx |
1296 | 1331 | exit ;; |
1297 | NEO-?:NONSTOP_KERNEL:*:*) | |
1298 | echo neo-tandem-nsk${UNAME_RELEASE} | |
1332 | NEO-*:NONSTOP_KERNEL:*:*) | |
1333 | echo neo-tandem-nsk"$UNAME_RELEASE" | |
1299 | 1334 | exit ;; |
1300 | 1335 | NSE-*:NONSTOP_KERNEL:*:*) |
1301 | echo nse-tandem-nsk${UNAME_RELEASE} | |
1302 | exit ;; | |
1303 | NSR-?:NONSTOP_KERNEL:*:*) | |
1304 | echo nsr-tandem-nsk${UNAME_RELEASE} | |
1336 | echo nse-tandem-nsk"$UNAME_RELEASE" | |
1337 | exit ;; | |
1338 | NSR-*:NONSTOP_KERNEL:*:*) | |
1339 | echo nsr-tandem-nsk"$UNAME_RELEASE" | |
1340 | exit ;; | |
1341 | NSV-*:NONSTOP_KERNEL:*:*) | |
1342 | echo nsv-tandem-nsk"$UNAME_RELEASE" | |
1343 | exit ;; | |
1344 | NSX-*:NONSTOP_KERNEL:*:*) | |
1345 | echo nsx-tandem-nsk"$UNAME_RELEASE" | |
1305 | 1346 | exit ;; |
1306 | 1347 | *:NonStop-UX:*:*) |
1307 | 1348 | echo mips-compaq-nonstopux |
1310 | 1351 | echo bs2000-siemens-sysv |
1311 | 1352 | exit ;; |
1312 | 1353 | DS/*:UNIX_System_V:*:*) |
1313 | echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} | |
1354 | echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" | |
1314 | 1355 | exit ;; |
1315 | 1356 | *:Plan9:*:*) |
1316 | 1357 | # "uname -m" is not consistent, so use $cputype instead. 386 |
1317 | 1358 | # is converted to i386 for consistency with other x86 |
1318 | 1359 | # operating systems. |
1319 | if test "$cputype" = "386"; then | |
1360 | if test "$cputype" = 386; then | |
1320 | 1361 | UNAME_MACHINE=i386 |
1321 | 1362 | else |
1322 | 1363 | UNAME_MACHINE="$cputype" |
1323 | 1364 | fi |
1324 | echo ${UNAME_MACHINE}-unknown-plan9 | |
1365 | echo "$UNAME_MACHINE"-unknown-plan9 | |
1325 | 1366 | exit ;; |
1326 | 1367 | *:TOPS-10:*:*) |
1327 | 1368 | echo pdp10-unknown-tops10 |
1342 | 1383 | echo pdp10-unknown-its |
1343 | 1384 | exit ;; |
1344 | 1385 | SEI:*:*:SEIUX) |
1345 | echo mips-sei-seiux${UNAME_RELEASE} | |
1386 | echo mips-sei-seiux"$UNAME_RELEASE" | |
1346 | 1387 | exit ;; |
1347 | 1388 | *:DragonFly:*:*) |
1348 | echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` | |
1389 | echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" | |
1349 | 1390 | exit ;; |
1350 | 1391 | *:*VMS:*:*) |
1351 | 1392 | UNAME_MACHINE=`(uname -p) 2>/dev/null` |
1352 | case "${UNAME_MACHINE}" in | |
1393 | case "$UNAME_MACHINE" in | |
1353 | 1394 | A*) echo alpha-dec-vms ; exit ;; |
1354 | 1395 | I*) echo ia64-dec-vms ; exit ;; |
1355 | 1396 | V*) echo vax-dec-vms ; exit ;; |
1358 | 1399 | echo i386-pc-xenix |
1359 | 1400 | exit ;; |
1360 | 1401 | i*86:skyos:*:*) |
1361 | echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' | |
1402 | echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`" | |
1362 | 1403 | exit ;; |
1363 | 1404 | i*86:rdos:*:*) |
1364 | echo ${UNAME_MACHINE}-pc-rdos | |
1405 | echo "$UNAME_MACHINE"-pc-rdos | |
1365 | 1406 | exit ;; |
1366 | 1407 | i*86:AROS:*:*) |
1367 | echo ${UNAME_MACHINE}-pc-aros | |
1408 | echo "$UNAME_MACHINE"-pc-aros | |
1368 | 1409 | exit ;; |
1369 | 1410 | x86_64:VMkernel:*:*) |
1370 | echo ${UNAME_MACHINE}-unknown-esx | |
1411 | echo "$UNAME_MACHINE"-unknown-esx | |
1412 | exit ;; | |
1413 | amd64:Isilon\ OneFS:*:*) | |
1414 | echo x86_64-unknown-onefs | |
1371 | 1415 | exit ;; |
1372 | 1416 | esac |
1373 | 1417 | |
1418 | echo "$0: unable to guess system type" >&2 | |
1419 | ||
1420 | case "$UNAME_MACHINE:$UNAME_SYSTEM" in | |
1421 | mips:Linux | mips64:Linux) | |
1422 | # If we got here on MIPS GNU/Linux, output extra information. | |
1423 | cat >&2 <<EOF | |
1424 | ||
1425 | NOTE: MIPS GNU/Linux systems require a C compiler to fully recognize | |
1426 | the system type. Please install a C compiler and try again. | |
1427 | EOF | |
1428 | ;; | |
1429 | esac | |
1430 | ||
1374 | 1431 | cat >&2 <<EOF |
1375 | $0: unable to guess system type | |
1376 | ||
1377 | This script, last modified $timestamp, has failed to recognize | |
1378 | the operating system you are using. It is advised that you | |
1379 | download the most up to date version of the config scripts from | |
1380 | ||
1381 | http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD | |
1432 | ||
1433 | This script (version $timestamp), has failed to recognize the | |
1434 | operating system you are using. If your script is old, overwrite *all* | |
1435 | copies of config.guess and config.sub with the latest versions from: | |
1436 | ||
1437 | https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess | |
1382 | 1438 | and |
1383 | http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD | |
1384 | ||
1385 | If the version you run ($0) is already up to date, please | |
1386 | send the following data and any information you think might be | |
1387 | pertinent to <config-patches@gnu.org> in order to provide the needed | |
1388 | information to handle your system. | |
1439 | https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub | |
1440 | ||
1441 | If $0 has already been updated, send the following data and any | |
1442 | information you think might be pertinent to config-patches@gnu.org to | |
1443 | provide the necessary information to handle your system. | |
1389 | 1444 | |
1390 | 1445 | config.guess timestamp = $timestamp |
1391 | 1446 | |
1404 | 1459 | /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` |
1405 | 1460 | /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` |
1406 | 1461 | |
1407 | UNAME_MACHINE = ${UNAME_MACHINE} | |
1408 | UNAME_RELEASE = ${UNAME_RELEASE} | |
1409 | UNAME_SYSTEM = ${UNAME_SYSTEM} | |
1410 | UNAME_VERSION = ${UNAME_VERSION} | |
1462 | UNAME_MACHINE = "$UNAME_MACHINE" | |
1463 | UNAME_RELEASE = "$UNAME_RELEASE" | |
1464 | UNAME_SYSTEM = "$UNAME_SYSTEM" | |
1465 | UNAME_VERSION = "$UNAME_VERSION" | |
1411 | 1466 | EOF |
1412 | 1467 | |
1413 | 1468 | exit 1 |
1414 | 1469 | |
1415 | 1470 | # Local variables: |
1416 | # eval: (add-hook 'write-file-hooks 'time-stamp) | |
1471 | # eval: (add-hook 'before-save-hook 'time-stamp) | |
1417 | 1472 | # time-stamp-start: "timestamp='" |
1418 | 1473 | # time-stamp-format: "%:y-%02m-%02d" |
1419 | 1474 | # time-stamp-end: "'" |
17 | 17 | /* found fribidi via pkg-config */ |
18 | 18 | #undef CONFIG_FRIBIDI |
19 | 19 | |
20 | /* found harfbuzz-ng via pkg-config */ | |
20 | /* found harfbuzz via pkg-config */ | |
21 | 21 | #undef CONFIG_HARFBUZZ |
22 | 22 | |
23 | 23 | /* use iconv */ |
0 | 0 | #! /bin/sh |
1 | 1 | # Configuration validation subroutine script. |
2 | # Copyright 1992-2014 Free Software Foundation, Inc. | |
3 | ||
4 | timestamp='2014-12-03' | |
2 | # Copyright 1992-2018 Free Software Foundation, Inc. | |
3 | ||
4 | timestamp='2018-03-08' | |
5 | 5 | |
6 | 6 | # This file is free software; you can redistribute it and/or modify it |
7 | 7 | # under the terms of the GNU General Public License as published by |
14 | 14 | # General Public License for more details. |
15 | 15 | # |
16 | 16 | # You should have received a copy of the GNU General Public License |
17 | # along with this program; if not, see <http://www.gnu.org/licenses/>. | |
17 | # along with this program; if not, see <https://www.gnu.org/licenses/>. | |
18 | 18 | # |
19 | 19 | # As a special exception to the GNU General Public License, if you |
20 | 20 | # distribute this file as part of a program that contains a |
32 | 32 | # Otherwise, we print the canonical config type on stdout and succeed. |
33 | 33 | |
34 | 34 | # You can get the latest version of this script from: |
35 | # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD | |
35 | # https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub | |
36 | 36 | |
37 | 37 | # This file is supposed to be the same for all GNU packages |
38 | 38 | # and recognize all the CPU types, system types and aliases |
52 | 52 | me=`echo "$0" | sed -e 's,.*/,,'` |
53 | 53 | |
54 | 54 | usage="\ |
55 | Usage: $0 [OPTION] CPU-MFR-OPSYS | |
56 | $0 [OPTION] ALIAS | |
55 | Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS | |
57 | 56 | |
58 | 57 | Canonicalize a configuration name. |
59 | 58 | |
60 | Operation modes: | |
59 | Options: | |
61 | 60 | -h, --help print this help, then exit |
62 | 61 | -t, --time-stamp print date of last modification, then exit |
63 | 62 | -v, --version print version number, then exit |
67 | 66 | version="\ |
68 | 67 | GNU config.sub ($timestamp) |
69 | 68 | |
70 | Copyright 1992-2014 Free Software Foundation, Inc. | |
69 | Copyright 1992-2018 Free Software Foundation, Inc. | |
71 | 70 | |
72 | 71 | This is free software; see the source for copying conditions. There is NO |
73 | 72 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." |
94 | 93 | |
95 | 94 | *local*) |
96 | 95 | # First pass through any local machine types. |
97 | echo $1 | |
96 | echo "$1" | |
98 | 97 | exit ;; |
99 | 98 | |
100 | 99 | * ) |
112 | 111 | |
113 | 112 | # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). |
114 | 113 | # Here we must recognize all the valid KERNEL-OS combinations. |
115 | maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` | |
114 | maybe_os=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` | |
116 | 115 | case $maybe_os in |
117 | 116 | nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ |
118 | 117 | linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ |
119 | knetbsd*-gnu* | netbsd*-gnu* | \ | |
120 | kopensolaris*-gnu* | \ | |
118 | knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ | |
119 | kopensolaris*-gnu* | cloudabi*-eabi* | \ | |
121 | 120 | storm-chaos* | os2-emx* | rtmk-nova*) |
122 | 121 | os=-$maybe_os |
123 | basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` | |
122 | basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` | |
124 | 123 | ;; |
125 | 124 | android-linux) |
126 | 125 | os=-linux-android |
127 | basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown | |
126 | basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown | |
128 | 127 | ;; |
129 | 128 | *) |
130 | basic_machine=`echo $1 | sed 's/-[^-]*$//'` | |
131 | if [ $basic_machine != $1 ] | |
132 | then os=`echo $1 | sed 's/.*-/-/'` | |
129 | basic_machine=`echo "$1" | sed 's/-[^-]*$//'` | |
130 | if [ "$basic_machine" != "$1" ] | |
131 | then os=`echo "$1" | sed 's/.*-/-/'` | |
133 | 132 | else os=; fi |
134 | 133 | ;; |
135 | 134 | esac |
178 | 177 | ;; |
179 | 178 | -sco6) |
180 | 179 | os=-sco5v6 |
181 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` | |
180 | basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` | |
182 | 181 | ;; |
183 | 182 | -sco5) |
184 | 183 | os=-sco3.2v5 |
185 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` | |
184 | basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` | |
186 | 185 | ;; |
187 | 186 | -sco4) |
188 | 187 | os=-sco3.2v4 |
189 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` | |
188 | basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` | |
190 | 189 | ;; |
191 | 190 | -sco3.2.[4-9]*) |
192 | 191 | os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` |
193 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` | |
192 | basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` | |
194 | 193 | ;; |
195 | 194 | -sco3.2v[4-9]*) |
196 | 195 | # Don't forget version if it is 3.2v4 or newer. |
197 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` | |
196 | basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` | |
198 | 197 | ;; |
199 | 198 | -sco5v6*) |
200 | 199 | # Don't forget version if it is 3.2v4 or newer. |
201 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` | |
200 | basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` | |
202 | 201 | ;; |
203 | 202 | -sco*) |
204 | 203 | os=-sco3.2v2 |
205 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` | |
204 | basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` | |
206 | 205 | ;; |
207 | 206 | -udk*) |
208 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` | |
207 | basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` | |
209 | 208 | ;; |
210 | 209 | -isc) |
211 | 210 | os=-isc2.2 |
212 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` | |
211 | basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` | |
213 | 212 | ;; |
214 | 213 | -clix*) |
215 | 214 | basic_machine=clipper-intergraph |
216 | 215 | ;; |
217 | 216 | -isc*) |
218 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` | |
217 | basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` | |
219 | 218 | ;; |
220 | 219 | -lynx*178) |
221 | 220 | os=-lynxos178 |
227 | 226 | os=-lynxos |
228 | 227 | ;; |
229 | 228 | -ptx*) |
230 | basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` | |
231 | ;; | |
232 | -windowsnt*) | |
233 | os=`echo $os | sed -e 's/windowsnt/winnt/'` | |
229 | basic_machine=`echo "$1" | sed -e 's/86-.*/86-sequent/'` | |
234 | 230 | ;; |
235 | 231 | -psos*) |
236 | 232 | os=-psos |
254 | 250 | | arc | arceb \ |
255 | 251 | | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ |
256 | 252 | | avr | avr32 \ |
253 | | ba \ | |
257 | 254 | | be32 | be64 \ |
258 | 255 | | bfin \ |
259 | 256 | | c4x | c8051 | clipper \ |
260 | 257 | | d10v | d30v | dlx | dsp16xx \ |
261 | | epiphany \ | |
262 | | fido | fr30 | frv \ | |
258 | | e2k | epiphany \ | |
259 | | fido | fr30 | frv | ft32 \ | |
263 | 260 | | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ |
264 | 261 | | hexagon \ |
265 | | i370 | i860 | i960 | ia64 \ | |
262 | | i370 | i860 | i960 | ia16 | ia64 \ | |
266 | 263 | | ip2k | iq2000 \ |
267 | 264 | | k1om \ |
268 | 265 | | le32 | le64 \ |
298 | 295 | | nios | nios2 | nios2eb | nios2el \ |
299 | 296 | | ns16k | ns32k \ |
300 | 297 | | open8 | or1k | or1knd | or32 \ |
301 | | pdp10 | pdp11 | pj | pjl \ | |
298 | | pdp10 | pj | pjl \ | |
302 | 299 | | powerpc | powerpc64 | powerpc64le | powerpcle \ |
300 | | pru \ | |
303 | 301 | | pyramid \ |
304 | 302 | | riscv32 | riscv64 \ |
305 | 303 | | rl78 | rx \ |
306 | 304 | | score \ |
307 | | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | |
305 | | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | |
308 | 306 | | sh64 | sh64le \ |
309 | 307 | | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ |
310 | 308 | | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ |
313 | 311 | | ubicom32 \ |
314 | 312 | | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ |
315 | 313 | | visium \ |
316 | | we32k \ | |
314 | | wasm32 \ | |
317 | 315 | | x86 | xc16x | xstormy16 | xtensa \ |
318 | 316 | | z8k | z80) |
319 | 317 | basic_machine=$basic_machine-unknown |
334 | 332 | basic_machine=$basic_machine-unknown |
335 | 333 | os=-none |
336 | 334 | ;; |
337 | m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) | |
335 | m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65) | |
338 | 336 | ;; |
339 | 337 | ms1) |
340 | 338 | basic_machine=mt-unknown |
363 | 361 | ;; |
364 | 362 | # Object if more than one company name word. |
365 | 363 | *-*-*) |
366 | echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 | |
364 | echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 | |
367 | 365 | exit 1 |
368 | 366 | ;; |
369 | 367 | # Recognize the basic CPU types with company name. |
375 | 373 | | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ |
376 | 374 | | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ |
377 | 375 | | avr-* | avr32-* \ |
376 | | ba-* \ | |
378 | 377 | | be32-* | be64-* \ |
379 | 378 | | bfin-* | bs2000-* \ |
380 | 379 | | c[123]* | c30-* | [cjt]90-* | c4x-* \ |
381 | 380 | | c8051-* | clipper-* | craynv-* | cydra-* \ |
382 | 381 | | d10v-* | d30v-* | dlx-* \ |
383 | | elxsi-* \ | |
382 | | e2k-* | elxsi-* \ | |
384 | 383 | | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ |
385 | 384 | | h8300-* | h8500-* \ |
386 | 385 | | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ |
387 | 386 | | hexagon-* \ |
388 | | i*86-* | i860-* | i960-* | ia64-* \ | |
387 | | i*86-* | i860-* | i960-* | ia16-* | ia64-* \ | |
389 | 388 | | ip2k-* | iq2000-* \ |
390 | 389 | | k1om-* \ |
391 | 390 | | le32-* | le64-* \ |
426 | 425 | | orion-* \ |
427 | 426 | | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ |
428 | 427 | | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ |
428 | | pru-* \ | |
429 | 429 | | pyramid-* \ |
430 | | riscv32-* | riscv64-* \ | |
430 | 431 | | rl78-* | romp-* | rs6000-* | rx-* \ |
431 | 432 | | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ |
432 | 433 | | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ |
433 | 434 | | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ |
434 | 435 | | sparclite-* \ |
435 | | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | |
436 | | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ | |
436 | 437 | | tahoe-* \ |
437 | 438 | | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ |
438 | 439 | | tile*-* \ |
441 | 442 | | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ |
442 | 443 | | vax-* \ |
443 | 444 | | visium-* \ |
445 | | wasm32-* \ | |
444 | 446 | | we32k-* \ |
445 | 447 | | x86-* | x86_64-* | xc16x-* | xps100-* \ |
446 | 448 | | xstormy16-* | xtensa*-* \ |
454 | 456 | # Recognize the various machine names and aliases which stand |
455 | 457 | # for a CPU type and a company and sometimes even an OS. |
456 | 458 | 386bsd) |
457 | basic_machine=i386-unknown | |
459 | basic_machine=i386-pc | |
458 | 460 | os=-bsd |
459 | 461 | ;; |
460 | 462 | 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) |
488 | 490 | basic_machine=x86_64-pc |
489 | 491 | ;; |
490 | 492 | amd64-*) |
491 | basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` | |
493 | basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
492 | 494 | ;; |
493 | 495 | amdahl) |
494 | 496 | basic_machine=580-amdahl |
517 | 519 | basic_machine=i386-pc |
518 | 520 | os=-aros |
519 | 521 | ;; |
522 | asmjs) | |
523 | basic_machine=asmjs-unknown | |
524 | ;; | |
520 | 525 | aux) |
521 | 526 | basic_machine=m68k-apple |
522 | 527 | os=-aux |
530 | 535 | os=-linux |
531 | 536 | ;; |
532 | 537 | blackfin-*) |
533 | basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` | |
538 | basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
534 | 539 | os=-linux |
535 | 540 | ;; |
536 | 541 | bluegene*) |
538 | 543 | os=-cnk |
539 | 544 | ;; |
540 | 545 | c54x-*) |
541 | basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` | |
546 | basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
542 | 547 | ;; |
543 | 548 | c55x-*) |
544 | basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` | |
549 | basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
545 | 550 | ;; |
546 | 551 | c6x-*) |
547 | basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` | |
552 | basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
548 | 553 | ;; |
549 | 554 | c90) |
550 | 555 | basic_machine=c90-cray |
633 | 638 | basic_machine=rs6000-bull |
634 | 639 | os=-bosx |
635 | 640 | ;; |
636 | dpx2* | dpx2*-bull) | |
641 | dpx2*) | |
637 | 642 | basic_machine=m68k-bull |
638 | 643 | os=-sysv3 |
644 | ;; | |
645 | e500v[12]) | |
646 | basic_machine=powerpc-unknown | |
647 | os=$os"spe" | |
648 | ;; | |
649 | e500v[12]-*) | |
650 | basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
651 | os=$os"spe" | |
639 | 652 | ;; |
640 | 653 | ebmon29k) |
641 | 654 | basic_machine=a29k-amd |
726 | 739 | hp9k8[0-9][0-9] | hp8[0-9][0-9]) |
727 | 740 | basic_machine=hppa1.0-hp |
728 | 741 | ;; |
729 | hppa-next) | |
730 | os=-nextstep3 | |
731 | ;; | |
732 | 742 | hppaosf) |
733 | 743 | basic_machine=hppa1.1-hp |
734 | 744 | os=-osf |
741 | 751 | basic_machine=i370-ibm |
742 | 752 | ;; |
743 | 753 | i*86v32) |
744 | basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` | |
754 | basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` | |
745 | 755 | os=-sysv32 |
746 | 756 | ;; |
747 | 757 | i*86v4*) |
748 | basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` | |
758 | basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` | |
749 | 759 | os=-sysv4 |
750 | 760 | ;; |
751 | 761 | i*86v) |
752 | basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` | |
762 | basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` | |
753 | 763 | os=-sysv |
754 | 764 | ;; |
755 | 765 | i*86sol2) |
756 | basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` | |
766 | basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` | |
757 | 767 | os=-solaris2 |
758 | 768 | ;; |
759 | 769 | i386mach) |
760 | 770 | basic_machine=i386-mach |
761 | 771 | os=-mach |
762 | 772 | ;; |
763 | i386-vsta | vsta) | |
773 | vsta) | |
764 | 774 | basic_machine=i386-unknown |
765 | 775 | os=-vsta |
766 | 776 | ;; |
779 | 789 | os=-sysv |
780 | 790 | ;; |
781 | 791 | leon-*|leon[3-9]-*) |
782 | basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` | |
792 | basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'` | |
783 | 793 | ;; |
784 | 794 | m68knommu) |
785 | 795 | basic_machine=m68k-unknown |
786 | 796 | os=-linux |
787 | 797 | ;; |
788 | 798 | m68knommu-*) |
789 | basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` | |
799 | basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
790 | 800 | os=-linux |
791 | ;; | |
792 | m88k-omron*) | |
793 | basic_machine=m88k-omron | |
794 | 801 | ;; |
795 | 802 | magnum | m3230) |
796 | 803 | basic_machine=mips-mips |
823 | 830 | os=-mint |
824 | 831 | ;; |
825 | 832 | mips3*-*) |
826 | basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` | |
833 | basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'` | |
827 | 834 | ;; |
828 | 835 | mips3*) |
829 | basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown | |
836 | basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown | |
830 | 837 | ;; |
831 | 838 | monitor) |
832 | 839 | basic_machine=m68k-rom68k |
845 | 852 | os=-msdos |
846 | 853 | ;; |
847 | 854 | ms1-*) |
848 | basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` | |
855 | basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'` | |
849 | 856 | ;; |
850 | 857 | msys) |
851 | 858 | basic_machine=i686-pc |
887 | 894 | basic_machine=v70-nec |
888 | 895 | os=-sysv |
889 | 896 | ;; |
890 | next | m*-next ) | |
897 | next | m*-next) | |
891 | 898 | basic_machine=m68k-next |
892 | 899 | case $os in |
893 | 900 | -nextstep* ) |
932 | 939 | nsr-tandem) |
933 | 940 | basic_machine=nsr-tandem |
934 | 941 | ;; |
942 | nsv-tandem) | |
943 | basic_machine=nsv-tandem | |
944 | ;; | |
945 | nsx-tandem) | |
946 | basic_machine=nsx-tandem | |
947 | ;; | |
935 | 948 | op50n-* | op60c-*) |
936 | 949 | basic_machine=hppa1.1-oki |
937 | 950 | os=-proelf |
964 | 977 | os=-linux |
965 | 978 | ;; |
966 | 979 | parisc-*) |
967 | basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` | |
980 | basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
968 | 981 | os=-linux |
969 | 982 | ;; |
970 | 983 | pbd) |
980 | 993 | basic_machine=i386-pc |
981 | 994 | ;; |
982 | 995 | pc98-*) |
983 | basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` | |
996 | basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
984 | 997 | ;; |
985 | 998 | pentium | p5 | k5 | k6 | nexgen | viac3) |
986 | 999 | basic_machine=i586-pc |
995 | 1008 | basic_machine=i786-pc |
996 | 1009 | ;; |
997 | 1010 | pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) |
998 | basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` | |
1011 | basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
999 | 1012 | ;; |
1000 | 1013 | pentiumpro-* | p6-* | 6x86-* | athlon-*) |
1001 | basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` | |
1014 | basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
1002 | 1015 | ;; |
1003 | 1016 | pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) |
1004 | basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` | |
1017 | basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
1005 | 1018 | ;; |
1006 | 1019 | pentium4-*) |
1007 | basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` | |
1020 | basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
1008 | 1021 | ;; |
1009 | 1022 | pn) |
1010 | 1023 | basic_machine=pn-gould |
1014 | 1027 | ppc | ppcbe) basic_machine=powerpc-unknown |
1015 | 1028 | ;; |
1016 | 1029 | ppc-* | ppcbe-*) |
1017 | basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` | |
1018 | ;; | |
1019 | ppcle | powerpclittle | ppc-le | powerpc-little) | |
1030 | basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
1031 | ;; | |
1032 | ppcle | powerpclittle) | |
1020 | 1033 | basic_machine=powerpcle-unknown |
1021 | 1034 | ;; |
1022 | 1035 | ppcle-* | powerpclittle-*) |
1023 | basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` | |
1036 | basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
1024 | 1037 | ;; |
1025 | 1038 | ppc64) basic_machine=powerpc64-unknown |
1026 | 1039 | ;; |
1027 | ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` | |
1028 | ;; | |
1029 | ppc64le | powerpc64little | ppc64-le | powerpc64-little) | |
1040 | ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
1041 | ;; | |
1042 | ppc64le | powerpc64little) | |
1030 | 1043 | basic_machine=powerpc64le-unknown |
1031 | 1044 | ;; |
1032 | 1045 | ppc64le-* | powerpc64little-*) |
1033 | basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` | |
1046 | basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
1034 | 1047 | ;; |
1035 | 1048 | ps2) |
1036 | 1049 | basic_machine=i386-ibm |
1084 | 1097 | sequent) |
1085 | 1098 | basic_machine=i386-sequent |
1086 | 1099 | ;; |
1087 | sh) | |
1088 | basic_machine=sh-hitachi | |
1089 | os=-hms | |
1090 | ;; | |
1091 | 1100 | sh5el) |
1092 | 1101 | basic_machine=sh5le-unknown |
1093 | 1102 | ;; |
1094 | sh64) | |
1095 | basic_machine=sh64-unknown | |
1096 | ;; | |
1097 | sparclite-wrs | simso-wrs) | |
1103 | simso-wrs) | |
1098 | 1104 | basic_machine=sparclite-wrs |
1099 | 1105 | os=-vxworks |
1100 | 1106 | ;; |
1113 | 1119 | os=-sysv4 |
1114 | 1120 | ;; |
1115 | 1121 | strongarm-* | thumb-*) |
1116 | basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` | |
1122 | basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'` | |
1117 | 1123 | ;; |
1118 | 1124 | sun2) |
1119 | 1125 | basic_machine=m68000-sun |
1235 | 1241 | basic_machine=hppa1.1-winbond |
1236 | 1242 | os=-proelf |
1237 | 1243 | ;; |
1244 | x64) | |
1245 | basic_machine=x86_64-pc | |
1246 | ;; | |
1238 | 1247 | xbox) |
1239 | 1248 | basic_machine=i686-pc |
1240 | 1249 | os=-mingw32 |
1243 | 1252 | basic_machine=xps100-honeywell |
1244 | 1253 | ;; |
1245 | 1254 | xscale-* | xscalee[bl]-*) |
1246 | basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` | |
1255 | basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'` | |
1247 | 1256 | ;; |
1248 | 1257 | ymp) |
1249 | 1258 | basic_machine=ymp-cray |
1250 | 1259 | os=-unicos |
1251 | ;; | |
1252 | z8k-*-coff) | |
1253 | basic_machine=z8k-unknown | |
1254 | os=-sim | |
1255 | ;; | |
1256 | z80-*-coff) | |
1257 | basic_machine=z80-unknown | |
1258 | os=-sim | |
1259 | 1260 | ;; |
1260 | 1261 | none) |
1261 | 1262 | basic_machine=none-none |
1285 | 1286 | vax) |
1286 | 1287 | basic_machine=vax-dec |
1287 | 1288 | ;; |
1288 | pdp10) | |
1289 | # there are many clones, so DEC is not a safe bet | |
1290 | basic_machine=pdp10-unknown | |
1291 | ;; | |
1292 | 1289 | pdp11) |
1293 | 1290 | basic_machine=pdp11-dec |
1294 | 1291 | ;; |
1298 | 1295 | sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) |
1299 | 1296 | basic_machine=sh-unknown |
1300 | 1297 | ;; |
1301 | sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) | |
1302 | basic_machine=sparc-sun | |
1303 | ;; | |
1304 | 1298 | cydra) |
1305 | 1299 | basic_machine=cydra-cydrome |
1306 | 1300 | ;; |
1320 | 1314 | # Make sure to match an already-canonicalized machine name. |
1321 | 1315 | ;; |
1322 | 1316 | *) |
1323 | echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 | |
1317 | echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 | |
1324 | 1318 | exit 1 |
1325 | 1319 | ;; |
1326 | 1320 | esac |
1328 | 1322 | # Here we canonicalize certain aliases for manufacturers. |
1329 | 1323 | case $basic_machine in |
1330 | 1324 | *-digital*) |
1331 | basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` | |
1325 | basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'` | |
1332 | 1326 | ;; |
1333 | 1327 | *-commodore*) |
1334 | basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` | |
1328 | basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'` | |
1335 | 1329 | ;; |
1336 | 1330 | *) |
1337 | 1331 | ;; |
1342 | 1336 | if [ x"$os" != x"" ] |
1343 | 1337 | then |
1344 | 1338 | case $os in |
1345 | # First match some system type aliases | |
1346 | # that might get confused with valid system types. | |
1339 | # First match some system type aliases that might get confused | |
1340 | # with valid system types. | |
1347 | 1341 | # -solaris* is a basic system type, with this one exception. |
1348 | 1342 | -auroraux) |
1349 | 1343 | os=-auroraux |
1354 | 1348 | -solaris) |
1355 | 1349 | os=-solaris2 |
1356 | 1350 | ;; |
1357 | -svr4*) | |
1358 | os=-sysv4 | |
1359 | ;; | |
1360 | 1351 | -unixware*) |
1361 | 1352 | os=-sysv4.2uw |
1362 | 1353 | ;; |
1363 | 1354 | -gnu/linux*) |
1364 | 1355 | os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` |
1365 | 1356 | ;; |
1366 | # First accept the basic system types. | |
1357 | # es1800 is here to avoid being matched by es* (a different OS) | |
1358 | -es1800*) | |
1359 | os=-ose | |
1360 | ;; | |
1361 | # Now accept the basic system types. | |
1367 | 1362 | # The portable systems comes first. |
1368 | # Each alternative MUST END IN A *, to match a version number. | |
1363 | # Each alternative MUST end in a * to match a version number. | |
1369 | 1364 | # -sysv* is not here because it comes later, after sysvr4. |
1370 | 1365 | -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ |
1371 | 1366 | | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ |
1372 | 1367 | | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ |
1373 | 1368 | | -sym* | -kopensolaris* | -plan9* \ |
1374 | 1369 | | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ |
1375 | | -aos* | -aros* \ | |
1370 | | -aos* | -aros* | -cloudabi* | -sortix* \ | |
1376 | 1371 | | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ |
1377 | 1372 | | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ |
1378 | | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | |
1379 | | -bitrig* | -openbsd* | -solidbsd* \ | |
1373 | | -hiux* | -knetbsd* | -mirbsd* | -netbsd* \ | |
1374 | | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ | |
1380 | 1375 | | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ |
1381 | 1376 | | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ |
1382 | 1377 | | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ |
1383 | | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | |
1384 | | -chorusos* | -chorusrdb* | -cegcc* \ | |
1378 | | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* | -hcos* \ | |
1379 | | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ | |
1385 | 1380 | | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ |
1386 | | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | |
1381 | | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | |
1387 | 1382 | | -linux-newlib* | -linux-musl* | -linux-uclibc* \ |
1388 | 1383 | | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ |
1389 | | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | |
1384 | | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* \ | |
1390 | 1385 | | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ |
1391 | 1386 | | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ |
1392 | 1387 | | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ |
1393 | | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | |
1388 | | -morphos* | -superux* | -rtmk* | -windiss* \ | |
1394 | 1389 | | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ |
1395 | | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) | |
1390 | | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ | |
1391 | | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox* | -bme* \ | |
1392 | | -midnightbsd*) | |
1396 | 1393 | # Remember, each alternative MUST END IN *, to match a version number. |
1397 | 1394 | ;; |
1398 | 1395 | -qnx*) |
1409 | 1406 | -nto*) |
1410 | 1407 | os=`echo $os | sed -e 's|nto|nto-qnx|'` |
1411 | 1408 | ;; |
1412 | -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | |
1413 | | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | |
1409 | -sim | -xray | -os68k* | -v88r* \ | |
1410 | | -windows* | -osx | -abug | -netware* | -os9* \ | |
1414 | 1411 | | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) |
1415 | 1412 | ;; |
1416 | 1413 | -mac*) |
1417 | os=`echo $os | sed -e 's|mac|macos|'` | |
1414 | os=`echo "$os" | sed -e 's|mac|macos|'` | |
1418 | 1415 | ;; |
1419 | 1416 | -linux-dietlibc) |
1420 | 1417 | os=-linux-dietlibc |
1423 | 1420 | os=`echo $os | sed -e 's|linux|linux-gnu|'` |
1424 | 1421 | ;; |
1425 | 1422 | -sunos5*) |
1426 | os=`echo $os | sed -e 's|sunos5|solaris2|'` | |
1423 | os=`echo "$os" | sed -e 's|sunos5|solaris2|'` | |
1427 | 1424 | ;; |
1428 | 1425 | -sunos6*) |
1429 | os=`echo $os | sed -e 's|sunos6|solaris3|'` | |
1426 | os=`echo "$os" | sed -e 's|sunos6|solaris3|'` | |
1430 | 1427 | ;; |
1431 | 1428 | -opened*) |
1432 | 1429 | os=-openedition |
1437 | 1434 | -wince*) |
1438 | 1435 | os=-wince |
1439 | 1436 | ;; |
1440 | -osfrose*) | |
1441 | os=-osfrose | |
1442 | ;; | |
1443 | -osf*) | |
1444 | os=-osf | |
1445 | ;; | |
1446 | 1437 | -utek*) |
1447 | 1438 | os=-bsd |
1448 | 1439 | ;; |
1467 | 1458 | -nova*) |
1468 | 1459 | os=-rtmk-nova |
1469 | 1460 | ;; |
1470 | -ns2 ) | |
1461 | -ns2) | |
1471 | 1462 | os=-nextstep2 |
1472 | 1463 | ;; |
1473 | 1464 | -nsk*) |
1489 | 1480 | -oss*) |
1490 | 1481 | os=-sysv3 |
1491 | 1482 | ;; |
1492 | -svr4) | |
1483 | -svr4*) | |
1493 | 1484 | os=-sysv4 |
1494 | 1485 | ;; |
1495 | 1486 | -svr3) |
1504 | 1495 | -ose*) |
1505 | 1496 | os=-ose |
1506 | 1497 | ;; |
1507 | -es1800*) | |
1508 | os=-ose | |
1509 | ;; | |
1510 | -xenix) | |
1511 | os=-xenix | |
1512 | ;; | |
1513 | 1498 | -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) |
1514 | 1499 | os=-mint |
1515 | 1500 | ;; |
1516 | -aros*) | |
1517 | os=-aros | |
1518 | ;; | |
1519 | 1501 | -zvmoe) |
1520 | 1502 | os=-zvmoe |
1521 | 1503 | ;; |
1522 | 1504 | -dicos*) |
1523 | 1505 | os=-dicos |
1524 | 1506 | ;; |
1507 | -pikeos*) | |
1508 | # Until real need of OS specific support for | |
1509 | # particular features comes up, bare metal | |
1510 | # configurations are quite functional. | |
1511 | case $basic_machine in | |
1512 | arm*) | |
1513 | os=-eabi | |
1514 | ;; | |
1515 | *) | |
1516 | os=-elf | |
1517 | ;; | |
1518 | esac | |
1519 | ;; | |
1525 | 1520 | -nacl*) |
1521 | ;; | |
1522 | -ios) | |
1526 | 1523 | ;; |
1527 | 1524 | -none) |
1528 | 1525 | ;; |
1529 | 1526 | *) |
1530 | 1527 | # Get rid of the `-' at the beginning of $os. |
1531 | 1528 | os=`echo $os | sed 's/[^-]*-//'` |
1532 | echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 | |
1529 | echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2 | |
1533 | 1530 | exit 1 |
1534 | 1531 | ;; |
1535 | 1532 | esac |
1619 | 1616 | sparc-* | *-sun) |
1620 | 1617 | os=-sunos4.1.1 |
1621 | 1618 | ;; |
1619 | pru-*) | |
1620 | os=-elf | |
1621 | ;; | |
1622 | 1622 | *-be) |
1623 | 1623 | os=-beos |
1624 | 1624 | ;; |
1625 | *-haiku) | |
1626 | os=-haiku | |
1627 | ;; | |
1628 | 1625 | *-ibm) |
1629 | 1626 | os=-aix |
1630 | 1627 | ;; |
1664 | 1661 | m88k-omron*) |
1665 | 1662 | os=-luna |
1666 | 1663 | ;; |
1667 | *-next ) | |
1664 | *-next) | |
1668 | 1665 | os=-nextstep |
1669 | 1666 | ;; |
1670 | 1667 | *-sequent) |
1678 | 1675 | ;; |
1679 | 1676 | i370-*) |
1680 | 1677 | os=-mvs |
1681 | ;; | |
1682 | *-next) | |
1683 | os=-nextstep3 | |
1684 | 1678 | ;; |
1685 | 1679 | *-gould) |
1686 | 1680 | os=-sysv |
1791 | 1785 | vendor=stratus |
1792 | 1786 | ;; |
1793 | 1787 | esac |
1794 | basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` | |
1788 | basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"` | |
1795 | 1789 | ;; |
1796 | 1790 | esac |
1797 | 1791 | |
1798 | echo $basic_machine$os | |
1792 | echo "$basic_machine$os" | |
1799 | 1793 | exit |
1800 | 1794 | |
1801 | 1795 | # Local variables: |
1802 | # eval: (add-hook 'write-file-hooks 'time-stamp) | |
1796 | # eval: (add-hook 'before-save-hook 'time-stamp) | |
1803 | 1797 | # time-stamp-start: "timestamp='" |
1804 | 1798 | # time-stamp-format: "%:y-%02m-%02d" |
1805 | 1799 | # time-stamp-end: "'" |
0 | 0 | #! /bin/sh |
1 | 1 | # Guess values for system-dependent variables and create Makefiles. |
2 | # Generated by GNU Autoconf 2.69 for libass 0.14.0. | |
2 | # Generated by GNU Autoconf 2.69 for libass 0.15.0. | |
3 | 3 | # |
4 | 4 | # |
5 | 5 | # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. |
586 | 586 | # Identity of this package. |
587 | 587 | PACKAGE_NAME='libass' |
588 | 588 | PACKAGE_TARNAME='libass' |
589 | PACKAGE_VERSION='0.14.0' | |
590 | PACKAGE_STRING='libass 0.14.0' | |
589 | PACKAGE_VERSION='0.15.0' | |
590 | PACKAGE_STRING='libass 0.15.0' | |
591 | 591 | PACKAGE_BUGREPORT='' |
592 | 592 | PACKAGE_URL='' |
593 | 593 | |
638 | 638 | PKG_LIBS_DEFAULT |
639 | 639 | ENABLE_PROFILE_FALSE |
640 | 640 | ENABLE_PROFILE_TRUE |
641 | HAVE_LIBPNG_FALSE | |
642 | HAVE_LIBPNG_TRUE | |
641 | ENABLE_COMPARE_FALSE | |
642 | ENABLE_COMPARE_TRUE | |
643 | ENABLE_TEST_FALSE | |
644 | ENABLE_TEST_TRUE | |
643 | 645 | LIBPNG_LIBS |
644 | 646 | LIBPNG_CFLAGS |
645 | 647 | HARFBUZZ_LIBS |
706 | 708 | AMDEPBACKSLASH |
707 | 709 | AMDEP_FALSE |
708 | 710 | AMDEP_TRUE |
709 | am__quote | |
710 | 711 | am__include |
711 | 712 | DEPDIR |
712 | 713 | OBJEXT |
789 | 790 | PACKAGE_TARNAME |
790 | 791 | PACKAGE_NAME |
791 | 792 | PATH_SEPARATOR |
792 | SHELL' | |
793 | SHELL | |
794 | am__quote' | |
793 | 795 | ac_subst_files='' |
794 | 796 | ac_user_opts=' |
795 | 797 | enable_option_checking |
804 | 806 | with_sysroot |
805 | 807 | enable_libtool_lock |
806 | 808 | enable_test |
809 | enable_compare | |
807 | 810 | enable_profile |
808 | 811 | enable_fontconfig |
809 | 812 | enable_directwrite |
810 | 813 | enable_coretext |
811 | 814 | enable_require_system_font_provider |
812 | enable_harfbuzz | |
813 | 815 | enable_asm |
814 | 816 | enable_large_tiles |
815 | 817 | ' |
1378 | 1380 | # Omit some internal or obsolete options to make the list less imposing. |
1379 | 1381 | # This message is too long to be a string in the A/UX 3.1 sh. |
1380 | 1382 | cat <<_ACEOF |
1381 | \`configure' configures libass 0.14.0 to adapt to many kinds of systems. | |
1383 | \`configure' configures libass 0.15.0 to adapt to many kinds of systems. | |
1382 | 1384 | |
1383 | 1385 | Usage: $0 [OPTION]... [VAR=VALUE]... |
1384 | 1386 | |
1448 | 1450 | |
1449 | 1451 | if test -n "$ac_init_help"; then |
1450 | 1452 | case $ac_init_help in |
1451 | short | recursive ) echo "Configuration of libass 0.14.0:";; | |
1453 | short | recursive ) echo "Configuration of libass 0.15.0:";; | |
1452 | 1454 | esac |
1453 | 1455 | cat <<\_ACEOF |
1454 | 1456 | |
1468 | 1470 | speeds up one-time build |
1469 | 1471 | --disable-libtool-lock avoid locking (might break parallel builds) |
1470 | 1472 | --enable-test enable test program (requires libpng) [default=no] |
1473 | --enable-compare enable compare program (requires libpng) | |
1474 | [default=no] | |
1471 | 1475 | --enable-profile enable profiling program [default=no] |
1472 | 1476 | --disable-fontconfig disable fontconfig support [default=enabled] |
1473 | 1477 | --disable-directwrite disable DirectWrite support (win32 only) |
1476 | 1480 | --disable-require-system-font-provider |
1477 | 1481 | allow compilation even if no system font provider |
1478 | 1482 | was found [default=enabled:>@ |
1479 | --disable-harfbuzz disable HarfBuzz support [default=check] | |
1480 | 1483 | --disable-asm disable compiling with ASM [default=check] |
1481 | 1484 | --enable-large-tiles use larger tiles in the rasterizer (better |
1482 | 1485 | performance, slightly worse quality) |
1598 | 1601 | test -n "$ac_init_help" && exit $ac_status |
1599 | 1602 | if $ac_init_version; then |
1600 | 1603 | cat <<\_ACEOF |
1601 | libass configure 0.14.0 | |
1604 | libass configure 0.15.0 | |
1602 | 1605 | generated by GNU Autoconf 2.69 |
1603 | 1606 | |
1604 | 1607 | Copyright (C) 2012 Free Software Foundation, Inc. |
2017 | 2020 | This file contains any messages produced by compilers while |
2018 | 2021 | running configure, to aid debugging if configure makes a mistake. |
2019 | 2022 | |
2020 | It was created by libass $as_me 0.14.0, which was | |
2023 | It was created by libass $as_me 0.15.0, which was | |
2021 | 2024 | generated by GNU Autoconf 2.69. Invocation command line was |
2022 | 2025 | |
2023 | 2026 | $ $0 $@ |
2365 | 2368 | ac_compiler_gnu=$ac_cv_c_compiler_gnu |
2366 | 2369 | |
2367 | 2370 | |
2368 | am__api_version='1.15' | |
2371 | am__api_version='1.16' | |
2369 | 2372 | |
2370 | 2373 | ac_aux_dir= |
2371 | 2374 | for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do |
2880 | 2883 | |
2881 | 2884 | # Define the identity of the package. |
2882 | 2885 | PACKAGE='libass' |
2883 | VERSION='0.14.0' | |
2886 | VERSION='0.15.0' | |
2884 | 2887 | |
2885 | 2888 | |
2886 | 2889 | cat >>confdefs.h <<_ACEOF |
2910 | 2913 | |
2911 | 2914 | # For better backward compatibility. To be removed once Automake 1.9.x |
2912 | 2915 | # dies out for good. For more background, see: |
2913 | # <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html> | |
2914 | # <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html> | |
2916 | # <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html> | |
2917 | # <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html> | |
2915 | 2918 | mkdir_p='$(MKDIR_P)' |
2916 | 2919 | |
2917 | 2920 | # We need awk for the "check" target (and possibly the TAP driver). The |
2962 | 2965 | Aborting the configuration process, to ensure you take notice of the issue. |
2963 | 2966 | |
2964 | 2967 | You can download and install GNU coreutils to get an 'rm' implementation |
2965 | that behaves properly: <http://www.gnu.org/software/coreutils/>. | |
2968 | that behaves properly: <https://www.gnu.org/software/coreutils/>. | |
2966 | 2969 | |
2967 | 2970 | If you want to complete the configuration process using your problematic |
2968 | 2971 | 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM |
3145 | 3148 | |
3146 | 3149 | ac_config_commands="$ac_config_commands depfiles" |
3147 | 3150 | |
3148 | ||
3149 | am_make=${MAKE-make} | |
3150 | cat > confinc << 'END' | |
3151 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 | |
3152 | $as_echo_n "checking whether ${MAKE-make} supports the include directive... " >&6; } | |
3153 | cat > confinc.mk << 'END' | |
3151 | 3154 | am__doit: |
3152 | @echo this is the am__doit target | |
3155 | @echo this is the am__doit target >confinc.out | |
3153 | 3156 | .PHONY: am__doit |
3154 | 3157 | END |
3155 | # If we don't find an include directive, just comment out the code. | |
3156 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 | |
3157 | $as_echo_n "checking for style of include used by $am_make... " >&6; } | |
3158 | 3158 | am__include="#" |
3159 | 3159 | am__quote= |
3160 | _am_result=none | |
3161 | # First try GNU make style include. | |
3162 | echo "include confinc" > confmf | |
3163 | # Ignore all kinds of additional output from 'make'. | |
3164 | case `$am_make -s -f confmf 2> /dev/null` in #( | |
3165 | *the\ am__doit\ target*) | |
3166 | am__include=include | |
3167 | am__quote= | |
3168 | _am_result=GNU | |
3169 | ;; | |
3160 | # BSD make does it like this. | |
3161 | echo '.include "confinc.mk" # ignored' > confmf.BSD | |
3162 | # Other make implementations (GNU, Solaris 10, AIX) do it like this. | |
3163 | echo 'include confinc.mk # ignored' > confmf.GNU | |
3164 | _am_result=no | |
3165 | for s in GNU BSD; do | |
3166 | { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 | |
3167 | (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 | |
3168 | ac_status=$? | |
3169 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | |
3170 | (exit $ac_status); } | |
3171 | case $?:`cat confinc.out 2>/dev/null` in #( | |
3172 | '0:this is the am__doit target') : | |
3173 | case $s in #( | |
3174 | BSD) : | |
3175 | am__include='.include' am__quote='"' ;; #( | |
3176 | *) : | |
3177 | am__include='include' am__quote='' ;; | |
3178 | esac ;; #( | |
3179 | *) : | |
3180 | ;; | |
3170 | 3181 | esac |
3171 | # Now try BSD make style include. | |
3172 | if test "$am__include" = "#"; then | |
3173 | echo '.include "confinc"' > confmf | |
3174 | case `$am_make -s -f confmf 2> /dev/null` in #( | |
3175 | *the\ am__doit\ target*) | |
3176 | am__include=.include | |
3177 | am__quote="\"" | |
3178 | _am_result=BSD | |
3179 | ;; | |
3180 | esac | |
3181 | fi | |
3182 | ||
3183 | ||
3184 | { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 | |
3185 | $as_echo "$_am_result" >&6; } | |
3186 | rm -f confinc confmf | |
3182 | if test "$am__include" != "#"; then | |
3183 | _am_result="yes ($s style)" | |
3184 | break | |
3185 | fi | |
3186 | done | |
3187 | rm -f confinc.* confmf.* | |
3188 | { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 | |
3189 | $as_echo "${_am_result}" >&6; } | |
3187 | 3190 | |
3188 | 3191 | # Check whether --enable-dependency-tracking was given. |
3189 | 3192 | if test "${enable_dependency_tracking+set}" = set; then : |
7439 | 7442 | _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; |
7440 | 7443 | darwin1.*) |
7441 | 7444 | _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; |
7442 | darwin*) # darwin 5.x on | |
7443 | # if running on 10.5 or later, the deployment target defaults | |
7444 | # to the OS version, if on x86, and 10.4, the deployment | |
7445 | # target defaults to 10.4. Don't you love it? | |
7446 | case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in | |
7447 | 10.0,*86*-darwin8*|10.0,*-darwin[91]*) | |
7448 | _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; | |
7449 | 10.[012][,.]*) | |
7445 | darwin*) | |
7446 | case ${MACOSX_DEPLOYMENT_TARGET},$host in | |
7447 | 10.[012],*|,*powerpc*) | |
7450 | 7448 | _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; |
7451 | 10.*) | |
7449 | *) | |
7452 | 7450 | _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; |
7453 | 7451 | esac |
7454 | 7452 | ;; |
13492 | 13490 | enableval=$enable_test; |
13493 | 13491 | fi |
13494 | 13492 | |
13493 | # Check whether --enable-compare was given. | |
13494 | if test "${enable_compare+set}" = set; then : | |
13495 | enableval=$enable_compare; | |
13496 | fi | |
13497 | ||
13495 | 13498 | # Check whether --enable-profile was given. |
13496 | 13499 | if test "${enable_profile+set}" = set; then : |
13497 | 13500 | enableval=$enable_profile; |
13515 | 13518 | # Check whether --enable-require-system-font-provider was given. |
13516 | 13519 | if test "${enable_require_system_font_provider+set}" = set; then : |
13517 | 13520 | enableval=$enable_require_system_font_provider; |
13518 | fi | |
13519 | ||
13520 | # Check whether --enable-harfbuzz was given. | |
13521 | if test "${enable_harfbuzz+set}" = set; then : | |
13522 | enableval=$enable_harfbuzz; | |
13523 | 13521 | fi |
13524 | 13522 | |
13525 | 13523 | # Check whether --enable-asm was given. |
14259 | 14257 | fi |
14260 | 14258 | |
14261 | 14259 | |
14262 | if test x$enable_harfbuzz != xno; then | |
14263 | 14260 | |
14264 | 14261 | pkg_failed=no |
14265 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking for harfbuzz >= 0.9.5" >&5 | |
14266 | $as_echo_n "checking for harfbuzz >= 0.9.5... " >&6; } | |
14262 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking for harfbuzz >= 1.2.3" >&5 | |
14263 | $as_echo_n "checking for harfbuzz >= 1.2.3... " >&6; } | |
14267 | 14264 | |
14268 | 14265 | if test -n "$HARFBUZZ_CFLAGS"; then |
14269 | 14266 | pkg_cv_HARFBUZZ_CFLAGS="$HARFBUZZ_CFLAGS" |
14270 | 14267 | elif test -n "$PKG_CONFIG"; then |
14271 | 14268 | if test -n "$PKG_CONFIG" && \ |
14272 | { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"harfbuzz >= 0.9.5\""; } >&5 | |
14273 | ($PKG_CONFIG --exists --print-errors "harfbuzz >= 0.9.5") 2>&5 | |
14269 | { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"harfbuzz >= 1.2.3\""; } >&5 | |
14270 | ($PKG_CONFIG --exists --print-errors "harfbuzz >= 1.2.3") 2>&5 | |
14274 | 14271 | ac_status=$? |
14275 | 14272 | $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 |
14276 | 14273 | test $ac_status = 0; }; then |
14277 | pkg_cv_HARFBUZZ_CFLAGS=`$PKG_CONFIG --cflags "harfbuzz >= 0.9.5" 2>/dev/null` | |
14274 | pkg_cv_HARFBUZZ_CFLAGS=`$PKG_CONFIG --cflags "harfbuzz >= 1.2.3" 2>/dev/null` | |
14278 | 14275 | test "x$?" != "x0" && pkg_failed=yes |
14279 | 14276 | else |
14280 | 14277 | pkg_failed=yes |
14286 | 14283 | pkg_cv_HARFBUZZ_LIBS="$HARFBUZZ_LIBS" |
14287 | 14284 | elif test -n "$PKG_CONFIG"; then |
14288 | 14285 | if test -n "$PKG_CONFIG" && \ |
14289 | { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"harfbuzz >= 0.9.5\""; } >&5 | |
14290 | ($PKG_CONFIG --exists --print-errors "harfbuzz >= 0.9.5") 2>&5 | |
14286 | { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"harfbuzz >= 1.2.3\""; } >&5 | |
14287 | ($PKG_CONFIG --exists --print-errors "harfbuzz >= 1.2.3") 2>&5 | |
14291 | 14288 | ac_status=$? |
14292 | 14289 | $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 |
14293 | 14290 | test $ac_status = 0; }; then |
14294 | pkg_cv_HARFBUZZ_LIBS=`$PKG_CONFIG --libs "harfbuzz >= 0.9.5" 2>/dev/null` | |
14291 | pkg_cv_HARFBUZZ_LIBS=`$PKG_CONFIG --libs "harfbuzz >= 1.2.3" 2>/dev/null` | |
14295 | 14292 | test "x$?" != "x0" && pkg_failed=yes |
14296 | 14293 | else |
14297 | 14294 | pkg_failed=yes |
14312 | 14309 | _pkg_short_errors_supported=no |
14313 | 14310 | fi |
14314 | 14311 | if test $_pkg_short_errors_supported = yes; then |
14315 | HARFBUZZ_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "harfbuzz >= 0.9.5" 2>&1` | |
14312 | HARFBUZZ_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "harfbuzz >= 1.2.3" 2>&1` | |
14316 | 14313 | else |
14317 | HARFBUZZ_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "harfbuzz >= 0.9.5" 2>&1` | |
14314 | HARFBUZZ_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "harfbuzz >= 1.2.3" 2>&1` | |
14318 | 14315 | fi |
14319 | 14316 | # Put the nasty error message in config.log where it belongs |
14320 | 14317 | echo "$HARFBUZZ_PKG_ERRORS" >&5 |
14321 | 14318 | |
14322 | harfbuzz=false | |
14319 | as_fn_error $? "Package requirements (harfbuzz >= 1.2.3) were not met: | |
14320 | ||
14321 | $HARFBUZZ_PKG_ERRORS | |
14322 | ||
14323 | Consider adjusting the PKG_CONFIG_PATH environment variable if you | |
14324 | installed software in a non-standard prefix. | |
14325 | ||
14326 | Alternatively, you may set the environment variables HARFBUZZ_CFLAGS | |
14327 | and HARFBUZZ_LIBS to avoid the need to call pkg-config. | |
14328 | See the pkg-config man page for more details." "$LINENO" 5 | |
14323 | 14329 | elif test $pkg_failed = untried; then |
14324 | 14330 | { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 |
14325 | 14331 | $as_echo "no" >&6; } |
14326 | harfbuzz=false | |
14332 | { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 | |
14333 | $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} | |
14334 | as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it | |
14335 | is in your PATH or set the PKG_CONFIG environment variable to the full | |
14336 | path to pkg-config. | |
14337 | ||
14338 | Alternatively, you may set the environment variables HARFBUZZ_CFLAGS | |
14339 | and HARFBUZZ_LIBS to avoid the need to call pkg-config. | |
14340 | See the pkg-config man page for more details. | |
14341 | ||
14342 | To get pkg-config, see <http://pkg-config.freedesktop.org/>. | |
14343 | See \`config.log' for more details" "$LINENO" 5; } | |
14327 | 14344 | else |
14328 | 14345 | HARFBUZZ_CFLAGS=$pkg_cv_HARFBUZZ_CFLAGS |
14329 | 14346 | HARFBUZZ_LIBS=$pkg_cv_HARFBUZZ_LIBS |
14335 | 14352 | |
14336 | 14353 | $as_echo "#define CONFIG_HARFBUZZ 1" >>confdefs.h |
14337 | 14354 | |
14338 | harfbuzz=true | |
14339 | ||
14340 | fi | |
14355 | ||
14341 | 14356 | fi |
14342 | 14357 | |
14343 | 14358 | libpng=false |
14344 | if test x$enable_test = xyes; then | |
14359 | if test x$enable_test = xyes || test x$enable_compare = xyes; then | |
14345 | 14360 | |
14346 | 14361 | pkg_failed=no |
14347 | 14362 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libpng >= 1.2.0" >&5 |
14440 | 14455 | fi |
14441 | 14456 | fi |
14442 | 14457 | |
14443 | if test x$libpng = xtrue; then | |
14444 | HAVE_LIBPNG_TRUE= | |
14445 | HAVE_LIBPNG_FALSE='#' | |
14446 | else | |
14447 | HAVE_LIBPNG_TRUE='#' | |
14448 | HAVE_LIBPNG_FALSE= | |
14458 | if test x$enable_test = xyes && test x$libpng = xtrue; then | |
14459 | ENABLE_TEST_TRUE= | |
14460 | ENABLE_TEST_FALSE='#' | |
14461 | else | |
14462 | ENABLE_TEST_TRUE='#' | |
14463 | ENABLE_TEST_FALSE= | |
14464 | fi | |
14465 | ||
14466 | if test x$enable_compare = xyes && test x$libpng = xtrue; then | |
14467 | ENABLE_COMPARE_TRUE= | |
14468 | ENABLE_COMPARE_FALSE='#' | |
14469 | else | |
14470 | ENABLE_COMPARE_TRUE='#' | |
14471 | ENABLE_COMPARE_FALSE= | |
14449 | 14472 | fi |
14450 | 14473 | |
14451 | 14474 | |
14470 | 14493 | fi |
14471 | 14494 | pkg_requires="freetype2 >= 9.10.3" |
14472 | 14495 | pkg_requires="fribidi >= 0.19.0, ${pkg_requires}" |
14496 | pkg_requires="harfbuzz >= 1.2.3, ${pkg_requires}" | |
14473 | 14497 | if test x$fontconfig = xtrue; then |
14474 | 14498 | pkg_requires="fontconfig >= 2.10.92, ${pkg_requires}" |
14475 | fi | |
14476 | if test x$harfbuzz = xtrue; then | |
14477 | pkg_requires="harfbuzz >= 0.9.5, ${pkg_requires}" | |
14478 | 14499 | fi |
14479 | 14500 | |
14480 | 14501 | if test x$enable_require_system_font_provider != xno && |
14538 | 14559 | AM_BACKSLASH='\' |
14539 | 14560 | |
14540 | 14561 | |
14541 | ac_config_files="$ac_config_files Makefile libass/Makefile test/Makefile profile/Makefile libass.pc" | |
14562 | ac_config_files="$ac_config_files Makefile libass/Makefile test/Makefile compare/Makefile profile/Makefile libass.pc" | |
14542 | 14563 | |
14543 | 14564 | cat >confcache <<\_ACEOF |
14544 | 14565 | # This file is a shell script that caches the results of configure |
14713 | 14734 | as_fn_error $? "conditional \"DIRECTWRITE\" was never defined. |
14714 | 14735 | Usually this means the macro was only invoked conditionally." "$LINENO" 5 |
14715 | 14736 | fi |
14716 | if test -z "${HAVE_LIBPNG_TRUE}" && test -z "${HAVE_LIBPNG_FALSE}"; then | |
14717 | as_fn_error $? "conditional \"HAVE_LIBPNG\" was never defined. | |
14737 | if test -z "${ENABLE_TEST_TRUE}" && test -z "${ENABLE_TEST_FALSE}"; then | |
14738 | as_fn_error $? "conditional \"ENABLE_TEST\" was never defined. | |
14739 | Usually this means the macro was only invoked conditionally." "$LINENO" 5 | |
14740 | fi | |
14741 | if test -z "${ENABLE_COMPARE_TRUE}" && test -z "${ENABLE_COMPARE_FALSE}"; then | |
14742 | as_fn_error $? "conditional \"ENABLE_COMPARE\" was never defined. | |
14718 | 14743 | Usually this means the macro was only invoked conditionally." "$LINENO" 5 |
14719 | 14744 | fi |
14720 | 14745 | if test -z "${ENABLE_PROFILE_TRUE}" && test -z "${ENABLE_PROFILE_FALSE}"; then |
15118 | 15143 | # report actual input values of CONFIG_FILES etc. instead of their |
15119 | 15144 | # values after options handling. |
15120 | 15145 | ac_log=" |
15121 | This file was extended by libass $as_me 0.14.0, which was | |
15146 | This file was extended by libass $as_me 0.15.0, which was | |
15122 | 15147 | generated by GNU Autoconf 2.69. Invocation command line was |
15123 | 15148 | |
15124 | 15149 | CONFIG_FILES = $CONFIG_FILES |
15184 | 15209 | cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 |
15185 | 15210 | ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" |
15186 | 15211 | ac_cs_version="\\ |
15187 | libass config.status 0.14.0 | |
15212 | libass config.status 0.15.0 | |
15188 | 15213 | configured by $0, generated by GNU Autoconf 2.69, |
15189 | 15214 | with options \\"\$ac_cs_config\\" |
15190 | 15215 | |
15303 | 15328 | # |
15304 | 15329 | # INIT-COMMANDS |
15305 | 15330 | # |
15306 | AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" | |
15331 | AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" | |
15307 | 15332 | |
15308 | 15333 | |
15309 | 15334 | # The HP-UX ksh and POSIX shell print the target directory to stdout |
15602 | 15627 | "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; |
15603 | 15628 | "libass/Makefile") CONFIG_FILES="$CONFIG_FILES libass/Makefile" ;; |
15604 | 15629 | "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;; |
15630 | "compare/Makefile") CONFIG_FILES="$CONFIG_FILES compare/Makefile" ;; | |
15605 | 15631 | "profile/Makefile") CONFIG_FILES="$CONFIG_FILES profile/Makefile" ;; |
15606 | 15632 | "libass.pc") CONFIG_FILES="$CONFIG_FILES libass.pc" ;; |
15607 | 15633 | |
16203 | 16229 | # Older Autoconf quotes --file arguments for eval, but not when files |
16204 | 16230 | # are listed without --file. Let's play safe and only enable the eval |
16205 | 16231 | # if we detect the quoting. |
16206 | case $CONFIG_FILES in | |
16207 | *\'*) eval set x "$CONFIG_FILES" ;; | |
16208 | *) set x $CONFIG_FILES ;; | |
16209 | esac | |
16232 | # TODO: see whether this extra hack can be removed once we start | |
16233 | # requiring Autoconf 2.70 or later. | |
16234 | case $CONFIG_FILES in #( | |
16235 | *\'*) : | |
16236 | eval set x "$CONFIG_FILES" ;; #( | |
16237 | *) : | |
16238 | set x $CONFIG_FILES ;; #( | |
16239 | *) : | |
16240 | ;; | |
16241 | esac | |
16210 | 16242 | shift |
16211 | for mf | |
16243 | # Used to flag and report bootstrapping failures. | |
16244 | am_rc=0 | |
16245 | for am_mf | |
16212 | 16246 | do |
16213 | 16247 | # Strip MF so we end up with the name of the file. |
16214 | mf=`echo "$mf" | sed -e 's/:.*$//'` | |
16215 | # Check whether this is an Automake generated Makefile or not. | |
16216 | # We used to match only the files named 'Makefile.in', but | |
16217 | # some people rename them; so instead we look at the file content. | |
16218 | # Grep'ing the first line is not enough: some people post-process | |
16219 | # each Makefile.in and add a new line on top of each file to say so. | |
16220 | # Grep'ing the whole file is not good either: AIX grep has a line | |
16248 | am_mf=`$as_echo "$am_mf" | sed -e 's/:.*$//'` | |
16249 | # Check whether this is an Automake generated Makefile which includes | |
16250 | # dependency-tracking related rules and includes. | |
16251 | # Grep'ing the whole file directly is not great: AIX grep has a line | |
16221 | 16252 | # limit of 2048, but all sed's we know have understand at least 4000. |
16222 | if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then | |
16223 | dirpart=`$as_dirname -- "$mf" || | |
16224 | $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ | |
16225 | X"$mf" : 'X\(//\)[^/]' \| \ | |
16226 | X"$mf" : 'X\(//\)$' \| \ | |
16227 | X"$mf" : 'X\(/\)' \| . 2>/dev/null || | |
16228 | $as_echo X"$mf" | | |
16253 | sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ | |
16254 | || continue | |
16255 | am_dirpart=`$as_dirname -- "$am_mf" || | |
16256 | $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ | |
16257 | X"$am_mf" : 'X\(//\)[^/]' \| \ | |
16258 | X"$am_mf" : 'X\(//\)$' \| \ | |
16259 | X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || | |
16260 | $as_echo X"$am_mf" | | |
16229 | 16261 | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ |
16230 | 16262 | s//\1/ |
16231 | 16263 | q |
16243 | 16275 | q |
16244 | 16276 | } |
16245 | 16277 | s/.*/./; q'` |
16246 | else | |
16247 | continue | |
16248 | fi | |
16249 | # Extract the definition of DEPDIR, am__include, and am__quote | |
16250 | # from the Makefile without running 'make'. | |
16251 | DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` | |
16252 | test -z "$DEPDIR" && continue | |
16253 | am__include=`sed -n 's/^am__include = //p' < "$mf"` | |
16254 | test -z "$am__include" && continue | |
16255 | am__quote=`sed -n 's/^am__quote = //p' < "$mf"` | |
16256 | # Find all dependency output files, they are included files with | |
16257 | # $(DEPDIR) in their names. We invoke sed twice because it is the | |
16258 | # simplest approach to changing $(DEPDIR) to its actual value in the | |
16259 | # expansion. | |
16260 | for file in `sed -n " | |
16261 | s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ | |
16262 | sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do | |
16263 | # Make sure the directory exists. | |
16264 | test -f "$dirpart/$file" && continue | |
16265 | fdir=`$as_dirname -- "$file" || | |
16266 | $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ | |
16267 | X"$file" : 'X\(//\)[^/]' \| \ | |
16268 | X"$file" : 'X\(//\)$' \| \ | |
16269 | X"$file" : 'X\(/\)' \| . 2>/dev/null || | |
16270 | $as_echo X"$file" | | |
16271 | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ | |
16278 | am_filepart=`$as_basename -- "$am_mf" || | |
16279 | $as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ | |
16280 | X"$am_mf" : 'X\(//\)$' \| \ | |
16281 | X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || | |
16282 | $as_echo X/"$am_mf" | | |
16283 | sed '/^.*\/\([^/][^/]*\)\/*$/{ | |
16272 | 16284 | s//\1/ |
16273 | 16285 | q |
16274 | 16286 | } |
16275 | /^X\(\/\/\)[^/].*/{ | |
16287 | /^X\/\(\/\/\)$/{ | |
16276 | 16288 | s//\1/ |
16277 | 16289 | q |
16278 | 16290 | } |
16279 | /^X\(\/\/\)$/{ | |
16280 | s//\1/ | |
16281 | q | |
16282 | } | |
16283 | /^X\(\/\).*/{ | |
16291 | /^X\/\(\/\).*/{ | |
16284 | 16292 | s//\1/ |
16285 | 16293 | q |
16286 | 16294 | } |
16287 | 16295 | s/.*/./; q'` |
16288 | as_dir=$dirpart/$fdir; as_fn_mkdir_p | |
16289 | # echo "creating $dirpart/$file" | |
16290 | echo '# dummy' > "$dirpart/$file" | |
16291 | done | |
16296 | { echo "$as_me:$LINENO: cd "$am_dirpart" \ | |
16297 | && sed -e '/# am--include-marker/d' "$am_filepart" \ | |
16298 | | $MAKE -f - am--depfiles" >&5 | |
16299 | (cd "$am_dirpart" \ | |
16300 | && sed -e '/# am--include-marker/d' "$am_filepart" \ | |
16301 | | $MAKE -f - am--depfiles) >&5 2>&5 | |
16302 | ac_status=$? | |
16303 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | |
16304 | (exit $ac_status); } || am_rc=$? | |
16292 | 16305 | done |
16306 | if test $am_rc -ne 0; then | |
16307 | { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 | |
16308 | $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} | |
16309 | as_fn_error $? "Something went wrong bootstrapping makefile fragments | |
16310 | for automatic dependency tracking. Try re-running configure with the | |
16311 | '--disable-dependency-tracking' option to at least be able to build | |
16312 | the package (albeit without support for automatic dependency tracking). | |
16313 | See \`config.log' for more details" "$LINENO" 5; } | |
16314 | fi | |
16315 | { am_dirpart=; unset am_dirpart;} | |
16316 | { am_filepart=; unset am_filepart;} | |
16317 | { am_mf=; unset am_mf;} | |
16318 | { am_rc=; unset am_rc;} | |
16319 | rm -f conftest-deps.mk | |
16293 | 16320 | } |
16294 | 16321 | ;; |
16295 | 16322 | "libtool":C) |
0 | AC_INIT(libass, 0.14.0) | |
0 | AC_INIT(libass, 0.15.0) | |
1 | 1 | AM_INIT_AUTOMAKE |
2 | 2 | AC_CONFIG_MACRO_DIR([m4]) |
3 | 3 | # Disable Fortran checks |
34 | 34 | # Check for libraries via pkg-config |
35 | 35 | AC_ARG_ENABLE([test], AS_HELP_STRING([--enable-test], |
36 | 36 | [enable test program (requires libpng) @<:@default=no@:>@])) |
37 | AC_ARG_ENABLE([compare], AS_HELP_STRING([--enable-compare], | |
38 | [enable compare program (requires libpng) @<:@default=no@:>@])) | |
37 | 39 | AC_ARG_ENABLE([profile], AS_HELP_STRING([--enable-profile], |
38 | 40 | [enable profiling program @<:@default=no@:>@])) |
39 | 41 | AC_ARG_ENABLE([fontconfig], AS_HELP_STRING([--disable-fontconfig], |
44 | 46 | [disable CoreText support (OSX only) @<:@default=check@:>@])) |
45 | 47 | AC_ARG_ENABLE([require-system-font-provider], AS_HELP_STRING([--disable-require-system-font-provider], |
46 | 48 | [allow compilation even if no system font provider was found @<:@default=enabled:>@])) |
47 | AC_ARG_ENABLE([harfbuzz], AS_HELP_STRING([--disable-harfbuzz], | |
48 | [disable HarfBuzz support @<:@default=check@:>@])) | |
49 | 49 | AC_ARG_ENABLE([asm], AS_HELP_STRING([--disable-asm], |
50 | 50 | [disable compiling with ASM @<:@default=check@:>@])) |
51 | 51 | AC_ARG_ENABLE([large-tiles], AS_HELP_STRING([--enable-large-tiles], |
207 | 207 | fi |
208 | 208 | AM_CONDITIONAL([DIRECTWRITE], [test x$directwrite = xtrue]) |
209 | 209 | |
210 | if test x$enable_harfbuzz != xno; then | |
211 | PKG_CHECK_MODULES([HARFBUZZ], harfbuzz >= 0.9.5, [ | |
210 | PKG_CHECK_MODULES([HARFBUZZ], harfbuzz >= 1.2.3, [ | |
212 | 211 | CFLAGS="$CFLAGS $HARFBUZZ_CFLAGS" |
213 | 212 | LIBS="$LIBS $HARFBUZZ_LIBS" |
214 | AC_DEFINE(CONFIG_HARFBUZZ, 1, [found harfbuzz-ng via pkg-config]) | |
215 | harfbuzz=true | |
216 | ], [harfbuzz=false]) | |
217 | fi | |
213 | AC_DEFINE(CONFIG_HARFBUZZ, 1, [found harfbuzz via pkg-config]) | |
214 | ]) | |
218 | 215 | |
219 | 216 | libpng=false |
220 | if test x$enable_test = xyes; then | |
217 | if test x$enable_test = xyes || test x$enable_compare = xyes; then | |
221 | 218 | PKG_CHECK_MODULES([LIBPNG], libpng >= 1.2.0, [ |
222 | 219 | CFLAGS="$CFLAGS $LIBPNG_CFLAGS" |
223 | 220 | AC_DEFINE(CONFIG_LIBPNG, 1, [found libpng via pkg-config]) |
224 | 221 | libpng=true]) |
225 | 222 | fi |
226 | 223 | |
227 | AM_CONDITIONAL([HAVE_LIBPNG], [test x$libpng = xtrue]) | |
224 | AM_CONDITIONAL([ENABLE_TEST], [test x$enable_test = xyes && test x$libpng = xtrue]) | |
225 | AM_CONDITIONAL([ENABLE_COMPARE], [test x$enable_compare = xyes && test x$libpng = xtrue]) | |
228 | 226 | |
229 | 227 | AM_CONDITIONAL([ENABLE_PROFILE], [test x$enable_profile = xyes]) |
230 | 228 | |
238 | 236 | fi |
239 | 237 | pkg_requires="freetype2 >= 9.10.3" |
240 | 238 | pkg_requires="fribidi >= 0.19.0, ${pkg_requires}" |
239 | pkg_requires="harfbuzz >= 1.2.3, ${pkg_requires}" | |
241 | 240 | if test x$fontconfig = xtrue; then |
242 | 241 | pkg_requires="fontconfig >= 2.10.92, ${pkg_requires}" |
243 | fi | |
244 | if test x$harfbuzz = xtrue; then | |
245 | pkg_requires="harfbuzz >= 0.9.5, ${pkg_requires}" | |
246 | 242 | fi |
247 | 243 | |
248 | 244 | if test x$enable_require_system_font_provider != xno && |
264 | 260 | # Setup output beautifier. |
265 | 261 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) |
266 | 262 | |
267 | AC_CONFIG_FILES([Makefile libass/Makefile test/Makefile profile/Makefile libass.pc]) | |
263 | AC_CONFIG_FILES([Makefile libass/Makefile test/Makefile compare/Makefile profile/Makefile libass.pc]) | |
268 | 264 | AC_OUTPUT |
0 | 0 | #! /bin/sh |
1 | 1 | # depcomp - compile a program generating dependencies as side-effects |
2 | 2 | |
3 | scriptversion=2013-05-30.07; # UTC | |
4 | ||
5 | # Copyright (C) 1999-2014 Free Software Foundation, Inc. | |
3 | scriptversion=2018-03-07.03; # UTC | |
4 | ||
5 | # Copyright (C) 1999-2018 Free Software Foundation, Inc. | |
6 | 6 | |
7 | 7 | # This program is free software; you can redistribute it and/or modify |
8 | 8 | # it under the terms of the GNU General Public License as published by |
15 | 15 | # GNU General Public License for more details. |
16 | 16 | |
17 | 17 | # You should have received a copy of the GNU General Public License |
18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | # along with this program. If not, see <https://www.gnu.org/licenses/>. | |
19 | 19 | |
20 | 20 | # As a special exception to the GNU General Public License, if you |
21 | 21 | # distribute this file as part of a program that contains a |
782 | 782 | # Local Variables: |
783 | 783 | # mode: shell-script |
784 | 784 | # sh-indentation: 2 |
785 | # eval: (add-hook 'write-file-hooks 'time-stamp) | |
785 | # eval: (add-hook 'before-save-hook 'time-stamp) | |
786 | 786 | # time-stamp-start: "scriptversion=" |
787 | 787 | # time-stamp-format: "%:y-%02m-%02d.%02H" |
788 | # time-stamp-time-zone: "UTC" | |
788 | # time-stamp-time-zone: "UTC0" | |
789 | 789 | # time-stamp-end: "; # UTC" |
790 | 790 | # End: |
0 | 0 | #!/bin/sh |
1 | 1 | # install - install a program, script, or datafile |
2 | 2 | |
3 | scriptversion=2013-12-25.23; # UTC | |
3 | scriptversion=2018-03-11.20; # UTC | |
4 | 4 | |
5 | 5 | # This originates from X11R5 (mit/util/scripts/install.sh), which was |
6 | 6 | # later released in X11R6 (xc/config/util/install.sh) with the |
270 | 270 | fi |
271 | 271 | dst=$dst_arg |
272 | 272 | |
273 | # If destination is a directory, append the input filename; won't work | |
274 | # if double slashes aren't ignored. | |
273 | # If destination is a directory, append the input filename. | |
275 | 274 | if test -d "$dst"; then |
276 | 275 | if test "$is_target_a_directory" = never; then |
277 | 276 | echo "$0: $dst_arg: Is a directory" >&2 |
278 | 277 | exit 1 |
279 | 278 | fi |
280 | 279 | dstdir=$dst |
281 | dst=$dstdir/`basename "$src"` | |
280 | dstbase=`basename "$src"` | |
281 | case $dst in | |
282 | */) dst=$dst$dstbase;; | |
283 | *) dst=$dst/$dstbase;; | |
284 | esac | |
282 | 285 | dstdir_status=0 |
283 | 286 | else |
284 | 287 | dstdir=`dirname "$dst"` |
286 | 289 | dstdir_status=$? |
287 | 290 | fi |
288 | 291 | fi |
292 | ||
293 | case $dstdir in | |
294 | */) dstdirslash=$dstdir;; | |
295 | *) dstdirslash=$dstdir/;; | |
296 | esac | |
289 | 297 | |
290 | 298 | obsolete_mkdir_used=false |
291 | 299 | |
323 | 331 | # is incompatible with FreeBSD 'install' when (umask & 300) != 0. |
324 | 332 | ;; |
325 | 333 | *) |
334 | # Note that $RANDOM variable is not portable (e.g. dash); Use it | |
335 | # here however when possible just to lower collision chance. | |
326 | 336 | tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ |
327 | trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 | |
328 | ||
337 | ||
338 | trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 | |
339 | ||
340 | # Because "mkdir -p" follows existing symlinks and we likely work | |
341 | # directly in world-writeable /tmp, make sure that the '$tmpdir' | |
342 | # directory is successfully created first before we actually test | |
343 | # 'mkdir -p' feature. | |
329 | 344 | if (umask $mkdir_umask && |
330 | exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 | |
345 | $mkdirprog $mkdir_mode "$tmpdir" && | |
346 | exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 | |
331 | 347 | then |
332 | 348 | if test -z "$dir_arg" || { |
333 | 349 | # Check for POSIX incompatibilities with -m. |
334 | 350 | # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or |
335 | 351 | # other-writable bit of parent directory when it shouldn't. |
336 | 352 | # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. |
337 | ls_ld_tmpdir=`ls -ld "$tmpdir"` | |
353 | test_tmpdir="$tmpdir/a" | |
354 | ls_ld_tmpdir=`ls -ld "$test_tmpdir"` | |
338 | 355 | case $ls_ld_tmpdir in |
339 | 356 | d????-?r-*) different_mode=700;; |
340 | 357 | d????-?--*) different_mode=755;; |
341 | 358 | *) false;; |
342 | 359 | esac && |
343 | $mkdirprog -m$different_mode -p -- "$tmpdir" && { | |
344 | ls_ld_tmpdir_1=`ls -ld "$tmpdir"` | |
360 | $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { | |
361 | ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` | |
345 | 362 | test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" |
346 | 363 | } |
347 | 364 | } |
348 | 365 | then posix_mkdir=: |
349 | 366 | fi |
350 | rmdir "$tmpdir/d" "$tmpdir" | |
367 | rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" | |
351 | 368 | else |
352 | 369 | # Remove any dirs left behind by ancient mkdir implementations. |
353 | rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null | |
370 | rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null | |
354 | 371 | fi |
355 | 372 | trap '' 0;; |
356 | 373 | esac;; |
426 | 443 | else |
427 | 444 | |
428 | 445 | # Make a couple of temp file names in the proper directory. |
429 | dsttmp=$dstdir/_inst.$$_ | |
430 | rmtmp=$dstdir/_rm.$$_ | |
446 | dsttmp=${dstdirslash}_inst.$$_ | |
447 | rmtmp=${dstdirslash}_rm.$$_ | |
431 | 448 | |
432 | 449 | # Trap to clean up those temp files at exit. |
433 | 450 | trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 |
492 | 509 | done |
493 | 510 | |
494 | 511 | # Local variables: |
495 | # eval: (add-hook 'write-file-hooks 'time-stamp) | |
512 | # eval: (add-hook 'before-save-hook 'time-stamp) | |
496 | 513 | # time-stamp-start: "scriptversion=" |
497 | 514 | # time-stamp-format: "%:y-%02m-%02d.%02H" |
498 | # time-stamp-time-zone: "UTC" | |
515 | # time-stamp-time-zone: "UTC0" | |
499 | 516 | # time-stamp-end: "; # UTC" |
500 | 517 | # End: |
2 | 2 | -Wpointer-arith -Wredundant-decls -Wno-missing-field-initializers\ |
3 | 3 | -D_GNU_SOURCE |
4 | 4 | |
5 | LIBASS_LT_CURRENT = 9 | |
6 | LIBASS_LT_REVISION = 2 | |
7 | LIBASS_LT_AGE = 0 | |
5 | LIBASS_LT_CURRENT = 10 | |
6 | LIBASS_LT_REVISION = 1 | |
7 | LIBASS_LT_AGE = 1 | |
8 | 8 | |
9 | 9 | nasm_verbose = $(nasm_verbose_$(V)) |
10 | 10 | nasm_verbose_ = $(nasm_verbose_$(AM_DEFAULT_VERBOSITY)) |
27 | 27 | ass_library.h ass_library.c ass_cache.h ass_cache.c ass_cache_template.h \ |
28 | 28 | ass_font.h ass_font.c ass_fontselect.h ass_fontselect.c \ |
29 | 29 | ass_render.h ass_render.c ass_render_api.c \ |
30 | ass_parse.h ass_parse.c ass_shaper.h ass_shaper.c \ | |
30 | ass_parse.h ass_parse.c ass_priv.h ass_shaper.h ass_shaper.c \ | |
31 | 31 | ass_outline.h ass_outline.c ass_drawing.h ass_drawing.c \ |
32 | 32 | ass_rasterizer.h ass_rasterizer.c ass_rasterizer_c.c \ |
33 | 33 | ass_bitmap.h ass_bitmap.c ass_blur.c ass_func_template.h |
0 | # Makefile.in generated by automake 1.15 from Makefile.am. | |
0 | # Makefile.in generated by automake 1.16.1 from Makefile.am. | |
1 | 1 | # @configure_input@ |
2 | 2 | |
3 | # Copyright (C) 1994-2014 Free Software Foundation, Inc. | |
3 | # Copyright (C) 1994-2018 Free Software Foundation, Inc. | |
4 | 4 | |
5 | 5 | # This Makefile.in is free software; the Free Software Foundation |
6 | 6 | # gives unlimited permission to copy and/or distribute it, |
142 | 142 | ass_strtod.c ass_library.h ass_library.c ass_cache.h \ |
143 | 143 | ass_cache.c ass_cache_template.h ass_font.h ass_font.c \ |
144 | 144 | ass_fontselect.h ass_fontselect.c ass_render.h ass_render.c \ |
145 | ass_render_api.c ass_parse.h ass_parse.c ass_shaper.h \ | |
146 | ass_shaper.c ass_outline.h ass_outline.c ass_drawing.h \ | |
147 | ass_drawing.c ass_rasterizer.h ass_rasterizer.c \ | |
145 | ass_render_api.c ass_parse.h ass_parse.c ass_priv.h \ | |
146 | ass_shaper.h ass_shaper.c ass_outline.h ass_outline.c \ | |
147 | ass_drawing.h ass_drawing.c ass_rasterizer.h ass_rasterizer.c \ | |
148 | 148 | ass_rasterizer_c.c ass_bitmap.h ass_bitmap.c ass_blur.c \ |
149 | 149 | ass_func_template.h ass_fontconfig.c ass_fontconfig.h \ |
150 | 150 | ass_directwrite.c ass_directwrite.h dwrite_c.h ass_coretext.c \ |
191 | 191 | am__v_at_1 = |
192 | 192 | DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) |
193 | 193 | depcomp = $(SHELL) $(top_srcdir)/depcomp |
194 | am__depfiles_maybe = depfiles | |
194 | am__maybe_remake_depfiles = depfiles | |
195 | am__depfiles_remade = ./$(DEPDIR)/ass.Plo ./$(DEPDIR)/ass_bitmap.Plo \ | |
196 | ./$(DEPDIR)/ass_blur.Plo ./$(DEPDIR)/ass_cache.Plo \ | |
197 | ./$(DEPDIR)/ass_coretext.Plo ./$(DEPDIR)/ass_directwrite.Plo \ | |
198 | ./$(DEPDIR)/ass_drawing.Plo ./$(DEPDIR)/ass_font.Plo \ | |
199 | ./$(DEPDIR)/ass_fontconfig.Plo ./$(DEPDIR)/ass_fontselect.Plo \ | |
200 | ./$(DEPDIR)/ass_library.Plo ./$(DEPDIR)/ass_outline.Plo \ | |
201 | ./$(DEPDIR)/ass_parse.Plo ./$(DEPDIR)/ass_rasterizer.Plo \ | |
202 | ./$(DEPDIR)/ass_rasterizer_c.Plo ./$(DEPDIR)/ass_render.Plo \ | |
203 | ./$(DEPDIR)/ass_render_api.Plo ./$(DEPDIR)/ass_shaper.Plo \ | |
204 | ./$(DEPDIR)/ass_string.Plo ./$(DEPDIR)/ass_strtod.Plo \ | |
205 | ./$(DEPDIR)/ass_utils.Plo | |
195 | 206 | am__mv = mv -f |
196 | 207 | COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ |
197 | 208 | $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) |
383 | 394 | -Wpointer-arith -Wredundant-decls -Wno-missing-field-initializers\ |
384 | 395 | -D_GNU_SOURCE |
385 | 396 | |
386 | LIBASS_LT_CURRENT = 9 | |
387 | LIBASS_LT_REVISION = 2 | |
388 | LIBASS_LT_AGE = 0 | |
397 | LIBASS_LT_CURRENT = 10 | |
398 | LIBASS_LT_REVISION = 1 | |
399 | LIBASS_LT_AGE = 1 | |
389 | 400 | nasm_verbose = $(nasm_verbose_$(V)) |
390 | 401 | nasm_verbose_ = $(nasm_verbose_$(AM_DEFAULT_VERBOSITY)) |
391 | 402 | nasm_verbose_0 = @echo " NASM " $@; |
402 | 413 | ass_library.h ass_library.c ass_cache.h ass_cache.c \ |
403 | 414 | ass_cache_template.h ass_font.h ass_font.c ass_fontselect.h \ |
404 | 415 | ass_fontselect.c ass_render.h ass_render.c ass_render_api.c \ |
405 | ass_parse.h ass_parse.c ass_shaper.h ass_shaper.c \ | |
416 | ass_parse.h ass_parse.c ass_priv.h ass_shaper.h ass_shaper.c \ | |
406 | 417 | ass_outline.h ass_outline.c ass_drawing.h ass_drawing.c \ |
407 | 418 | ass_rasterizer.h ass_rasterizer.c ass_rasterizer_c.c \ |
408 | 419 | ass_bitmap.h ass_bitmap.c ass_blur.c ass_func_template.h \ |
427 | 438 | exit 1;; \ |
428 | 439 | esac; \ |
429 | 440 | done; \ |
430 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libass/Makefile'; \ | |
441 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libass/Makefile'; \ | |
431 | 442 | $(am__cd) $(top_srcdir) && \ |
432 | $(AUTOMAKE) --gnu libass/Makefile | |
443 | $(AUTOMAKE) --foreign libass/Makefile | |
433 | 444 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status |
434 | 445 | @case '$?' in \ |
435 | 446 | *config.status*) \ |
436 | 447 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ |
437 | 448 | *) \ |
438 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ | |
439 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ | |
449 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ | |
450 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ | |
440 | 451 | esac; |
441 | 452 | |
442 | 453 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) |
506 | 517 | distclean-compile: |
507 | 518 | -rm -f *.tab.c |
508 | 519 | |
509 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass.Plo@am__quote@ | |
510 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_bitmap.Plo@am__quote@ | |
511 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_blur.Plo@am__quote@ | |
512 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_cache.Plo@am__quote@ | |
513 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_coretext.Plo@am__quote@ | |
514 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_directwrite.Plo@am__quote@ | |
515 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_drawing.Plo@am__quote@ | |
516 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_font.Plo@am__quote@ | |
517 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_fontconfig.Plo@am__quote@ | |
518 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_fontselect.Plo@am__quote@ | |
519 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_library.Plo@am__quote@ | |
520 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_outline.Plo@am__quote@ | |
521 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_parse.Plo@am__quote@ | |
522 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_rasterizer.Plo@am__quote@ | |
523 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_rasterizer_c.Plo@am__quote@ | |
524 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_render.Plo@am__quote@ | |
525 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_render_api.Plo@am__quote@ | |
526 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_shaper.Plo@am__quote@ | |
527 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_string.Plo@am__quote@ | |
528 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_strtod.Plo@am__quote@ | |
529 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_utils.Plo@am__quote@ | |
520 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass.Plo@am__quote@ # am--include-marker | |
521 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_bitmap.Plo@am__quote@ # am--include-marker | |
522 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_blur.Plo@am__quote@ # am--include-marker | |
523 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_cache.Plo@am__quote@ # am--include-marker | |
524 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_coretext.Plo@am__quote@ # am--include-marker | |
525 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_directwrite.Plo@am__quote@ # am--include-marker | |
526 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_drawing.Plo@am__quote@ # am--include-marker | |
527 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_font.Plo@am__quote@ # am--include-marker | |
528 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_fontconfig.Plo@am__quote@ # am--include-marker | |
529 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_fontselect.Plo@am__quote@ # am--include-marker | |
530 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_library.Plo@am__quote@ # am--include-marker | |
531 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_outline.Plo@am__quote@ # am--include-marker | |
532 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_parse.Plo@am__quote@ # am--include-marker | |
533 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_rasterizer.Plo@am__quote@ # am--include-marker | |
534 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_rasterizer_c.Plo@am__quote@ # am--include-marker | |
535 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_render.Plo@am__quote@ # am--include-marker | |
536 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_render_api.Plo@am__quote@ # am--include-marker | |
537 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_shaper.Plo@am__quote@ # am--include-marker | |
538 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_string.Plo@am__quote@ # am--include-marker | |
539 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_strtod.Plo@am__quote@ # am--include-marker | |
540 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_utils.Plo@am__quote@ # am--include-marker | |
541 | ||
542 | $(am__depfiles_remade): | |
543 | @$(MKDIR_P) $(@D) | |
544 | @echo '# dummy' >$@-t && $(am__mv) $@-t $@ | |
545 | ||
546 | am--depfiles: $(am__depfiles_remade) | |
530 | 547 | |
531 | 548 | .c.o: |
532 | 549 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< |
629 | 646 | distclean-tags: |
630 | 647 | -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags |
631 | 648 | |
632 | distdir: $(DISTFILES) | |
649 | distdir: $(BUILT_SOURCES) | |
650 | $(MAKE) $(AM_MAKEFLAGS) distdir-am | |
651 | ||
652 | distdir-am: $(DISTFILES) | |
633 | 653 | @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ |
634 | 654 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ |
635 | 655 | list='$(DISTFILES)'; \ |
704 | 724 | mostlyclean-am |
705 | 725 | |
706 | 726 | distclean: distclean-am |
707 | -rm -rf ./$(DEPDIR) | |
727 | -rm -f ./$(DEPDIR)/ass.Plo | |
728 | -rm -f ./$(DEPDIR)/ass_bitmap.Plo | |
729 | -rm -f ./$(DEPDIR)/ass_blur.Plo | |
730 | -rm -f ./$(DEPDIR)/ass_cache.Plo | |
731 | -rm -f ./$(DEPDIR)/ass_coretext.Plo | |
732 | -rm -f ./$(DEPDIR)/ass_directwrite.Plo | |
733 | -rm -f ./$(DEPDIR)/ass_drawing.Plo | |
734 | -rm -f ./$(DEPDIR)/ass_font.Plo | |
735 | -rm -f ./$(DEPDIR)/ass_fontconfig.Plo | |
736 | -rm -f ./$(DEPDIR)/ass_fontselect.Plo | |
737 | -rm -f ./$(DEPDIR)/ass_library.Plo | |
738 | -rm -f ./$(DEPDIR)/ass_outline.Plo | |
739 | -rm -f ./$(DEPDIR)/ass_parse.Plo | |
740 | -rm -f ./$(DEPDIR)/ass_rasterizer.Plo | |
741 | -rm -f ./$(DEPDIR)/ass_rasterizer_c.Plo | |
742 | -rm -f ./$(DEPDIR)/ass_render.Plo | |
743 | -rm -f ./$(DEPDIR)/ass_render_api.Plo | |
744 | -rm -f ./$(DEPDIR)/ass_shaper.Plo | |
745 | -rm -f ./$(DEPDIR)/ass_string.Plo | |
746 | -rm -f ./$(DEPDIR)/ass_strtod.Plo | |
747 | -rm -f ./$(DEPDIR)/ass_utils.Plo | |
708 | 748 | -rm -f Makefile |
709 | 749 | distclean-am: clean-am distclean-compile distclean-generic \ |
710 | 750 | distclean-tags |
750 | 790 | installcheck-am: |
751 | 791 | |
752 | 792 | maintainer-clean: maintainer-clean-am |
753 | -rm -rf ./$(DEPDIR) | |
793 | -rm -f ./$(DEPDIR)/ass.Plo | |
794 | -rm -f ./$(DEPDIR)/ass_bitmap.Plo | |
795 | -rm -f ./$(DEPDIR)/ass_blur.Plo | |
796 | -rm -f ./$(DEPDIR)/ass_cache.Plo | |
797 | -rm -f ./$(DEPDIR)/ass_coretext.Plo | |
798 | -rm -f ./$(DEPDIR)/ass_directwrite.Plo | |
799 | -rm -f ./$(DEPDIR)/ass_drawing.Plo | |
800 | -rm -f ./$(DEPDIR)/ass_font.Plo | |
801 | -rm -f ./$(DEPDIR)/ass_fontconfig.Plo | |
802 | -rm -f ./$(DEPDIR)/ass_fontselect.Plo | |
803 | -rm -f ./$(DEPDIR)/ass_library.Plo | |
804 | -rm -f ./$(DEPDIR)/ass_outline.Plo | |
805 | -rm -f ./$(DEPDIR)/ass_parse.Plo | |
806 | -rm -f ./$(DEPDIR)/ass_rasterizer.Plo | |
807 | -rm -f ./$(DEPDIR)/ass_rasterizer_c.Plo | |
808 | -rm -f ./$(DEPDIR)/ass_render.Plo | |
809 | -rm -f ./$(DEPDIR)/ass_render_api.Plo | |
810 | -rm -f ./$(DEPDIR)/ass_shaper.Plo | |
811 | -rm -f ./$(DEPDIR)/ass_string.Plo | |
812 | -rm -f ./$(DEPDIR)/ass_strtod.Plo | |
813 | -rm -f ./$(DEPDIR)/ass_utils.Plo | |
754 | 814 | -rm -f Makefile |
755 | 815 | maintainer-clean-am: distclean-am maintainer-clean-generic |
756 | 816 | |
772 | 832 | |
773 | 833 | .MAKE: install-am install-strip |
774 | 834 | |
775 | .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ | |
776 | clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \ | |
777 | ctags-am distclean distclean-compile distclean-generic \ | |
835 | .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ | |
836 | clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ | |
837 | ctags ctags-am distclean distclean-compile distclean-generic \ | |
778 | 838 | distclean-libtool distclean-tags distdir dvi dvi-am html \ |
779 | 839 | html-am info info-am install install-am install-data \ |
780 | 840 | install-data-am install-dist_assheadersHEADERS install-dvi \ |
34 | 34 | #include "ass.h" |
35 | 35 | #include "ass_utils.h" |
36 | 36 | #include "ass_library.h" |
37 | #include "ass_priv.h" | |
38 | #include "ass_shaper.h" | |
37 | 39 | #include "ass_string.h" |
38 | 40 | |
39 | 41 | #define ass_atof(STR) (ass_strtod((STR),NULL)) |
40 | 42 | |
41 | typedef enum { | |
42 | PST_UNKNOWN = 0, | |
43 | PST_INFO, | |
44 | PST_STYLES, | |
45 | PST_EVENTS, | |
46 | PST_FONTS | |
47 | } ParserState; | |
48 | ||
49 | struct parser_priv { | |
50 | ParserState state; | |
51 | char *fontname; | |
52 | char *fontdata; | |
53 | int fontdata_size; | |
54 | int fontdata_used; | |
55 | ||
56 | // contains bitmap of ReadOrder IDs of all read events | |
57 | uint32_t *read_order_bitmap; | |
58 | int read_order_elems; // size in uint32_t units of read_order_bitmap | |
59 | int check_readorder; | |
60 | }; | |
43 | static const char *const ass_style_format = | |
44 | "Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, " | |
45 | "OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, " | |
46 | "ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, " | |
47 | "Alignment, MarginL, MarginR, MarginV, Encoding"; | |
48 | static const char *const ass_event_format = | |
49 | "Layer, Start, End, Style, Name, " | |
50 | "MarginL, MarginR, MarginV, Effect, Text"; | |
51 | static const char *const ssa_style_format = | |
52 | "Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, " | |
53 | "TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, " | |
54 | "Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding"; | |
55 | static const char *const ssa_event_format = | |
56 | "Marked, Start, End, Style, Name, " | |
57 | "MarginL, MarginR, MarginV, Effect, Text"; | |
61 | 58 | |
62 | 59 | #define ASS_STYLES_ALLOC 20 |
63 | 60 | |
69 | 66 | void ass_free_track(ASS_Track *track) |
70 | 67 | { |
71 | 68 | int i; |
69 | ||
70 | if (!track) | |
71 | return; | |
72 | 72 | |
73 | 73 | if (track->parser_priv) { |
74 | 74 | free(track->parser_priv->read_order_bitmap); |
95 | 95 | |
96 | 96 | /// \brief Allocate a new style struct |
97 | 97 | /// \param track track |
98 | /// \return style id | |
98 | /// \return style id or negative value on failure | |
99 | 99 | int ass_alloc_style(ASS_Track *track) |
100 | 100 | { |
101 | 101 | int sid; |
103 | 103 | assert(track->n_styles <= track->max_styles); |
104 | 104 | |
105 | 105 | if (track->n_styles == track->max_styles) { |
106 | track->max_styles += ASS_STYLES_ALLOC; | |
107 | track->styles = | |
108 | (ASS_Style *) realloc(track->styles, | |
109 | sizeof(ASS_Style) * | |
110 | track->max_styles); | |
106 | if (track->max_styles >= FFMIN(SIZE_MAX, INT_MAX) - ASS_STYLES_ALLOC) | |
107 | return -1; | |
108 | int new_max = track->max_styles + ASS_STYLES_ALLOC; | |
109 | if (!ASS_REALLOC_ARRAY(track->styles, new_max)) | |
110 | return -1; | |
111 | track->max_styles = new_max; | |
111 | 112 | } |
112 | 113 | |
113 | 114 | sid = track->n_styles++; |
117 | 118 | |
118 | 119 | /// \brief Allocate a new event struct |
119 | 120 | /// \param track track |
120 | /// \return event id | |
121 | /// \return event id or negative value on failure | |
121 | 122 | int ass_alloc_event(ASS_Track *track) |
122 | 123 | { |
123 | 124 | int eid; |
125 | 126 | assert(track->n_events <= track->max_events); |
126 | 127 | |
127 | 128 | if (track->n_events == track->max_events) { |
128 | track->max_events = track->max_events * 2 + 1; | |
129 | track->events = | |
130 | (ASS_Event *) realloc(track->events, | |
131 | sizeof(ASS_Event) * | |
132 | track->max_events); | |
129 | if (track->max_events >= FFMIN(SIZE_MAX, INT_MAX) / 2) | |
130 | return -1; | |
131 | int new_max = track->max_events * 2 + 1; | |
132 | if (!ASS_REALLOC_ARRAY(track->events, new_max)) | |
133 | return -1; | |
134 | track->max_events = new_max; | |
133 | 135 | } |
134 | 136 | |
135 | 137 | eid = track->n_events++; |
160 | 162 | // Don't allow malicious files to OOM us easily. Also avoids int overflows. |
161 | 163 | if (max_id < 0 || max_id >= 10 * 1024 * 1024 * 8) |
162 | 164 | goto fail; |
165 | assert(track->parser_priv->read_order_bitmap || !track->parser_priv->read_order_elems); | |
163 | 166 | if (max_id >= track->parser_priv->read_order_elems * 32) { |
164 | 167 | int oldelems = track->parser_priv->read_order_elems; |
165 | 168 | int elems = ((max_id + 31) / 32 + 1) * 2; |
187 | 190 | if (resize_read_order_bitmap(track, id) < 0) |
188 | 191 | return -1; |
189 | 192 | int index = id / 32; |
190 | int bit = 1 << (id % 32); | |
193 | uint32_t bit = 1u << (id % 32); | |
191 | 194 | if (track->parser_priv->read_order_bitmap[index] & bit) |
192 | 195 | return 1; |
193 | 196 | track->parser_priv->read_order_bitmap[index] |= bit; |
236 | 239 | } |
237 | 240 | |
238 | 241 | #define NEXT(str,token) \ |
239 | token = next_token(&str); \ | |
240 | if (!token) break; | |
242 | token = next_token(&str); \ | |
243 | if (!token) break; | |
241 | 244 | |
242 | 245 | |
243 | 246 | #define ALIAS(alias,name) \ |
257 | 260 | #define PARSE_END } |
258 | 261 | |
259 | 262 | #define ANYVAL(name,func) \ |
260 | } else if (ass_strcasecmp(tname, #name) == 0) { \ | |
261 | target->name = func(token); | |
263 | } else if (ass_strcasecmp(tname, #name) == 0) { \ | |
264 | target->name = func(token); | |
262 | 265 | |
263 | 266 | #define STRVAL(name) \ |
264 | } else if (ass_strcasecmp(tname, #name) == 0) { \ | |
265 | if (target->name != NULL) free(target->name); \ | |
266 | target->name = strdup(token); | |
267 | } else if (ass_strcasecmp(tname, #name) == 0) { \ | |
268 | char *new_str = strdup(token); \ | |
269 | if (new_str) { \ | |
270 | free(target->name); \ | |
271 | target->name = new_str; \ | |
272 | } | |
267 | 273 | |
268 | 274 | #define STARREDSTRVAL(name) \ |
269 | 275 | } else if (ass_strcasecmp(tname, #name) == 0) { \ |
270 | if (target->name != NULL) free(target->name); \ | |
271 | 276 | while (*token == '*') ++token; \ |
272 | target->name = strdup(token); | |
277 | char *new_str = strdup(token); \ | |
278 | if (new_str) { \ | |
279 | free(target->name); \ | |
280 | target->name = new_str; \ | |
281 | } | |
273 | 282 | |
274 | 283 | #define COLORVAL(name) ANYVAL(name,parse_color_header) |
275 | 284 | #define INTVAL(name) ANYVAL(name,atoi) |
276 | 285 | #define FPVAL(name) ANYVAL(name,ass_atof) |
277 | 286 | #define TIMEVAL(name) \ |
278 | } else if (ass_strcasecmp(tname, #name) == 0) { \ | |
279 | target->name = string2timecode(track->library, token); | |
287 | } else if (ass_strcasecmp(tname, #name) == 0) { \ | |
288 | target->name = string2timecode(track->library, token); | |
280 | 289 | |
281 | 290 | #define STYLEVAL(name) \ |
282 | } else if (ass_strcasecmp(tname, #name) == 0) { \ | |
283 | target->name = lookup_style(track, token); | |
291 | } else if (ass_strcasecmp(tname, #name) == 0) { \ | |
292 | target->name = lookup_style(track, token); | |
293 | ||
294 | // skip spaces in str beforehand, or trim leading spaces afterwards | |
295 | static inline void advance_token_pos(const char **const str, | |
296 | const char **const start, | |
297 | const char **const end) | |
298 | { | |
299 | *start = *str; | |
300 | *end = *start; | |
301 | while (**end != '\0' && **end != ',') ++*end; | |
302 | *str = *end + (**end == ','); | |
303 | rskip_spaces((char**)end, (char*)*start); | |
304 | } | |
284 | 305 | |
285 | 306 | static char *next_token(char **str) |
286 | 307 | { |
287 | char *p = *str; | |
308 | char *p; | |
288 | 309 | char *start; |
289 | skip_spaces(&p); | |
290 | if (*p == '\0') { | |
291 | *str = p; | |
310 | skip_spaces(str); | |
311 | if (**str == '\0') { | |
292 | 312 | return 0; |
293 | 313 | } |
294 | start = p; // start of the token | |
295 | for (; (*p != '\0') && (*p != ','); ++p) { | |
296 | } | |
297 | if (*p == '\0') { | |
298 | *str = p; // eos found, str will point to '\0' at exit | |
299 | } else { | |
300 | *p = '\0'; | |
301 | *str = p + 1; // ',' found, str will point to the next char (beginning of the next token) | |
302 | } | |
303 | rskip_spaces(&p, start); // end of current token: the first space character, or '\0' | |
314 | ||
315 | advance_token_pos((const char**)str, | |
316 | (const char**)&start, | |
317 | (const char**)&p); | |
318 | ||
304 | 319 | *p = '\0'; |
305 | 320 | return start; |
306 | 321 | } |
322 | 337 | ASS_Event *target = event; |
323 | 338 | |
324 | 339 | char *format = strdup(track->event_format); |
340 | if (!format) | |
341 | return -1; | |
325 | 342 | char *q = format; // format scanning pointer |
326 | ||
327 | if (track->n_styles == 0) { | |
328 | // add "Default" style to the end | |
329 | // will be used if track does not contain a default style (or even does not contain styles at all) | |
330 | int sid = ass_alloc_style(track); | |
331 | set_default_style(&track->styles[sid]); | |
332 | track->default_style = sid; | |
333 | } | |
334 | 343 | |
335 | 344 | for (i = 0; i < n_ignored; ++i) { |
336 | 345 | NEXT(q, tname); |
341 | 350 | if (ass_strcasecmp(tname, "Text") == 0) { |
342 | 351 | char *last; |
343 | 352 | event->Text = strdup(p); |
344 | if (*event->Text != 0) { | |
353 | if (event->Text && *event->Text != 0) { | |
345 | 354 | last = event->Text + strlen(event->Text) - 1; |
346 | 355 | if (last >= event->Text && *last == '\r') |
347 | 356 | *last = 0; |
348 | 357 | } |
349 | 358 | event->Duration -= event->Start; |
350 | 359 | free(format); |
351 | return 0; // "Text" is always the last | |
360 | return event->Text ? 0 : -1; // "Text" is always the last | |
352 | 361 | } |
353 | 362 | NEXT(p, token); |
354 | 363 | |
475 | 484 | // no style format header |
476 | 485 | // probably an ancient script version |
477 | 486 | if (track->track_type == TRACK_TYPE_SSA) |
478 | track->style_format = | |
479 | strdup | |
480 | ("Name, Fontname, Fontsize, PrimaryColour, SecondaryColour," | |
481 | "TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline," | |
482 | "Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding"); | |
487 | track->style_format = strdup(ssa_style_format); | |
483 | 488 | else |
484 | track->style_format = | |
485 | strdup | |
486 | ("Name, Fontname, Fontsize, PrimaryColour, SecondaryColour," | |
487 | "OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut," | |
488 | "ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow," | |
489 | "Alignment, MarginL, MarginR, MarginV, Encoding"); | |
489 | track->style_format = strdup(ass_style_format); | |
490 | if (!track->style_format) | |
491 | return -1; | |
490 | 492 | } |
491 | 493 | |
492 | 494 | q = format = strdup(track->style_format); |
493 | ||
494 | // Add default style first | |
495 | if (track->n_styles == 0) { | |
496 | // will be used if track does not contain a default style (or even does not contain styles at all) | |
497 | int sid = ass_alloc_style(track); | |
498 | set_default_style(&track->styles[sid]); | |
499 | track->default_style = sid; | |
500 | } | |
495 | if (!q) | |
496 | return -1; | |
501 | 497 | |
502 | 498 | ass_msg(track->library, MSGL_V, "[%p] Style: %s", track, str); |
503 | 499 | |
504 | 500 | sid = ass_alloc_style(track); |
501 | if (sid < 0) { | |
502 | free(format); | |
503 | return -1; | |
504 | } | |
505 | 505 | |
506 | 506 | style = track->styles + sid; |
507 | 507 | target = style; |
516 | 516 | |
517 | 517 | PARSE_START |
518 | 518 | STARREDSTRVAL(Name) |
519 | if (strcmp(target->Name, "Default") == 0) | |
520 | track->default_style = sid; | |
521 | 519 | STRVAL(FontName) |
522 | 520 | COLORVAL(PrimaryColour) |
523 | 521 | COLORVAL(SecondaryColour) |
553 | 551 | FPVAL(Shadow) |
554 | 552 | PARSE_END |
555 | 553 | } |
554 | free(format); | |
556 | 555 | style->ScaleX = FFMAX(style->ScaleX, 0.) / 100.; |
557 | 556 | style->ScaleY = FFMAX(style->ScaleY, 0.) / 100.; |
558 | 557 | style->Spacing = FFMAX(style->Spacing, 0.); |
566 | 565 | style->Name = strdup("Default"); |
567 | 566 | if (!style->FontName) |
568 | 567 | style->FontName = strdup("Arial"); |
569 | free(format); | |
568 | if (!style->Name || !style->FontName) { | |
569 | ass_free_style(track, sid); | |
570 | track->n_styles--; | |
571 | return -1; | |
572 | } | |
573 | if (strcmp(target->Name, "Default") == 0) | |
574 | track->default_style = sid; | |
570 | 575 | return 0; |
571 | 576 | |
572 | 577 | } |
573 | 578 | |
579 | static bool format_line_compare(const char *fmt1, const char *fmt2) | |
580 | { | |
581 | while (true) { | |
582 | const char *tk1_start, *tk2_start; | |
583 | const char *tk1_end, *tk2_end; | |
584 | ||
585 | skip_spaces((char**)&fmt1); | |
586 | skip_spaces((char**)&fmt2); | |
587 | if (!*fmt1 || !*fmt2) | |
588 | break; | |
589 | ||
590 | advance_token_pos(&fmt1, &tk1_start, &tk1_end); | |
591 | advance_token_pos(&fmt2, &tk2_start, &tk2_end); | |
592 | ||
593 | if ((tk1_end-tk1_start) != (tk2_end-tk2_start)) | |
594 | return false; | |
595 | if (ass_strncasecmp(tk1_start, tk2_start, tk1_end-tk1_start)) | |
596 | return false; | |
597 | } | |
598 | return *fmt1 == *fmt2; | |
599 | } | |
600 | ||
601 | ||
602 | /** | |
603 | * \brief Set SBAS=1 if not set explicitly in case of custom format line | |
604 | * \param track track | |
605 | * \param fmt format line of file | |
606 | * \param std standard format line | |
607 | * | |
608 | * As of writing libass is the only renderer accepting custom format lines. | |
609 | * For years libass defaultet SBAS to yes instead of no. | |
610 | * To avoid breaking released scripts with custom format lines, | |
611 | * keep SBAS=1 default for custom format files. | |
612 | */ | |
613 | static void custom_format_line_compatibility(ASS_Track *const track, | |
614 | const char *const fmt, | |
615 | const char *const std) | |
616 | { | |
617 | if (!(track->parser_priv->header_flags & SINFO_SCALEDBORDER) | |
618 | && !format_line_compare(fmt, std)) { | |
619 | ass_msg(track->library, MSGL_INFO, | |
620 | "Track has custom format line(s). " | |
621 | "'ScaledBorderAndShadow' will default to 'yes'."); | |
622 | track->ScaledBorderAndShadow = 1; | |
623 | } | |
624 | } | |
625 | ||
574 | 626 | static int process_styles_line(ASS_Track *track, char *str) |
575 | 627 | { |
628 | int ret = 0; | |
576 | 629 | if (!strncmp(str, "Format:", 7)) { |
577 | 630 | char *p = str + 7; |
578 | 631 | skip_spaces(&p); |
579 | 632 | free(track->style_format); |
580 | 633 | track->style_format = strdup(p); |
634 | if (!track->style_format) | |
635 | return -1; | |
581 | 636 | ass_msg(track->library, MSGL_DBG2, "Style format: %s", |
582 | 637 | track->style_format); |
638 | if (track->track_type == TRACK_TYPE_ASS) | |
639 | custom_format_line_compatibility(track, p, ass_style_format); | |
640 | else | |
641 | custom_format_line_compatibility(track, p, ssa_style_format); | |
583 | 642 | } else if (!strncmp(str, "Style:", 6)) { |
584 | 643 | char *p = str + 6; |
585 | 644 | skip_spaces(&p); |
586 | process_style(track, p); | |
587 | } | |
588 | return 0; | |
645 | ret = process_style(track, p); | |
646 | } | |
647 | return ret; | |
648 | } | |
649 | ||
650 | static inline void check_duplicate_info_line(const ASS_Track *const track, | |
651 | const ScriptInfo si, | |
652 | const char *const name) | |
653 | { | |
654 | if (track->parser_priv->header_flags & si) | |
655 | ass_msg(track->library, MSGL_WARN, | |
656 | "Duplicate Script Info Header '%s'. Previous value overwritten!", | |
657 | name); | |
658 | else | |
659 | track->parser_priv->header_flags |= si; | |
589 | 660 | } |
590 | 661 | |
591 | 662 | static int process_info_line(ASS_Track *track, char *str) |
592 | 663 | { |
593 | 664 | if (!strncmp(str, "PlayResX:", 9)) { |
665 | check_duplicate_info_line(track, SINFO_PLAYRESX, "PlayResX"); | |
594 | 666 | track->PlayResX = atoi(str + 9); |
595 | 667 | } else if (!strncmp(str, "PlayResY:", 9)) { |
668 | check_duplicate_info_line(track, SINFO_PLAYRESY, "PlayResY"); | |
596 | 669 | track->PlayResY = atoi(str + 9); |
597 | 670 | } else if (!strncmp(str, "Timer:", 6)) { |
671 | check_duplicate_info_line(track, SINFO_TIMER, "Timer"); | |
598 | 672 | track->Timer = ass_atof(str + 6); |
599 | 673 | } else if (!strncmp(str, "WrapStyle:", 10)) { |
674 | check_duplicate_info_line(track, SINFO_WRAPSTYLE, "WrapStyle"); | |
600 | 675 | track->WrapStyle = atoi(str + 10); |
601 | 676 | } else if (!strncmp(str, "ScaledBorderAndShadow:", 22)) { |
677 | check_duplicate_info_line(track, SINFO_SCALEDBORDER, | |
678 | "ScaledBorderAndShadow"); | |
602 | 679 | track->ScaledBorderAndShadow = parse_bool(str + 22); |
603 | 680 | } else if (!strncmp(str, "Kerning:", 8)) { |
681 | check_duplicate_info_line(track, SINFO_KERNING, "Kerning"); | |
604 | 682 | track->Kerning = parse_bool(str + 8); |
605 | 683 | } else if (!strncmp(str, "YCbCr Matrix:", 13)) { |
684 | check_duplicate_info_line(track, SINFO_COLOURMATRIX, "YCbCr Matrix"); | |
606 | 685 | track->YCbCrMatrix = parse_ycbcr_matrix(str + 13); |
607 | 686 | } else if (!strncmp(str, "Language:", 9)) { |
687 | check_duplicate_info_line(track, SINFO_LANGUAGE, "Language"); | |
608 | 688 | char *p = str + 9; |
609 | 689 | while (*p && ass_isspace(*p)) p++; |
610 | 690 | free(track->Language); |
611 | 691 | track->Language = strndup(p, 2); |
692 | } else if (!strncmp(str, "; Script generated by ", 22)) { | |
693 | if (!strncmp(str + 22,"FFmpeg/Lavc", 11)) | |
694 | track->parser_priv->header_flags |= GENBY_FFMPEG; | |
612 | 695 | } |
613 | 696 | return 0; |
614 | 697 | } |
617 | 700 | { |
618 | 701 | track->parser_priv->state = PST_EVENTS; |
619 | 702 | if (track->track_type == TRACK_TYPE_SSA) |
620 | track->event_format = strdup("Marked, Start, End, Style, " | |
621 | "Name, MarginL, MarginR, MarginV, Effect, Text"); | |
703 | track->event_format = strdup(ssa_event_format); | |
622 | 704 | else |
623 | track->event_format = strdup("Layer, Start, End, Style, " | |
624 | "Actor, MarginL, MarginR, MarginV, Effect, Text"); | |
705 | track->event_format = strdup(ass_event_format); | |
625 | 706 | ass_msg(track->library, MSGL_V, |
626 | 707 | "No event format found, using fallback"); |
627 | 708 | } |
709 | ||
710 | /** | |
711 | * \brief Return if track is post-signature and pre-SBAS ffmpeg track | |
712 | * \param track track | |
713 | */ | |
714 | static bool detect_legacy_conv_subs(ASS_Track *track) | |
715 | { | |
716 | /* | |
717 | * FFmpeg and libav convert srt subtitles to ass. | |
718 | * In legacy versions, they did not set the 'ScaledBorderAndShadow' header, | |
719 | * but expected it to default to yes (which libass did). | |
720 | * To avoid breaking them, we try to detect these | |
721 | * converted subs by common properties of ffmpeg/libav's converted subs. | |
722 | * Since files with custom format lines (-2014.10.11) default to SBAS=1 | |
723 | * regardless of being ffmpeg generated or not, we are only concerned with | |
724 | * post-signature and pre-SBAS ffmpeg-files (2014.10.11-2020.04.17). | |
725 | * We want to avoid matching modified ffmpeg files though. | |
726 | * | |
727 | * Relevant ffmpeg commits are: | |
728 | * 2c77c90684e24ef16f7e7c4462e011434cee6a98 2010.12.29 | |
729 | * Initial conversion format. | |
730 | * Style "Format:" line is mix of SSA and ASS | |
731 | * Event "Format:" line | |
732 | * "Format: Layer, Start, End, Text\r\n" | |
733 | * Only Header in ScriptInfo is "ScriptType: v4.00+" | |
734 | * 0e7782c08ec77739edb0b98ba5d896b45e98235f 2012.06.15 | |
735 | * Adds 'Style' to Event "Format:" line | |
736 | * 5039aadf68deb9ad6dd0737ea11259fe53d3727b 2014.06.18 | |
737 | * Adds PlayerRes(X|Y) (384x288) | |
738 | * (moved below ScriptType: a few minutes later) | |
739 | * 40b9f28641b696c6bb73ce49dc97c2ce2700cbdb 2014.10.11 14:31:23 +0200 | |
740 | * Regular full ASS Event and Style "Format:" lines | |
741 | * 52b0a0ecaa02e17f7e01bead8c3f215f1cfd48dc 2014.10.11 18:37:43 +0200 <== | |
742 | * Signature comment | |
743 | * 56bc0a6736cdc7edab837ff8f304661fd16de0e4 2015.02.08 | |
744 | * Allow custom PlayRes(X|Y) | |
745 | * a8ba2a2c1294a330a0e79ae7f0d3a203a7599166 2020.04.17 | |
746 | * Set 'ScaledBorderAndShadow: yes' | |
747 | * | |
748 | * libav outputs initial ffmpeg format. (no longer maintained) | |
749 | */ | |
750 | ||
751 | // GENBY_FFMPEG and exact ffmpeg headers required | |
752 | // Note: If there's SINFO_SCRIPTTYPE in the future this needs to be updated | |
753 | if (track->parser_priv->header_flags | |
754 | ^ (SINFO_PLAYRESX | SINFO_PLAYRESY | GENBY_FFMPEG)) | |
755 | return false; | |
756 | ||
757 | // Legacy ffmpeg only ever has one style | |
758 | // Check 2 not 1 because libass also adds a def style | |
759 | if (track->n_styles != 2 | |
760 | || strncmp(track->styles[1].Name, "Default", 7)) | |
761 | return false; | |
762 | ||
763 | return true; | |
764 | } | |
765 | ||
628 | 766 | |
629 | 767 | static int process_events_line(ASS_Track *track, char *str) |
630 | 768 | { |
633 | 771 | skip_spaces(&p); |
634 | 772 | free(track->event_format); |
635 | 773 | track->event_format = strdup(p); |
774 | if (!track->event_format) | |
775 | return -1; | |
636 | 776 | ass_msg(track->library, MSGL_DBG2, "Event format: %s", track->event_format); |
777 | if (track->track_type == TRACK_TYPE_ASS) | |
778 | custom_format_line_compatibility(track, p, ass_event_format); | |
779 | else | |
780 | custom_format_line_compatibility(track, p, ssa_event_format); | |
781 | ||
782 | // Guess if we are dealing with legacy ffmpeg subs and change accordingly | |
783 | // If file has no event format it was probably not created by ffmpeg/libav | |
784 | if (detect_legacy_conv_subs(track)) { | |
785 | track->ScaledBorderAndShadow = 1; | |
786 | ass_msg(track->library, MSGL_INFO, | |
787 | "Track treated as legacy ffmpeg sub."); | |
788 | } | |
637 | 789 | } else if (!strncmp(str, "Dialogue:", 9)) { |
638 | 790 | // This should never be reached for embedded subtitles. |
639 | 791 | // They have slightly different format and are parsed in ass_process_chunk, |
641 | 793 | int eid; |
642 | 794 | ASS_Event *event; |
643 | 795 | |
796 | // We can't parse events without event_format | |
797 | if (!track->event_format) { | |
798 | event_format_fallback(track); | |
799 | if (!track->event_format) | |
800 | return -1; | |
801 | } | |
802 | ||
644 | 803 | str += 9; |
645 | 804 | skip_spaces(&str); |
646 | 805 | |
647 | 806 | eid = ass_alloc_event(track); |
807 | if (eid < 0) | |
808 | return -1; | |
648 | 809 | event = track->events + eid; |
649 | 810 | |
650 | // We can't parse events with event_format | |
651 | if (!track->event_format) | |
652 | event_format_fallback(track); | |
653 | ||
654 | process_event_tail(track, event, str, 0); | |
811 | return process_event_tail(track, event, str, 0); | |
655 | 812 | } else { |
656 | 813 | ass_msg(track->library, MSGL_V, "Not understood: '%.30s'", str); |
657 | 814 | } |
659 | 816 | } |
660 | 817 | |
661 | 818 | static unsigned char *decode_chars(const unsigned char *src, |
662 | unsigned char *dst, int cnt_in) | |
819 | unsigned char *dst, size_t cnt_in) | |
663 | 820 | { |
664 | 821 | uint32_t value = 0; |
665 | 822 | for (int i = 0; i < cnt_in; i++) |
673 | 830 | return dst; |
674 | 831 | } |
675 | 832 | |
833 | static void reset_embedded_font_parsing(ASS_ParserPriv *parser_priv) | |
834 | { | |
835 | free(parser_priv->fontname); | |
836 | free(parser_priv->fontdata); | |
837 | parser_priv->fontname = NULL; | |
838 | parser_priv->fontdata = NULL; | |
839 | parser_priv->fontdata_size = 0; | |
840 | parser_priv->fontdata_used = 0; | |
841 | } | |
842 | ||
676 | 843 | static int decode_font(ASS_Track *track) |
677 | 844 | { |
678 | 845 | unsigned char *p; |
679 | 846 | unsigned char *q; |
680 | int i; | |
681 | int size; // original size | |
682 | int dsize; // decoded size | |
847 | size_t i; | |
848 | size_t size; // original size | |
849 | size_t dsize; // decoded size | |
683 | 850 | unsigned char *buf = 0; |
684 | 851 | |
685 | 852 | ass_msg(track->library, MSGL_V, "Font: %d bytes encoded data", |
712 | 879 | |
713 | 880 | error_decode_font: |
714 | 881 | free(buf); |
715 | free(track->parser_priv->fontname); | |
716 | free(track->parser_priv->fontdata); | |
717 | track->parser_priv->fontname = 0; | |
718 | track->parser_priv->fontdata = 0; | |
719 | track->parser_priv->fontdata_size = 0; | |
720 | track->parser_priv->fontdata_used = 0; | |
882 | reset_embedded_font_parsing(track->parser_priv); | |
721 | 883 | return 0; |
722 | 884 | } |
723 | 885 | |
724 | 886 | static int process_fonts_line(ASS_Track *track, char *str) |
725 | 887 | { |
726 | int len; | |
888 | size_t len; | |
727 | 889 | |
728 | 890 | if (!strncmp(str, "fontname:", 9)) { |
729 | 891 | char *p = str + 9; |
732 | 894 | decode_font(track); |
733 | 895 | } |
734 | 896 | track->parser_priv->fontname = strdup(p); |
897 | if (!track->parser_priv->fontname) | |
898 | return -1; | |
735 | 899 | ass_msg(track->library, MSGL_V, "Fontname: %s", |
736 | track->parser_priv->fontname); | |
900 | track->parser_priv->fontname); | |
737 | 901 | return 0; |
738 | 902 | } |
739 | 903 | |
740 | 904 | if (!track->parser_priv->fontname) { |
741 | 905 | ass_msg(track->library, MSGL_V, "Not understood: '%s'", str); |
742 | return 0; | |
906 | return 1; | |
743 | 907 | } |
744 | 908 | |
745 | 909 | len = strlen(str); |
746 | if (track->parser_priv->fontdata_used + len > | |
747 | track->parser_priv->fontdata_size) { | |
748 | track->parser_priv->fontdata_size += FFMAX(len, 100 * 1024); | |
749 | track->parser_priv->fontdata = | |
750 | realloc(track->parser_priv->fontdata, | |
751 | track->parser_priv->fontdata_size); | |
910 | if (track->parser_priv->fontdata_used >= | |
911 | SIZE_MAX - FFMAX(len, 100 * 1024)) { | |
912 | goto mem_fail; | |
913 | } else if (track->parser_priv->fontdata_used + len > | |
914 | track->parser_priv->fontdata_size) { | |
915 | size_t new_size = | |
916 | track->parser_priv->fontdata_size + FFMAX(len, 100 * 1024); | |
917 | if (!ASS_REALLOC_ARRAY(track->parser_priv->fontdata, new_size)) | |
918 | goto mem_fail; | |
919 | track->parser_priv->fontdata_size = new_size; | |
752 | 920 | } |
753 | 921 | memcpy(track->parser_priv->fontdata + track->parser_priv->fontdata_used, |
754 | 922 | str, len); |
755 | 923 | track->parser_priv->fontdata_used += len; |
756 | 924 | |
757 | 925 | return 0; |
926 | ||
927 | mem_fail: | |
928 | reset_embedded_font_parsing(track->parser_priv); | |
929 | return -1; | |
758 | 930 | } |
759 | 931 | |
760 | 932 | /** |
764 | 936 | */ |
765 | 937 | static int process_line(ASS_Track *track, char *str) |
766 | 938 | { |
939 | skip_spaces(&str); | |
767 | 940 | if (!ass_strncasecmp(str, "[Script Info]", 13)) { |
768 | 941 | track->parser_priv->state = PST_INFO; |
769 | 942 | } else if (!ass_strncasecmp(str, "[V4 Styles]", 11)) { |
893 | 1066 | void ass_process_chunk(ASS_Track *track, char *data, int size, |
894 | 1067 | long long timecode, long long duration) |
895 | 1068 | { |
896 | char *str; | |
1069 | char *str = NULL; | |
897 | 1070 | int eid; |
898 | 1071 | char *p; |
899 | 1072 | char *token; |
909 | 1082 | |
910 | 1083 | if (!track->event_format) { |
911 | 1084 | ass_msg(track->library, MSGL_WARN, "Event format header missing"); |
912 | return; | |
1085 | goto cleanup; | |
913 | 1086 | } |
914 | 1087 | |
915 | 1088 | str = malloc(size + 1); |
916 | 1089 | if (!str) |
917 | return; | |
1090 | goto cleanup; | |
918 | 1091 | memcpy(str, data, size); |
919 | 1092 | str[size] = '\0'; |
920 | 1093 | ass_msg(track->library, MSGL_V, "Event at %" PRId64 ", +%" PRId64 ": %s", |
921 | 1094 | (int64_t) timecode, (int64_t) duration, str); |
922 | 1095 | |
923 | 1096 | eid = ass_alloc_event(track); |
1097 | if (eid < 0) | |
1098 | goto cleanup; | |
924 | 1099 | event = track->events + eid; |
925 | 1100 | |
926 | 1101 | p = str; |
939 | 1114 | event->Start = timecode; |
940 | 1115 | event->Duration = duration; |
941 | 1116 | |
942 | free(str); | |
943 | return; | |
1117 | goto cleanup; | |
944 | 1118 | // dump_events(tid); |
945 | 1119 | } while (0); |
946 | 1120 | // some error |
947 | 1121 | ass_free_event(track, eid); |
948 | 1122 | track->n_events--; |
1123 | ||
1124 | cleanup: | |
949 | 1125 | free(str); |
950 | 1126 | } |
951 | 1127 | |
1112 | 1288 | int i; |
1113 | 1289 | |
1114 | 1290 | track = ass_new_track(library); |
1291 | if (!track) | |
1292 | return NULL; | |
1115 | 1293 | |
1116 | 1294 | // process header |
1117 | 1295 | process_text(track, buf); |
1312 | 1490 | |
1313 | 1491 | ASS_Track *ass_new_track(ASS_Library *library) |
1314 | 1492 | { |
1493 | int def_sid = -1; | |
1315 | 1494 | ASS_Track *track = calloc(1, sizeof(ASS_Track)); |
1316 | 1495 | if (!track) |
1317 | return NULL; | |
1496 | goto fail; | |
1318 | 1497 | track->library = library; |
1319 | track->ScaledBorderAndShadow = 1; | |
1498 | track->ScaledBorderAndShadow = 0; | |
1320 | 1499 | track->parser_priv = calloc(1, sizeof(ASS_ParserPriv)); |
1321 | if (!track->parser_priv) { | |
1322 | free(track); | |
1323 | return NULL; | |
1324 | } | |
1500 | if (!track->parser_priv) | |
1501 | goto fail; | |
1502 | def_sid = ass_alloc_style(track); | |
1503 | if (def_sid < 0) | |
1504 | goto fail; | |
1505 | set_default_style(track->styles + def_sid); | |
1506 | track->default_style = def_sid; | |
1507 | if (!track->styles[def_sid].Name || !track->styles[def_sid].FontName) | |
1508 | goto fail; | |
1325 | 1509 | track->parser_priv->check_readorder = 1; |
1326 | 1510 | return track; |
1511 | ||
1512 | fail: | |
1513 | if (track) { | |
1514 | if (def_sid >= 0) | |
1515 | ass_free_style(track, def_sid); | |
1516 | free(track->parser_priv); | |
1517 | free(track); | |
1518 | } | |
1519 | return NULL; | |
1520 | } | |
1521 | ||
1522 | int ass_track_set_feature(ASS_Track *track, ASS_Feature feature, int enable) | |
1523 | { | |
1524 | switch (feature) { | |
1525 | case ASS_FEATURE_INCOMPATIBLE_EXTENSIONS: | |
1526 | //-fallthrough | |
1527 | #ifdef USE_FRIBIDI_EX_API | |
1528 | case ASS_FEATURE_BIDI_BRACKETS: | |
1529 | track->parser_priv->bidi_brackets = !!enable; | |
1530 | #endif | |
1531 | return 0; | |
1532 | default: | |
1533 | return -1; | |
1534 | } | |
1327 | 1535 | } |
1328 | 1536 | |
1329 | 1537 | /** |
1344 | 1552 | ass_msg(lib, MSGL_WARN, |
1345 | 1553 | "PlayResY undefined, setting to %d", track->PlayResY); |
1346 | 1554 | } else if (track->PlayResY <= 0) { |
1347 | track->PlayResY = FFMAX(1, track->PlayResX * 3 / 4); | |
1555 | track->PlayResY = FFMAX(1, track->PlayResX * 3LL / 4); | |
1348 | 1556 | ass_msg(lib, MSGL_WARN, |
1349 | 1557 | "PlayResY undefined, setting to %d", track->PlayResY); |
1350 | 1558 | } else if (track->PlayResX <= 0 && track->PlayResY == 1024) { |
1352 | 1560 | ass_msg(lib, MSGL_WARN, |
1353 | 1561 | "PlayResX undefined, setting to %d", track->PlayResX); |
1354 | 1562 | } else if (track->PlayResX <= 0) { |
1355 | track->PlayResX = FFMAX(1, track->PlayResY * 4 / 3); | |
1563 | track->PlayResX = FFMAX(1, track->PlayResY * 4LL / 3); | |
1356 | 1564 | ass_msg(lib, MSGL_WARN, |
1357 | 1565 | "PlayResX undefined, setting to %d", track->PlayResX); |
1358 | 1566 | } |
23 | 23 | #include <stdarg.h> |
24 | 24 | #include "ass_types.h" |
25 | 25 | |
26 | #define LIBASS_VERSION 0x01400000 | |
26 | #define LIBASS_VERSION 0x01500000 | |
27 | 27 | |
28 | 28 | #ifdef __cplusplus |
29 | 29 | extern "C" { |
30 | 30 | #endif |
31 | ||
32 | #if (defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))) || defined(__clang__) | |
33 | #define ASS_DEPRECATED(msg) __attribute__((deprecated(msg))) | |
34 | #if __GNUC__ > 5 || defined(__clang__) | |
35 | #define ASS_DEPRECATED_ENUM(msg) __attribute__((deprecated(msg))) | |
36 | #else | |
37 | #define ASS_DEPRECATED_ENUM(msg) | |
38 | #endif | |
39 | #elif defined(_MSC_VER) | |
40 | #define ASS_DEPRECATED(msg) __declspec(deprecated(msg)) | |
41 | #define ASS_DEPRECATED_ENUM(msg) | |
42 | #else | |
43 | #define ASS_DEPRECATED(msg) | |
44 | #define ASS_DEPRECATED_ENUM(msg) | |
45 | #endif | |
46 | ||
31 | 47 | |
32 | 48 | /* |
33 | 49 | * A linked list of images produced by an ass renderer. |
55 | 71 | IMAGE_TYPE_SHADOW |
56 | 72 | } type; |
57 | 73 | |
74 | // New fields can be added here in new ABI-compatible library releases. | |
58 | 75 | } ASS_Image; |
59 | 76 | |
60 | 77 | /* |
127 | 144 | /** |
128 | 145 | * Old alias for ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE. Deprecated. Do not use. |
129 | 146 | */ |
130 | ASS_OVERRIDE_BIT_FONT_SIZE = 1 << 1, | |
147 | ASS_OVERRIDE_BIT_FONT_SIZE ASS_DEPRECATED_ENUM("replaced by ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE") = 1 << 1, | |
131 | 148 | /** |
132 | 149 | * On dialogue events override: FontSize, Spacing, Blur, ScaleX, ScaleY |
133 | 150 | */ |
169 | 186 | * On dialogue events override: Justify |
170 | 187 | */ |
171 | 188 | ASS_OVERRIDE_BIT_JUSTIFY = 1 << 10, |
189 | // New enum values can be added here in new ABI-compatible library releases. | |
172 | 190 | } ASS_OverrideBits; |
173 | 191 | |
174 | 192 | /** |
195 | 213 | ASS_FONTPROVIDER_FONTCONFIG, |
196 | 214 | ASS_FONTPROVIDER_DIRECTWRITE, |
197 | 215 | } ASS_DefaultFontProvider; |
216 | ||
217 | typedef enum { | |
218 | /** | |
219 | * Enable libass extensions that would display ASS subtitles incorrectly. | |
220 | * These may be useful for applications, which use libass as renderer for | |
221 | * subtitles converted from another format, or which use libass for other | |
222 | * purposes that do not involve actual ASS subtitles authored for | |
223 | * distribution. | |
224 | */ | |
225 | ASS_FEATURE_INCOMPATIBLE_EXTENSIONS, | |
226 | ||
227 | /** | |
228 | * Match bracket pairs in bidirectional text according to the revised | |
229 | * Unicode Bidirectional Algorithm introduced in Unicode 6.3. | |
230 | * This is incompatible with VSFilter and disabled by default. | |
231 | * | |
232 | * (Directional isolates, also introduced in Unicode 6.3, | |
233 | * are unconditionally processed when FriBidi is new enough.) | |
234 | * | |
235 | * This feature may be unavailable at runtime (ass_track_set_feature | |
236 | * may return -1) if libass was compiled against old FriBidi. | |
237 | */ | |
238 | ASS_FEATURE_BIDI_BRACKETS, | |
239 | ||
240 | // New enum values can be added here in new ABI-compatible library releases. | |
241 | } ASS_Feature; | |
198 | 242 | |
199 | 243 | /** |
200 | 244 | * \brief Initialize the library. |
373 | 417 | * \param dar display aspect ratio (DAR), prescaled for output PAR |
374 | 418 | * \param sar storage aspect ratio (SAR) |
375 | 419 | */ |
376 | void ass_set_aspect_ratio(ASS_Renderer *priv, double dar, double sar); | |
420 | ASS_DEPRECATED("use 'ass_set_pixel_aspect' instead") void ass_set_aspect_ratio(ASS_Renderer *priv, double dar, double sar); | |
377 | 421 | |
378 | 422 | /** |
379 | 423 | * \brief Set a fixed font scaling factor. |
472 | 516 | * \param priv renderer handle |
473 | 517 | * \return success |
474 | 518 | */ |
475 | int ass_fonts_update(ASS_Renderer *priv); | |
519 | ASS_DEPRECATED("it does nothing") int ass_fonts_update(ASS_Renderer *priv); | |
476 | 520 | |
477 | 521 | /** |
478 | 522 | * \brief Set hard cache limits. Do not set, or set to zero, for reasonable |
505 | 549 | /** |
506 | 550 | * \brief Allocate a new empty track object. |
507 | 551 | * \param library handle |
508 | * \return pointer to empty track | |
552 | * \return pointer to empty track or NULL on failure | |
509 | 553 | */ |
510 | 554 | ASS_Track *ass_new_track(ASS_Library *); |
511 | 555 | |
512 | 556 | /** |
557 | * \brief Enable or disable certain features | |
558 | * This manages flags that control the behavior of the renderer and how certain | |
559 | * tags etc. within the track are interpreted. The defaults on a newly created | |
560 | * ASS_Track are such that rendering is compatible with traditional renderers | |
561 | * like VSFilter, and/or old versions of libass. Calling ass_process_data() or | |
562 | * ass_process_codec_private() may change some of these flags according to file | |
563 | * headers. (ass_process_chunk() will not change any of the flags.) | |
564 | * Additions to ASS_Feature are backward compatible to old libass releases (ABI | |
565 | * compatibility). | |
566 | * \param track track | |
567 | * \param feature the specific feature to enable or disable | |
568 | * \param enable 0 for disable, any non-0 value for enable | |
569 | * \return 0 if feature set, -1 if feature is unknown | |
570 | */ | |
571 | int ass_track_set_feature(ASS_Track *track, ASS_Feature feature, int enable); | |
572 | ||
573 | /** | |
513 | 574 | * \brief Deallocate track and all its child objects (styles and events). |
514 | * \param track track to deallocate | |
575 | * \param track track to deallocate or NULL | |
515 | 576 | */ |
516 | 577 | void ass_free_track(ASS_Track *track); |
517 | 578 | |
518 | 579 | /** |
519 | 580 | * \brief Allocate new style. |
520 | 581 | * \param track track |
521 | * \return newly allocated style id | |
582 | * \return newly allocated style id >= 0, or a value < 0 on failure | |
522 | 583 | */ |
523 | 584 | int ass_alloc_style(ASS_Track *track); |
524 | 585 | |
525 | 586 | /** |
526 | 587 | * \brief Allocate new event. |
527 | 588 | * \param track track |
528 | * \return newly allocated event id | |
589 | * \return newly allocated event id >= 0, or a value < 0 on failure | |
529 | 590 | */ |
530 | 591 | int ass_alloc_event(ASS_Track *track); |
531 | 592 | |
601 | 662 | * \param library library handle |
602 | 663 | * \param fname file name |
603 | 664 | * \param codepage encoding (iconv format) |
604 | * \return newly allocated track | |
665 | * \return newly allocated track or NULL on failure | |
605 | 666 | */ |
606 | 667 | ASS_Track *ass_read_file(ASS_Library *library, char *fname, |
607 | 668 | char *codepage); |
612 | 673 | * \param buf pointer to subtitles text |
613 | 674 | * \param bufsize size of buffer |
614 | 675 | * \param codepage encoding (iconv format) |
615 | * \return newly allocated track | |
676 | * \return newly allocated track or NULL on failure | |
616 | 677 | */ |
617 | 678 | ASS_Track *ass_read_memory(ASS_Library *library, char *buf, |
618 | 679 | size_t bufsize, char *codepage); |
58 | 58 | #endif |
59 | 59 | |
60 | 60 | |
61 | void ass_synth_blur(const BitmapEngine *engine, int opaque_box, int be, | |
62 | double blur_radius, Bitmap *bm_g, Bitmap *bm_o) | |
63 | { | |
64 | bool blur_g = !bm_o || opaque_box; | |
65 | if (blur_g && !bm_g) | |
61 | void ass_synth_blur(const BitmapEngine *engine, Bitmap *bm, | |
62 | int be, double blur_r2) | |
63 | { | |
64 | if (!bm->buffer) | |
66 | 65 | return; |
67 | 66 | |
68 | 67 | // Apply gaussian blur |
69 | double r2 = blur_radius * blur_radius / log(256); | |
70 | if (r2 > 0.001) { | |
71 | if (bm_o) | |
72 | ass_gaussian_blur(engine, bm_o, r2); | |
73 | if (blur_g) | |
74 | ass_gaussian_blur(engine, bm_g, r2); | |
75 | } | |
68 | if (blur_r2 > 0.001) | |
69 | ass_gaussian_blur(engine, bm, blur_r2); | |
70 | ||
71 | if (!be) | |
72 | return; | |
76 | 73 | |
77 | 74 | // Apply box blur (multiple passes, if requested) |
78 | if (be) { | |
79 | size_t size_o = 0, size_g = 0; | |
80 | if (bm_o) | |
81 | size_o = sizeof(uint16_t) * bm_o->stride * 2; | |
82 | if (blur_g) | |
83 | size_g = sizeof(uint16_t) * bm_g->stride * 2; | |
84 | size_t size = FFMAX(size_o, size_g); | |
85 | uint16_t *tmp = size ? ass_aligned_alloc(32, size, false) : NULL; | |
86 | if (!tmp) | |
87 | return; | |
88 | if (bm_o) { | |
89 | unsigned passes = be; | |
90 | unsigned w = bm_o->w; | |
91 | unsigned h = bm_o->h; | |
92 | unsigned stride = bm_o->stride; | |
93 | unsigned char *buf = bm_o->buffer; | |
94 | if(w && h){ | |
95 | if(passes > 1){ | |
96 | be_blur_pre(buf, w, h, stride); | |
97 | while(--passes){ | |
98 | memset(tmp, 0, stride * 2); | |
99 | engine->be_blur(buf, w, h, stride, tmp); | |
100 | } | |
101 | be_blur_post(buf, w, h, stride); | |
102 | } | |
103 | memset(tmp, 0, stride * 2); | |
104 | engine->be_blur(buf, w, h, stride, tmp); | |
105 | } | |
106 | } | |
107 | if (blur_g) { | |
108 | unsigned passes = be; | |
109 | unsigned w = bm_g->w; | |
110 | unsigned h = bm_g->h; | |
111 | unsigned stride = bm_g->stride; | |
112 | unsigned char *buf = bm_g->buffer; | |
113 | if(w && h){ | |
114 | if(passes > 1){ | |
115 | be_blur_pre(buf, w, h, stride); | |
116 | while(--passes){ | |
117 | memset(tmp, 0, stride * 2); | |
118 | engine->be_blur(buf, w, h, stride, tmp); | |
119 | } | |
120 | be_blur_post(buf, w, h, stride); | |
121 | } | |
122 | memset(tmp, 0, stride * 2); | |
123 | engine->be_blur(buf, w, h, stride, tmp); | |
124 | } | |
125 | } | |
126 | ass_aligned_free(tmp); | |
127 | } | |
128 | } | |
129 | ||
130 | static bool alloc_bitmap_buffer(const BitmapEngine *engine, Bitmap *bm, int w, int h, | |
131 | bool zero) | |
75 | size_t size = sizeof(uint16_t) * bm->stride * 2; | |
76 | uint16_t *tmp = ass_aligned_alloc(32, size, false); | |
77 | if (!tmp) | |
78 | return; | |
79 | ||
80 | int32_t w = bm->w; | |
81 | int32_t h = bm->h; | |
82 | ptrdiff_t stride = bm->stride; | |
83 | uint8_t *buf = bm->buffer; | |
84 | if (--be) { | |
85 | be_blur_pre(buf, w, h, stride); | |
86 | do { | |
87 | memset(tmp, 0, stride * 2); | |
88 | engine->be_blur(buf, w, h, stride, tmp); | |
89 | } while (--be); | |
90 | be_blur_post(buf, w, h, stride); | |
91 | } | |
92 | memset(tmp, 0, stride * 2); | |
93 | engine->be_blur(buf, w, h, stride, tmp); | |
94 | ass_aligned_free(tmp); | |
95 | } | |
96 | ||
97 | bool alloc_bitmap(const BitmapEngine *engine, Bitmap *bm, | |
98 | int32_t w, int32_t h, bool zero) | |
132 | 99 | { |
133 | 100 | unsigned align = 1 << engine->align_order; |
134 | 101 | size_t s = ass_align(align, w); |
145 | 112 | return true; |
146 | 113 | } |
147 | 114 | |
148 | Bitmap *alloc_bitmap(const BitmapEngine *engine, int w, int h, bool zero) | |
149 | { | |
150 | Bitmap *bm = malloc(sizeof(Bitmap)); | |
151 | if (!bm) | |
152 | return NULL; | |
153 | if (!alloc_bitmap_buffer(engine, bm, w, h, zero)) { | |
154 | free(bm); | |
155 | return NULL; | |
156 | } | |
157 | bm->left = bm->top = 0; | |
158 | return bm; | |
159 | } | |
160 | ||
161 | bool realloc_bitmap(const BitmapEngine *engine, Bitmap *bm, int w, int h) | |
115 | bool realloc_bitmap(const BitmapEngine *engine, Bitmap *bm, int32_t w, int32_t h) | |
162 | 116 | { |
163 | 117 | uint8_t *old = bm->buffer; |
164 | if (!alloc_bitmap_buffer(engine, bm, w, h, false)) | |
118 | if (!alloc_bitmap(engine, bm, w, h, false)) | |
165 | 119 | return false; |
166 | 120 | ass_aligned_free(old); |
167 | 121 | return true; |
169 | 123 | |
170 | 124 | void ass_free_bitmap(Bitmap *bm) |
171 | 125 | { |
172 | if (bm) | |
173 | ass_aligned_free(bm->buffer); | |
174 | free(bm); | |
175 | } | |
176 | ||
177 | Bitmap *copy_bitmap(const BitmapEngine *engine, const Bitmap *src) | |
178 | { | |
179 | Bitmap *dst = alloc_bitmap(engine, src->w, src->h, false); | |
180 | if (!dst) | |
181 | return NULL; | |
126 | ass_aligned_free(bm->buffer); | |
127 | } | |
128 | ||
129 | bool copy_bitmap(const BitmapEngine *engine, Bitmap *dst, const Bitmap *src) | |
130 | { | |
131 | if (!src->buffer) { | |
132 | memset(dst, 0, sizeof(*dst)); | |
133 | return true; | |
134 | } | |
135 | if (!alloc_bitmap(engine, dst, src->w, src->h, false)) | |
136 | return false; | |
182 | 137 | dst->left = src->left; |
183 | dst->top = src->top; | |
138 | dst->top = src->top; | |
184 | 139 | memcpy(dst->buffer, src->buffer, src->stride * src->h); |
185 | return dst; | |
186 | } | |
187 | ||
188 | Bitmap *outline_to_bitmap(ASS_Renderer *render_priv, | |
189 | ASS_Outline *outline1, ASS_Outline *outline2, | |
190 | int bord) | |
140 | return true; | |
141 | } | |
142 | ||
143 | bool outline_to_bitmap(ASS_Renderer *render_priv, Bitmap *bm, | |
144 | ASS_Outline *outline1, ASS_Outline *outline2) | |
191 | 145 | { |
192 | 146 | RasterizerData *rst = &render_priv->rasterizer; |
193 | 147 | if (outline1 && !rasterizer_set_outline(rst, outline1, false)) { |
194 | 148 | ass_msg(render_priv->library, MSGL_WARN, "Failed to process glyph outline!\n"); |
195 | return NULL; | |
149 | return false; | |
196 | 150 | } |
197 | 151 | if (outline2 && !rasterizer_set_outline(rst, outline2, !!outline1)) { |
198 | 152 | ass_msg(render_priv->library, MSGL_WARN, "Failed to process glyph outline!\n"); |
199 | return NULL; | |
200 | } | |
201 | ||
202 | if (bord < 0 || bord > INT_MAX / 2) | |
203 | return NULL; | |
204 | if (rst->bbox.x_max > INT_MAX - 63 || rst->bbox.y_max > INT_MAX - 63) | |
205 | return NULL; | |
206 | ||
207 | int x_min = rst->bbox.x_min >> 6; | |
208 | int y_min = rst->bbox.y_min >> 6; | |
209 | int x_max = (rst->bbox.x_max + 63) >> 6; | |
210 | int y_max = (rst->bbox.y_max + 63) >> 6; | |
211 | int w = x_max - x_min; | |
212 | int h = y_max - y_min; | |
153 | return false; | |
154 | } | |
155 | if (rst->bbox.x_min > rst->bbox.x_max || rst->bbox.y_min > rst->bbox.y_max) | |
156 | return false; | |
157 | ||
158 | // enlarge by 1/64th of pixel to bypass slow rasterizer path, add 1 pixel for shift_bitmap | |
159 | int32_t x_min = (rst->bbox.x_min - 1) >> 6; | |
160 | int32_t y_min = (rst->bbox.y_min - 1) >> 6; | |
161 | int32_t x_max = (rst->bbox.x_max + 127) >> 6; | |
162 | int32_t y_max = (rst->bbox.y_max + 127) >> 6; | |
163 | int32_t w = x_max - x_min; | |
164 | int32_t h = y_max - y_min; | |
213 | 165 | |
214 | 166 | int mask = (1 << render_priv->engine->tile_order) - 1; |
215 | 167 | |
216 | if (w < 0 || h < 0 || | |
217 | w > INT_MAX - (2 * bord + mask) || h > INT_MAX - (2 * bord + mask)) { | |
218 | ass_msg(render_priv->library, MSGL_WARN, "Glyph bounding box too large: %dx%dpx", | |
219 | w, h); | |
220 | return NULL; | |
221 | } | |
222 | ||
223 | int tile_w = (w + 2 * bord + mask) & ~mask; | |
224 | int tile_h = (h + 2 * bord + mask) & ~mask; | |
225 | Bitmap *bm = alloc_bitmap(render_priv->engine, tile_w, tile_h, false); | |
226 | if (!bm) | |
227 | return NULL; | |
228 | bm->left = x_min - bord; | |
229 | bm->top = y_min - bord; | |
168 | // XXX: is that possible to trigger at all? | |
169 | if (w < 0 || h < 0 || w > INT_MAX - mask || h > INT_MAX - mask) { | |
170 | ass_msg(render_priv->library, MSGL_WARN, | |
171 | "Glyph bounding box too large: %dx%dpx", w, h); | |
172 | return false; | |
173 | } | |
174 | ||
175 | int32_t tile_w = (w + mask) & ~mask; | |
176 | int32_t tile_h = (h + mask) & ~mask; | |
177 | if (!alloc_bitmap(render_priv->engine, bm, tile_w, tile_h, false)) | |
178 | return false; | |
179 | bm->left = x_min; | |
180 | bm->top = y_min; | |
230 | 181 | |
231 | 182 | if (!rasterizer_fill(render_priv->engine, rst, bm->buffer, |
232 | x_min - bord, y_min - bord, | |
233 | bm->stride, tile_h, bm->stride)) { | |
183 | x_min, y_min, bm->stride, tile_h, bm->stride)) { | |
234 | 184 | ass_msg(render_priv->library, MSGL_WARN, "Failed to rasterize glyph!\n"); |
235 | 185 | ass_free_bitmap(bm); |
236 | return NULL; | |
237 | } | |
238 | ||
239 | return bm; | |
186 | return false; | |
187 | } | |
188 | ||
189 | return true; | |
240 | 190 | } |
241 | 191 | |
242 | 192 | /** |
247 | 197 | */ |
248 | 198 | void fix_outline(Bitmap *bm_g, Bitmap *bm_o) |
249 | 199 | { |
250 | int x, y; | |
251 | const int l = bm_o->left > bm_g->left ? bm_o->left : bm_g->left; | |
252 | const int t = bm_o->top > bm_g->top ? bm_o->top : bm_g->top; | |
253 | const int r = | |
254 | bm_o->left + bm_o->stride < | |
255 | bm_g->left + bm_g->stride ? bm_o->left + bm_o->stride : bm_g->left + bm_g->stride; | |
256 | const int b = | |
257 | bm_o->top + bm_o->h < | |
258 | bm_g->top + bm_g->h ? bm_o->top + bm_o->h : bm_g->top + bm_g->h; | |
259 | ||
260 | unsigned char *g = | |
261 | bm_g->buffer + (t - bm_g->top) * bm_g->stride + (l - bm_g->left); | |
262 | unsigned char *o = | |
263 | bm_o->buffer + (t - bm_o->top) * bm_o->stride + (l - bm_o->left); | |
264 | ||
265 | for (y = 0; y < b - t; ++y) { | |
266 | for (x = 0; x < r - l; ++x) { | |
267 | unsigned char c_g, c_o; | |
268 | c_g = g[x]; | |
269 | c_o = o[x]; | |
270 | o[x] = (c_o > c_g) ? c_o - (c_g / 2) : 0; | |
271 | } | |
200 | if (!bm_g->buffer || !bm_o->buffer) | |
201 | return; | |
202 | ||
203 | int32_t l = FFMAX(bm_o->left, bm_g->left); | |
204 | int32_t t = FFMAX(bm_o->top, bm_g->top); | |
205 | int32_t r = FFMIN(bm_o->left + bm_o->stride, bm_g->left + bm_g->stride); | |
206 | int32_t b = FFMIN(bm_o->top + bm_o->h, bm_g->top + bm_g->h); | |
207 | ||
208 | uint8_t *g = bm_g->buffer + (t - bm_g->top) * bm_g->stride + (l - bm_g->left); | |
209 | uint8_t *o = bm_o->buffer + (t - bm_o->top) * bm_o->stride + (l - bm_o->left); | |
210 | ||
211 | for (int32_t y = 0; y < b - t; y++) { | |
212 | for (int32_t x = 0; x < r - l; x++) | |
213 | o[x] = (o[x] > g[x]) ? o[x] - (g[x] / 2) : 0; | |
272 | 214 | g += bm_g->stride; |
273 | 215 | o += bm_o->stride; |
274 | 216 | } |
280 | 222 | */ |
281 | 223 | void shift_bitmap(Bitmap *bm, int shift_x, int shift_y) |
282 | 224 | { |
283 | int x, y, b; | |
284 | int w = bm->w; | |
285 | int h = bm->h; | |
286 | int s = bm->stride; | |
287 | unsigned char *buf = bm->buffer; | |
288 | ||
289 | 225 | assert((shift_x & ~63) == 0 && (shift_y & ~63) == 0); |
290 | 226 | |
227 | if (!bm->buffer) | |
228 | return; | |
229 | ||
230 | int32_t w = bm->w, h = bm->h; | |
231 | ptrdiff_t s = bm->stride; | |
232 | uint8_t *buf = bm->buffer; | |
233 | ||
291 | 234 | // Shift in x direction |
292 | for (y = 0; y < h; y++) { | |
293 | for (x = w - 1; x > 0; x--) { | |
294 | b = (buf[x + y * s - 1] * shift_x) >> 6; | |
295 | buf[x + y * s - 1] -= b; | |
296 | buf[x + y * s] += b; | |
297 | } | |
298 | } | |
235 | if (shift_x) | |
236 | for (int32_t y = 0; y < h; y++) { | |
237 | for (int32_t x = w - 1; x > 0; x--) { | |
238 | uint8_t b = buf[x + y * s - 1] * shift_x >> 6; | |
239 | buf[x + y * s - 1] -= b; | |
240 | buf[x + y * s] += b; | |
241 | } | |
242 | } | |
299 | 243 | |
300 | 244 | // Shift in y direction |
301 | for (x = 0; x < w; x++) { | |
302 | for (y = h - 1; y > 0; y--) { | |
303 | b = (buf[x + (y - 1) * s] * shift_y) >> 6; | |
304 | buf[x + (y - 1) * s] -= b; | |
305 | buf[x + y * s] += b; | |
306 | } | |
307 | } | |
245 | if (shift_y) | |
246 | for (int32_t x = 0; x < w; x++) { | |
247 | for (int32_t y = h - 1; y > 0; y--) { | |
248 | uint8_t b = buf[x + y * s - s] * shift_y >> 6; | |
249 | buf[x + y * s - s] -= b; | |
250 | buf[x + y * s] += b; | |
251 | } | |
252 | } | |
308 | 253 | } |
309 | 254 | |
310 | 255 | /** |
433 | 378 | return FFMAX(128 - be, 0); |
434 | 379 | } |
435 | 380 | |
436 | bool outline_to_bitmap2(ASS_Renderer *render_priv, ASS_Outline *outline, | |
437 | ASS_Outline *border1, ASS_Outline *border2, | |
438 | Bitmap **bm_g, Bitmap **bm_o) | |
439 | { | |
440 | assert(bm_g && bm_o); | |
441 | *bm_g = *bm_o = NULL; | |
442 | ||
443 | if (outline && !outline->n_points) | |
444 | outline = NULL; | |
445 | if (border1 && !border1->n_points) | |
446 | border1 = NULL; | |
447 | if (border2 && !border2->n_points) | |
448 | border2 = NULL; | |
449 | ||
450 | if (outline) { | |
451 | *bm_g = outline_to_bitmap(render_priv, outline, NULL, 1); | |
452 | if (!*bm_g) | |
453 | return false; | |
454 | } | |
455 | ||
456 | if (border1 || border2) { | |
457 | *bm_o = outline_to_bitmap(render_priv, border1, border2, 1); | |
458 | if (!*bm_o) { | |
459 | return false; | |
460 | } | |
461 | } | |
462 | ||
463 | return true; | |
464 | } | |
465 | ||
466 | 381 | /** |
467 | 382 | * \brief Add two bitmaps together at a given position |
468 | 383 | * Uses additive blending, clipped to [0,255]. Pure C implementation. |
79 | 79 | Convert16to8Func stripe_pack; |
80 | 80 | FilterFunc shrink_horz, shrink_vert; |
81 | 81 | FilterFunc expand_horz, expand_vert; |
82 | FilterFunc pre_blur_horz[3], pre_blur_vert[3]; | |
83 | ParamFilterFunc main_blur_horz[3], main_blur_vert[3]; | |
82 | ParamFilterFunc blur_horz[5], blur_vert[5]; | |
84 | 83 | } BitmapEngine; |
85 | 84 | |
86 | 85 | extern const BitmapEngine ass_bitmap_engine_c; |
89 | 88 | |
90 | 89 | |
91 | 90 | typedef struct { |
92 | int left, top; | |
93 | int w, h; // width, height | |
94 | int stride; | |
95 | unsigned char *buffer; // h * stride buffer | |
91 | int32_t left, top; | |
92 | int32_t w, h; // width, height | |
93 | ptrdiff_t stride; | |
94 | uint8_t *buffer; // h * stride buffer | |
96 | 95 | } Bitmap; |
97 | 96 | |
98 | Bitmap *alloc_bitmap(const BitmapEngine *engine, int w, int h, bool zero); | |
99 | bool realloc_bitmap(const BitmapEngine *engine, Bitmap *bm, int w, int h); | |
100 | Bitmap *copy_bitmap(const BitmapEngine *engine, const Bitmap *src); | |
97 | bool alloc_bitmap(const BitmapEngine *engine, Bitmap *bm, int32_t w, int32_t h, bool zero); | |
98 | bool realloc_bitmap(const BitmapEngine *engine, Bitmap *bm, int32_t w, int32_t h); | |
99 | bool copy_bitmap(const BitmapEngine *engine, Bitmap *dst, const Bitmap *src); | |
101 | 100 | void ass_free_bitmap(Bitmap *bm); |
102 | 101 | |
103 | Bitmap *outline_to_bitmap(ASS_Renderer *render_priv, | |
104 | ASS_Outline *outline1, ASS_Outline *outline2, | |
105 | int bord); | |
102 | bool outline_to_bitmap(ASS_Renderer *render_priv, Bitmap *bm, | |
103 | ASS_Outline *outline1, ASS_Outline *outline2); | |
106 | 104 | |
107 | void ass_synth_blur(const BitmapEngine *engine, int opaque_box, int be, | |
108 | double blur_radius, Bitmap *bm_g, Bitmap *bm_o); | |
109 | ||
110 | /** | |
111 | * \brief perform glyph rendering | |
112 | * \param outline original glyph | |
113 | * \param border1 inside "border" outline, produced by stroker | |
114 | * \param border2 outside "border" outline, produced by stroker | |
115 | * \param bm_g out: pointer to the bitmap of original glyph is returned here | |
116 | * \param bm_o out: pointer to the bitmap of border glyph is returned here | |
117 | */ | |
118 | bool outline_to_bitmap2(ASS_Renderer *render_priv, ASS_Outline *outline, | |
119 | ASS_Outline *border1, ASS_Outline *border2, | |
120 | Bitmap **bm_g, Bitmap **bm_o); | |
105 | void ass_synth_blur(const BitmapEngine *engine, Bitmap *bm, | |
106 | int be, double blur_r2); | |
121 | 107 | |
122 | 108 | int be_padding(int be); |
123 | 109 | void be_blur_pre(uint8_t *buf, intptr_t w, |
28 | 28 | /* |
29 | 29 | * Cascade Blur Algorithm |
30 | 30 | * |
31 | * The main idea is simple: to approximate gaussian blur with large radius | |
32 | * you can downscale, then apply filter with small pattern, then upscale back. | |
33 | * | |
34 | * To achieve desired precision down/upscaling should be done with sufficiently smooth kernel. | |
35 | * Experiment shows that downscaling of factor 2 with kernel [1, 5, 10, 10, 5, 1] and | |
31 | * The main idea is simple: to approximate a gaussian blur with large radius, | |
32 | * you can scale down, apply a filter with a relatively small pattern, then scale back up. | |
33 | * | |
34 | * To achieve the desired precision, scaling should be done with sufficiently smooth kernel. | |
35 | * Experiments show that downscaling of factor 2 with kernel [1, 5, 10, 10, 5, 1] and | |
36 | 36 | * corresponding upscaling are enough for 8-bit precision. |
37 | 37 | * |
38 | * For central filter here is used generic 9-tap filter with one of 3 different patterns | |
39 | * combined with one of optional prefilters with fixed kernels. Kernel coefficients | |
40 | * of the main filter are obtained from solution of least squares problem | |
41 | * for Fourier transform of resulting kernel. | |
38 | * Here we use generic filters with 5 different kernel widths (9 to 17-tap). | |
39 | * Kernel coefficients of that filter are obtained from the solution of the least-squares problem | |
40 | * for the Fourier transform of the resulting kernel. | |
42 | 41 | */ |
43 | 42 | |
44 | 43 | |
62 | 61 | |
63 | 62 | inline static void copy_line(int16_t *buf, const int16_t *ptr, uintptr_t offs, uintptr_t size) |
64 | 63 | { |
65 | ptr = get_line(ptr, offs, size); | |
66 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
67 | buf[k] = ptr[k]; | |
64 | memcpy(buf, get_line(ptr, offs, size), STRIPE_WIDTH * sizeof(buf[0])); | |
68 | 65 | } |
69 | 66 | |
70 | 67 | /* |
78 | 75 | void ass_stripe_unpack_c(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, |
79 | 76 | uintptr_t width, uintptr_t height) |
80 | 77 | { |
81 | for (uintptr_t y = 0; y < height; ++y) { | |
78 | for (uintptr_t y = 0; y < height; y++) { | |
82 | 79 | int16_t *ptr = dst; |
83 | 80 | for (uintptr_t x = 0; x < width; x += STRIPE_WIDTH) { |
84 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
81 | for (int k = 0; k < STRIPE_WIDTH; k++) | |
85 | 82 | ptr[k] = (uint16_t) (((src[x + k] << 7) | (src[x + k] >> 1)) + 1) >> 1; |
86 | 83 | //ptr[k] = (0x4000 * src[x + k] + 127) / 255; |
87 | 84 | ptr += STRIPE_WIDTH * height; |
96 | 93 | { |
97 | 94 | for (uintptr_t x = 0; x < width; x += STRIPE_WIDTH) { |
98 | 95 | uint8_t *ptr = dst; |
99 | for (uintptr_t y = 0; y < height; ++y) { | |
96 | for (uintptr_t y = 0; y < height; y++) { | |
100 | 97 | const int16_t *dither = dither_line + (y & 1) * STRIPE_WIDTH; |
101 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
98 | for (int k = 0; k < STRIPE_WIDTH; k++) | |
102 | 99 | ptr[k] = (uint16_t) (src[k] - (src[k] >> 8) + dither[k]) >> 6; |
103 | 100 | //ptr[k] = (255 * src[k] + 0x1FFF) / 0x4000; |
104 | 101 | ptr += dst_stride; |
107 | 104 | dst += STRIPE_WIDTH; |
108 | 105 | } |
109 | 106 | uintptr_t left = dst_stride - ((width + STRIPE_MASK) & ~STRIPE_MASK); |
110 | for (uintptr_t y = 0; y < height; ++y) { | |
111 | for (uintptr_t x = 0; x < left; ++x) | |
107 | for (uintptr_t y = 0; y < height; y++) { | |
108 | for (uintptr_t x = 0; x < left; x++) | |
112 | 109 | dst[x] = 0; |
113 | 110 | dst += dst_stride; |
114 | 111 | } |
144 | 141 | int16_t buf[3 * STRIPE_WIDTH]; |
145 | 142 | int16_t *ptr = buf + STRIPE_WIDTH; |
146 | 143 | for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) { |
147 | for (uintptr_t y = 0; y < src_height; ++y) { | |
144 | for (uintptr_t y = 0; y < src_height; y++) { | |
148 | 145 | copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); |
149 | 146 | copy_line(ptr + 0 * STRIPE_WIDTH, src, offs + 0 * step, size); |
150 | 147 | copy_line(ptr + 1 * STRIPE_WIDTH, src, offs + 1 * step, size); |
151 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
148 | for (int k = 0; k < STRIPE_WIDTH; k++) | |
152 | 149 | dst[k] = shrink_func(ptr[2 * k - 4], ptr[2 * k - 3], |
153 | 150 | ptr[2 * k - 2], ptr[2 * k - 1], |
154 | 151 | ptr[2 * k + 0], ptr[2 * k + 1]); |
155 | dst += STRIPE_WIDTH; | |
152 | dst += STRIPE_WIDTH; | |
156 | 153 | offs += STRIPE_WIDTH; |
157 | 154 | } |
158 | 155 | offs += step; |
167 | 164 | |
168 | 165 | for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) { |
169 | 166 | uintptr_t offs = 0; |
170 | for (uintptr_t y = 0; y < dst_height; ++y) { | |
167 | for (uintptr_t y = 0; y < dst_height; y++) { | |
171 | 168 | const int16_t *p1p = get_line(src, offs - 4 * STRIPE_WIDTH, step); |
172 | 169 | const int16_t *p1n = get_line(src, offs - 3 * STRIPE_WIDTH, step); |
173 | 170 | const int16_t *z0p = get_line(src, offs - 2 * STRIPE_WIDTH, step); |
174 | 171 | const int16_t *z0n = get_line(src, offs - 1 * STRIPE_WIDTH, step); |
175 | 172 | const int16_t *n1p = get_line(src, offs - 0 * STRIPE_WIDTH, step); |
176 | 173 | const int16_t *n1n = get_line(src, offs + 1 * STRIPE_WIDTH, step); |
177 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
174 | for (int k = 0; k < STRIPE_WIDTH; k++) | |
178 | 175 | dst[k] = shrink_func(p1p[k], p1n[k], z0p[k], z0n[k], n1p[k], n1n[k]); |
179 | dst += STRIPE_WIDTH; | |
176 | dst += 1 * STRIPE_WIDTH; | |
180 | 177 | offs += 2 * STRIPE_WIDTH; |
181 | 178 | } |
182 | 179 | src += step; |
212 | 209 | int16_t buf[2 * STRIPE_WIDTH]; |
213 | 210 | int16_t *ptr = buf + STRIPE_WIDTH; |
214 | 211 | for (uintptr_t x = STRIPE_WIDTH; x < dst_width; x += 2 * STRIPE_WIDTH) { |
215 | for (uintptr_t y = 0; y < src_height; ++y) { | |
212 | for (uintptr_t y = 0; y < src_height; y++) { | |
216 | 213 | copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); |
217 | 214 | copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size); |
218 | for (int k = 0; k < STRIPE_WIDTH / 2; ++k) | |
215 | for (int k = 0; k < STRIPE_WIDTH / 2; k++) | |
219 | 216 | expand_func(&dst[2 * k], &dst[2 * k + 1], |
220 | 217 | ptr[k - 2], ptr[k - 1], ptr[k]); |
221 | 218 | int16_t *next = dst + step - STRIPE_WIDTH; |
222 | for (int k = STRIPE_WIDTH / 2; k < STRIPE_WIDTH; ++k) | |
219 | for (int k = STRIPE_WIDTH / 2; k < STRIPE_WIDTH; k++) | |
223 | 220 | expand_func(&next[2 * k], &next[2 * k + 1], |
224 | 221 | ptr[k - 2], ptr[k - 1], ptr[k]); |
225 | dst += STRIPE_WIDTH; | |
222 | dst += STRIPE_WIDTH; | |
226 | 223 | offs += STRIPE_WIDTH; |
227 | 224 | } |
228 | 225 | dst += step; |
230 | 227 | if ((dst_width - 1) & STRIPE_WIDTH) |
231 | 228 | return; |
232 | 229 | |
233 | for (uintptr_t y = 0; y < src_height; ++y) { | |
230 | for (uintptr_t y = 0; y < src_height; y++) { | |
234 | 231 | copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); |
235 | 232 | copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size); |
236 | for (int k = 0; k < STRIPE_WIDTH / 2; ++k) | |
233 | for (int k = 0; k < STRIPE_WIDTH / 2; k++) | |
237 | 234 | expand_func(&dst[2 * k], &dst[2 * k + 1], |
238 | 235 | ptr[k - 2], ptr[k - 1], ptr[k]); |
239 | dst += STRIPE_WIDTH; | |
236 | dst += STRIPE_WIDTH; | |
240 | 237 | offs += STRIPE_WIDTH; |
241 | 238 | } |
242 | 239 | } |
253 | 250 | const int16_t *p1 = get_line(src, offs - 2 * STRIPE_WIDTH, step); |
254 | 251 | const int16_t *z0 = get_line(src, offs - 1 * STRIPE_WIDTH, step); |
255 | 252 | const int16_t *n1 = get_line(src, offs - 0 * STRIPE_WIDTH, step); |
256 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
253 | for (int k = 0; k < STRIPE_WIDTH; k++) | |
257 | 254 | expand_func(&dst[k], &dst[k + STRIPE_WIDTH], |
258 | 255 | p1[k], z0[k], n1[k]); |
259 | dst += 2 * STRIPE_WIDTH; | |
260 | offs += STRIPE_WIDTH; | |
256 | dst += 2 * STRIPE_WIDTH; | |
257 | offs += 1 * STRIPE_WIDTH; | |
261 | 258 | } |
262 | 259 | src += step; |
263 | 260 | } |
264 | 261 | } |
265 | 262 | |
266 | 263 | /* |
267 | * First Supplementary Filters | |
268 | * | |
269 | * Perform 1D convolution with kernel [1, 2, 1]. | |
270 | */ | |
271 | ||
272 | static inline int16_t pre_blur1_func(int16_t p1, int16_t z0, int16_t n1) | |
273 | { | |
274 | /* | |
275 | return (1 * p1 + 2 * z0 + 1 * n1 + 2) >> 2; | |
276 | */ | |
277 | return (uint16_t) (((uint16_t) (p1 + n1) >> 1) + z0 + 1) >> 1; | |
278 | } | |
279 | ||
280 | void ass_pre_blur1_horz_c(int16_t *dst, const int16_t *src, | |
281 | uintptr_t src_width, uintptr_t src_height) | |
282 | { | |
283 | uintptr_t dst_width = src_width + 2; | |
264 | * Main Parametric Filters | |
265 | * | |
266 | * Perform 1D convolution with kernel [..., c2, c1, c0, d, c0, c1, c2, ...], | |
267 | * cN = param[N], d = 1 - 2 * (c0 + c1 + c2 + ...), | |
268 | * number of parameters is part of the function name. | |
269 | */ | |
270 | ||
271 | static inline void blur_horz(int16_t *dst, const int16_t *src, | |
272 | uintptr_t src_width, uintptr_t src_height, | |
273 | const int16_t *param, const int n) | |
274 | { | |
275 | uintptr_t dst_width = src_width + 2 * n; | |
284 | 276 | uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height; |
285 | 277 | uintptr_t step = STRIPE_WIDTH * src_height; |
286 | 278 | |
287 | 279 | uintptr_t offs = 0; |
288 | int16_t buf[2 * STRIPE_WIDTH]; | |
289 | int16_t *ptr = buf + STRIPE_WIDTH; | |
280 | int16_t buf[3 * STRIPE_WIDTH]; | |
281 | int16_t *ptr = buf + 2 * STRIPE_WIDTH; | |
290 | 282 | for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) { |
291 | for (uintptr_t y = 0; y < src_height; ++y) { | |
292 | copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); | |
293 | copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size); | |
294 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
295 | dst[k] = pre_blur1_func(ptr[k - 2], ptr[k - 1], ptr[k]); | |
296 | dst += STRIPE_WIDTH; | |
283 | for (uintptr_t y = 0; y < src_height; y++) { | |
284 | for (int i = -((2 * n + STRIPE_WIDTH - 1u) / STRIPE_WIDTH); i <= 0; i++) | |
285 | copy_line(ptr + i * STRIPE_WIDTH, src, offs + i * step, size); | |
286 | int32_t acc[STRIPE_WIDTH]; | |
287 | for (int k = 0; k < STRIPE_WIDTH; k++) | |
288 | acc[k] = 0x8000; | |
289 | for (int i = n; i > 0; i--) | |
290 | for (int k = 0; k < STRIPE_WIDTH; k++) | |
291 | acc[k] += (int16_t) (ptr[k - n - i] - ptr[k - n]) * param[i - 1] + | |
292 | (int16_t) (ptr[k - n + i] - ptr[k - n]) * param[i - 1]; | |
293 | for (int k = 0; k < STRIPE_WIDTH; k++) | |
294 | dst[k] = ptr[k - n] + (acc[k] >> 16); | |
295 | ||
296 | dst += STRIPE_WIDTH; | |
297 | 297 | offs += STRIPE_WIDTH; |
298 | 298 | } |
299 | 299 | } |
300 | 300 | } |
301 | 301 | |
302 | void ass_pre_blur1_vert_c(int16_t *dst, const int16_t *src, | |
303 | uintptr_t src_width, uintptr_t src_height) | |
304 | { | |
305 | uintptr_t dst_height = src_height + 2; | |
302 | static inline void blur_vert(int16_t *dst, const int16_t *src, | |
303 | uintptr_t src_width, uintptr_t src_height, | |
304 | const int16_t *param, const int n) | |
305 | { | |
306 | uintptr_t dst_height = src_height + 2 * n; | |
306 | 307 | uintptr_t step = STRIPE_WIDTH * src_height; |
307 | 308 | |
308 | 309 | for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) { |
309 | 310 | uintptr_t offs = 0; |
310 | for (uintptr_t y = 0; y < dst_height; ++y) { | |
311 | const int16_t *p1 = get_line(src, offs - 2 * STRIPE_WIDTH, step); | |
312 | const int16_t *z0 = get_line(src, offs - 1 * STRIPE_WIDTH, step); | |
313 | const int16_t *n1 = get_line(src, offs - 0 * STRIPE_WIDTH, step); | |
314 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
315 | dst[k] = pre_blur1_func(p1[k], z0[k], n1[k]); | |
316 | dst += STRIPE_WIDTH; | |
311 | for (uintptr_t y = 0; y < dst_height; y++) { | |
312 | int32_t acc[STRIPE_WIDTH]; | |
313 | for (int k = 0; k < STRIPE_WIDTH; k++) | |
314 | acc[k] = 0x8000; | |
315 | const int16_t *center = get_line(src, offs - n * STRIPE_WIDTH, step); | |
316 | for (int i = n; i > 0; i--) { | |
317 | const int16_t *line1 = get_line(src, offs - (n + i) * STRIPE_WIDTH, step); | |
318 | const int16_t *line2 = get_line(src, offs - (n - i) * STRIPE_WIDTH, step); | |
319 | for (int k = 0; k < STRIPE_WIDTH; k++) | |
320 | acc[k] += (int16_t) (line1[k] - center[k]) * param[i - 1] + | |
321 | (int16_t) (line2[k] - center[k]) * param[i - 1]; | |
322 | } | |
323 | for (int k = 0; k < STRIPE_WIDTH; k++) | |
324 | dst[k] = center[k] + (acc[k] >> 16); | |
325 | ||
326 | dst += STRIPE_WIDTH; | |
317 | 327 | offs += STRIPE_WIDTH; |
318 | 328 | } |
319 | 329 | src += step; |
320 | 330 | } |
321 | 331 | } |
322 | 332 | |
323 | /* | |
324 | * Second Supplementary Filters | |
325 | * | |
326 | * Perform 1D convolution with kernel [1, 4, 6, 4, 1]. | |
327 | */ | |
328 | ||
329 | static inline int16_t pre_blur2_func(int16_t p2, int16_t p1, int16_t z0, | |
330 | int16_t n1, int16_t n2) | |
331 | { | |
332 | /* | |
333 | return (1 * p2 + 4 * p1 + 6 * z0 + 4 * n1 + 1 * n2 + 8) >> 4; | |
334 | */ | |
335 | uint16_t r1 = ((uint16_t) (((uint16_t) (p2 + n2) >> 1) + z0) >> 1) + z0; | |
336 | uint16_t r2 = p1 + n1; | |
337 | uint16_t r = ((uint16_t) (r1 + r2) >> 1) | (0x8000 & r1 & r2); | |
338 | return (uint16_t) (r + 1) >> 1; | |
339 | } | |
340 | ||
341 | void ass_pre_blur2_horz_c(int16_t *dst, const int16_t *src, | |
342 | uintptr_t src_width, uintptr_t src_height) | |
343 | { | |
344 | uintptr_t dst_width = src_width + 4; | |
345 | uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height; | |
346 | uintptr_t step = STRIPE_WIDTH * src_height; | |
347 | ||
348 | uintptr_t offs = 0; | |
349 | int16_t buf[2 * STRIPE_WIDTH]; | |
350 | int16_t *ptr = buf + STRIPE_WIDTH; | |
351 | for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) { | |
352 | for (uintptr_t y = 0; y < src_height; ++y) { | |
353 | copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); | |
354 | copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size); | |
355 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
356 | dst[k] = pre_blur2_func(ptr[k - 4], ptr[k - 3], ptr[k - 2], ptr[k - 1], ptr[k]); | |
357 | dst += STRIPE_WIDTH; | |
358 | offs += STRIPE_WIDTH; | |
359 | } | |
360 | } | |
361 | } | |
362 | ||
363 | void ass_pre_blur2_vert_c(int16_t *dst, const int16_t *src, | |
364 | uintptr_t src_width, uintptr_t src_height) | |
365 | { | |
366 | uintptr_t dst_height = src_height + 4; | |
367 | uintptr_t step = STRIPE_WIDTH * src_height; | |
368 | ||
369 | for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) { | |
370 | uintptr_t offs = 0; | |
371 | for (uintptr_t y = 0; y < dst_height; ++y) { | |
372 | const int16_t *p2 = get_line(src, offs - 4 * STRIPE_WIDTH, step); | |
373 | const int16_t *p1 = get_line(src, offs - 3 * STRIPE_WIDTH, step); | |
374 | const int16_t *z0 = get_line(src, offs - 2 * STRIPE_WIDTH, step); | |
375 | const int16_t *n1 = get_line(src, offs - 1 * STRIPE_WIDTH, step); | |
376 | const int16_t *n2 = get_line(src, offs - 0 * STRIPE_WIDTH, step); | |
377 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
378 | dst[k] = pre_blur2_func(p2[k], p1[k], z0[k], n1[k], n2[k]); | |
379 | dst += STRIPE_WIDTH; | |
380 | offs += STRIPE_WIDTH; | |
381 | } | |
382 | src += step; | |
383 | } | |
384 | } | |
385 | ||
386 | /* | |
387 | * Third Supplementary Filters | |
388 | * | |
389 | * Perform 1D convolution with kernel [1, 6, 15, 20, 15, 6, 1]. | |
390 | */ | |
391 | ||
392 | static inline int16_t pre_blur3_func(int16_t p3, int16_t p2, int16_t p1, int16_t z0, | |
393 | int16_t n1, int16_t n2, int16_t n3) | |
394 | { | |
395 | /* | |
396 | return (1 * p3 + 6 * p2 + 15 * p1 + 20 * z0 + 15 * n1 + 6 * n2 + 1 * n3 + 32) >> 6; | |
397 | */ | |
398 | return (20 * (uint16_t) z0 + | |
399 | 15 * (uint16_t) (p1 + n1) + | |
400 | 6 * (uint16_t) (p2 + n2) + | |
401 | 1 * (uint16_t) (p3 + n3) + 32) >> 6; | |
402 | } | |
403 | ||
404 | void ass_pre_blur3_horz_c(int16_t *dst, const int16_t *src, | |
405 | uintptr_t src_width, uintptr_t src_height) | |
406 | { | |
407 | uintptr_t dst_width = src_width + 6; | |
408 | uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height; | |
409 | uintptr_t step = STRIPE_WIDTH * src_height; | |
410 | ||
411 | uintptr_t offs = 0; | |
412 | int16_t buf[2 * STRIPE_WIDTH]; | |
413 | int16_t *ptr = buf + STRIPE_WIDTH; | |
414 | for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) { | |
415 | for (uintptr_t y = 0; y < src_height; ++y) { | |
416 | copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); | |
417 | copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size); | |
418 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
419 | dst[k] = pre_blur3_func(ptr[k - 6], ptr[k - 5], ptr[k - 4], ptr[k - 3], | |
420 | ptr[k - 2], ptr[k - 1], ptr[k]); | |
421 | dst += STRIPE_WIDTH; | |
422 | offs += STRIPE_WIDTH; | |
423 | } | |
424 | } | |
425 | } | |
426 | ||
427 | void ass_pre_blur3_vert_c(int16_t *dst, const int16_t *src, | |
428 | uintptr_t src_width, uintptr_t src_height) | |
429 | { | |
430 | uintptr_t dst_height = src_height + 6; | |
431 | uintptr_t step = STRIPE_WIDTH * src_height; | |
432 | ||
433 | for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) { | |
434 | uintptr_t offs = 0; | |
435 | for (uintptr_t y = 0; y < dst_height; ++y) { | |
436 | const int16_t *p3 = get_line(src, offs - 6 * STRIPE_WIDTH, step); | |
437 | const int16_t *p2 = get_line(src, offs - 5 * STRIPE_WIDTH, step); | |
438 | const int16_t *p1 = get_line(src, offs - 4 * STRIPE_WIDTH, step); | |
439 | const int16_t *z0 = get_line(src, offs - 3 * STRIPE_WIDTH, step); | |
440 | const int16_t *n1 = get_line(src, offs - 2 * STRIPE_WIDTH, step); | |
441 | const int16_t *n2 = get_line(src, offs - 1 * STRIPE_WIDTH, step); | |
442 | const int16_t *n3 = get_line(src, offs - 0 * STRIPE_WIDTH, step); | |
443 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
444 | dst[k] = pre_blur3_func(p3[k], p2[k], p1[k], z0[k], n1[k], n2[k], n3[k]); | |
445 | dst += STRIPE_WIDTH; | |
446 | offs += STRIPE_WIDTH; | |
447 | } | |
448 | src += step; | |
449 | } | |
450 | } | |
451 | ||
452 | /* | |
453 | * Main 9-tap Parametric Filters | |
454 | * | |
455 | * Perform 1D convolution with kernel | |
456 | * [c3, c2, c1, c0, d, c0, c1, c2, c3] or | |
457 | * [c3, 0, c2, c1, c0, d, c0, c1, c2, 0, c3] or | |
458 | * [c3, 0, c2, 0, c1, c0, d, c0, c1, 0, c2, 0, c3] accordingly. | |
459 | * | |
460 | * cN = param[N], d = 1 - 2 * (c0 + c1 + c2 + c3). | |
461 | */ | |
462 | ||
463 | static inline int16_t blur_func(int16_t p4, int16_t p3, int16_t p2, int16_t p1, int16_t z0, | |
464 | int16_t n1, int16_t n2, int16_t n3, int16_t n4, const int16_t c[]) | |
465 | { | |
466 | p1 -= z0; | |
467 | p2 -= z0; | |
468 | p3 -= z0; | |
469 | p4 -= z0; | |
470 | n1 -= z0; | |
471 | n2 -= z0; | |
472 | n3 -= z0; | |
473 | n4 -= z0; | |
474 | return (((p1 + n1) * c[0] + | |
475 | (p2 + n2) * c[1] + | |
476 | (p3 + n3) * c[2] + | |
477 | (p4 + n4) * c[3] + | |
478 | 0x8000) >> 16) + z0; | |
479 | } | |
480 | ||
481 | void ass_blur1234_horz_c(int16_t *dst, const int16_t *src, | |
482 | uintptr_t src_width, uintptr_t src_height, | |
483 | const int16_t *param) | |
484 | { | |
485 | uintptr_t dst_width = src_width + 8; | |
486 | uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height; | |
487 | uintptr_t step = STRIPE_WIDTH * src_height; | |
488 | ||
489 | uintptr_t offs = 0; | |
490 | int16_t buf[2 * STRIPE_WIDTH]; | |
491 | int16_t *ptr = buf + STRIPE_WIDTH; | |
492 | for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) { | |
493 | for (uintptr_t y = 0; y < src_height; ++y) { | |
494 | copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); | |
495 | copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size); | |
496 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
497 | dst[k] = blur_func(ptr[k - 8], ptr[k - 7], ptr[k - 6], ptr[k - 5], ptr[k - 4], | |
498 | ptr[k - 3], ptr[k - 2], ptr[k - 1], ptr[k - 0], param); | |
499 | dst += STRIPE_WIDTH; | |
500 | offs += STRIPE_WIDTH; | |
501 | } | |
502 | } | |
503 | } | |
504 | ||
505 | void ass_blur1234_vert_c(int16_t *dst, const int16_t *src, | |
506 | uintptr_t src_width, uintptr_t src_height, | |
507 | const int16_t *param) | |
508 | { | |
509 | uintptr_t dst_height = src_height + 8; | |
510 | uintptr_t step = STRIPE_WIDTH * src_height; | |
511 | ||
512 | for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) { | |
513 | uintptr_t offs = 0; | |
514 | for (uintptr_t y = 0; y < dst_height; ++y) { | |
515 | const int16_t *p4 = get_line(src, offs - 8 * STRIPE_WIDTH, step); | |
516 | const int16_t *p3 = get_line(src, offs - 7 * STRIPE_WIDTH, step); | |
517 | const int16_t *p2 = get_line(src, offs - 6 * STRIPE_WIDTH, step); | |
518 | const int16_t *p1 = get_line(src, offs - 5 * STRIPE_WIDTH, step); | |
519 | const int16_t *z0 = get_line(src, offs - 4 * STRIPE_WIDTH, step); | |
520 | const int16_t *n1 = get_line(src, offs - 3 * STRIPE_WIDTH, step); | |
521 | const int16_t *n2 = get_line(src, offs - 2 * STRIPE_WIDTH, step); | |
522 | const int16_t *n3 = get_line(src, offs - 1 * STRIPE_WIDTH, step); | |
523 | const int16_t *n4 = get_line(src, offs - 0 * STRIPE_WIDTH, step); | |
524 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
525 | dst[k] = blur_func(p4[k], p3[k], p2[k], p1[k], z0[k], | |
526 | n1[k], n2[k], n3[k], n4[k], param); | |
527 | dst += STRIPE_WIDTH; | |
528 | offs += STRIPE_WIDTH; | |
529 | } | |
530 | src += step; | |
531 | } | |
532 | } | |
533 | ||
534 | void ass_blur1235_horz_c(int16_t *dst, const int16_t *src, | |
535 | uintptr_t src_width, uintptr_t src_height, | |
536 | const int16_t *param) | |
537 | { | |
538 | uintptr_t dst_width = src_width + 10; | |
539 | uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height; | |
540 | uintptr_t step = STRIPE_WIDTH * src_height; | |
541 | ||
542 | uintptr_t offs = 0; | |
543 | #if STRIPE_WIDTH < 10 | |
544 | int16_t buf[3 * STRIPE_WIDTH]; | |
545 | int16_t *ptr = buf + 2 * STRIPE_WIDTH; | |
546 | #else | |
547 | int16_t buf[2 * STRIPE_WIDTH]; | |
548 | int16_t *ptr = buf + STRIPE_WIDTH; | |
549 | #endif | |
550 | for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) { | |
551 | for (uintptr_t y = 0; y < src_height; ++y) { | |
552 | #if STRIPE_WIDTH < 10 | |
553 | copy_line(ptr - 2 * STRIPE_WIDTH, src, offs - 2 * step, size); | |
554 | #endif | |
555 | copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); | |
556 | copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size); | |
557 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
558 | dst[k] = blur_func(ptr[k - 10], ptr[k - 8], ptr[k - 7], ptr[k - 6], ptr[k - 5], | |
559 | ptr[k - 4], ptr[k - 3], ptr[k - 2], ptr[k - 0], param); | |
560 | dst += STRIPE_WIDTH; | |
561 | offs += STRIPE_WIDTH; | |
562 | } | |
563 | } | |
564 | } | |
565 | ||
566 | void ass_blur1235_vert_c(int16_t *dst, const int16_t *src, | |
567 | uintptr_t src_width, uintptr_t src_height, | |
568 | const int16_t *param) | |
569 | { | |
570 | uintptr_t dst_height = src_height + 10; | |
571 | uintptr_t step = STRIPE_WIDTH * src_height; | |
572 | ||
573 | for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) { | |
574 | uintptr_t offs = 0; | |
575 | for (uintptr_t y = 0; y < dst_height; ++y) { | |
576 | const int16_t *p4 = get_line(src, offs - 10 * STRIPE_WIDTH, step); | |
577 | const int16_t *p3 = get_line(src, offs - 8 * STRIPE_WIDTH, step); | |
578 | const int16_t *p2 = get_line(src, offs - 7 * STRIPE_WIDTH, step); | |
579 | const int16_t *p1 = get_line(src, offs - 6 * STRIPE_WIDTH, step); | |
580 | const int16_t *z0 = get_line(src, offs - 5 * STRIPE_WIDTH, step); | |
581 | const int16_t *n1 = get_line(src, offs - 4 * STRIPE_WIDTH, step); | |
582 | const int16_t *n2 = get_line(src, offs - 3 * STRIPE_WIDTH, step); | |
583 | const int16_t *n3 = get_line(src, offs - 2 * STRIPE_WIDTH, step); | |
584 | const int16_t *n4 = get_line(src, offs - 0 * STRIPE_WIDTH, step); | |
585 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
586 | dst[k] = blur_func(p4[k], p3[k], p2[k], p1[k], z0[k], | |
587 | n1[k], n2[k], n3[k], n4[k], param); | |
588 | dst += STRIPE_WIDTH; | |
589 | offs += STRIPE_WIDTH; | |
590 | } | |
591 | src += step; | |
592 | } | |
593 | } | |
594 | ||
595 | void ass_blur1246_horz_c(int16_t *dst, const int16_t *src, | |
596 | uintptr_t src_width, uintptr_t src_height, | |
597 | const int16_t *param) | |
598 | { | |
599 | uintptr_t dst_width = src_width + 12; | |
600 | uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height; | |
601 | uintptr_t step = STRIPE_WIDTH * src_height; | |
602 | ||
603 | uintptr_t offs = 0; | |
604 | #if STRIPE_WIDTH < 12 | |
605 | int16_t buf[3 * STRIPE_WIDTH]; | |
606 | int16_t *ptr = buf + 2 * STRIPE_WIDTH; | |
607 | #else | |
608 | int16_t buf[2 * STRIPE_WIDTH]; | |
609 | int16_t *ptr = buf + STRIPE_WIDTH; | |
610 | #endif | |
611 | for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) { | |
612 | for (uintptr_t y = 0; y < src_height; ++y) { | |
613 | #if STRIPE_WIDTH < 12 | |
614 | copy_line(ptr - 2 * STRIPE_WIDTH, src, offs - 2 * step, size); | |
615 | #endif | |
616 | copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size); | |
617 | copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size); | |
618 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
619 | dst[k] = blur_func(ptr[k - 12], ptr[k - 10], ptr[k - 8], ptr[k - 7], ptr[k - 6], | |
620 | ptr[k - 5], ptr[k - 4], ptr[k - 2], ptr[k - 0], param); | |
621 | dst += STRIPE_WIDTH; | |
622 | offs += STRIPE_WIDTH; | |
623 | } | |
624 | } | |
625 | } | |
626 | ||
627 | void ass_blur1246_vert_c(int16_t *dst, const int16_t *src, | |
628 | uintptr_t src_width, uintptr_t src_height, | |
629 | const int16_t *param) | |
630 | { | |
631 | uintptr_t dst_height = src_height + 12; | |
632 | uintptr_t step = STRIPE_WIDTH * src_height; | |
633 | ||
634 | for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) { | |
635 | uintptr_t offs = 0; | |
636 | for (uintptr_t y = 0; y < dst_height; ++y) { | |
637 | const int16_t *p4 = get_line(src, offs - 12 * STRIPE_WIDTH, step); | |
638 | const int16_t *p3 = get_line(src, offs - 10 * STRIPE_WIDTH, step); | |
639 | const int16_t *p2 = get_line(src, offs - 8 * STRIPE_WIDTH, step); | |
640 | const int16_t *p1 = get_line(src, offs - 7 * STRIPE_WIDTH, step); | |
641 | const int16_t *z0 = get_line(src, offs - 6 * STRIPE_WIDTH, step); | |
642 | const int16_t *n1 = get_line(src, offs - 5 * STRIPE_WIDTH, step); | |
643 | const int16_t *n2 = get_line(src, offs - 4 * STRIPE_WIDTH, step); | |
644 | const int16_t *n3 = get_line(src, offs - 2 * STRIPE_WIDTH, step); | |
645 | const int16_t *n4 = get_line(src, offs - 0 * STRIPE_WIDTH, step); | |
646 | for (int k = 0; k < STRIPE_WIDTH; ++k) | |
647 | dst[k] = blur_func(p4[k], p3[k], p2[k], p1[k], z0[k], | |
648 | n1[k], n2[k], n3[k], n4[k], param); | |
649 | dst += STRIPE_WIDTH; | |
650 | offs += STRIPE_WIDTH; | |
651 | } | |
652 | src += step; | |
653 | } | |
333 | void ass_blur4_horz_c(int16_t *dst, const int16_t *src, | |
334 | uintptr_t src_width, uintptr_t src_height, | |
335 | const int16_t *param) | |
336 | { | |
337 | blur_horz(dst, src, src_width, src_height, param, 4); | |
338 | } | |
339 | ||
340 | void ass_blur4_vert_c(int16_t *dst, const int16_t *src, | |
341 | uintptr_t src_width, uintptr_t src_height, | |
342 | const int16_t *param) | |
343 | { | |
344 | blur_vert(dst, src, src_width, src_height, param, 4); | |
345 | } | |
346 | ||
347 | void ass_blur5_horz_c(int16_t *dst, const int16_t *src, | |
348 | uintptr_t src_width, uintptr_t src_height, | |
349 | const int16_t *param) | |
350 | { | |
351 | blur_horz(dst, src, src_width, src_height, param, 5); | |
352 | } | |
353 | ||
354 | void ass_blur5_vert_c(int16_t *dst, const int16_t *src, | |
355 | uintptr_t src_width, uintptr_t src_height, | |
356 | const int16_t *param) | |
357 | { | |
358 | blur_vert(dst, src, src_width, src_height, param, 5); | |
359 | } | |
360 | ||
361 | void ass_blur6_horz_c(int16_t *dst, const int16_t *src, | |
362 | uintptr_t src_width, uintptr_t src_height, | |
363 | const int16_t *param) | |
364 | { | |
365 | blur_horz(dst, src, src_width, src_height, param, 6); | |
366 | } | |
367 | ||
368 | void ass_blur6_vert_c(int16_t *dst, const int16_t *src, | |
369 | uintptr_t src_width, uintptr_t src_height, | |
370 | const int16_t *param) | |
371 | { | |
372 | blur_vert(dst, src, src_width, src_height, param, 6); | |
373 | } | |
374 | ||
375 | void ass_blur7_horz_c(int16_t *dst, const int16_t *src, | |
376 | uintptr_t src_width, uintptr_t src_height, | |
377 | const int16_t *param) | |
378 | { | |
379 | blur_horz(dst, src, src_width, src_height, param, 7); | |
380 | } | |
381 | ||
382 | void ass_blur7_vert_c(int16_t *dst, const int16_t *src, | |
383 | uintptr_t src_width, uintptr_t src_height, | |
384 | const int16_t *param) | |
385 | { | |
386 | blur_vert(dst, src, src_width, src_height, param, 7); | |
387 | } | |
388 | ||
389 | void ass_blur8_horz_c(int16_t *dst, const int16_t *src, | |
390 | uintptr_t src_width, uintptr_t src_height, | |
391 | const int16_t *param) | |
392 | { | |
393 | blur_horz(dst, src, src_width, src_height, param, 8); | |
394 | } | |
395 | ||
396 | void ass_blur8_vert_c(int16_t *dst, const int16_t *src, | |
397 | uintptr_t src_width, uintptr_t src_height, | |
398 | const int16_t *param) | |
399 | { | |
400 | blur_vert(dst, src, src_width, src_height, param, 8); | |
654 | 401 | } |
655 | 402 | |
656 | 403 | |
664 | 411 | res[0] = cur; |
665 | 412 | cur *= mul; |
666 | 413 | res[1] = cur; |
667 | for (int i = 2; i <= n; ++i) { | |
414 | for (int i = 2; i < n; i++) { | |
668 | 415 | mul *= mul2; |
669 | 416 | cur *= mul; |
670 | 417 | res[i] = cur; |
671 | 418 | } |
672 | 419 | } |
673 | 420 | |
674 | static void coeff_blur121(double *coeff, int n) | |
675 | { | |
676 | double prev = coeff[1]; | |
677 | for (int i = 0; i <= n; ++i) { | |
678 | double res = (prev + 2 * coeff[i] + coeff[i + 1]) / 4; | |
679 | prev = coeff[i]; | |
680 | coeff[i] = res; | |
681 | } | |
682 | } | |
683 | ||
684 | 421 | static void coeff_filter(double *coeff, int n, const double kernel[4]) |
685 | 422 | { |
686 | 423 | double prev1 = coeff[1], prev2 = coeff[2], prev3 = coeff[3]; |
687 | for (int i = 0; i <= n; ++i) { | |
424 | for (int i = 0; i < n; i++) { | |
688 | 425 | double res = coeff[i + 0] * kernel[0] + |
689 | 426 | (prev1 + coeff[i + 1]) * kernel[1] + |
690 | 427 | (prev2 + coeff[i + 2]) * kernel[2] + |
696 | 433 | } |
697 | 434 | } |
698 | 435 | |
699 | static void calc_matrix(double mat[4][4], const double *mat_freq, const int *index) | |
700 | { | |
701 | for (int i = 0; i < 4; ++i) { | |
702 | mat[i][i] = mat_freq[2 * index[i]] + 3 * mat_freq[0] - 4 * mat_freq[index[i]]; | |
703 | for (int j = i + 1; j < 4; ++j) | |
704 | mat[i][j] = mat[j][i] = | |
705 | mat_freq[index[i] + index[j]] + mat_freq[index[j] - index[i]] + | |
706 | 2 * (mat_freq[0] - mat_freq[index[i]] - mat_freq[index[j]]); | |
436 | static void calc_matrix(double mat[][8], const double *mat_freq, int n) | |
437 | { | |
438 | for (int i = 0; i < n; i++) { | |
439 | mat[i][i] = mat_freq[2 * i + 2] + 3 * mat_freq[0] - 4 * mat_freq[i + 1]; | |
440 | for (int j = i + 1; j < n; j++) | |
441 | mat[i][j] = mat[j][i] = mat_freq[i + j + 2] + mat_freq[j - i] + | |
442 | 2 * (mat_freq[0] - mat_freq[i + 1] - mat_freq[j + 1]); | |
707 | 443 | } |
708 | 444 | |
709 | 445 | // invert transpose |
710 | for (int k = 0; k < 4; ++k) { | |
711 | int ip = k, jp = k; // pivot | |
712 | double z = 1 / mat[ip][jp]; | |
713 | mat[ip][jp] = 1; | |
714 | for (int i = 0; i < 4; ++i) { | |
715 | if (i == ip) | |
446 | for (int k = 0; k < n; k++) { | |
447 | double z = 1 / mat[k][k]; | |
448 | mat[k][k] = 1; | |
449 | for (int i = 0; i < n; i++) { | |
450 | if (i == k) | |
716 | 451 | continue; |
717 | 452 | |
718 | double mul = mat[i][jp] * z; | |
719 | mat[i][jp] = 0; | |
720 | for (int j = 0; j < 4; ++j) | |
721 | mat[i][j] -= mat[ip][j] * mul; | |
722 | } | |
723 | for (int j = 0; j < 4; ++j) | |
724 | mat[ip][j] *= z; | |
453 | double mul = mat[i][k] * z; | |
454 | mat[i][k] = 0; | |
455 | for (int j = 0; j < n; j++) | |
456 | mat[i][j] -= mat[k][j] * mul; | |
457 | } | |
458 | for (int j = 0; j < n; j++) | |
459 | mat[k][j] *= z; | |
725 | 460 | } |
726 | 461 | } |
727 | 462 | |
728 | 463 | /** |
729 | 464 | * \brief Solve least squares problem for kernel of the main filter |
730 | 465 | * \param mu out: output coefficients |
731 | * \param index in: filter tap positions | |
732 | * \param prefilter in: supplementary filter type | |
466 | * \param n in: filter kernel radius | |
733 | 467 | * \param r2 in: desired standard deviation squared |
734 | 468 | * \param mul in: scale multiplier |
735 | 469 | */ |
736 | static void calc_coeff(double mu[4], const int index[4], int prefilter, double r2, double mul) | |
737 | { | |
738 | double mul2 = mul * mul, mul3 = mul2 * mul; | |
470 | static void calc_coeff(double mu[], int n, double r2, double mul) | |
471 | { | |
472 | assert(n > 0 && n <= 8); | |
473 | ||
474 | const double w = 12096; | |
739 | 475 | double kernel[] = { |
740 | (5204 + 2520 * mul + 1092 * mul2 + 3280 * mul3) / 12096, | |
741 | (2943 - 210 * mul - 273 * mul2 - 2460 * mul3) / 12096, | |
742 | ( 486 - 924 * mul - 546 * mul2 + 984 * mul3) / 12096, | |
743 | ( 17 - 126 * mul + 273 * mul2 - 164 * mul3) / 12096, | |
476 | ((( + 3280 / w) * mul + 1092 / w) * mul + 2520 / w) * mul + 5204 / w, | |
477 | ((( - 2460 / w) * mul - 273 / w) * mul - 210 / w) * mul + 2943 / w, | |
478 | ((( + 984 / w) * mul - 546 / w) * mul - 924 / w) * mul + 486 / w, | |
479 | ((( - 164 / w) * mul + 273 / w) * mul - 126 / w) * mul + 17 / w, | |
744 | 480 | }; |
745 | 481 | |
746 | double mat_freq[14]; | |
747 | memcpy(mat_freq, kernel, sizeof(kernel)); | |
748 | memset(mat_freq + 4, 0, sizeof(mat_freq) - sizeof(kernel)); | |
749 | int n = 6; | |
750 | coeff_filter(mat_freq, n, kernel); | |
751 | for (int k = 0; k < 2 * prefilter; ++k) | |
752 | coeff_blur121(mat_freq, ++n); | |
753 | ||
754 | double vec_freq[13]; | |
755 | n = index[3] + prefilter + 3; | |
756 | calc_gauss(vec_freq, n, r2); | |
757 | memset(vec_freq + n + 1, 0, sizeof(vec_freq) - (n + 1) * sizeof(vec_freq[0])); | |
758 | n -= 3; | |
759 | coeff_filter(vec_freq, n, kernel); | |
760 | for (int k = 0; k < prefilter; ++k) | |
761 | coeff_blur121(vec_freq, --n); | |
762 | ||
763 | double mat[4][4]; | |
764 | calc_matrix(mat, mat_freq, index); | |
765 | ||
766 | double vec[4]; | |
767 | for (int i = 0; i < 4; ++i) | |
768 | vec[i] = mat_freq[0] - mat_freq[index[i]] - vec_freq[0] + vec_freq[index[i]]; | |
769 | ||
770 | for (int i = 0; i < 4; ++i) { | |
482 | double mat_freq[17] = { kernel[0], kernel[1], kernel[2], kernel[3] }; | |
483 | coeff_filter(mat_freq, 7, kernel); | |
484 | ||
485 | double vec_freq[12]; | |
486 | calc_gauss(vec_freq, n + 4, r2 * mul); | |
487 | coeff_filter(vec_freq, n + 1, kernel); | |
488 | ||
489 | double mat[8][8]; | |
490 | calc_matrix(mat, mat_freq, n); | |
491 | ||
492 | double vec[8]; | |
493 | for (int i = 0; i < n; i++) | |
494 | vec[i] = mat_freq[0] - mat_freq[i + 1] - vec_freq[0] + vec_freq[i + 1]; | |
495 | ||
496 | for (int i = 0; i < n; i++) { | |
771 | 497 | double res = 0; |
772 | for (int j = 0; j < 4; ++j) | |
498 | for (int j = 0; j < n; j++) | |
773 | 499 | res += mat[i][j] * vec[j]; |
774 | 500 | mu[i] = FFMAX(0, res); |
775 | 501 | } |
776 | 502 | } |
777 | 503 | |
778 | 504 | typedef struct { |
779 | int level, prefilter, filter; | |
780 | int16_t coeff[4]; | |
505 | int level, radius; | |
506 | int16_t coeff[8]; | |
781 | 507 | } BlurMethod; |
782 | 508 | |
783 | 509 | static void find_best_method(BlurMethod *blur, double r2) |
784 | 510 | { |
785 | static const int index[][4] = { | |
786 | { 1, 2, 3, 4 }, | |
787 | { 1, 2, 3, 5 }, | |
788 | { 1, 2, 4, 6 }, | |
789 | }; | |
790 | ||
791 | double mu[5]; | |
792 | if (r2 < 1.9) { | |
793 | blur->level = blur->prefilter = blur->filter = 0; | |
794 | ||
795 | if (r2 < 0.5) { | |
796 | mu[2] = 0.085 * r2 * r2 * r2; | |
797 | mu[1] = 0.5 * r2 - 4 * mu[2]; | |
798 | mu[3] = mu[4] = 0; | |
799 | } else { | |
800 | calc_gauss(mu, 4, r2); | |
801 | } | |
511 | double mu[8]; | |
512 | if (r2 < 0.5) { | |
513 | blur->level = 0; | |
514 | blur->radius = 4; | |
515 | mu[1] = 0.085 * r2 * r2 * r2; | |
516 | mu[0] = 0.5 * r2 - 4 * mu[1]; | |
517 | mu[2] = mu[3] = 0; | |
802 | 518 | } else { |
803 | double mul = 1; | |
804 | if (r2 < 6.693) { | |
805 | blur->level = 0; | |
806 | ||
807 | if (r2 < 2.8) | |
808 | blur->prefilter = 1; | |
809 | else if (r2 < 4.4) | |
810 | blur->prefilter = 2; | |
811 | else | |
812 | blur->prefilter = 3; | |
813 | ||
814 | blur->filter = blur->prefilter - 1; | |
815 | } else { | |
816 | frexp((r2 + 0.7) / 26.5, &blur->level); | |
817 | blur->level = (blur->level + 3) >> 1; | |
818 | mul = pow(0.25, blur->level); | |
819 | r2 *= mul; | |
820 | ||
821 | if (r2 < 3.15 - 1.5 * mul) | |
822 | blur->prefilter = 0; | |
823 | else if (r2 < 5.3 - 5.2 * mul) | |
824 | blur->prefilter = 1; | |
825 | else | |
826 | blur->prefilter = 2; | |
827 | ||
828 | blur->filter = blur->prefilter; | |
829 | } | |
830 | calc_coeff(mu + 1, index[blur->filter], blur->prefilter, r2, mul); | |
831 | } | |
832 | ||
833 | for (int i = 1; i <= 4; ++i) | |
834 | blur->coeff[i - 1] = (int) (0x10000 * mu[i] + 0.5); | |
519 | double frac = frexp(sqrt(0.11569 * r2 + 0.20591047), &blur->level); | |
520 | double mul = pow(0.25, blur->level); | |
521 | blur->radius = 8 - (int) ((10.1525 + 0.8335 * mul) * (1 - frac)); | |
522 | blur->radius = FFMAX(blur->radius, 4); | |
523 | calc_coeff(mu, blur->radius, r2, mul); | |
524 | } | |
525 | for (int i = 0; i < blur->radius; i++) | |
526 | blur->coeff[i] = (int) (0x10000 * mu[i] + 0.5); | |
835 | 527 | } |
836 | 528 | |
837 | 529 | /** |
843 | 535 | BlurMethod blur; |
844 | 536 | find_best_method(&blur, r2); |
845 | 537 | |
846 | int w = bm->w, h = bm->h; | |
847 | int offset = ((2 * (blur.prefilter + blur.filter) + 17) << blur.level) - 5; | |
848 | int end_w = ((w + offset) & ~((1 << blur.level) - 1)) - 4; | |
849 | int end_h = ((h + offset) & ~((1 << blur.level) - 1)) - 4; | |
538 | uint32_t w = bm->w, h = bm->h; | |
539 | int offset = ((2 * blur.radius + 9) << blur.level) - 5; | |
540 | uint32_t end_w = ((w + offset) & ~((1 << blur.level) - 1)) - 4; | |
541 | uint32_t end_h = ((h + offset) & ~((1 << blur.level) - 1)) - 4; | |
850 | 542 | |
851 | 543 | const int stripe_width = 1 << (engine->align_order - 1); |
852 | int size = end_h * ((end_w + stripe_width - 1) & ~(stripe_width - 1)); | |
544 | uint64_t size = (((uint64_t) end_w + stripe_width - 1) & ~(stripe_width - 1)) * end_h; | |
545 | if (size > INT_MAX / 4) | |
546 | return false; | |
547 | ||
853 | 548 | int16_t *tmp = ass_aligned_alloc(2 * stripe_width, 4 * size, false); |
854 | 549 | if (!tmp) |
855 | 550 | return false; |
858 | 553 | int16_t *buf[2] = {tmp, tmp + size}; |
859 | 554 | int index = 0; |
860 | 555 | |
861 | for (int i = 0; i < blur.level; ++i) { | |
556 | for (int i = 0; i < blur.level; i++) { | |
862 | 557 | engine->shrink_vert(buf[index ^ 1], buf[index], w, h); |
863 | 558 | h = (h + 5) >> 1; |
864 | 559 | index ^= 1; |
865 | 560 | } |
866 | for (int i = 0; i < blur.level; ++i) { | |
561 | for (int i = 0; i < blur.level; i++) { | |
867 | 562 | engine->shrink_horz(buf[index ^ 1], buf[index], w, h); |
868 | 563 | w = (w + 5) >> 1; |
869 | 564 | index ^= 1; |
870 | 565 | } |
871 | if (blur.prefilter) { | |
872 | engine->pre_blur_horz[blur.prefilter - 1](buf[index ^ 1], buf[index], w, h); | |
873 | w += 2 * blur.prefilter; | |
874 | index ^= 1; | |
875 | } | |
876 | engine->main_blur_horz[blur.filter](buf[index ^ 1], buf[index], w, h, blur.coeff); | |
877 | w += 2 * blur.filter + 8; | |
566 | assert(blur.radius >= 4 && blur.radius <= 8); | |
567 | engine->blur_horz[blur.radius - 4](buf[index ^ 1], buf[index], w, h, blur.coeff); | |
568 | w += 2 * blur.radius; | |
878 | 569 | index ^= 1; |
879 | for (int i = 0; i < blur.level; ++i) { | |
570 | engine->blur_vert[blur.radius - 4](buf[index ^ 1], buf[index], w, h, blur.coeff); | |
571 | h += 2 * blur.radius; | |
572 | index ^= 1; | |
573 | for (int i = 0; i < blur.level; i++) { | |
880 | 574 | engine->expand_horz(buf[index ^ 1], buf[index], w, h); |
881 | 575 | w = 2 * w + 4; |
882 | 576 | index ^= 1; |
883 | 577 | } |
884 | if (blur.prefilter) { | |
885 | engine->pre_blur_vert[blur.prefilter - 1](buf[index ^ 1], buf[index], w, h); | |
886 | h += 2 * blur.prefilter; | |
887 | index ^= 1; | |
888 | } | |
889 | engine->main_blur_vert[blur.filter](buf[index ^ 1], buf[index], w, h, blur.coeff); | |
890 | h += 2 * blur.filter + 8; | |
891 | index ^= 1; | |
892 | for (int i = 0; i < blur.level; ++i) { | |
578 | for (int i = 0; i < blur.level; i++) { | |
893 | 579 | engine->expand_vert(buf[index ^ 1], buf[index], w, h); |
894 | 580 | h = 2 * h + 4; |
895 | 581 | index ^= 1; |
900 | 586 | ass_aligned_free(tmp); |
901 | 587 | return false; |
902 | 588 | } |
903 | offset = ((blur.prefilter + blur.filter + 8) << blur.level) - 4; | |
589 | offset = ((blur.radius + 4) << blur.level) - 4; | |
904 | 590 | bm->left -= offset; |
905 | 591 | bm->top -= offset; |
906 | 592 |
37 | 37 | #include "ass_cache_template.h" |
38 | 38 | |
39 | 39 | // font cache |
40 | static unsigned font_hash(void *buf, size_t len) | |
40 | static uint32_t font_hash(void *buf, uint32_t hval) | |
41 | 41 | { |
42 | 42 | ASS_FontDesc *desc = buf; |
43 | unsigned hval; | |
44 | hval = fnv_32a_str(desc->family, FNV1_32A_INIT); | |
43 | hval = fnv_32a_str(desc->family, hval); | |
45 | 44 | hval = fnv_32a_buf(&desc->bold, sizeof(desc->bold), hval); |
46 | 45 | hval = fnv_32a_buf(&desc->italic, sizeof(desc->italic), hval); |
47 | 46 | hval = fnv_32a_buf(&desc->vertical, sizeof(desc->vertical), hval); |
48 | 47 | return hval; |
49 | 48 | } |
50 | 49 | |
51 | static unsigned font_compare(void *key1, void *key2, size_t key_size) | |
50 | static bool font_compare(void *key1, void *key2) | |
52 | 51 | { |
53 | 52 | ASS_FontDesc *a = key1; |
54 | 53 | ASS_FontDesc *b = key2; |
55 | 54 | if (strcmp(a->family, b->family) != 0) |
56 | return 0; | |
55 | return false; | |
57 | 56 | if (a->bold != b->bold) |
58 | return 0; | |
57 | return false; | |
59 | 58 | if (a->italic != b->italic) |
60 | return 0; | |
59 | return false; | |
61 | 60 | if (a->vertical != b->vertical) |
62 | return 0; | |
63 | return 1; | |
64 | } | |
65 | ||
66 | static bool font_key_move(void *dst, void *src, size_t key_size) | |
61 | return false; | |
62 | return true; | |
63 | } | |
64 | ||
65 | static bool font_key_move(void *dst, void *src) | |
67 | 66 | { |
68 | 67 | ASS_FontDesc *k = src; |
69 | 68 | if (dst) |
70 | memcpy(dst, src, key_size); | |
69 | memcpy(dst, src, sizeof(ASS_FontDesc)); | |
71 | 70 | else |
72 | 71 | free(k->family); |
73 | 72 | return true; |
77 | 76 | { |
78 | 77 | ass_font_clear(value); |
79 | 78 | } |
79 | ||
80 | size_t ass_font_construct(void *key, void *value, void *priv); | |
80 | 81 | |
81 | 82 | const CacheDesc font_cache_desc = { |
82 | 83 | .hash_func = font_hash, |
83 | 84 | .compare_func = font_compare, |
84 | 85 | .key_move_func = font_key_move, |
86 | .construct_func = ass_font_construct, | |
85 | 87 | .destruct_func = font_destruct, |
86 | 88 | .key_size = sizeof(ASS_FontDesc), |
87 | 89 | .value_size = sizeof(ASS_Font) |
89 | 91 | |
90 | 92 | |
91 | 93 | // bitmap cache |
92 | static unsigned bitmap_hash(void *key, size_t key_size) | |
94 | static bool bitmap_key_move(void *dst, void *src) | |
95 | { | |
96 | BitmapHashKey *k = src; | |
97 | if (dst) | |
98 | memcpy(dst, src, sizeof(BitmapHashKey)); | |
99 | else | |
100 | ass_cache_dec_ref(k->outline); | |
101 | return true; | |
102 | } | |
103 | ||
104 | static void bitmap_destruct(void *key, void *value) | |
93 | 105 | { |
94 | 106 | BitmapHashKey *k = key; |
95 | switch (k->type) { | |
96 | case BITMAP_OUTLINE: return outline_bitmap_hash(&k->u, key_size); | |
97 | case BITMAP_CLIP: return clip_bitmap_hash(&k->u, key_size); | |
98 | default: return 0; | |
99 | } | |
100 | } | |
101 | ||
102 | static unsigned bitmap_compare(void *a, void *b, size_t key_size) | |
103 | { | |
104 | BitmapHashKey *ak = a; | |
105 | BitmapHashKey *bk = b; | |
106 | if (ak->type != bk->type) return 0; | |
107 | switch (ak->type) { | |
108 | case BITMAP_OUTLINE: return outline_bitmap_compare(&ak->u, &bk->u, key_size); | |
109 | case BITMAP_CLIP: return clip_bitmap_compare(&ak->u, &bk->u, key_size); | |
110 | default: return 0; | |
111 | } | |
112 | } | |
113 | ||
114 | static bool bitmap_key_move(void *dst, void *src, size_t key_size) | |
115 | { | |
116 | BitmapHashKey *d = dst, *s = src; | |
117 | if (!dst) { | |
118 | if (s->type == BITMAP_OUTLINE) | |
119 | ass_cache_dec_ref(s->u.outline.outline); | |
120 | return true; | |
121 | } | |
122 | memcpy(dst, src, key_size); | |
123 | if (s->type != BITMAP_CLIP) | |
124 | return true; | |
125 | d->u.clip.text = strdup(s->u.clip.text); | |
126 | return d->u.clip.text; | |
127 | } | |
128 | ||
129 | static void bitmap_destruct(void *key, void *value) | |
130 | { | |
131 | BitmapHashValue *v = value; | |
132 | BitmapHashKey *k = key; | |
133 | if (v->bm) | |
134 | ass_free_bitmap(v->bm); | |
135 | if (v->bm_o) | |
136 | ass_free_bitmap(v->bm_o); | |
137 | switch (k->type) { | |
138 | case BITMAP_OUTLINE: ass_cache_dec_ref(k->u.outline.outline); break; | |
139 | case BITMAP_CLIP: free(k->u.clip.text); break; | |
140 | } | |
141 | } | |
107 | ass_free_bitmap(value); | |
108 | ass_cache_dec_ref(k->outline); | |
109 | } | |
110 | ||
111 | size_t ass_bitmap_construct(void *key, void *value, void *priv); | |
142 | 112 | |
143 | 113 | const CacheDesc bitmap_cache_desc = { |
144 | 114 | .hash_func = bitmap_hash, |
145 | 115 | .compare_func = bitmap_compare, |
146 | 116 | .key_move_func = bitmap_key_move, |
117 | .construct_func = ass_bitmap_construct, | |
147 | 118 | .destruct_func = bitmap_destruct, |
148 | 119 | .key_size = sizeof(BitmapHashKey), |
149 | .value_size = sizeof(BitmapHashValue) | |
120 | .value_size = sizeof(Bitmap) | |
150 | 121 | }; |
151 | 122 | |
152 | 123 | |
153 | 124 | // composite cache |
154 | static unsigned composite_hash(void *key, size_t key_size) | |
125 | static uint32_t composite_hash(void *key, uint32_t hval) | |
155 | 126 | { |
156 | 127 | CompositeHashKey *k = key; |
157 | unsigned hval = filter_hash(&k->filter, key_size); | |
158 | for (size_t i = 0; i < k->bitmap_count; i++) { | |
159 | hval = fnv_32a_buf(&k->bitmaps[i].image, sizeof(k->bitmaps[i].image), hval); | |
160 | hval = fnv_32a_buf(&k->bitmaps[i].x, sizeof(k->bitmaps[i].x), hval); | |
161 | hval = fnv_32a_buf(&k->bitmaps[i].y, sizeof(k->bitmaps[i].y), hval); | |
162 | } | |
128 | hval = filter_hash(&k->filter, hval); | |
129 | for (size_t i = 0; i < k->bitmap_count; i++) | |
130 | hval = bitmap_ref_hash(&k->bitmaps[i], hval); | |
163 | 131 | return hval; |
164 | 132 | } |
165 | 133 | |
166 | static unsigned composite_compare(void *a, void *b, size_t key_size) | |
134 | static bool composite_compare(void *a, void *b) | |
167 | 135 | { |
168 | 136 | CompositeHashKey *ak = a; |
169 | 137 | CompositeHashKey *bk = b; |
138 | if (!filter_compare(&ak->filter, &bk->filter)) | |
139 | return false; | |
170 | 140 | if (ak->bitmap_count != bk->bitmap_count) |
171 | return 0; | |
172 | for (size_t i = 0; i < ak->bitmap_count; i++) { | |
173 | if (ak->bitmaps[i].image != bk->bitmaps[i].image || | |
174 | ak->bitmaps[i].x != bk->bitmaps[i].x || | |
175 | ak->bitmaps[i].y != bk->bitmaps[i].y) | |
176 | return 0; | |
177 | } | |
178 | return filter_compare(&ak->filter, &bk->filter, key_size); | |
179 | } | |
180 | ||
181 | static bool composite_key_move(void *dst, void *src, size_t key_size) | |
141 | return false; | |
142 | for (size_t i = 0; i < ak->bitmap_count; i++) | |
143 | if (!bitmap_ref_compare(&ak->bitmaps[i], &bk->bitmaps[i])) | |
144 | return false; | |
145 | return true; | |
146 | } | |
147 | ||
148 | static bool composite_key_move(void *dst, void *src) | |
182 | 149 | { |
183 | 150 | if (dst) { |
184 | memcpy(dst, src, key_size); | |
151 | memcpy(dst, src, sizeof(CompositeHashKey)); | |
185 | 152 | return true; |
186 | 153 | } |
187 | 154 | CompositeHashKey *k = src; |
188 | for (size_t i = 0; i < k->bitmap_count; i++) | |
189 | ass_cache_dec_ref(k->bitmaps[i].image); | |
155 | for (size_t i = 0; i < k->bitmap_count; i++) { | |
156 | ass_cache_dec_ref(k->bitmaps[i].bm); | |
157 | ass_cache_dec_ref(k->bitmaps[i].bm_o); | |
158 | } | |
190 | 159 | free(k->bitmaps); |
191 | 160 | return true; |
192 | 161 | } |
195 | 164 | { |
196 | 165 | CompositeHashValue *v = value; |
197 | 166 | CompositeHashKey *k = key; |
198 | if (v->bm) | |
199 | ass_free_bitmap(v->bm); | |
200 | if (v->bm_o) | |
201 | ass_free_bitmap(v->bm_o); | |
202 | if (v->bm_s) | |
203 | ass_free_bitmap(v->bm_s); | |
204 | for (size_t i = 0; i < k->bitmap_count; i++) | |
205 | ass_cache_dec_ref(k->bitmaps[i].image); | |
167 | ass_free_bitmap(&v->bm); | |
168 | ass_free_bitmap(&v->bm_o); | |
169 | ass_free_bitmap(&v->bm_s); | |
170 | for (size_t i = 0; i < k->bitmap_count; i++) { | |
171 | ass_cache_dec_ref(k->bitmaps[i].bm); | |
172 | ass_cache_dec_ref(k->bitmaps[i].bm_o); | |
173 | } | |
206 | 174 | free(k->bitmaps); |
207 | 175 | } |
176 | ||
177 | size_t ass_composite_construct(void *key, void *value, void *priv); | |
208 | 178 | |
209 | 179 | const CacheDesc composite_cache_desc = { |
210 | 180 | .hash_func = composite_hash, |
211 | 181 | .compare_func = composite_compare, |
212 | 182 | .key_move_func = composite_key_move, |
183 | .construct_func = ass_composite_construct, | |
213 | 184 | .destruct_func = composite_destruct, |
214 | 185 | .key_size = sizeof(CompositeHashKey), |
215 | 186 | .value_size = sizeof(CompositeHashValue) |
217 | 188 | |
218 | 189 | |
219 | 190 | // outline cache |
220 | static unsigned outline_hash(void *key, size_t key_size) | |
191 | static uint32_t outline_hash(void *key, uint32_t hval) | |
221 | 192 | { |
222 | 193 | OutlineHashKey *k = key; |
223 | 194 | switch (k->type) { |
224 | case OUTLINE_GLYPH: return glyph_hash(&k->u, key_size); | |
225 | case OUTLINE_DRAWING: return drawing_hash(&k->u, key_size); | |
226 | default: return 0; | |
227 | } | |
228 | } | |
229 | ||
230 | static unsigned outline_compare(void *a, void *b, size_t key_size) | |
195 | case OUTLINE_GLYPH: | |
196 | return glyph_hash(&k->u, hval); | |
197 | case OUTLINE_DRAWING: | |
198 | return drawing_hash(&k->u, hval); | |
199 | case OUTLINE_BORDER: | |
200 | return border_hash(&k->u, hval); | |
201 | default: // OUTLINE_BOX | |
202 | return hval; | |
203 | } | |
204 | } | |
205 | ||
206 | static bool outline_compare(void *a, void *b) | |
231 | 207 | { |
232 | 208 | OutlineHashKey *ak = a; |
233 | 209 | OutlineHashKey *bk = b; |
234 | if (ak->type != bk->type) return 0; | |
210 | if (ak->type != bk->type) | |
211 | return false; | |
235 | 212 | switch (ak->type) { |
236 | case OUTLINE_GLYPH: return glyph_compare(&ak->u, &bk->u, key_size); | |
237 | case OUTLINE_DRAWING: return drawing_compare(&ak->u, &bk->u, key_size); | |
238 | default: return 0; | |
239 | } | |
240 | } | |
241 | ||
242 | static bool outline_key_move(void *dst, void *src, size_t key_size) | |
213 | case OUTLINE_GLYPH: | |
214 | return glyph_compare(&ak->u, &bk->u); | |
215 | case OUTLINE_DRAWING: | |
216 | return drawing_compare(&ak->u, &bk->u); | |
217 | case OUTLINE_BORDER: | |
218 | return border_compare(&ak->u, &bk->u); | |
219 | default: // OUTLINE_BOX | |
220 | return true; | |
221 | } | |
222 | } | |
223 | ||
224 | static bool outline_key_move(void *dst, void *src) | |
243 | 225 | { |
244 | 226 | OutlineHashKey *d = dst, *s = src; |
245 | 227 | if (!dst) { |
247 | 229 | ass_cache_dec_ref(s->u.glyph.font); |
248 | 230 | return true; |
249 | 231 | } |
250 | memcpy(dst, src, key_size); | |
251 | if (s->type != OUTLINE_DRAWING) | |
252 | return true; | |
253 | d->u.drawing.text = strdup(s->u.drawing.text); | |
254 | return d->u.drawing.text; | |
232 | memcpy(dst, src, sizeof(OutlineHashKey)); | |
233 | if (s->type == OUTLINE_DRAWING) { | |
234 | d->u.drawing.text = strdup(s->u.drawing.text); | |
235 | return d->u.drawing.text; | |
236 | } | |
237 | if (s->type == OUTLINE_BORDER) | |
238 | ass_cache_inc_ref(s->u.border.outline); | |
239 | return true; | |
255 | 240 | } |
256 | 241 | |
257 | 242 | static void outline_destruct(void *key, void *value) |
258 | 243 | { |
259 | 244 | OutlineHashValue *v = value; |
260 | 245 | OutlineHashKey *k = key; |
261 | outline_free(&v->outline); | |
262 | outline_free(&v->border[0]); | |
263 | outline_free(&v->border[1]); | |
246 | outline_free(&v->outline[0]); | |
247 | outline_free(&v->outline[1]); | |
264 | 248 | switch (k->type) { |
265 | case OUTLINE_GLYPH: ass_cache_dec_ref(k->u.glyph.font); break; | |
266 | case OUTLINE_DRAWING: free(k->u.drawing.text); break; | |
267 | } | |
268 | } | |
249 | case OUTLINE_GLYPH: | |
250 | ass_cache_dec_ref(k->u.glyph.font); | |
251 | break; | |
252 | case OUTLINE_DRAWING: | |
253 | free(k->u.drawing.text); | |
254 | break; | |
255 | case OUTLINE_BORDER: | |
256 | ass_cache_dec_ref(k->u.border.outline); | |
257 | break; | |
258 | default: // OUTLINE_BOX | |
259 | break; | |
260 | } | |
261 | } | |
262 | ||
263 | size_t ass_outline_construct(void *key, void *value, void *priv); | |
269 | 264 | |
270 | 265 | const CacheDesc outline_cache_desc = { |
271 | 266 | .hash_func = outline_hash, |
272 | 267 | .compare_func = outline_compare, |
273 | 268 | .key_move_func = outline_key_move, |
269 | .construct_func = ass_outline_construct, | |
274 | 270 | .destruct_func = outline_destruct, |
275 | 271 | .key_size = sizeof(OutlineHashKey), |
276 | 272 | .value_size = sizeof(OutlineHashValue) |
278 | 274 | |
279 | 275 | |
280 | 276 | // glyph metric cache |
281 | static bool glyph_metrics_key_move(void *dst, void *src, size_t key_size) | |
277 | static bool glyph_metrics_key_move(void *dst, void *src) | |
282 | 278 | { |
283 | 279 | if (!dst) |
284 | 280 | return true; |
285 | memcpy(dst, src, key_size); | |
281 | memcpy(dst, src, sizeof(GlyphMetricsHashKey)); | |
286 | 282 | GlyphMetricsHashKey *k = src; |
287 | 283 | ass_cache_inc_ref(k->font); |
288 | 284 | return true; |
293 | 289 | GlyphMetricsHashKey *k = key; |
294 | 290 | ass_cache_dec_ref(k->font); |
295 | 291 | } |
292 | ||
293 | size_t ass_glyph_metrics_construct(void *key, void *value, void *priv); | |
296 | 294 | |
297 | 295 | const CacheDesc glyph_metrics_cache_desc = { |
298 | 296 | .hash_func = glyph_metrics_hash, |
299 | 297 | .compare_func = glyph_metrics_compare, |
300 | 298 | .key_move_func = glyph_metrics_key_move, |
299 | .construct_func = ass_glyph_metrics_construct, | |
301 | 300 | .destruct_func = glyph_metrics_destruct, |
302 | 301 | .key_size = sizeof(GlyphMetricsHashKey), |
303 | .value_size = sizeof(GlyphMetricsHashValue) | |
302 | .value_size = sizeof(FT_Glyph_Metrics) | |
304 | 303 | }; |
305 | 304 | |
306 | 305 | |
359 | 358 | return cache; |
360 | 359 | } |
361 | 360 | |
362 | bool ass_cache_get(Cache *cache, void *key, void *value_ptr) | |
363 | { | |
364 | char **value = (char **) value_ptr; | |
361 | void *ass_cache_get(Cache *cache, void *key, void *priv) | |
362 | { | |
365 | 363 | const CacheDesc *desc = cache->desc; |
366 | 364 | size_t key_offs = CACHE_ITEM_SIZE + align_cache(desc->value_size); |
367 | unsigned bucket = desc->hash_func(key, desc->key_size) % cache->buckets; | |
365 | unsigned bucket = desc->hash_func(key, FNV1_32A_INIT) % cache->buckets; | |
368 | 366 | CacheItem *item = cache->map[bucket]; |
369 | 367 | while (item) { |
370 | if (desc->compare_func(key, (char *) item + key_offs, desc->key_size)) { | |
368 | if (desc->compare_func(key, (char *) item + key_offs)) { | |
371 | 369 | assert(item->size); |
372 | 370 | if (!item->queue_prev || item->queue_next) { |
373 | 371 | if (item->queue_prev) { |
381 | 379 | item->queue_next = NULL; |
382 | 380 | } |
383 | 381 | cache->hits++; |
384 | desc->key_move_func(NULL, key, desc->key_size); | |
385 | *value = (char *) item + CACHE_ITEM_SIZE; | |
382 | desc->key_move_func(NULL, key); | |
386 | 383 | item->ref_count++; |
387 | return true; | |
384 | return (char *) item + CACHE_ITEM_SIZE; | |
388 | 385 | } |
389 | 386 | item = item->next; |
390 | 387 | } |
392 | 389 | |
393 | 390 | item = malloc(key_offs + desc->key_size); |
394 | 391 | if (!item) { |
395 | desc->key_move_func(NULL, key, desc->key_size); | |
396 | *value = NULL; | |
397 | return false; | |
398 | } | |
399 | item->size = 0; | |
392 | desc->key_move_func(NULL, key); | |
393 | return NULL; | |
394 | } | |
400 | 395 | item->cache = cache; |
401 | 396 | item->desc = desc; |
402 | if (!desc->key_move_func((char *) item + key_offs, key, desc->key_size)) { | |
397 | void *new_key = (char *) item + key_offs; | |
398 | if (!desc->key_move_func(new_key, key)) { | |
403 | 399 | free(item); |
404 | *value = NULL; | |
405 | return false; | |
406 | } | |
407 | *value = (char *) item + CACHE_ITEM_SIZE; | |
400 | return NULL; | |
401 | } | |
402 | void *value = (char *) item + CACHE_ITEM_SIZE; | |
403 | item->size = desc->construct_func(new_key, value, priv); | |
404 | assert(item->size); | |
408 | 405 | |
409 | 406 | CacheItem **bucketptr = &cache->map[bucket]; |
410 | 407 | if (*bucketptr) |
413 | 410 | item->next = *bucketptr; |
414 | 411 | *bucketptr = item; |
415 | 412 | |
416 | item->queue_prev = NULL; | |
417 | item->queue_next = NULL; | |
418 | item->ref_count = 1; | |
419 | return false; | |
420 | } | |
421 | ||
422 | void *ass_cache_key(void *value) | |
423 | { | |
424 | CacheItem *item = value_to_item(value); | |
425 | return (char *) value + align_cache(item->desc->value_size); | |
426 | } | |
427 | ||
428 | void ass_cache_commit(void *value, size_t item_size) | |
429 | { | |
430 | CacheItem *item = value_to_item(value); | |
431 | assert(!item->size && item_size); | |
432 | item->size = item_size; | |
433 | Cache *cache = item->cache; | |
434 | cache->cache_size += item_size; | |
435 | cache->items++; | |
436 | ||
437 | 413 | *cache->queue_last = item; |
438 | 414 | item->queue_prev = cache->queue_last; |
439 | 415 | cache->queue_last = &item->queue_next; |
440 | item->ref_count++; | |
416 | item->queue_next = NULL; | |
417 | item->ref_count = 2; | |
418 | ||
419 | cache->cache_size += item->size; | |
420 | cache->items++; | |
421 | return value; | |
422 | } | |
423 | ||
424 | void *ass_cache_key(void *value) | |
425 | { | |
426 | CacheItem *item = value_to_item(value); | |
427 | return (char *) value + align_cache(item->desc->value_size); | |
441 | 428 | } |
442 | 429 | |
443 | 430 | static inline void destroy_item(const CacheDesc *desc, CacheItem *item) |
29 | 29 | // cache values |
30 | 30 | |
31 | 31 | typedef struct { |
32 | bool valid; | |
33 | Bitmap *bm; // the actual bitmaps | |
34 | Bitmap *bm_o; | |
35 | } BitmapHashValue; | |
36 | ||
37 | typedef struct { | |
38 | Bitmap *bm; | |
39 | Bitmap *bm_o; | |
40 | Bitmap *bm_s; | |
32 | Bitmap bm, bm_o, bm_s; | |
41 | 33 | } CompositeHashValue; |
42 | 34 | |
43 | 35 | typedef struct { |
44 | 36 | bool valid; |
45 | ASS_Outline outline; | |
46 | ASS_Outline border[2]; | |
47 | ASS_Rect bbox_scaled; // bbox after scaling, but before rotation | |
48 | ASS_Vector advance; // 26.6, advance distance to the next outline in line | |
49 | int asc, desc; // ascender/descender | |
37 | ASS_Outline outline[2]; | |
38 | ASS_Rect cbox; // bounding box of all control points | |
39 | int advance; // 26.6, advance distance to the next outline in line | |
40 | int asc, desc; // ascender/descender | |
50 | 41 | } OutlineHashValue; |
51 | ||
52 | typedef struct { | |
53 | FT_Glyph_Metrics metrics; | |
54 | } GlyphMetricsHashValue; | |
55 | 42 | |
56 | 43 | // Create definitions for bitmap, outline and composite hash keys |
57 | 44 | #define CREATE_STRUCT_DEFINITIONS |
58 | 45 | #include "ass_cache_template.h" |
59 | 46 | |
60 | 47 | // Type-specific function pointers |
61 | typedef unsigned(*HashFunction)(void *key, size_t key_size); | |
62 | typedef unsigned(*HashCompare)(void *a, void *b, size_t key_size); | |
63 | typedef bool(*CacheKeyMove)(void *dst, void *src, size_t key_size); | |
64 | typedef void(*CacheItemDestructor)(void *key, void *value); | |
48 | typedef uint32_t (*HashFunction)(void *key, uint32_t hval); | |
49 | typedef bool (*HashCompare)(void *a, void *b); | |
50 | typedef bool (*CacheKeyMove)(void *dst, void *src); | |
51 | typedef size_t (*CacheValueConstructor)(void *key, void *value, void *priv); | |
52 | typedef void (*CacheItemDestructor)(void *key, void *value); | |
65 | 53 | |
66 | 54 | // cache hash keys |
67 | 55 | |
69 | 57 | enum { |
70 | 58 | OUTLINE_GLYPH, |
71 | 59 | OUTLINE_DRAWING, |
60 | OUTLINE_BORDER, | |
61 | OUTLINE_BOX, | |
72 | 62 | } type; |
73 | 63 | union { |
74 | 64 | GlyphHashKey glyph; |
75 | 65 | DrawingHashKey drawing; |
66 | BorderHashKey border; | |
76 | 67 | } u; |
77 | 68 | } OutlineHashKey; |
78 | 69 | |
79 | typedef struct bitmap_hash_key { | |
80 | enum { | |
81 | BITMAP_OUTLINE, | |
82 | BITMAP_CLIP, | |
83 | } type; | |
84 | union { | |
85 | OutlineBitmapHashKey outline; | |
86 | ClipMaskHashKey clip; | |
87 | } u; | |
88 | } BitmapHashKey; | |
89 | ||
90 | typedef struct { | |
91 | BitmapHashValue *image; | |
92 | int x, y; | |
93 | } BitmapRef; | |
94 | ||
95 | 70 | enum { |
96 | FILTER_BORDER_STYLE_3 = 1, | |
97 | FILTER_NONZERO_BORDER = 2, | |
98 | FILTER_NONZERO_SHADOW = 4, | |
99 | FILTER_DRAW_SHADOW = 8, // VSFilter compatibility | |
71 | FILTER_BORDER_STYLE_3 = 0x01, | |
72 | FILTER_NONZERO_BORDER = 0x02, | |
73 | FILTER_NONZERO_SHADOW = 0x04, | |
74 | FILTER_FILL_IN_SHADOW = 0x08, | |
75 | FILTER_FILL_IN_BORDER = 0x10, | |
100 | 76 | }; |
101 | 77 | |
102 | 78 | typedef struct { |
110 | 86 | HashFunction hash_func; |
111 | 87 | HashCompare compare_func; |
112 | 88 | CacheKeyMove key_move_func; |
89 | CacheValueConstructor construct_func; | |
113 | 90 | CacheItemDestructor destruct_func; |
114 | 91 | size_t key_size; |
115 | 92 | size_t value_size; |
116 | 93 | } CacheDesc; |
117 | 94 | |
118 | 95 | Cache *ass_cache_create(const CacheDesc *desc); |
119 | bool ass_cache_get(Cache *cache, void *key, void *value_ptr); | |
96 | void *ass_cache_get(Cache *cache, void *key, void *priv); | |
120 | 97 | void *ass_cache_key(void *value); |
121 | void ass_cache_commit(void *value, size_t item_size); | |
122 | 98 | void ass_cache_inc_ref(void *value); |
123 | 99 | void ass_cache_dec_ref(void *value); |
124 | 100 | void ass_cache_cut(Cache *cache, size_t max_size); |
7 | 7 | char *member; |
8 | 8 | #define VECTOR(member) \ |
9 | 9 | ASS_Vector member; |
10 | #define BITMAPHASHKEY(member) \ | |
11 | BitmapHashKey member; | |
12 | 10 | #define END(typedefnamename) \ |
13 | 11 | } typedefnamename; |
14 | 12 | |
15 | 13 | #elif defined(CREATE_COMPARISON_FUNCTIONS) |
16 | 14 | #undef CREATE_COMPARISON_FUNCTIONS |
17 | 15 | #define START(funcname, structname) \ |
18 | static unsigned funcname##_compare(void *key1, void *key2, size_t key_size) \ | |
16 | static bool funcname##_compare(void *key1, void *key2) \ | |
19 | 17 | { \ |
20 | 18 | struct structname *a = key1; \ |
21 | 19 | struct structname *b = key2; \ |
26 | 24 | strcmp(a->member, b->member) == 0 && |
27 | 25 | #define VECTOR(member) \ |
28 | 26 | a->member.x == b->member.x && a->member.y == b->member.y && |
29 | #define BITMAPHASHKEY(member) \ | |
30 | bitmap_compare(&a->member, &b->member, sizeof(a->member)) && | |
31 | 27 | #define END(typedefname) \ |
32 | 1; \ | |
28 | true; \ | |
33 | 29 | } |
34 | 30 | |
35 | 31 | #elif defined(CREATE_HASH_FUNCTIONS) |
36 | 32 | #undef CREATE_HASH_FUNCTIONS |
37 | 33 | #define START(funcname, structname) \ |
38 | static unsigned funcname##_hash(void *buf, size_t len) \ | |
34 | static uint32_t funcname##_hash(void *buf, uint32_t hval) \ | |
39 | 35 | { \ |
40 | struct structname *p = buf; \ | |
41 | unsigned hval = FNV1_32A_INIT; | |
36 | struct structname *p = buf; | |
42 | 37 | #define GENERIC(type, member) \ |
43 | 38 | hval = fnv_32a_buf(&p->member, sizeof(p->member), hval); |
44 | 39 | #define STRING(member) \ |
45 | 40 | hval = fnv_32a_str(p->member, hval); |
46 | 41 | #define VECTOR(member) GENERIC(, member.x); GENERIC(, member.y); |
47 | #define BITMAPHASHKEY(member) { \ | |
48 | unsigned temp = bitmap_hash(&p->member, sizeof(p->member)); \ | |
49 | hval = fnv_32a_buf(&temp, sizeof(temp), hval); \ | |
50 | } | |
51 | 42 | #define END(typedefname) \ |
52 | 43 | return hval; \ |
53 | 44 | } |
59 | 50 | |
60 | 51 | |
61 | 52 | // describes an outline bitmap |
62 | START(outline_bitmap, outline_bitmap_hash_key) | |
53 | START(bitmap, bitmap_hash_key) | |
63 | 54 | GENERIC(OutlineHashValue *, outline) |
64 | GENERIC(int, frx) // signed 10.22 | |
65 | GENERIC(int, fry) // signed 10.22 | |
66 | GENERIC(int, frz) // signed 10.22 | |
67 | GENERIC(int, fax) // signed 16.16 | |
68 | GENERIC(int, fay) // signed 16.16 | |
69 | // shift vector that was added to glyph before applying rotation | |
70 | // = 0, if frx = fry = frx = 0 | |
71 | // = (glyph base point) - (rotation origin), otherwise | |
72 | GENERIC(int, shift_x) | |
73 | GENERIC(int, shift_y) | |
74 | VECTOR(advance) // subpixel shift vector | |
75 | END(OutlineBitmapHashKey) | |
55 | // quantized transform matrix | |
56 | VECTOR(offset) | |
57 | VECTOR(matrix_x) | |
58 | VECTOR(matrix_y) | |
59 | VECTOR(matrix_z) | |
60 | END(BitmapHashKey) | |
76 | 61 | |
77 | // describe a clip mask bitmap | |
78 | START(clip_bitmap, clip_bitmap_hash_key) | |
79 | STRING(text) | |
80 | END(ClipMaskHashKey) | |
62 | START(glyph_metrics, glyph_metrics_hash_key) | |
63 | GENERIC(ASS_Font *, font) | |
64 | GENERIC(double, size) | |
65 | GENERIC(int, face_index) | |
66 | GENERIC(int, glyph_index) | |
67 | END(GlyphMetricsHashKey) | |
81 | 68 | |
82 | 69 | // describes an outline glyph |
83 | 70 | START(glyph, glyph_hash_key) |
87 | 74 | GENERIC(int, glyph_index) |
88 | 75 | GENERIC(int, bold) |
89 | 76 | GENERIC(int, italic) |
90 | GENERIC(unsigned, scale_x) // 16.16 | |
91 | GENERIC(unsigned, scale_y) // 16.16 | |
92 | VECTOR(outline) // border width, 26.6 | |
93 | GENERIC(unsigned, flags) // glyph decoration flags | |
94 | GENERIC(unsigned, border_style) | |
95 | GENERIC(int, hspacing) // 16.16 | |
77 | GENERIC(unsigned, flags) // glyph decoration flags | |
96 | 78 | END(GlyphHashKey) |
97 | ||
98 | START(glyph_metrics, glyph_metrics_hash_key) | |
99 | GENERIC(ASS_Font *, font) | |
100 | GENERIC(double, size) | |
101 | GENERIC(int, face_index) | |
102 | GENERIC(int, glyph_index) | |
103 | GENERIC(unsigned, scale_x) | |
104 | GENERIC(unsigned, scale_y) | |
105 | END(GlyphMetricsHashKey) | |
106 | 79 | |
107 | 80 | // describes an outline drawing |
108 | 81 | START(drawing, drawing_hash_key) |
109 | GENERIC(unsigned, scale_x) | |
110 | GENERIC(unsigned, scale_y) | |
111 | GENERIC(int, pbo) | |
112 | VECTOR(outline) | |
113 | GENERIC(unsigned, border_style) | |
114 | GENERIC(int, hspacing) | |
115 | GENERIC(int, scale) | |
116 | GENERIC(unsigned, hash) | |
117 | 82 | STRING(text) |
118 | 83 | END(DrawingHashKey) |
84 | ||
85 | // describes an offset outline | |
86 | START(border, border_hash_key) | |
87 | GENERIC(OutlineHashValue *, outline) | |
88 | // outline is scaled by 2^scale_ord_x|y before stroking | |
89 | // to keep stoker error in allowable range | |
90 | GENERIC(int, scale_ord_x) | |
91 | GENERIC(int, scale_ord_y) | |
92 | VECTOR(border) // border size in STROKER_ACCURACY units | |
93 | END(BorderHashKey) | |
119 | 94 | |
120 | 95 | // describes post-combining effects |
121 | 96 | START(filter, filter_desc) |
122 | 97 | GENERIC(int, flags) |
123 | 98 | GENERIC(int, be) |
124 | GENERIC(double, blur) | |
99 | GENERIC(int, blur) | |
125 | 100 | VECTOR(shadow) |
126 | 101 | END(FilterDesc) |
102 | ||
103 | // describes glyph bitmap reference | |
104 | START(bitmap_ref, bitmap_ref_key) | |
105 | GENERIC(Bitmap *, bm) | |
106 | GENERIC(Bitmap *, bm_o) | |
107 | VECTOR(pos) | |
108 | VECTOR(pos_o) | |
109 | END(BitmapRef) | |
127 | 110 | |
128 | 111 | #undef START |
129 | 112 | #undef GENERIC |
130 | 113 | #undef STRING |
131 | 114 | #undef VECTOR |
132 | #undef BITMAPHASHKEY | |
133 | 115 | #undef END |
28 | 28 | |
29 | 29 | #include "ass_coretext.h" |
30 | 30 | |
31 | #define SAFE_CFRelease(x) do { if (x) CFRelease(x); } while(0) | |
31 | #define SAFE_CFRelease(x) do { if (x) CFRelease(x); } while (0) | |
32 | 32 | |
33 | 33 | static const ASS_FontMapping font_substitutions[] = { |
34 | 34 | {"sans-serif", "Helvetica"}, |
59 | 59 | SAFE_CFRelease(fontd); |
60 | 60 | } |
61 | 61 | |
62 | static bool is_postscript_font_format(CFNumberRef cfformat) | |
63 | { | |
64 | bool ret = false; | |
65 | int format; | |
66 | if (CFNumberGetValue(cfformat, kCFNumberIntType, &format)) { | |
67 | ret = format == kCTFontFormatOpenTypePostScript || | |
68 | format == kCTFontFormatPostScript; | |
69 | } | |
70 | return ret; | |
71 | } | |
72 | ||
62 | 73 | static bool check_postscript(void *priv) |
63 | 74 | { |
64 | 75 | CTFontDescriptorRef fontd = priv; |
65 | 76 | CFNumberRef cfformat = |
66 | 77 | CTFontDescriptorCopyAttribute(fontd, kCTFontFormatAttribute); |
67 | int format; | |
68 | ||
69 | if (!CFNumberGetValue(cfformat, kCFNumberIntType, &format)) | |
70 | return false; | |
71 | ||
78 | bool ret = is_postscript_font_format(cfformat); | |
72 | 79 | SAFE_CFRelease(cfformat); |
73 | ||
74 | return format == kCTFontFormatOpenTypePostScript || | |
75 | format == kCTFontFormatPostScript; | |
80 | return ret; | |
76 | 81 | } |
77 | 82 | |
78 | 83 | static bool check_glyph(void *priv, uint32_t code) |
95 | 100 | static char *get_font_file(CTFontDescriptorRef fontd) |
96 | 101 | { |
97 | 102 | CFURLRef url = CTFontDescriptorCopyAttribute(fontd, kCTFontURLAttribute); |
103 | if (!url) | |
104 | return NULL; | |
98 | 105 | CFStringRef path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); |
106 | if (!path) { | |
107 | SAFE_CFRelease(url); | |
108 | return NULL; | |
109 | } | |
99 | 110 | char *buffer = cfstr2buf(path); |
100 | 111 | SAFE_CFRelease(path); |
101 | 112 | SAFE_CFRelease(url); |
102 | 113 | return buffer; |
103 | 114 | } |
104 | 115 | |
105 | static void get_name(CTFontDescriptorRef fontd, CFStringRef attr, | |
106 | char **array, int *idx) | |
107 | { | |
108 | ||
116 | static char *get_name(CTFontDescriptorRef fontd, CFStringRef attr) | |
117 | { | |
118 | char *ret = NULL; | |
109 | 119 | CFStringRef name = CTFontDescriptorCopyAttribute(fontd, attr); |
110 | 120 | if (name) { |
111 | array[*idx] = cfstr2buf(name); | |
121 | ret = cfstr2buf(name); | |
112 | 122 | SAFE_CFRelease(name); |
113 | *idx += 1; | |
114 | } | |
115 | } | |
116 | ||
117 | static void get_trait(CFDictionaryRef traits, CFStringRef attribute, | |
118 | float *trait) | |
119 | { | |
120 | CFNumberRef cftrait = CFDictionaryGetValue(traits, attribute); | |
121 | if (!CFNumberGetValue(cftrait, kCFNumberFloatType, trait)) | |
122 | *trait = 0.0; | |
123 | } | |
124 | ||
125 | static void get_font_traits(CTFontDescriptorRef fontd, | |
126 | ASS_FontProviderMetaData *meta) | |
127 | { | |
128 | float weight, slant, width; | |
129 | ||
130 | CFDictionaryRef traits = | |
131 | CTFontDescriptorCopyAttribute(fontd, kCTFontTraitsAttribute); | |
132 | ||
133 | get_trait(traits, kCTFontWeightTrait, &weight); | |
134 | get_trait(traits, kCTFontSlantTrait, &slant); | |
135 | get_trait(traits, kCTFontWidthTrait, &width); | |
136 | ||
137 | SAFE_CFRelease(traits); | |
138 | ||
139 | // Printed all of my system fonts (see if'deffed code below). Here is how | |
140 | // CoreText 'normalized' weights maps to CSS/libass: | |
141 | ||
142 | // opentype: 0 100 200 300 400 500 600 700 800 900 | |
143 | // css: LIGHT REG MED SBOLD BOLD BLACK EXTRABL | |
144 | // libass: LIGHT MEDIUM BOLD | |
145 | // coretext: -0.4 0.0 0.23 0.3 0.4 0.62 | |
146 | ||
147 | if (weight >= 0.62) | |
148 | meta->weight = 800; | |
149 | else if (weight >= 0.4) | |
150 | meta->weight = 700; | |
151 | else if (weight >= 0.3) | |
152 | meta->weight = 600; | |
153 | else if (weight >= 0.23) | |
154 | meta->weight = 500; | |
155 | else if (weight >= -0.4) | |
156 | meta->weight = 400; | |
157 | else | |
158 | meta->weight = 200; | |
159 | ||
160 | if (slant > 0.03) | |
161 | meta->slant = FONT_SLANT_ITALIC; | |
162 | else | |
163 | meta->slant = FONT_SLANT_NONE; | |
164 | ||
165 | if (width <= -0.2) | |
166 | meta->width = FONT_WIDTH_CONDENSED; | |
167 | else if (width >= 0.2) | |
168 | meta->width = FONT_WIDTH_EXPANDED; | |
169 | else | |
170 | meta->width = FONT_WIDTH_NORMAL; | |
171 | ||
172 | #if 0 | |
173 | char *name[1]; | |
174 | int idx = 0; | |
175 | get_name(fontd, kCTFontDisplayNameAttribute, name, &idx); | |
176 | char *file = get_font_file(fontd); | |
177 | printf( | |
178 | "Font traits for: %-40s [%-50s] " | |
179 | "<slant: %f, %03d>, <weight: (%f, %03d)>, <width: %f, %03d>\n", | |
180 | name[0], file, | |
181 | slant, meta->slant, weight, meta->weight, width, meta->width); | |
182 | free(name[0]); | |
183 | free(file); | |
184 | #endif | |
185 | } | |
186 | ||
187 | static void process_descriptors(ASS_FontProvider *provider, CFArrayRef fontsd) | |
188 | { | |
189 | ASS_FontProviderMetaData meta; | |
190 | char *families[1]; | |
191 | char *identifiers[1]; | |
192 | char *fullnames[1]; | |
193 | ||
123 | } | |
124 | return ret; | |
125 | } | |
126 | ||
127 | static void process_descriptors(ASS_Library *lib, ASS_FontProvider *provider, | |
128 | CFArrayRef fontsd) | |
129 | { | |
194 | 130 | if (!fontsd) |
195 | 131 | return; |
196 | 132 | |
133 | FT_Library ftlib; | |
134 | if (FT_Init_FreeType(&ftlib)) { | |
135 | ass_msg(lib, MSGL_WARN, "Failed to create FT lib"); | |
136 | return; | |
137 | } | |
138 | ||
197 | 139 | for (int i = 0; i < CFArrayGetCount(fontsd); i++) { |
140 | ASS_FontProviderMetaData meta = {0}; | |
198 | 141 | CTFontDescriptorRef fontd = CFArrayGetValueAtIndex(fontsd, i); |
199 | 142 | int index = -1; |
200 | 143 | |
201 | 144 | char *path = get_font_file(fontd); |
202 | if (strcmp("", path) == 0) { | |
145 | if (!path || strcmp("", path) == 0) { | |
203 | 146 | // skip the font if the URL field in the font descriptor is empty |
204 | 147 | free(path); |
205 | 148 | continue; |
206 | 149 | } |
207 | 150 | |
208 | memset(&meta, 0, sizeof(meta)); | |
209 | get_font_traits(fontd, &meta); | |
210 | ||
211 | get_name(fontd, kCTFontFamilyNameAttribute, families, &meta.n_family); | |
212 | meta.families = families; | |
213 | ||
214 | get_name(fontd, kCTFontDisplayNameAttribute, fullnames, &meta.n_fullname); | |
215 | meta.fullnames = fullnames; | |
216 | ||
217 | int zero = 0; | |
218 | get_name(fontd, kCTFontNameAttribute, identifiers, &zero); | |
219 | meta.postscript_name = identifiers[0]; | |
220 | ||
221 | CFRetain(fontd); | |
222 | ass_font_provider_add_font(provider, &meta, path, index, (void*)fontd); | |
151 | char *ps_name = get_name(fontd, kCTFontNameAttribute); | |
152 | ||
153 | if (ass_get_font_info(lib, ftlib, path, ps_name, -1, &meta)) { | |
154 | CFRetain(fontd); | |
155 | ass_font_provider_add_font(provider, &meta, path, index, (void*)fontd); | |
156 | } | |
223 | 157 | |
224 | 158 | for (int j = 0; j < meta.n_family; j++) |
225 | 159 | free(meta.families[j]); |
227 | 161 | for (int j = 0; j < meta.n_fullname; j++) |
228 | 162 | free(meta.fullnames[j]); |
229 | 163 | |
164 | free(meta.families); | |
165 | free(meta.fullnames); | |
166 | ||
230 | 167 | free(meta.postscript_name); |
231 | 168 | |
169 | free(ps_name); | |
232 | 170 | free(path); |
233 | 171 | } |
172 | ||
173 | FT_Done_FreeType(ftlib); | |
234 | 174 | } |
235 | 175 | |
236 | 176 | static void match_fonts(ASS_Library *lib, ASS_FontProvider *provider, |
263 | 203 | CFArrayRef fontsd = |
264 | 204 | CTFontCollectionCreateMatchingFontDescriptors(ctcoll); |
265 | 205 | |
266 | process_descriptors(provider, fontsd); | |
206 | process_descriptors(lib, provider, fontsd); | |
267 | 207 | |
268 | 208 | SAFE_CFRelease(fontsd); |
269 | 209 | SAFE_CFRelease(ctcoll); |
287 | 227 | 0, (UInt8*)&codepointle, sizeof(codepointle), |
288 | 228 | kCFStringEncodingUTF32LE, false); |
289 | 229 | CTFontRef fb = CTFontCreateForString(font, r, CFRangeMake(0, 1)); |
290 | CFStringRef cffamily = CTFontCopyFamilyName(fb); | |
291 | char *res_family = cfstr2buf(cffamily); | |
230 | CFNumberRef cfformat = CTFontCopyAttribute(fb, kCTFontFormatAttribute); | |
231 | CFStringRef cfname = is_postscript_font_format(cfformat) ? | |
232 | CTFontCopyPostScriptName(fb) : CTFontCopyFullName(fb); | |
233 | char *res_name = cfstr2buf(cfname); | |
292 | 234 | |
293 | 235 | SAFE_CFRelease(name); |
294 | 236 | SAFE_CFRelease(font); |
295 | 237 | SAFE_CFRelease(r); |
296 | 238 | SAFE_CFRelease(fb); |
297 | SAFE_CFRelease(cffamily); | |
298 | ||
299 | return res_family; | |
239 | SAFE_CFRelease(cfformat); | |
240 | SAFE_CFRelease(cfname); | |
241 | ||
242 | return res_name; | |
300 | 243 | } |
301 | 244 | |
302 | 245 | static void get_substitutions(void *priv, const char *name, |
203 | 203 | static void init_FallbackLogTextRenderer(FallbackLogTextRenderer *r, |
204 | 204 | IDWriteFactory *factory) |
205 | 205 | { |
206 | *r = (FallbackLogTextRenderer){ | |
206 | *r = (FallbackLogTextRenderer) { | |
207 | 207 | .iface = { |
208 | 208 | .lpVtbl = &r->vtbl, |
209 | 209 | }, |
28 | 28 | #include "ass_drawing.h" |
29 | 29 | #include "ass_font.h" |
30 | 30 | |
31 | #define GLYPH_INITIAL_POINTS 100 | |
32 | #define GLYPH_INITIAL_SEGMENTS 100 | |
33 | ||
34 | /* | |
35 | * \brief Prepare drawing for parsing. This just sets a few parameters. | |
36 | */ | |
37 | static void drawing_prepare(ASS_Drawing *drawing) | |
38 | { | |
39 | // Scaling parameters | |
40 | drawing->point_scale_x = drawing->scale_x / (1 << (drawing->scale - 1)); | |
41 | drawing->point_scale_y = drawing->scale_y / (1 << (drawing->scale - 1)); | |
42 | } | |
43 | ||
44 | /* | |
45 | * \brief Finish a drawing. This only sets the horizontal advance according | |
46 | * to the outline's bbox at the moment. | |
47 | */ | |
48 | static void drawing_finish(ASS_Drawing *drawing, bool raw_mode) | |
49 | { | |
50 | ASS_Rect bbox = drawing->cbox; | |
51 | ASS_Outline *ol = &drawing->outline; | |
52 | ||
53 | if (drawing->library) | |
54 | ass_msg(drawing->library, MSGL_V, | |
55 | "Parsed drawing with %d points and %d segments", | |
56 | ol->n_points, ol->n_segments); | |
57 | ||
58 | if (raw_mode) | |
59 | return; | |
60 | ||
61 | drawing->advance.x = bbox.x_max - bbox.x_min; | |
62 | ||
63 | double pbo = drawing->pbo / (1 << (drawing->scale - 1)); | |
64 | drawing->desc = double_to_d6(pbo * drawing->scale_y); | |
65 | drawing->asc = bbox.y_max - bbox.y_min - drawing->desc; | |
66 | ||
67 | // Place it onto the baseline | |
68 | for (size_t i = 0; i < ol->n_points; i++) | |
69 | ol->points[i].y -= drawing->asc; | |
70 | } | |
31 | #define DRAWING_INITIAL_POINTS 100 | |
32 | #define DRAWING_INITIAL_SEGMENTS 100 | |
71 | 33 | |
72 | 34 | /* |
73 | 35 | * \brief Check whether a number of items on the list is available |
74 | 36 | */ |
75 | static int token_check_values(ASS_DrawingToken *token, int i, int type) | |
37 | static bool token_check_values(ASS_DrawingToken *token, int i, int type) | |
76 | 38 | { |
77 | 39 | for (int j = 0; j < i; j++) { |
78 | if (!token || token->type != type) return 0; | |
40 | if (!token || token->type != type) return false; | |
79 | 41 | token = token->next; |
80 | 42 | } |
81 | 43 | |
82 | return 1; | |
44 | return true; | |
83 | 45 | } |
84 | 46 | |
85 | 47 | /* |
86 | 48 | * \brief Tokenize a drawing string into a list of ASS_DrawingToken |
87 | 49 | * This also expands points for closing b-splines |
88 | 50 | */ |
89 | static ASS_DrawingToken *drawing_tokenize(char *str) | |
90 | { | |
91 | char *p = str; | |
51 | static ASS_DrawingToken *drawing_tokenize(const char *str) | |
52 | { | |
53 | char *p = (char *) str; | |
92 | 54 | int type = -1, is_set = 0; |
93 | 55 | double val; |
94 | 56 | ASS_Vector point = {0, 0}; |
173 | 135 | } |
174 | 136 | |
175 | 137 | /* |
176 | * \brief Translate and scale a point coordinate according to baseline | |
177 | * offset and scale. | |
178 | */ | |
179 | static inline void translate_point(ASS_Drawing *drawing, ASS_Vector *point) | |
180 | { | |
181 | point->x = lrint(drawing->point_scale_x * point->x); | |
182 | point->y = lrint(drawing->point_scale_y * point->y); | |
183 | ||
184 | rectangle_update(&drawing->cbox, point->x, point->y, point->x, point->y); | |
185 | } | |
186 | ||
187 | /* | |
188 | 138 | * \brief Add curve to drawing |
189 | 139 | */ |
190 | static bool drawing_add_curve(ASS_Drawing *drawing, ASS_DrawingToken *token, | |
191 | bool spline, int started) | |
140 | static bool drawing_add_curve(ASS_Outline *outline, ASS_Rect *cbox, | |
141 | ASS_DrawingToken *token, bool spline, int started) | |
192 | 142 | { |
193 | 143 | ASS_Vector p[4]; |
194 | 144 | for (int i = 0; i < 4; ++i) { |
195 | 145 | p[i] = token->point; |
196 | translate_point(drawing, &p[i]); | |
146 | rectangle_update(cbox, p[i].x, p[i].y, p[i].x, p[i].y); | |
197 | 147 | token = token->next; |
198 | 148 | } |
199 | 149 | |
216 | 166 | } |
217 | 167 | |
218 | 168 | return (started || |
219 | outline_add_point(&drawing->outline, p[0], 0)) && | |
220 | outline_add_point(&drawing->outline, p[1], 0) && | |
221 | outline_add_point(&drawing->outline, p[2], 0) && | |
222 | outline_add_point(&drawing->outline, p[3], OUTLINE_CUBIC_SPLINE); | |
223 | } | |
224 | ||
225 | /* | |
226 | * \brief Create and initialize a new drawing and return it | |
227 | */ | |
228 | ASS_Drawing *ass_drawing_new(ASS_Library *lib) | |
229 | { | |
230 | ASS_Drawing *drawing = calloc(1, sizeof(*drawing)); | |
231 | if (!drawing) | |
232 | return NULL; | |
233 | rectangle_reset(&drawing->cbox); | |
234 | drawing->library = lib; | |
235 | drawing->scale_x = 1.; | |
236 | drawing->scale_y = 1.; | |
237 | ||
238 | if (!outline_alloc(&drawing->outline, GLYPH_INITIAL_POINTS, GLYPH_INITIAL_SEGMENTS)) { | |
239 | free(drawing); | |
240 | return NULL; | |
241 | } | |
242 | return drawing; | |
243 | } | |
244 | ||
245 | /* | |
246 | * \brief Free a drawing | |
247 | */ | |
248 | void ass_drawing_free(ASS_Drawing *drawing) | |
249 | { | |
250 | if (drawing) { | |
251 | free(drawing->text); | |
252 | outline_free(&drawing->outline); | |
253 | } | |
254 | free(drawing); | |
255 | } | |
256 | ||
257 | /* | |
258 | * \brief Copy an ASCII string to the drawing text buffer | |
259 | */ | |
260 | void ass_drawing_set_text(ASS_Drawing *drawing, char *str, size_t len) | |
261 | { | |
262 | free(drawing->text); | |
263 | drawing->text = strndup(str, len); | |
264 | } | |
265 | ||
266 | /* | |
267 | * \brief Create a hashcode for the drawing | |
268 | * XXX: To avoid collisions a better hash algorithm might be useful. | |
269 | */ | |
270 | void ass_drawing_hash(ASS_Drawing *drawing) | |
271 | { | |
272 | if (!drawing->text) | |
273 | return; | |
274 | drawing->hash = fnv_32a_str(drawing->text, FNV1_32A_INIT); | |
169 | outline_add_point(outline, p[0], 0)) && | |
170 | outline_add_point(outline, p[1], 0) && | |
171 | outline_add_point(outline, p[2], 0) && | |
172 | outline_add_point(outline, p[3], OUTLINE_CUBIC_SPLINE); | |
275 | 173 | } |
276 | 174 | |
277 | 175 | /* |
278 | 176 | * \brief Convert token list to outline. Calls the line and curve evaluators. |
279 | 177 | */ |
280 | ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, bool raw_mode) | |
281 | { | |
178 | bool ass_drawing_parse(ASS_Outline *outline, ASS_Rect *cbox, | |
179 | const char *text, ASS_Library *lib) | |
180 | { | |
181 | if (!outline_alloc(outline, DRAWING_INITIAL_POINTS, DRAWING_INITIAL_SEGMENTS)) | |
182 | return false; | |
183 | rectangle_reset(cbox); | |
184 | ||
185 | ASS_DrawingToken *tokens = drawing_tokenize(text); | |
186 | ||
282 | 187 | bool started = false; |
283 | ASS_DrawingToken *token; | |
284 | 188 | ASS_Vector pen = {0, 0}; |
285 | ||
286 | drawing->tokens = drawing_tokenize(drawing->text); | |
287 | drawing_prepare(drawing); | |
288 | ||
289 | token = drawing->tokens; | |
189 | ASS_DrawingToken *token = tokens; | |
290 | 190 | while (token) { |
291 | 191 | // Draw something according to current command |
292 | 192 | switch (token->type) { |
293 | 193 | case TOKEN_MOVE_NC: |
294 | 194 | pen = token->point; |
295 | translate_point(drawing, &pen); | |
195 | rectangle_update(cbox, pen.x, pen.y, pen.x, pen.y); | |
296 | 196 | token = token->next; |
297 | 197 | break; |
298 | 198 | case TOKEN_MOVE: |
299 | 199 | pen = token->point; |
300 | translate_point(drawing, &pen); | |
200 | rectangle_update(cbox, pen.x, pen.y, pen.x, pen.y); | |
301 | 201 | if (started) { |
302 | if (!outline_add_segment(&drawing->outline, OUTLINE_LINE_SEGMENT)) | |
303 | goto error; | |
304 | if (!outline_close_contour(&drawing->outline)) | |
202 | if (!outline_add_segment(outline, OUTLINE_LINE_SEGMENT)) | |
203 | goto error; | |
204 | if (!outline_close_contour(outline)) | |
305 | 205 | goto error; |
306 | 206 | started = false; |
307 | 207 | } |
309 | 209 | break; |
310 | 210 | case TOKEN_LINE: { |
311 | 211 | ASS_Vector to = token->point; |
312 | translate_point(drawing, &to); | |
313 | if (!started && !outline_add_point(&drawing->outline, pen, 0)) | |
212 | rectangle_update(cbox, to.x, to.y, to.x, to.y); | |
213 | if (!started && !outline_add_point(outline, pen, 0)) | |
314 | 214 | goto error; |
315 | if (!outline_add_point(&drawing->outline, to, OUTLINE_LINE_SEGMENT)) | |
215 | if (!outline_add_point(outline, to, OUTLINE_LINE_SEGMENT)) | |
316 | 216 | goto error; |
317 | 217 | started = true; |
318 | 218 | token = token->next; |
321 | 221 | case TOKEN_CUBIC_BEZIER: |
322 | 222 | if (token_check_values(token, 3, TOKEN_CUBIC_BEZIER) && |
323 | 223 | token->prev) { |
324 | if (!drawing_add_curve(drawing, token->prev, false, started)) | |
224 | if (!drawing_add_curve(outline, cbox, token->prev, false, started)) | |
325 | 225 | goto error; |
326 | 226 | token = token->next; |
327 | 227 | token = token->next; |
333 | 233 | case TOKEN_B_SPLINE: |
334 | 234 | if (token_check_values(token, 3, TOKEN_B_SPLINE) && |
335 | 235 | token->prev) { |
336 | if (!drawing_add_curve(drawing, token->prev, true, started)) | |
236 | if (!drawing_add_curve(outline, cbox, token->prev, true, started)) | |
337 | 237 | goto error; |
338 | 238 | token = token->next; |
339 | 239 | started = true; |
348 | 248 | |
349 | 249 | // Close the last contour |
350 | 250 | if (started) { |
351 | if (!outline_add_segment(&drawing->outline, OUTLINE_LINE_SEGMENT)) | |
251 | if (!outline_add_segment(outline, OUTLINE_LINE_SEGMENT)) | |
352 | 252 | goto error; |
353 | if (!outline_close_contour(&drawing->outline)) | |
253 | if (!outline_close_contour(outline)) | |
354 | 254 | goto error; |
355 | 255 | } |
356 | 256 | |
357 | drawing_finish(drawing, raw_mode); | |
358 | drawing_free_tokens(drawing->tokens); | |
359 | return &drawing->outline; | |
257 | if (lib) | |
258 | ass_msg(lib, MSGL_V, | |
259 | "Parsed drawing with %d points and %d segments", | |
260 | outline->n_points, outline->n_segments); | |
261 | ||
262 | drawing_free_tokens(tokens); | |
263 | return true; | |
360 | 264 | |
361 | 265 | error: |
362 | drawing_free_tokens(drawing->tokens); | |
363 | return NULL; | |
364 | } | |
266 | drawing_free_tokens(tokens); | |
267 | outline_free(outline); | |
268 | return false; | |
269 | } |
40 | 40 | struct ass_drawing_token *prev; |
41 | 41 | } ASS_DrawingToken; |
42 | 42 | |
43 | typedef struct { | |
44 | char *text; // drawing string | |
45 | int scale; // scale (1-64) for subpixel accuracy | |
46 | double pbo; // drawing will be shifted in y direction by this amount | |
47 | double scale_x; // FontScaleX | |
48 | double scale_y; // FontScaleY | |
49 | int asc; // ascender | |
50 | int desc; // descender | |
51 | ASS_Outline outline; // target outline | |
52 | ASS_Vector advance; // advance (from cbox) | |
53 | int hash; // hash value (for caching) | |
54 | ||
55 | // private | |
56 | ASS_Library *library; | |
57 | ASS_DrawingToken *tokens; // tokenized drawing | |
58 | double point_scale_x; | |
59 | double point_scale_y; | |
60 | ASS_Rect cbox; // bounding box, or let's say... VSFilter's idea of it | |
61 | } ASS_Drawing; | |
62 | ||
63 | ASS_Drawing *ass_drawing_new(ASS_Library *lib); | |
64 | void ass_drawing_free(ASS_Drawing *drawing); | |
65 | void ass_drawing_set_text(ASS_Drawing *drawing, char *str, size_t n); | |
66 | void ass_drawing_hash(ASS_Drawing *drawing); | |
67 | ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, bool raw_mode); | |
43 | bool ass_drawing_parse(ASS_Outline *outline, ASS_Rect *cbox, | |
44 | const char *text, ASS_Library *lib); | |
68 | 45 | |
69 | 46 | #endif /* LIBASS_DRAWING_H */ |
86 | 86 | if (!face->charmap) |
87 | 87 | return symbol; |
88 | 88 | |
89 | switch(face->charmap->encoding){ | |
89 | switch (face->charmap->encoding) { | |
90 | 90 | case FT_ENCODING_MS_SYMBOL: |
91 | 91 | return 0xF000 | symbol; |
92 | 92 | default: |
94 | 94 | } |
95 | 95 | } |
96 | 96 | |
97 | static void buggy_font_workaround(FT_Face face) | |
98 | { | |
99 | // Some fonts have zero Ascender/Descender fields in 'hhea' table. | |
100 | // In this case, get the information from 'os2' table or, as | |
101 | // a last resort, from face.bbox. | |
102 | if (face->ascender + face->descender == 0 || face->height == 0) { | |
103 | TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); | |
104 | if (os2) { | |
97 | static void set_font_metrics(FT_Face face) | |
98 | { | |
99 | // Mimicking GDI's behavior for asc/desc/height. | |
100 | // These fields are (apparently) sometimes used for signed values, | |
101 | // despite being unsigned in the spec. | |
102 | TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); | |
103 | if (os2 && ((short)os2->usWinAscent + (short)os2->usWinDescent != 0)) { | |
104 | face->ascender = (short)os2->usWinAscent; | |
105 | face->descender = -(short)os2->usWinDescent; | |
106 | face->height = face->ascender - face->descender; | |
107 | } | |
108 | ||
109 | // If we didn't have usable Win values in the OS/2 table, | |
110 | // then the values from FreeType will still be in these fields. | |
111 | // It'll use either the OS/2 typo metrics or the hhea ones. | |
112 | // If the font has typo metrics but FreeType didn't use them | |
113 | // (either old FT or USE_TYPO_METRICS not set), we'll try those. | |
114 | // In the case of a very broken font that has none of those options, | |
115 | // we fall back on using face.bbox. | |
116 | // Anything without valid OS/2 Win values isn't supported by VSFilter, | |
117 | // so at this point compatibility's out the window and we're just | |
118 | // trying to render _something_ readable. | |
119 | if (face->ascender - face->descender == 0 || face->height == 0) { | |
120 | if (os2 && (os2->sTypoAscender - os2->sTypoDescender) != 0) { | |
105 | 121 | face->ascender = os2->sTypoAscender; |
106 | 122 | face->descender = os2->sTypoDescender; |
107 | 123 | face->height = face->ascender - face->descender; |
212 | 228 | } |
213 | 229 | |
214 | 230 | charmap_magic(font->library, face); |
215 | buggy_font_workaround(face); | |
231 | set_font_metrics(face); | |
216 | 232 | |
217 | 233 | font->faces[font->n_faces] = face; |
218 | 234 | font->faces_uid[font->n_faces++] = uid; |
223 | 239 | /** |
224 | 240 | * \brief Create a new ASS_Font according to "desc" argument |
225 | 241 | */ |
226 | ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library, | |
227 | FT_Library ftlibrary, ASS_FontSelector *fontsel, | |
228 | ASS_FontDesc *desc) | |
229 | { | |
230 | ASS_Font *font; | |
231 | if (ass_cache_get(font_cache, desc, &font)) { | |
232 | if (font->desc.family) | |
233 | return font; | |
234 | ass_cache_dec_ref(font); | |
235 | return NULL; | |
236 | } | |
242 | ASS_Font *ass_font_new(ASS_Renderer *render_priv, ASS_FontDesc *desc) | |
243 | { | |
244 | ASS_Font *font = ass_cache_get(render_priv->cache.font_cache, desc, render_priv); | |
237 | 245 | if (!font) |
238 | 246 | return NULL; |
239 | ||
240 | font->library = library; | |
241 | font->ftlibrary = ftlibrary; | |
247 | if (font->library) | |
248 | return font; | |
249 | ass_cache_dec_ref(font); | |
250 | return NULL; | |
251 | } | |
252 | ||
253 | size_t ass_font_construct(void *key, void *value, void *priv) | |
254 | { | |
255 | ASS_Renderer *render_priv = priv; | |
256 | ASS_FontDesc *desc = key; | |
257 | ASS_Font *font = value; | |
258 | ||
259 | font->library = render_priv->library; | |
260 | font->ftlibrary = render_priv->ftlibrary; | |
242 | 261 | font->shaper_priv = NULL; |
243 | 262 | font->n_faces = 0; |
244 | ASS_FontDesc *new_desc = ass_cache_key(font); | |
245 | font->desc.family = new_desc->family; | |
263 | font->desc.family = desc->family; | |
246 | 264 | font->desc.bold = desc->bold; |
247 | 265 | font->desc.italic = desc->italic; |
248 | 266 | font->desc.vertical = desc->vertical; |
249 | 267 | |
250 | font->scale_x = font->scale_y = 1.; | |
251 | font->v.x = font->v.y = 0; | |
252 | 268 | font->size = 0.; |
253 | 269 | |
254 | int error = add_face(fontsel, font, 0); | |
255 | if (error == -1) { | |
256 | font->desc.family = NULL; | |
257 | ass_cache_commit(font, 1); | |
258 | ass_cache_dec_ref(font); | |
259 | return NULL; | |
260 | } | |
261 | ass_cache_commit(font, 1); | |
262 | return font; | |
263 | } | |
264 | ||
265 | /** | |
266 | * \brief Set font transformation matrix and shift vector | |
267 | **/ | |
268 | void ass_font_set_transform(ASS_Font *font, double scale_x, | |
269 | double scale_y, FT_Vector *v) | |
270 | { | |
271 | font->scale_x = scale_x; | |
272 | font->scale_y = scale_y; | |
273 | if (v) { | |
274 | font->v.x = v->x; | |
275 | font->v.y = v->y; | |
276 | } | |
270 | int error = add_face(render_priv->fontselect, font, 0); | |
271 | if (error == -1) | |
272 | font->library = NULL; | |
273 | return 1; | |
277 | 274 | } |
278 | 275 | |
279 | 276 | void ass_face_set_size(FT_Face face, double size) |
280 | 277 | { |
281 | TT_HoriHeader *hori = FT_Get_Sfnt_Table(face, ft_sfnt_hhea); | |
282 | TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); | |
283 | double mscale = 1.; | |
284 | 278 | FT_Size_RequestRec rq; |
285 | FT_Size_Metrics *m = &face->size->metrics; | |
286 | // VSFilter uses metrics from TrueType OS/2 table | |
287 | // The idea was borrowed from asa (http://asa.diac24.net) | |
288 | if (os2) { | |
289 | int ft_height = 0; | |
290 | if (hori) | |
291 | ft_height = hori->Ascender - hori->Descender; | |
292 | if (!ft_height) | |
293 | ft_height = os2->sTypoAscender - os2->sTypoDescender; | |
294 | /* sometimes used for signed values despite unsigned in spec */ | |
295 | int os2_height = (short)os2->usWinAscent + (short)os2->usWinDescent; | |
296 | if (ft_height && os2_height) | |
297 | mscale = (double) ft_height / os2_height; | |
298 | } | |
299 | 279 | memset(&rq, 0, sizeof(rq)); |
300 | 280 | rq.type = FT_SIZE_REQUEST_TYPE_REAL_DIM; |
301 | 281 | rq.width = 0; |
302 | rq.height = double_to_d6(size * mscale); | |
282 | rq.height = double_to_d6(size); | |
303 | 283 | rq.horiResolution = rq.vertResolution = 0; |
304 | 284 | FT_Request_Size(face, &rq); |
305 | m->ascender /= mscale; | |
306 | m->descender /= mscale; | |
307 | m->height /= mscale; | |
308 | 285 | } |
309 | 286 | |
310 | 287 | /** |
321 | 298 | } |
322 | 299 | |
323 | 300 | /** |
301 | * \brief Get face weight | |
302 | **/ | |
303 | int ass_face_get_weight(FT_Face face) | |
304 | { | |
305 | #if FREETYPE_MAJOR > 2 || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR >= 6) | |
306 | TT_OS2 *os2 = FT_Get_Sfnt_Table(face, FT_SFNT_OS2); | |
307 | #else | |
308 | // This old name is still included (as a macro), but deprecated as of 2.6, so avoid using it if we can | |
309 | TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); | |
310 | #endif | |
311 | if (os2 && os2->version != 0xffff && os2->usWeightClass) | |
312 | return os2->usWeightClass; | |
313 | else | |
314 | return 300 * !!(face->style_flags & FT_STYLE_FLAG_BOLD) + 400; | |
315 | } | |
316 | ||
317 | /** | |
324 | 318 | * \brief Get maximal font ascender and descender. |
325 | * \param ch character code | |
326 | * The values are extracted from the font face that provides glyphs for the given character | |
327 | 319 | **/ |
328 | void ass_font_get_asc_desc(ASS_Font *font, uint32_t ch, int *asc, | |
329 | int *desc) | |
330 | { | |
331 | int i; | |
332 | for (i = 0; i < font->n_faces; ++i) { | |
333 | FT_Face face = font->faces[i]; | |
334 | TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); | |
335 | if (FT_Get_Char_Index(face, ass_font_index_magic(face, ch))) { | |
336 | int y_scale = face->size->metrics.y_scale; | |
337 | if (os2) { | |
338 | *asc = FT_MulFix((short)os2->usWinAscent, y_scale); | |
339 | *desc = FT_MulFix((short)os2->usWinDescent, y_scale); | |
340 | } else { | |
341 | *asc = FT_MulFix(face->ascender, y_scale); | |
342 | *desc = FT_MulFix(-face->descender, y_scale); | |
343 | } | |
344 | return; | |
345 | } | |
346 | } | |
347 | ||
348 | *asc = *desc = 0; | |
320 | void ass_font_get_asc_desc(ASS_Font *font, int face_index, | |
321 | int *asc, int *desc) | |
322 | { | |
323 | FT_Face face = font->faces[face_index]; | |
324 | int y_scale = face->size->metrics.y_scale; | |
325 | *asc = FT_MulFix(face->ascender, y_scale); | |
326 | *desc = FT_MulFix(-face->descender, y_scale); | |
349 | 327 | } |
350 | 328 | |
351 | 329 | static void add_line(FT_Outline *ol, int bear, int advance, int dir, int pos, int size) { |
530 | 508 | * \brief Get a glyph |
531 | 509 | * \param ch character code |
532 | 510 | **/ |
533 | FT_Glyph ass_font_get_glyph(ASS_Font *font, uint32_t ch, int face_index, | |
534 | int index, ASS_Hinting hinting, int deco) | |
511 | FT_Glyph ass_font_get_glyph(ASS_Font *font, int face_index, int index, | |
512 | ASS_Hinting hinting, int deco) | |
535 | 513 | { |
536 | 514 | int error; |
537 | 515 | FT_Glyph glyph; |
538 | 516 | FT_Face face = font->faces[face_index]; |
539 | 517 | int flags = 0; |
540 | int vertical = font->desc.vertical; | |
541 | 518 | |
542 | 519 | flags = FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH |
543 | 520 | | FT_LOAD_IGNORE_TRANSFORM; |
566 | 543 | FT_GlyphSlot_Oblique(face->glyph); |
567 | 544 | } |
568 | 545 | |
569 | if (!(face->style_flags & FT_STYLE_FLAG_BOLD) && | |
570 | (font->desc.bold > 400)) { | |
546 | if (font->desc.bold > ass_face_get_weight(face) + 150) { | |
571 | 547 | ass_glyph_embolden(face->glyph); |
572 | 548 | } |
573 | 549 | error = FT_Get_Glyph(face->glyph, &glyph); |
578 | 554 | } |
579 | 555 | |
580 | 556 | // Rotate glyph, if needed |
581 | if (vertical && ch >= VERTICAL_LOWER_BOUND) { | |
557 | if (deco & DECO_ROTATE) { | |
582 | 558 | FT_Matrix m = { 0, double_to_d16(-1.0), double_to_d16(1.0), 0 }; |
583 | 559 | TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); |
584 | 560 | int desc = 0; |
595 | 571 | |
596 | 572 | ass_strike_outline_glyph(face, font, glyph, deco & DECO_UNDERLINE, |
597 | 573 | deco & DECO_STRIKETHROUGH); |
598 | ||
599 | // Apply scaling and shift | |
600 | FT_Matrix scale = { double_to_d16(font->scale_x), 0, 0, | |
601 | double_to_d16(font->scale_y) }; | |
602 | FT_Outline *outl = &((FT_OutlineGlyph) glyph)->outline; | |
603 | FT_Outline_Transform(outl, &scale); | |
604 | FT_Outline_Translate(outl, font->v.x, font->v.y); | |
605 | glyph->advance.x *= font->scale_x; | |
606 | 574 | |
607 | 575 | return glyph; |
608 | 576 | } |
34 | 34 | #define VERTICAL_LOWER_BOUND 0x02f1 |
35 | 35 | |
36 | 36 | #define ASS_FONT_MAX_FACES 10 |
37 | #define DECO_UNDERLINE 1 | |
37 | #define DECO_UNDERLINE 1 | |
38 | 38 | #define DECO_STRIKETHROUGH 2 |
39 | #define DECO_ROTATE 4 | |
39 | 40 | |
40 | 41 | struct ass_font_desc { |
41 | 42 | char *family; |
52 | 53 | FT_Face faces[ASS_FONT_MAX_FACES]; |
53 | 54 | ASS_ShaperFontData *shaper_priv; |
54 | 55 | int n_faces; |
55 | double scale_x, scale_y; // current transform | |
56 | FT_Vector v; // current shift | |
57 | 56 | double size; |
58 | 57 | }; |
59 | 58 | |
60 | 59 | void charmap_magic(ASS_Library *library, FT_Face face); |
61 | ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library, | |
62 | FT_Library ftlibrary, ASS_FontSelector *fontsel, | |
63 | ASS_FontDesc *desc); | |
64 | void ass_font_set_transform(ASS_Font *font, double scale_x, | |
65 | double scale_y, FT_Vector *v); | |
60 | ASS_Font *ass_font_new(ASS_Renderer *render_priv, ASS_FontDesc *desc); | |
66 | 61 | void ass_face_set_size(FT_Face face, double size); |
67 | 62 | void ass_font_set_size(ASS_Font *font, double size); |
68 | void ass_font_get_asc_desc(ASS_Font *font, uint32_t ch, int *asc, | |
69 | int *desc); | |
63 | int ass_face_get_weight(FT_Face face); | |
64 | void ass_font_get_asc_desc(ASS_Font *font, int face_index, | |
65 | int *asc, int *desc); | |
70 | 66 | int ass_font_get_index(ASS_FontSelector *fontsel, ASS_Font *font, |
71 | 67 | uint32_t symbol, int *face_index, int *glyph_index); |
72 | 68 | uint32_t ass_font_index_magic(FT_Face face, uint32_t symbol); |
73 | FT_Glyph ass_font_get_glyph(ASS_Font *font, | |
74 | uint32_t ch, int face_index, int index, | |
69 | FT_Glyph ass_font_get_glyph(ASS_Font *font, int face_index, int index, | |
75 | 70 | ASS_Hinting hinting, int deco); |
76 | 71 | void ass_font_clear(ASS_Font *font); |
77 | 72 |
95 | 95 | for (i = 0; i < fonts->nfont; i++) { |
96 | 96 | FcPattern *pat = fonts->fonts[i]; |
97 | 97 | FcBool outline; |
98 | int index, weight; | |
98 | int index; | |
99 | double weight; | |
99 | 100 | char *path; |
100 | 101 | char *fullnames[MAX_NAME]; |
101 | 102 | char *families[MAX_NAME]; |
108 | 109 | // simple types |
109 | 110 | result = FcPatternGetInteger(pat, FC_SLANT, 0, &meta.slant); |
110 | 111 | result |= FcPatternGetInteger(pat, FC_WIDTH, 0, &meta.width); |
111 | result |= FcPatternGetInteger(pat, FC_WEIGHT, 0, &weight); | |
112 | result |= FcPatternGetDouble(pat, FC_WEIGHT, 0, &weight); | |
112 | 113 | result |= FcPatternGetInteger(pat, FC_INDEX, 0, &index); |
113 | 114 | if (result != FcResultMatch) |
114 | 115 | continue; |
115 | 116 | |
116 | 117 | // fontconfig uses its own weight scale, apparently derived |
117 | 118 | // from typographical weight. we're using truetype weights, so |
118 | // convert appropriately | |
119 | if (weight <= FC_WEIGHT_LIGHT) | |
120 | meta.weight = FONT_WEIGHT_LIGHT; | |
121 | else if (weight <= FC_WEIGHT_MEDIUM) | |
122 | meta.weight = FONT_WEIGHT_MEDIUM; | |
119 | // convert appropriately. | |
120 | #if FC_VERSION >= 21292 | |
121 | meta.weight = FcWeightToOpenTypeDouble(weight) + 0.5; | |
122 | #elif FC_VERSION >= 21191 | |
123 | // Versions prior to 2.12.92 only had integer precision. | |
124 | meta.weight = FcWeightToOpenType(weight + 0.5) + 0.5; | |
125 | #else | |
126 | // On older fontconfig, FcWeightToOpenType is unavailable, and its inverse was | |
127 | // implemented more simply, using an if/else ladder instead of linear interpolation. | |
128 | // We implement an inverse of that ladder here. | |
129 | // We don't expect actual FC caches from these versions to have intermediate | |
130 | // values, so the average checks are only for completeness. | |
131 | #define AVG(x, y) (((double)x + y) / 2) | |
132 | #ifndef FC_WEIGHT_SEMILIGHT | |
133 | #define FC_WEIGHT_SEMILIGHT 55 | |
134 | #endif | |
135 | if (weight < AVG(FC_WEIGHT_THIN, FC_WEIGHT_EXTRALIGHT)) | |
136 | meta.weight = 100; | |
137 | else if (weight < AVG(FC_WEIGHT_EXTRALIGHT, FC_WEIGHT_LIGHT)) | |
138 | meta.weight = 200; | |
139 | else if (weight < AVG(FC_WEIGHT_LIGHT, FC_WEIGHT_SEMILIGHT)) | |
140 | meta.weight = 300; | |
141 | else if (weight < AVG(FC_WEIGHT_SEMILIGHT, FC_WEIGHT_BOOK)) | |
142 | meta.weight = 350; | |
143 | else if (weight < AVG(FC_WEIGHT_BOOK, FC_WEIGHT_REGULAR)) | |
144 | meta.weight = 380; | |
145 | else if (weight < AVG(FC_WEIGHT_REGULAR, FC_WEIGHT_MEDIUM)) | |
146 | meta.weight = 400; | |
147 | else if (weight < AVG(FC_WEIGHT_MEDIUM, FC_WEIGHT_SEMIBOLD)) | |
148 | meta.weight = 500; | |
149 | else if (weight < AVG(FC_WEIGHT_SEMIBOLD, FC_WEIGHT_BOLD)) | |
150 | meta.weight = 600; | |
151 | else if (weight < AVG(FC_WEIGHT_BOLD, FC_WEIGHT_EXTRABOLD)) | |
152 | meta.weight = 700; | |
153 | else if (weight < AVG(FC_WEIGHT_EXTRABOLD, FC_WEIGHT_BLACK)) | |
154 | meta.weight = 800; | |
155 | else if (weight < AVG(FC_WEIGHT_BLACK, FC_WEIGHT_EXTRABLACK)) | |
156 | meta.weight = 900; | |
123 | 157 | else |
124 | meta.weight = FONT_WEIGHT_BOLD; | |
158 | meta.weight = 1000; | |
159 | #endif | |
125 | 160 | |
126 | 161 | // path |
127 | 162 | result = FcPatternGetString(pat, FC_FILE, 0, (FcChar8 **)&path); |
778 | 778 | ass_utf16be_to_utf8(buf, sizeof(buf), (uint8_t *)name.string, |
779 | 779 | name.string_len); |
780 | 780 | |
781 | if (name.name_id == TT_NAME_ID_FULL_NAME) { | |
781 | if (name.name_id == TT_NAME_ID_FULL_NAME && num_fullname < MAX_FULLNAME) { | |
782 | 782 | fullnames[num_fullname] = strdup(buf); |
783 | 783 | if (fullnames[num_fullname] == NULL) |
784 | 784 | goto error; |
785 | 785 | num_fullname++; |
786 | 786 | } |
787 | 787 | |
788 | if (name.name_id == TT_NAME_ID_FONT_FAMILY) { | |
788 | if (name.name_id == TT_NAME_ID_FONT_FAMILY && num_family < MAX_FULLNAME) { | |
789 | 789 | families[num_family] = strdup(buf); |
790 | 790 | if (families[num_family] == NULL) |
791 | 791 | goto error; |
809 | 809 | |
810 | 810 | // calculate sensible slant and weight from style attributes |
811 | 811 | slant = 110 * !!(face->style_flags & FT_STYLE_FLAG_ITALIC); |
812 | weight = 300 * !!(face->style_flags & FT_STYLE_FLAG_BOLD) + 400; | |
812 | weight = ass_face_get_weight(face); | |
813 | 813 | |
814 | 814 | // fill our struct |
815 | 815 | info->slant = slant; |
844 | 844 | free(info->families); |
845 | 845 | free(info->fullnames); |
846 | 846 | |
847 | info->families = info->fullnames = NULL; | |
848 | info->n_family = info->n_fullname = 0; | |
849 | ||
847 | 850 | return false; |
851 | } | |
852 | ||
853 | bool ass_get_font_info(ASS_Library *lib, FT_Library ftlib, const char *path, | |
854 | const char *postscript_name, int index, | |
855 | ASS_FontProviderMetaData *info) | |
856 | { | |
857 | bool ret = false; | |
858 | FT_Face face = NULL; | |
859 | int error = FT_New_Face(ftlib, path, index, &face); | |
860 | if (error) { | |
861 | ass_msg(lib, MSGL_WARN, "Error opening font: '%s', %d", path, index); | |
862 | return false; | |
863 | } | |
864 | ||
865 | if (postscript_name && index < 0 && face->num_faces > 0) { | |
866 | // The font provider gave us a postscript name and is not sure | |
867 | // about the face index.. so use the postscript name to find the | |
868 | // correct face_index in the collection! | |
869 | for (int i = 0; i < face->num_faces; i++) { | |
870 | FT_Done_Face(face); | |
871 | error = FT_New_Face(ftlib, path, i, &face); | |
872 | if (error) { | |
873 | ass_msg(lib, MSGL_WARN, "Error opening font: '%s', %d", path, i); | |
874 | return false; | |
875 | } | |
876 | ||
877 | const char *face_psname = FT_Get_Postscript_Name(face); | |
878 | if (face_psname != NULL && | |
879 | strcmp(face_psname, postscript_name) == 0) | |
880 | break; | |
881 | } | |
882 | } | |
883 | ||
884 | if (face) { | |
885 | ret = get_font_info(ftlib, face, info); | |
886 | if (ret) | |
887 | info->postscript_name = strdup(info->postscript_name); | |
888 | FT_Done_Face(face); | |
889 | } | |
890 | ||
891 | return ret; | |
848 | 892 | } |
849 | 893 | |
850 | 894 | /** |
925 | 969 | if (!ass_font_provider_add_font(priv, &info, NULL, face_index, ft)) { |
926 | 970 | ass_msg(library, MSGL_WARN, "Failed to add embedded font '%s'", |
927 | 971 | name); |
972 | free(ft); | |
928 | 973 | } |
929 | 974 | |
930 | 975 | free_font_info(&info); |
44 | 44 | * font path (i.e. the path was set to NULL). |
45 | 45 | * |
46 | 46 | * \param font_priv font private data |
47 | * \param output buffer; set to NULL to query stream size | |
47 | * \param data output buffer; set to NULL to query stream size | |
48 | 48 | * \param offset stream offset |
49 | 49 | * \param len bytes to read into output buffer from stream |
50 | 50 | * \return actual number of bytes read, or stream size if data == NULL |
64 | 64 | * Check if a glyph is supported by a font. |
65 | 65 | * |
66 | 66 | * \param font_priv font private data |
67 | * \param codepont Unicode codepoint (UTF-32) | |
67 | * \param codepoint Unicode codepoint (UTF-32) | |
68 | 68 | * \return true if codepoint is supported by the font |
69 | 69 | */ |
70 | 70 | typedef bool (*CheckGlyphFunc)(void *font_priv, uint32_t codepoint); |
242 | 242 | * provide additional fonts to libass. |
243 | 243 | * \param priv parent renderer |
244 | 244 | * \param funcs callback functions |
245 | * \param private data for provider callbacks | |
245 | * \param data private data for provider callbacks | |
246 | 246 | * |
247 | 247 | */ |
248 | 248 | ASS_FontProvider * |
266 | 266 | int index, void *data); |
267 | 267 | |
268 | 268 | /** |
269 | * \brief Read a font's parameters | |
270 | * \param lib a FT_Library to use (need not be the global one) | |
271 | * \param path the path to the font file to read | |
272 | * \param postscript_name the PS name of the specific face to read (set either this or index) | |
273 | * \param index the face index to read, or -1 if not applicable | |
274 | * \param info the struct to store results into | |
275 | * \return success | |
276 | * | |
277 | */ | |
278 | bool ass_get_font_info(ASS_Library *lib, FT_Library ftlib, const char *path, | |
279 | const char *postscript_name, int index, | |
280 | ASS_FontProviderMetaData *info); | |
281 | ||
282 | /** | |
269 | 283 | * \brief Free font provider and associated fonts. |
270 | 284 | * \param provider the font provider |
271 | 285 | * |
56 | 56 | uintptr_t src_width, uintptr_t src_height); |
57 | 57 | void DECORATE(expand_vert)(int16_t *dst, const int16_t *src, |
58 | 58 | uintptr_t src_width, uintptr_t src_height); |
59 | void DECORATE(pre_blur1_horz)(int16_t *dst, const int16_t *src, | |
60 | uintptr_t src_width, uintptr_t src_height); | |
61 | void DECORATE(pre_blur1_vert)(int16_t *dst, const int16_t *src, | |
62 | uintptr_t src_width, uintptr_t src_height); | |
63 | void DECORATE(pre_blur2_horz)(int16_t *dst, const int16_t *src, | |
64 | uintptr_t src_width, uintptr_t src_height); | |
65 | void DECORATE(pre_blur2_vert)(int16_t *dst, const int16_t *src, | |
66 | uintptr_t src_width, uintptr_t src_height); | |
67 | void DECORATE(pre_blur3_horz)(int16_t *dst, const int16_t *src, | |
68 | uintptr_t src_width, uintptr_t src_height); | |
69 | void DECORATE(pre_blur3_vert)(int16_t *dst, const int16_t *src, | |
70 | uintptr_t src_width, uintptr_t src_height); | |
71 | void DECORATE(blur1234_horz)(int16_t *dst, const int16_t *src, | |
72 | uintptr_t src_width, uintptr_t src_height, | |
73 | const int16_t *param); | |
74 | void DECORATE(blur1234_vert)(int16_t *dst, const int16_t *src, | |
75 | uintptr_t src_width, uintptr_t src_height, | |
76 | const int16_t *param); | |
77 | void DECORATE(blur1235_horz)(int16_t *dst, const int16_t *src, | |
78 | uintptr_t src_width, uintptr_t src_height, | |
79 | const int16_t *param); | |
80 | void DECORATE(blur1235_vert)(int16_t *dst, const int16_t *src, | |
81 | uintptr_t src_width, uintptr_t src_height, | |
82 | const int16_t *param); | |
83 | void DECORATE(blur1246_horz)(int16_t *dst, const int16_t *src, | |
84 | uintptr_t src_width, uintptr_t src_height, | |
85 | const int16_t *param); | |
86 | void DECORATE(blur1246_vert)(int16_t *dst, const int16_t *src, | |
87 | uintptr_t src_width, uintptr_t src_height, | |
88 | const int16_t *param); | |
59 | void DECORATE(blur4_horz)(int16_t *dst, const int16_t *src, | |
60 | uintptr_t src_width, uintptr_t src_height, | |
61 | const int16_t *param); | |
62 | void DECORATE(blur4_vert)(int16_t *dst, const int16_t *src, | |
63 | uintptr_t src_width, uintptr_t src_height, | |
64 | const int16_t *param); | |
65 | void DECORATE(blur5_horz)(int16_t *dst, const int16_t *src, | |
66 | uintptr_t src_width, uintptr_t src_height, | |
67 | const int16_t *param); | |
68 | void DECORATE(blur5_vert)(int16_t *dst, const int16_t *src, | |
69 | uintptr_t src_width, uintptr_t src_height, | |
70 | const int16_t *param); | |
71 | void DECORATE(blur6_horz)(int16_t *dst, const int16_t *src, | |
72 | uintptr_t src_width, uintptr_t src_height, | |
73 | const int16_t *param); | |
74 | void DECORATE(blur6_vert)(int16_t *dst, const int16_t *src, | |
75 | uintptr_t src_width, uintptr_t src_height, | |
76 | const int16_t *param); | |
77 | void DECORATE(blur7_horz)(int16_t *dst, const int16_t *src, | |
78 | uintptr_t src_width, uintptr_t src_height, | |
79 | const int16_t *param); | |
80 | void DECORATE(blur7_vert)(int16_t *dst, const int16_t *src, | |
81 | uintptr_t src_width, uintptr_t src_height, | |
82 | const int16_t *param); | |
83 | void DECORATE(blur8_horz)(int16_t *dst, const int16_t *src, | |
84 | uintptr_t src_width, uintptr_t src_height, | |
85 | const int16_t *param); | |
86 | void DECORATE(blur8_vert)(int16_t *dst, const int16_t *src, | |
87 | uintptr_t src_width, uintptr_t src_height, | |
88 | const int16_t *param); | |
89 | 89 | |
90 | 90 | |
91 | 91 | const BitmapEngine DECORATE(bitmap_engine) = { |
124 | 124 | .shrink_vert = DECORATE(shrink_vert), |
125 | 125 | .expand_horz = DECORATE(expand_horz), |
126 | 126 | .expand_vert = DECORATE(expand_vert), |
127 | .pre_blur_horz = { DECORATE(pre_blur1_horz), DECORATE(pre_blur2_horz), DECORATE(pre_blur3_horz) }, | |
128 | .pre_blur_vert = { DECORATE(pre_blur1_vert), DECORATE(pre_blur2_vert), DECORATE(pre_blur3_vert) }, | |
129 | .main_blur_horz = { DECORATE(blur1234_horz), DECORATE(blur1235_horz), DECORATE(blur1246_horz) }, | |
130 | .main_blur_vert = { DECORATE(blur1234_vert), DECORATE(blur1235_vert), DECORATE(blur1246_vert) }, | |
127 | .blur_horz = { DECORATE(blur4_horz), DECORATE(blur5_horz), DECORATE(blur6_horz), DECORATE(blur7_horz), DECORATE(blur8_horz) }, | |
128 | .blur_vert = { DECORATE(blur4_vert), DECORATE(blur5_vert), DECORATE(blur6_vert), DECORATE(blur7_vert), DECORATE(blur8_vert) }, | |
131 | 129 | }; |
34 | 34 | |
35 | 35 | outline->max_points = n_points; |
36 | 36 | outline->max_segments = n_segments; |
37 | outline->n_points = outline->n_segments = 0; | |
37 | 38 | return true; |
38 | 39 | } |
39 | 40 | |
44 | 45 | |
45 | 46 | outline->n_points = outline->max_points = 0; |
46 | 47 | outline->n_segments = outline->max_segments = 0; |
48 | } | |
49 | ||
50 | static bool valid_point(const FT_Vector *pt) | |
51 | { | |
52 | return labs(pt->x) <= OUTLINE_MAX && labs(pt->y) <= OUTLINE_MAX; | |
47 | 53 | } |
48 | 54 | |
49 | 55 | bool outline_convert(ASS_Outline *outline, const FT_Outline *source) |
60 | 66 | S_ON, S_Q, S_C1, S_C2 |
61 | 67 | }; |
62 | 68 | |
63 | outline->n_points = outline->n_segments = 0; | |
64 | 69 | for (size_t i = 0, j = 0; i < source->n_contours; i++) { |
65 | 70 | ASS_Vector pt; |
66 | 71 | bool skip_last = false; |
76 | 81 | continue; |
77 | 82 | } |
78 | 83 | |
84 | if (!valid_point(source->points + j)) | |
85 | goto fail; | |
79 | 86 | switch (FT_CURVE_TAG(source->tags[j])) { |
80 | 87 | case FT_CURVE_TAG_ON: |
81 | 88 | st = S_ON; |
82 | 89 | break; |
83 | 90 | |
84 | 91 | case FT_CURVE_TAG_CONIC: |
92 | if (!valid_point(source->points + last)) | |
93 | goto fail; | |
85 | 94 | pt.x = source->points[last].x; |
86 | 95 | pt.y = -source->points[last].y; |
87 | 96 | switch (FT_CURVE_TAG(source->tags[last])) { |
109 | 118 | outline->points[outline->n_points++] = pt; |
110 | 119 | |
111 | 120 | for (j++; j <= last; j++) { |
121 | if (!valid_point(source->points + j)) | |
122 | goto fail; | |
112 | 123 | switch (FT_CURVE_TAG(source->tags[j])) { |
113 | 124 | case FT_CURVE_TAG_ON: |
114 | 125 | switch (st) { |
200 | 211 | return false; |
201 | 212 | } |
202 | 213 | |
203 | bool outline_copy(ASS_Outline *outline, const ASS_Outline *source) | |
214 | bool outline_scale_pow2(ASS_Outline *outline, const ASS_Outline *source, | |
215 | int scale_ord_x, int scale_ord_y) | |
204 | 216 | { |
205 | 217 | if (!source || !source->n_points) { |
206 | 218 | outline_clear(outline); |
207 | 219 | return true; |
208 | 220 | } |
209 | 221 | |
222 | int32_t lim_x = OUTLINE_MAX; | |
223 | if (scale_ord_x > 0) | |
224 | lim_x = scale_ord_x < 32 ? lim_x >> scale_ord_x : 0; | |
225 | else | |
226 | scale_ord_x = FFMAX(scale_ord_x, -32); | |
227 | ||
228 | int32_t lim_y = OUTLINE_MAX; | |
229 | if (scale_ord_y > 0) | |
230 | lim_y = scale_ord_y < 32 ? lim_y >> scale_ord_y : 0; | |
231 | else | |
232 | scale_ord_y = FFMAX(scale_ord_y, -32); | |
233 | ||
234 | if (!lim_x || !lim_y) { | |
235 | outline_clear(outline); | |
236 | return false; | |
237 | } | |
238 | ||
210 | 239 | if (!outline_alloc(outline, source->n_points, source->n_segments)) |
211 | 240 | return false; |
212 | 241 | |
213 | memcpy(outline->points, source->points, sizeof(ASS_Vector) * source->n_points); | |
242 | int sx = scale_ord_x + 32; | |
243 | int sy = scale_ord_y + 32; | |
244 | const ASS_Vector *pt = source->points; | |
245 | for (size_t i = 0; i < source->n_points; i++) { | |
246 | if (abs(pt[i].x) > lim_x || abs(pt[i].y) > lim_y) { | |
247 | outline_free(outline); | |
248 | return false; | |
249 | } | |
250 | // that's equivalent to pt[i].x << scale_ord_x, | |
251 | // but works even for negative coordinate and/or shift amount | |
252 | outline->points[i].x = pt[i].x * ((int64_t) 1 << sx) >> 32; | |
253 | outline->points[i].y = pt[i].y * ((int64_t) 1 << sy) >> 32; | |
254 | } | |
214 | 255 | memcpy(outline->segments, source->segments, source->n_segments); |
215 | 256 | outline->n_points = source->n_points; |
216 | 257 | outline->n_segments = source->n_segments; |
217 | 258 | return true; |
218 | 259 | } |
219 | 260 | |
261 | bool outline_transform_2d(ASS_Outline *outline, const ASS_Outline *source, | |
262 | const double m[2][3]) | |
263 | { | |
264 | if (!source || !source->n_points) { | |
265 | outline_clear(outline); | |
266 | return true; | |
267 | } | |
268 | ||
269 | if (!outline_alloc(outline, source->n_points, source->n_segments)) | |
270 | return false; | |
271 | ||
272 | const ASS_Vector *pt = source->points; | |
273 | for (size_t i = 0; i < source->n_points; i++) { | |
274 | double v[2]; | |
275 | for (int k = 0; k < 2; k++) | |
276 | v[k] = m[k][0] * pt[i].x + m[k][1] * pt[i].y + m[k][2]; | |
277 | ||
278 | if (!(fabs(v[0]) < OUTLINE_MAX && fabs(v[1]) < OUTLINE_MAX)) { | |
279 | outline_free(outline); | |
280 | return false; | |
281 | } | |
282 | outline->points[i].x = lrint(v[0]); | |
283 | outline->points[i].y = lrint(v[1]); | |
284 | } | |
285 | memcpy(outline->segments, source->segments, source->n_segments); | |
286 | outline->n_points = source->n_points; | |
287 | outline->n_segments = source->n_segments; | |
288 | return true; | |
289 | } | |
290 | ||
291 | bool outline_transform_3d(ASS_Outline *outline, const ASS_Outline *source, | |
292 | const double m[3][3]) | |
293 | { | |
294 | if (!source || !source->n_points) { | |
295 | outline_clear(outline); | |
296 | return true; | |
297 | } | |
298 | ||
299 | if (!outline_alloc(outline, source->n_points, source->n_segments)) | |
300 | return false; | |
301 | ||
302 | const ASS_Vector *pt = source->points; | |
303 | for (size_t i = 0; i < source->n_points; i++) { | |
304 | double v[3]; | |
305 | for (int k = 0; k < 3; k++) | |
306 | v[k] = m[k][0] * pt[i].x + m[k][1] * pt[i].y + m[k][2]; | |
307 | ||
308 | double w = 1 / FFMAX(v[2], 0.1); | |
309 | v[0] *= w; | |
310 | v[1] *= w; | |
311 | ||
312 | if (!(fabs(v[0]) < OUTLINE_MAX && fabs(v[1]) < OUTLINE_MAX)) { | |
313 | outline_free(outline); | |
314 | return false; | |
315 | } | |
316 | outline->points[i].x = lrint(v[0]); | |
317 | outline->points[i].y = lrint(v[1]); | |
318 | } | |
319 | memcpy(outline->segments, source->segments, source->n_segments); | |
320 | outline->n_points = source->n_points; | |
321 | outline->n_segments = source->n_segments; | |
322 | return true; | |
323 | } | |
324 | ||
325 | void outline_update_min_transformed_x(const ASS_Outline *outline, | |
326 | const double m[3][3], | |
327 | int32_t *min_x) { | |
328 | const ASS_Vector *pt = outline->points; | |
329 | for (size_t i = 0; i < outline->n_points; i++) { | |
330 | double z = m[2][0] * pt[i].x + m[2][1] * pt[i].y + m[2][2]; | |
331 | double x = (m[0][0] * pt[i].x + m[0][1] * pt[i].y + m[0][2]) / FFMAX(z, 0.1); | |
332 | if (isnan(x)) | |
333 | continue; | |
334 | int32_t ix = lrint(FFMINMAX(x, -OUTLINE_MAX, OUTLINE_MAX)); | |
335 | *min_x = FFMIN(*min_x, ix); | |
336 | } | |
337 | } | |
338 | ||
339 | ||
220 | 340 | void outline_free(ASS_Outline *outline) |
221 | 341 | { |
222 | 342 | if (!outline) |
235 | 355 | */ |
236 | 356 | bool outline_add_point(ASS_Outline *outline, ASS_Vector pt, char segment) |
237 | 357 | { |
358 | if (abs(pt.x) > OUTLINE_MAX || abs(pt.y) > OUTLINE_MAX) | |
359 | return false; | |
360 | ||
238 | 361 | if (outline->n_points >= outline->max_points) { |
239 | 362 | size_t new_size = 2 * outline->max_points; |
240 | 363 | if (!ASS_REALLOC_ARRAY(outline->points, new_size)) |
275 | 398 | } |
276 | 399 | |
277 | 400 | |
278 | void outline_translate(const ASS_Outline *outline, int32_t dx, int32_t dy) | |
279 | { | |
280 | for (size_t i = 0; i < outline->n_points; i++) { | |
281 | outline->points[i].x += dx; | |
282 | outline->points[i].y += dy; | |
283 | } | |
284 | } | |
285 | ||
286 | void outline_adjust(const ASS_Outline *outline, double scale_x, int32_t dx, int32_t dy) | |
287 | { | |
288 | int32_t mul = lrint(scale_x * 0x10000); | |
289 | if (mul == 0x10000) { | |
290 | outline_translate(outline, dx, dy); | |
291 | return; | |
292 | } | |
293 | for (size_t i = 0; i < outline->n_points; i++) { | |
294 | int32_t x = (int64_t) outline->points[i].x * mul >> 16; | |
295 | outline->points[i].x = x + dx; | |
296 | outline->points[i].y += dy; | |
297 | } | |
298 | } | |
299 | ||
300 | void outline_get_cbox(const ASS_Outline *outline, ASS_Rect *cbox) | |
301 | { | |
302 | if (!outline->n_points) { | |
303 | cbox->x_min = cbox->x_max = 0; | |
304 | cbox->y_min = cbox->y_max = 0; | |
305 | return; | |
306 | } | |
307 | cbox->x_min = cbox->x_max = outline->points[0].x; | |
308 | cbox->y_min = cbox->y_max = outline->points[0].y; | |
309 | for (size_t i = 1; i < outline->n_points; i++) { | |
310 | cbox->x_min = FFMIN(cbox->x_min, outline->points[i].x); | |
311 | cbox->x_max = FFMAX(cbox->x_max, outline->points[i].x); | |
312 | cbox->y_min = FFMIN(cbox->y_min, outline->points[i].y); | |
313 | cbox->y_max = FFMAX(cbox->y_max, outline->points[i].y); | |
314 | } | |
401 | /* | |
402 | * \brief Update bounding box of control points. | |
403 | */ | |
404 | void outline_update_cbox(const ASS_Outline *outline, ASS_Rect *cbox) | |
405 | { | |
406 | for (size_t i = 0; i < outline->n_points; i++) | |
407 | rectangle_update(cbox, | |
408 | outline->points[i].x, outline->points[i].y, | |
409 | outline->points[i].x, outline->points[i].y); | |
315 | 410 | } |
316 | 411 | |
317 | 412 | |
383 | 478 | int first_skip, last_skip; |
384 | 479 | // normal at first and last point |
385 | 480 | ASS_DVector first_normal, last_normal; |
386 | // first point of current contour | |
387 | ASS_Vector first_point; | |
481 | // first and last points of current contour | |
482 | ASS_Vector first_point, last_point; | |
388 | 483 | |
389 | 484 | // cosinus of maximal angle that do not require cap |
390 | 485 | double merge_cos; |
516 | 611 | static bool draw_arc(StrokerState *str, ASS_Vector pt, |
517 | 612 | ASS_DVector normal0, ASS_DVector normal1, double c, int dir) |
518 | 613 | { |
519 | const int max_subdiv = 15; | |
614 | enum { max_subdiv = 15 }; | |
520 | 615 | double mul[max_subdiv + 1]; |
521 | 616 | |
522 | 617 | ASS_DVector center; |
552 | 647 | */ |
553 | 648 | static bool draw_circle(StrokerState *str, ASS_Vector pt, int dir) |
554 | 649 | { |
555 | const int max_subdiv = 15; | |
650 | enum { max_subdiv = 15 }; | |
556 | 651 | double mul[max_subdiv + 1], c = 0; |
557 | 652 | |
558 | 653 | int pos = max_subdiv; |
647 | 742 | /** |
648 | 743 | * \brief Process source line segment |
649 | 744 | * \param str stroker state |
650 | * \param pt0 start point of the line segment | |
651 | 745 | * \param pt1 end point of the line segment |
652 | 746 | * \param dir destination outline flags |
653 | 747 | * \return false on allocation failure |
654 | 748 | */ |
655 | static bool add_line(StrokerState *str, ASS_Vector pt0, ASS_Vector pt1, int dir) | |
656 | { | |
657 | int32_t dx = pt1.x - pt0.x; | |
658 | int32_t dy = pt1.y - pt0.y; | |
749 | static bool add_line(StrokerState *str, ASS_Vector pt1, int dir) | |
750 | { | |
751 | int32_t dx = pt1.x - str->last_point.x; | |
752 | int32_t dy = pt1.y - str->last_point.y; | |
659 | 753 | if (dx > -str->eps && dx < str->eps && dy > -str->eps && dy < str->eps) |
660 | 754 | return true; |
661 | 755 | |
662 | 756 | ASS_DVector deriv = { dy * str->yscale, -dx * str->xscale }; |
663 | 757 | double scale = 1 / vec_len(deriv); |
664 | 758 | ASS_DVector normal = { deriv.x * scale, deriv.y * scale }; |
665 | if (!start_segment(str, pt0, normal, dir)) | |
759 | if (!start_segment(str, str->last_point, normal, dir)) | |
666 | 760 | return false; |
667 | if (!emit_first_point(str, pt0, OUTLINE_LINE_SEGMENT, dir)) | |
761 | if (!emit_first_point(str, str->last_point, OUTLINE_LINE_SEGMENT, dir)) | |
668 | 762 | return false; |
669 | 763 | str->last_normal = normal; |
764 | str->last_point = pt1; | |
670 | 765 | return true; |
671 | 766 | } |
672 | 767 | |
809 | 904 | /** |
810 | 905 | * \brief Process source quadratic spline |
811 | 906 | * \param str stroker state |
812 | * \param pt array of 3 source spline points | |
907 | * \param pt1 middle control point | |
908 | * \param pt2 final spline point | |
813 | 909 | * \param dir destination outline flags |
814 | 910 | * \return false on allocation failure |
815 | 911 | */ |
816 | static bool add_quadratic(StrokerState *str, const ASS_Vector *pt, int dir) | |
817 | { | |
818 | int32_t dx0 = pt[1].x - pt[0].x; | |
819 | int32_t dy0 = pt[1].y - pt[0].y; | |
912 | static bool add_quadratic(StrokerState *str, ASS_Vector pt1, ASS_Vector pt2, int dir) | |
913 | { | |
914 | int32_t dx0 = pt1.x - str->last_point.x; | |
915 | int32_t dy0 = pt1.y - str->last_point.y; | |
820 | 916 | if (dx0 > -str->eps && dx0 < str->eps && dy0 > -str->eps && dy0 < str->eps) |
821 | return add_line(str, pt[0], pt[2], dir); | |
822 | ||
823 | int32_t dx1 = pt[2].x - pt[1].x; | |
824 | int32_t dy1 = pt[2].y - pt[1].y; | |
917 | return add_line(str, pt2, dir); | |
918 | ||
919 | int32_t dx1 = pt2.x - pt1.x; | |
920 | int32_t dy1 = pt2.y - pt1.y; | |
825 | 921 | if (dx1 > -str->eps && dx1 < str->eps && dy1 > -str->eps && dy1 < str->eps) |
826 | return add_line(str, pt[0], pt[2], dir); | |
922 | return add_line(str, pt2, dir); | |
923 | ||
924 | ASS_Vector pt[3] = { str->last_point, pt1, pt2 }; | |
925 | str->last_point = pt2; | |
827 | 926 | |
828 | 927 | ASS_DVector deriv[2] = { |
829 | 928 | { dy0 * str->yscale, -dx0 * str->xscale }, |
1197 | 1296 | /** |
1198 | 1297 | * \brief Process source cubic spline |
1199 | 1298 | * \param str stroker state |
1200 | * \param pt array of 4 source spline points | |
1299 | * \param pt1 first middle control point | |
1300 | * \param pt2 second middle control point | |
1301 | * \param pt3 final spline point | |
1201 | 1302 | * \param dir destination outline flags |
1202 | 1303 | * \return false on allocation failure |
1203 | 1304 | */ |
1204 | static bool add_cubic(StrokerState *str, const ASS_Vector *pt, int dir) | |
1305 | static bool add_cubic(StrokerState *str, ASS_Vector pt1, ASS_Vector pt2, ASS_Vector pt3, int dir) | |
1205 | 1306 | { |
1206 | 1307 | int flags = 9; |
1207 | 1308 | |
1208 | int32_t dx0 = pt[1].x - pt[0].x; | |
1209 | int32_t dy0 = pt[1].y - pt[0].y; | |
1309 | int32_t dx0 = pt1.x - str->last_point.x; | |
1310 | int32_t dy0 = pt1.y - str->last_point.y; | |
1210 | 1311 | if (dx0 > -str->eps && dx0 < str->eps && dy0 > -str->eps && dy0 < str->eps) { |
1211 | dx0 = pt[2].x - pt[0].x; | |
1212 | dy0 = pt[2].y - pt[0].y; | |
1312 | dx0 = pt2.x - str->last_point.x; | |
1313 | dy0 = pt2.y - str->last_point.y; | |
1213 | 1314 | if (dx0 > -str->eps && dx0 < str->eps && dy0 > -str->eps && dy0 < str->eps) |
1214 | return add_line(str, pt[0], pt[3], dir); | |
1315 | return add_line(str, pt3, dir); | |
1215 | 1316 | flags ^= 1; |
1216 | 1317 | } |
1217 | 1318 | |
1218 | int32_t dx2 = pt[3].x - pt[2].x; | |
1219 | int32_t dy2 = pt[3].y - pt[2].y; | |
1319 | int32_t dx2 = pt3.x - pt2.x; | |
1320 | int32_t dy2 = pt3.y - pt2.y; | |
1220 | 1321 | if (dx2 > -str->eps && dx2 < str->eps && dy2 > -str->eps && dy2 < str->eps) { |
1221 | dx2 = pt[3].x - pt[1].x; | |
1222 | dy2 = pt[3].y - pt[1].y; | |
1322 | dx2 = pt3.x - pt1.x; | |
1323 | dy2 = pt3.y - pt1.y; | |
1223 | 1324 | if (dx2 > -str->eps && dx2 < str->eps && dy2 > -str->eps && dy2 < str->eps) |
1224 | return add_line(str, pt[0], pt[3], dir); | |
1325 | return add_line(str, pt3, dir); | |
1225 | 1326 | flags ^= 4; |
1226 | 1327 | } |
1227 | 1328 | |
1228 | 1329 | if (flags == 12) |
1229 | return add_line(str, pt[0], pt[3], dir); | |
1330 | return add_line(str, pt3, dir); | |
1331 | ||
1332 | ASS_Vector pt[4] = { str->last_point, pt1, pt2, pt3 }; | |
1333 | str->last_point = pt3; | |
1230 | 1334 | |
1231 | 1335 | int32_t dx1 = pt[flags >> 2].x - pt[flags & 3].x; |
1232 | 1336 | int32_t dy1 = pt[flags >> 2].y - pt[flags & 3].y; |
1252 | 1356 | /** |
1253 | 1357 | * \brief Process contour closing |
1254 | 1358 | * \param str stroker state |
1255 | * \param last_point last contour point | |
1256 | 1359 | * \param dir destination outline flags |
1257 | 1360 | * \return false on allocation failure |
1258 | 1361 | */ |
1259 | static bool close_contour(StrokerState *str, ASS_Vector last_point, int dir) | |
1362 | static bool close_contour(StrokerState *str, int dir) | |
1260 | 1363 | { |
1261 | 1364 | if (str->contour_start) { |
1262 | 1365 | if ((dir & 3) == 3) |
1263 | 1366 | dir = 1; |
1264 | if (!draw_circle(str, last_point, dir)) | |
1367 | if (!draw_circle(str, str->last_point, dir)) | |
1265 | 1368 | return false; |
1266 | 1369 | } else { |
1267 | if (!add_line(str, last_point, str->first_point, dir)) | |
1370 | if (!add_line(str, str->first_point, dir)) | |
1268 | 1371 | return false; |
1269 | 1372 | if (!start_segment(str, str->first_point, str->first_normal, dir)) |
1270 | 1373 | return false; |
1300 | 1403 | bool outline_stroke(ASS_Outline *result, ASS_Outline *result1, |
1301 | 1404 | const ASS_Outline *path, int xbord, int ybord, int eps) |
1302 | 1405 | { |
1406 | outline_alloc(result, 2 * path->n_points, 2 * path->n_segments); | |
1407 | outline_alloc(result1, 2 * path->n_points, 2 * path->n_segments); | |
1408 | if (!result->max_points || !result1->max_points) | |
1409 | return false; | |
1410 | ||
1303 | 1411 | const int dir = 3; |
1304 | 1412 | int rad = FFMAX(xbord, ybord); |
1305 | assert(rad >= eps); | |
1306 | ||
1307 | result->n_points = result->n_segments = 0; | |
1308 | result1->n_points = result1->n_segments = 0; | |
1413 | assert(rad >= eps && rad <= OUTLINE_MAX); | |
1309 | 1414 | |
1310 | 1415 | StrokerState str; |
1311 | 1416 | str.result[0] = result; |
1328 | 1433 | str.err_c = 390 * rel_err * rel_err; |
1329 | 1434 | str.err_a = e; |
1330 | 1435 | |
1331 | for (size_t i = 0; i < path->n_points; i++) { | |
1332 | if (path->points[i].x < OUTLINE_MIN || path->points[i].x > OUTLINE_MAX) | |
1333 | return false; | |
1334 | if (path->points[i].y < OUTLINE_MIN || path->points[i].y > OUTLINE_MAX) | |
1335 | return false; | |
1336 | } | |
1436 | #ifndef NDEBUG | |
1437 | for (size_t i = 0; i < path->n_points; i++) | |
1438 | assert(abs(path->points[i].x) <= OUTLINE_MAX && abs(path->points[i].y) <= OUTLINE_MAX); | |
1439 | #endif | |
1337 | 1440 | |
1338 | 1441 | ASS_Vector *start = path->points, *cur = start; |
1339 | 1442 | for (size_t i = 0; i < path->n_segments; i++) { |
1443 | if (start == cur) | |
1444 | str.last_point = *start; | |
1445 | ||
1340 | 1446 | int n = path->segments[i] & OUTLINE_COUNT_MASK; |
1341 | 1447 | cur += n; |
1342 | 1448 | |
1343 | ASS_Vector *end = cur, p[4]; | |
1449 | ASS_Vector *end = cur; | |
1344 | 1450 | if (path->segments[i] & OUTLINE_CONTOUR_END) { |
1345 | 1451 | end = start; |
1346 | 1452 | start = cur; |
1348 | 1454 | |
1349 | 1455 | switch (n) { |
1350 | 1456 | case OUTLINE_LINE_SEGMENT: |
1351 | if (!add_line(&str, cur[-1], *end, dir)) | |
1457 | if (!add_line(&str, *end, dir)) | |
1352 | 1458 | return false; |
1353 | 1459 | break; |
1354 | 1460 | |
1355 | 1461 | case OUTLINE_QUADRATIC_SPLINE: |
1356 | p[0] = cur[-2]; | |
1357 | p[1] = cur[-1]; | |
1358 | p[2] = *end; | |
1359 | if (!add_quadratic(&str, p, dir)) | |
1462 | if (!add_quadratic(&str, cur[-1], *end, dir)) | |
1360 | 1463 | return false; |
1361 | 1464 | break; |
1362 | 1465 | |
1363 | 1466 | case OUTLINE_CUBIC_SPLINE: |
1364 | p[0] = cur[-3]; | |
1365 | p[1] = cur[-2]; | |
1366 | p[2] = cur[-1]; | |
1367 | p[3] = *end; | |
1368 | if (!add_cubic(&str, p, dir)) | |
1467 | if (!add_cubic(&str, cur[-2], cur[-1], *end, dir)) | |
1369 | 1468 | return false; |
1370 | 1469 | break; |
1371 | 1470 | |
1373 | 1472 | return false; |
1374 | 1473 | } |
1375 | 1474 | |
1376 | if (start == cur && !close_contour(&str, *end, dir)) | |
1475 | if (start == cur && !close_contour(&str, dir)) | |
1377 | 1476 | return false; |
1378 | 1477 | } |
1379 | 1478 | assert(start == cur && cur == path->points + path->n_points); |
82 | 82 | char *segments; |
83 | 83 | } ASS_Outline; |
84 | 84 | |
85 | #define OUTLINE_MIN (-((int32_t) 1 << 28)) | |
85 | // ouline point coordinates should always be in [-OUTLINE_MAX, +OUTLINE_MAX] range | |
86 | 86 | #define OUTLINE_MAX (((int32_t) 1 << 28) - 1) |
87 | // cubic spline splitting requires 8 * OUTLINE_MAX + 4 <= INT32_MAX | |
87 | 88 | |
88 | 89 | bool outline_alloc(ASS_Outline *outline, size_t n_points, size_t n_segments); |
89 | 90 | bool outline_convert(ASS_Outline *outline, const FT_Outline *source); |
90 | bool outline_copy(ASS_Outline *outline, const ASS_Outline *source); | |
91 | bool outline_scale_pow2(ASS_Outline *outline, const ASS_Outline *source, | |
92 | int scale_ord_x, int scale_ord_y); | |
93 | bool outline_transform_2d(ASS_Outline *outline, const ASS_Outline *source, | |
94 | const double m[2][3]); | |
95 | bool outline_transform_3d(ASS_Outline *outline, const ASS_Outline *source, | |
96 | const double m[3][3]); | |
97 | void outline_update_min_transformed_x(const ASS_Outline *outline, | |
98 | const double m[3][3], | |
99 | int32_t *min_x); | |
91 | 100 | void outline_free(ASS_Outline *outline); |
92 | 101 | |
93 | 102 | bool outline_add_point(ASS_Outline *outline, ASS_Vector pt, char segment); |
94 | 103 | bool outline_add_segment(ASS_Outline *outline, char segment); |
95 | 104 | bool outline_close_contour(ASS_Outline *outline); |
96 | 105 | |
97 | void outline_translate(const ASS_Outline *outline, int32_t dx, int32_t dy); | |
98 | void outline_adjust(const ASS_Outline *outline, double scale_x, int32_t dx, int32_t dy); | |
99 | void outline_get_cbox(const ASS_Outline *outline, ASS_Rect *cbox); | |
106 | void outline_update_cbox(const ASS_Outline *outline, ASS_Rect *cbox); | |
100 | 107 | |
101 | 108 | bool outline_stroke(ASS_Outline *result, ASS_Outline *result1, |
102 | 109 | const ASS_Outline *path, int xbord, int ybord, int eps); |
23 | 23 | #include <string.h> |
24 | 24 | #include <math.h> |
25 | 25 | |
26 | #include "ass_library.h" | |
26 | 27 | #include "ass_render.h" |
27 | 28 | #include "ass_parse.h" |
28 | 29 | |
41 | 42 | return value; |
42 | 43 | } |
43 | 44 | |
44 | static inline long long argtoll(struct arg arg) | |
45 | { | |
46 | long long value; | |
47 | mystrtoll(&arg.start, &value); | |
45 | static inline int32_t argtoi32(struct arg arg) | |
46 | { | |
47 | int32_t value; | |
48 | mystrtoi32(&arg.start, 10, &value); | |
48 | 49 | return value; |
49 | 50 | } |
50 | 51 | |
72 | 73 | */ |
73 | 74 | static inline int mystrcmp(char **p, const char *sample) |
74 | 75 | { |
75 | int len = strlen(sample); | |
76 | if (strncmp(*p, sample, len) == 0) { | |
77 | (*p) += len; | |
76 | char *p2; | |
77 | for (p2 = *p; *sample != 0 && *p2 == *sample; p2++, sample++) | |
78 | ; | |
79 | if (*sample == 0) { | |
80 | *p = p2; | |
78 | 81 | return 1; |
79 | } else | |
80 | return 0; | |
82 | } | |
83 | return 0; | |
81 | 84 | } |
82 | 85 | |
83 | 86 | double ensure_font_size(ASS_Renderer *priv, double size) |
90 | 93 | return size; |
91 | 94 | } |
92 | 95 | |
93 | static void change_font_size(ASS_Renderer *render_priv, double sz) | |
94 | { | |
95 | render_priv->state.font_size = sz; | |
96 | } | |
97 | ||
98 | 96 | /** |
99 | 97 | * \brief Change current font, using setting from render_priv->state. |
100 | 98 | */ |
103 | 101 | unsigned val; |
104 | 102 | ASS_FontDesc desc; |
105 | 103 | |
104 | if (!render_priv->state.family) | |
105 | return; | |
106 | 106 | if (render_priv->state.family[0] == '@') { |
107 | 107 | desc.vertical = 1; |
108 | 108 | desc.family = strdup(render_priv->state.family + 1); |
110 | 110 | desc.vertical = 0; |
111 | 111 | desc.family = strdup(render_priv->state.family); |
112 | 112 | } |
113 | if (!desc.family) | |
114 | return; | |
113 | 115 | |
114 | 116 | val = render_priv->state.bold; |
115 | 117 | // 0 = normal, 1 = bold, >1 = exact weight |
127 | 129 | desc.italic = val; |
128 | 130 | |
129 | 131 | ass_cache_dec_ref(render_priv->state.font); |
130 | render_priv->state.font = | |
131 | ass_font_new(render_priv->cache.font_cache, render_priv->library, | |
132 | render_priv->ftlibrary, render_priv->fontselect, | |
133 | &desc); | |
134 | ||
135 | if (render_priv->state.font) | |
136 | change_font_size(render_priv, render_priv->state.font_size); | |
132 | render_priv->state.font = ass_font_new(render_priv, &desc); | |
133 | } | |
134 | ||
135 | /** | |
136 | * \brief Convert double to int32_t without UB | |
137 | * on out-of-range values; match x86 behavior | |
138 | */ | |
139 | static inline int32_t dtoi32(double val) | |
140 | { | |
141 | if (isnan(val) || val <= INT32_MIN || val >= INT32_MAX + 1LL) | |
142 | return INT32_MIN; | |
143 | return val; | |
144 | } | |
145 | ||
146 | static double calc_anim(double new, double old, double pwr) | |
147 | { | |
148 | return (1 - pwr) * old + new * pwr; | |
149 | } | |
150 | ||
151 | static int32_t calc_anim_int32(uint32_t new, uint32_t old, double pwr) | |
152 | { | |
153 | return dtoi32(calc_anim(new, old, pwr)); | |
137 | 154 | } |
138 | 155 | |
139 | 156 | /** |
142 | 159 | */ |
143 | 160 | static void change_color(uint32_t *var, uint32_t new, double pwr) |
144 | 161 | { |
145 | (*var) = ((uint32_t) (_r(*var) * (1 - pwr) + _r(new) * pwr) << 24) | | |
146 | ((uint32_t) (_g(*var) * (1 - pwr) + _g(new) * pwr) << 16) | | |
147 | ((uint32_t) (_b(*var) * (1 - pwr) + _b(new) * pwr) << 8) | _a(*var); | |
162 | uint32_t co = ass_bswap32(*var); | |
163 | uint32_t cn = ass_bswap32(new); | |
164 | ||
165 | uint32_t cc = (calc_anim_int32(cn & 0xff0000, co & 0xff0000, pwr) & 0xff0000) | | |
166 | (calc_anim_int32(cn & 0x00ff00, co & 0x00ff00, pwr) & 0x00ff00) | | |
167 | (calc_anim_int32(cn & 0x0000ff, co & 0x0000ff, pwr) & 0x0000ff); | |
168 | ||
169 | (*var) = (ass_bswap32(cc & 0xffffff)) | _a(*var); | |
148 | 170 | } |
149 | 171 | |
150 | 172 | // like change_color, but for alpha component only |
151 | 173 | inline void change_alpha(uint32_t *var, int32_t new, double pwr) |
152 | 174 | { |
153 | *var = (*var & 0xFFFFFF00) | (uint8_t) (_a(*var) * (1 - pwr) + new * pwr); | |
175 | *var = (*var & 0xFFFFFF00) | (uint8_t)calc_anim_int32(_a(new), _a(*var), pwr); | |
154 | 176 | } |
155 | 177 | |
156 | 178 | /** |
158 | 180 | * \param a first value |
159 | 181 | * \param b second value |
160 | 182 | * \return result of multiplication |
161 | * Parameters and result are limited by 0xFF. | |
183 | * At least one of the parameters must be less than or equal to 0xFF. | |
184 | * The result is less than or equal to max(a, b, 0xFF). | |
162 | 185 | */ |
163 | 186 | inline uint32_t mult_alpha(uint32_t a, uint32_t b) |
164 | 187 | { |
165 | return 0xFF - (0xFF - a) * (0xFF - b) / 0xFF; | |
188 | return a - ((uint64_t) a * b + 0x7F) / 0xFF + b; | |
166 | 189 | } |
167 | 190 | |
168 | 191 | /** |
170 | 193 | * Used for \fad, \fade implementation. |
171 | 194 | */ |
172 | 195 | static int |
173 | interpolate_alpha(long long now, long long t1, long long t2, long long t3, | |
174 | long long t4, int a1, int a2, int a3) | |
196 | interpolate_alpha(long long now, int32_t t1, int32_t t2, int32_t t3, | |
197 | int32_t t4, int a1, int a2, int a3) | |
175 | 198 | { |
176 | 199 | int a; |
177 | 200 | double cf; |
179 | 202 | if (now < t1) { |
180 | 203 | a = a1; |
181 | 204 | } else if (now < t2) { |
182 | cf = ((double) (now - t1)) / (t2 - t1); | |
205 | cf = ((double) (int32_t) ((uint32_t) now - t1)) / | |
206 | (int32_t) ((uint32_t) t2 - t1); | |
183 | 207 | a = a1 * (1 - cf) + a2 * cf; |
184 | 208 | } else if (now < t3) { |
185 | 209 | a = a2; |
186 | 210 | } else if (now < t4) { |
187 | cf = ((double) (now - t3)) / (t4 - t3); | |
211 | cf = ((double) (int32_t) ((uint32_t) now - t3)) / | |
212 | (int32_t) ((uint32_t) t4 - t3); | |
188 | 213 | a = a2 * (1 - cf) + a3 * cf; |
189 | 214 | } else { // now >= t4 |
190 | 215 | a = a3; |
197 | 222 | * Parse a vector clip into an outline, using the proper scaling |
198 | 223 | * parameters. Translate it to correct for screen borders, if needed. |
199 | 224 | */ |
200 | static int parse_vector_clip(ASS_Renderer *render_priv, | |
201 | struct arg *args, int nargs) | |
202 | { | |
225 | static bool parse_vector_clip(ASS_Renderer *render_priv, | |
226 | struct arg *args, int nargs) | |
227 | { | |
228 | if (nargs != 1 && nargs != 2) | |
229 | return false; | |
230 | ||
203 | 231 | int scale = 1; |
204 | ASS_Drawing *drawing = render_priv->state.clip_drawing; | |
205 | ||
206 | if (nargs != 1 && nargs != 2) | |
207 | return 0; | |
208 | 232 | if (nargs == 2) |
209 | 233 | scale = argtoi(args[0]); |
234 | ||
210 | 235 | struct arg text = args[nargs - 1]; |
211 | ||
212 | ass_drawing_free(drawing); | |
213 | render_priv->state.clip_drawing = ass_drawing_new(render_priv->library); | |
214 | drawing = render_priv->state.clip_drawing; | |
215 | if (drawing) { | |
216 | drawing->scale = scale; | |
217 | drawing->scale_x = render_priv->font_scale_x * render_priv->font_scale; | |
218 | drawing->scale_y = render_priv->font_scale; | |
219 | ass_drawing_set_text(drawing, text.start, text.end - text.start); | |
220 | } | |
221 | ||
222 | return 1; | |
236 | render_priv->state.clip_drawing_text = strndup(text.start, text.end - text.start); | |
237 | render_priv->state.clip_drawing_scale = scale; | |
238 | return true; | |
223 | 239 | } |
224 | 240 | |
225 | 241 | /** |
226 | * \brief Parse style override tag. | |
242 | * \brief Parse style override tags. | |
227 | 243 | * \param p string to parse |
228 | 244 | * \param end end of string to parse, which must be '}', ')', or the first |
229 | 245 | * of a number of spaces immediately preceding '}' or ')' |
230 | 246 | * \param pwr multiplier for some tag effects (comes from \t tags) |
231 | 247 | */ |
232 | char *parse_tag(ASS_Renderer *render_priv, char *p, char *end, double pwr) | |
233 | { | |
234 | while (*p != '\\' && p != end) | |
248 | char *parse_tags(ASS_Renderer *render_priv, char *p, char *end, double pwr, | |
249 | bool nested) | |
250 | { | |
251 | for (char *q; p < end; p = q) { | |
252 | while (*p != '\\' && p != end) | |
253 | ++p; | |
254 | if (*p != '\\') | |
255 | break; | |
235 | 256 | ++p; |
236 | if (*p != '\\') | |
237 | return p; | |
238 | ++p; | |
239 | if (p != end) | |
240 | skip_spaces(&p); | |
241 | ||
242 | char *q = p; | |
243 | while (*q != '(' && *q != '\\' && q != end) | |
244 | ++q; | |
245 | if (q == p) | |
246 | return q; | |
247 | ||
248 | char *name_end = q; | |
249 | ||
250 | // Store one extra element to be able to detect excess arguments | |
251 | struct arg args[MAX_VALID_NARGS + 1]; | |
252 | int nargs = 0; | |
253 | for (int i = 0; i <= MAX_VALID_NARGS; ++i) | |
254 | args[i].start = args[i].end = ""; | |
255 | ||
256 | // Split parenthesized arguments. Do this for all tags and before | |
257 | // any non-parenthesized argument because that's what VSFilter does. | |
258 | if (*q == '(') { | |
259 | ++q; | |
260 | while (1) { | |
261 | if (q != end) | |
262 | skip_spaces(&q); | |
263 | ||
264 | // Split on commas. If there is a backslash, ignore any | |
265 | // commas following it and lump everything starting from | |
266 | // the last comma, through the backslash and all the way | |
267 | // to the end of the argument string into a single argument. | |
268 | ||
269 | char *r = q; | |
270 | while (*r != ',' && *r != '\\' && *r != ')' && r != end) | |
271 | ++r; | |
272 | ||
273 | if (*r == ',') { | |
274 | push_arg(args, &nargs, q, r); | |
275 | q = r + 1; | |
276 | } else { | |
277 | // Swallow the rest of the parenthesized string. This could | |
278 | // be either a backslash-argument or simply the last argument. | |
279 | while (*r != ')' && r != end) | |
257 | if (p != end) | |
258 | skip_spaces(&p); | |
259 | ||
260 | q = p; | |
261 | while (*q != '(' && *q != '\\' && q != end) | |
262 | ++q; | |
263 | if (q == p) | |
264 | continue; | |
265 | ||
266 | char *name_end = q; | |
267 | ||
268 | // Store one extra element to be able to detect excess arguments | |
269 | struct arg args[MAX_VALID_NARGS + 1]; | |
270 | int nargs = 0; | |
271 | bool has_backslash_arg = false; | |
272 | for (int i = 0; i <= MAX_VALID_NARGS; ++i) | |
273 | args[i].start = args[i].end = ""; | |
274 | ||
275 | // Split parenthesized arguments. Do this for all tags and before | |
276 | // any non-parenthesized argument because that's what VSFilter does. | |
277 | if (*q == '(') { | |
278 | ++q; | |
279 | while (1) { | |
280 | if (q != end) | |
281 | skip_spaces(&q); | |
282 | ||
283 | // Split on commas. If there is a backslash, ignore any | |
284 | // commas following it and lump everything starting from | |
285 | // the last comma, through the backslash and all the way | |
286 | // to the end of the argument string into a single argument. | |
287 | ||
288 | char *r = q; | |
289 | while (*r != ',' && *r != '\\' && *r != ')' && r != end) | |
280 | 290 | ++r; |
281 | push_arg(args, &nargs, q, r); | |
282 | q = r; | |
283 | // The closing parenthesis could be missing. | |
284 | if (q != end) | |
285 | ++q; | |
286 | break; | |
291 | ||
292 | if (*r == ',') { | |
293 | push_arg(args, &nargs, q, r); | |
294 | q = r + 1; | |
295 | } else { | |
296 | // Swallow the rest of the parenthesized string. This could | |
297 | // be either a backslash-argument or simply the last argument. | |
298 | if (*r == '\\') { | |
299 | has_backslash_arg = true; | |
300 | while (*r != ')' && r != end) | |
301 | ++r; | |
302 | } | |
303 | push_arg(args, &nargs, q, r); | |
304 | q = r; | |
305 | // The closing parenthesis could be missing. | |
306 | if (q != end) | |
307 | ++q; | |
308 | break; | |
309 | } | |
287 | 310 | } |
288 | 311 | } |
289 | } | |
290 | 312 | |
291 | 313 | #define tag(name) (mystrcmp(&p, (name)) && (push_arg(args, &nargs, p, name_end), 1)) |
292 | 314 | #define complex_tag(name) mystrcmp(&p, (name)) |
293 | 315 | |
294 | // New tags introduced in vsfilter 2.39 | |
295 | if (tag("xbord")) { | |
296 | double val; | |
297 | if (nargs) { | |
298 | val = argtod(*args); | |
299 | val = render_priv->state.border_x * (1 - pwr) + val * pwr; | |
316 | // New tags introduced in vsfilter 2.39 | |
317 | if (tag("xbord")) { | |
318 | double val; | |
319 | if (nargs) { | |
320 | val = argtod(*args); | |
321 | val = render_priv->state.border_x * (1 - pwr) + val * pwr; | |
322 | val = (val < 0) ? 0 : val; | |
323 | } else | |
324 | val = render_priv->state.style->Outline; | |
325 | render_priv->state.border_x = val; | |
326 | } else if (tag("ybord")) { | |
327 | double val; | |
328 | if (nargs) { | |
329 | val = argtod(*args); | |
330 | val = render_priv->state.border_y * (1 - pwr) + val * pwr; | |
331 | val = (val < 0) ? 0 : val; | |
332 | } else | |
333 | val = render_priv->state.style->Outline; | |
334 | render_priv->state.border_y = val; | |
335 | } else if (tag("xshad")) { | |
336 | double val; | |
337 | if (nargs) { | |
338 | val = argtod(*args); | |
339 | val = render_priv->state.shadow_x * (1 - pwr) + val * pwr; | |
340 | } else | |
341 | val = render_priv->state.style->Shadow; | |
342 | render_priv->state.shadow_x = val; | |
343 | } else if (tag("yshad")) { | |
344 | double val; | |
345 | if (nargs) { | |
346 | val = argtod(*args); | |
347 | val = render_priv->state.shadow_y * (1 - pwr) + val * pwr; | |
348 | } else | |
349 | val = render_priv->state.style->Shadow; | |
350 | render_priv->state.shadow_y = val; | |
351 | } else if (tag("fax")) { | |
352 | double val; | |
353 | if (nargs) { | |
354 | val = argtod(*args); | |
355 | render_priv->state.fax = | |
356 | val * pwr + render_priv->state.fax * (1 - pwr); | |
357 | } else | |
358 | render_priv->state.fax = 0.; | |
359 | } else if (tag("fay")) { | |
360 | double val; | |
361 | if (nargs) { | |
362 | val = argtod(*args); | |
363 | render_priv->state.fay = | |
364 | val * pwr + render_priv->state.fay * (1 - pwr); | |
365 | } else | |
366 | render_priv->state.fay = 0.; | |
367 | } else if (complex_tag("iclip")) { | |
368 | if (nargs == 4) { | |
369 | int x0, y0, x1, y1; | |
370 | x0 = argtoi(args[0]); | |
371 | y0 = argtoi(args[1]); | |
372 | x1 = argtoi(args[2]); | |
373 | y1 = argtoi(args[3]); | |
374 | render_priv->state.clip_x0 = | |
375 | render_priv->state.clip_x0 * (1 - pwr) + x0 * pwr; | |
376 | render_priv->state.clip_x1 = | |
377 | render_priv->state.clip_x1 * (1 - pwr) + x1 * pwr; | |
378 | render_priv->state.clip_y0 = | |
379 | render_priv->state.clip_y0 * (1 - pwr) + y0 * pwr; | |
380 | render_priv->state.clip_y1 = | |
381 | render_priv->state.clip_y1 * (1 - pwr) + y1 * pwr; | |
382 | render_priv->state.clip_mode = 1; | |
383 | } else if (!render_priv->state.clip_drawing_text) { | |
384 | if (parse_vector_clip(render_priv, args, nargs)) | |
385 | render_priv->state.clip_drawing_mode = 1; | |
386 | } | |
387 | } else if (tag("blur")) { | |
388 | double val; | |
389 | if (nargs) { | |
390 | val = argtod(*args); | |
391 | val = render_priv->state.blur * (1 - pwr) + val * pwr; | |
392 | val = (val < 0) ? 0 : val; | |
393 | val = (val > BLUR_MAX_RADIUS) ? BLUR_MAX_RADIUS : val; | |
394 | render_priv->state.blur = val; | |
395 | } else | |
396 | render_priv->state.blur = 0.0; | |
397 | // ASS standard tags | |
398 | } else if (tag("fscx")) { | |
399 | double val; | |
400 | if (nargs) { | |
401 | val = argtod(*args) / 100; | |
402 | val = render_priv->state.scale_x * (1 - pwr) + val * pwr; | |
403 | val = (val < 0) ? 0 : val; | |
404 | } else | |
405 | val = render_priv->state.style->ScaleX; | |
406 | render_priv->state.scale_x = val; | |
407 | } else if (tag("fscy")) { | |
408 | double val; | |
409 | if (nargs) { | |
410 | val = argtod(*args) / 100; | |
411 | val = render_priv->state.scale_y * (1 - pwr) + val * pwr; | |
412 | val = (val < 0) ? 0 : val; | |
413 | } else | |
414 | val = render_priv->state.style->ScaleY; | |
415 | render_priv->state.scale_y = val; | |
416 | } else if (tag("fsc")) { | |
417 | render_priv->state.scale_x = render_priv->state.style->ScaleX; | |
418 | render_priv->state.scale_y = render_priv->state.style->ScaleY; | |
419 | } else if (tag("fsp")) { | |
420 | double val; | |
421 | if (nargs) { | |
422 | val = argtod(*args); | |
423 | render_priv->state.hspacing = | |
424 | render_priv->state.hspacing * (1 - pwr) + val * pwr; | |
425 | } else | |
426 | render_priv->state.hspacing = render_priv->state.style->Spacing; | |
427 | } else if (tag("fs")) { | |
428 | double val = 0; | |
429 | if (nargs) { | |
430 | val = argtod(*args); | |
431 | if (*args->start == '+' || *args->start == '-') | |
432 | val = render_priv->state.font_size * (1 + pwr * val / 10); | |
433 | else | |
434 | val = render_priv->state.font_size * (1 - pwr) + val * pwr; | |
435 | } | |
436 | if (val <= 0) | |
437 | val = render_priv->state.style->FontSize; | |
438 | render_priv->state.font_size = val; | |
439 | } else if (tag("bord")) { | |
440 | double val, xval, yval; | |
441 | if (nargs) { | |
442 | val = argtod(*args); | |
443 | xval = render_priv->state.border_x * (1 - pwr) + val * pwr; | |
444 | yval = render_priv->state.border_y * (1 - pwr) + val * pwr; | |
445 | xval = (xval < 0) ? 0 : xval; | |
446 | yval = (yval < 0) ? 0 : yval; | |
447 | } else | |
448 | xval = yval = render_priv->state.style->Outline; | |
449 | render_priv->state.border_x = xval; | |
450 | render_priv->state.border_y = yval; | |
451 | } else if (complex_tag("move")) { | |
452 | double x1, x2, y1, y2; | |
453 | int32_t t1, t2, delta_t, t; | |
454 | double x, y; | |
455 | double k; | |
456 | if (nargs == 4 || nargs == 6) { | |
457 | x1 = argtod(args[0]); | |
458 | y1 = argtod(args[1]); | |
459 | x2 = argtod(args[2]); | |
460 | y2 = argtod(args[3]); | |
461 | t1 = t2 = 0; | |
462 | if (nargs == 6) { | |
463 | t1 = argtoi32(args[4]); | |
464 | t2 = argtoi32(args[5]); | |
465 | if (t1 > t2) { | |
466 | long long tmp = t2; | |
467 | t2 = t1; | |
468 | t1 = tmp; | |
469 | } | |
470 | } | |
471 | } else | |
472 | continue; | |
473 | if (t1 <= 0 && t2 <= 0) { | |
474 | t1 = 0; | |
475 | t2 = render_priv->state.event->Duration; | |
476 | } | |
477 | delta_t = (uint32_t) t2 - t1; | |
478 | t = render_priv->time - render_priv->state.event->Start; | |
479 | if (t <= t1) | |
480 | k = 0.; | |
481 | else if (t >= t2) | |
482 | k = 1.; | |
483 | else | |
484 | k = ((double) (int32_t) ((uint32_t) t - t1)) / delta_t; | |
485 | x = k * (x2 - x1) + x1; | |
486 | y = k * (y2 - y1) + y1; | |
487 | if (!(render_priv->state.evt_type & EVENT_POSITIONED)) { | |
488 | render_priv->state.pos_x = x; | |
489 | render_priv->state.pos_y = y; | |
490 | render_priv->state.detect_collisions = 0; | |
491 | render_priv->state.evt_type |= EVENT_POSITIONED; | |
492 | } | |
493 | } else if (tag("frx")) { | |
494 | double val; | |
495 | if (nargs) { | |
496 | val = argtod(*args); | |
497 | render_priv->state.frx = | |
498 | val * pwr + render_priv->state.frx * (1 - pwr); | |
499 | } else | |
500 | render_priv->state.frx = 0.; | |
501 | } else if (tag("fry")) { | |
502 | double val; | |
503 | if (nargs) { | |
504 | val = argtod(*args); | |
505 | render_priv->state.fry = | |
506 | val * pwr + render_priv->state.fry * (1 - pwr); | |
507 | } else | |
508 | render_priv->state.fry = 0.; | |
509 | } else if (tag("frz") || tag("fr")) { | |
510 | double val; | |
511 | if (nargs) { | |
512 | val = argtod(*args); | |
513 | render_priv->state.frz = | |
514 | val * pwr + render_priv->state.frz * (1 - pwr); | |
515 | } else | |
516 | render_priv->state.frz = | |
517 | render_priv->state.style->Angle; | |
518 | } else if (tag("fn")) { | |
519 | char *family; | |
520 | char *start = args->start; | |
521 | if (nargs && strncmp(start, "0", args->end - start)) { | |
522 | skip_spaces(&start); | |
523 | family = strndup(start, args->end - start); | |
524 | } else { | |
525 | family = strdup(render_priv->state.style->FontName); | |
526 | } | |
527 | if (family) { | |
528 | free(render_priv->state.family); | |
529 | render_priv->state.family = family; | |
530 | update_font(render_priv); | |
531 | } | |
532 | } else if (tag("alpha")) { | |
533 | int i; | |
534 | if (nargs) { | |
535 | int32_t a = parse_alpha_tag(args->start); | |
536 | for (i = 0; i < 4; ++i) | |
537 | change_alpha(&render_priv->state.c[i], a, pwr); | |
538 | } else { | |
539 | change_alpha(&render_priv->state.c[0], | |
540 | _a(render_priv->state.style->PrimaryColour), 1); | |
541 | change_alpha(&render_priv->state.c[1], | |
542 | _a(render_priv->state.style->SecondaryColour), 1); | |
543 | change_alpha(&render_priv->state.c[2], | |
544 | _a(render_priv->state.style->OutlineColour), 1); | |
545 | change_alpha(&render_priv->state.c[3], | |
546 | _a(render_priv->state.style->BackColour), 1); | |
547 | } | |
548 | // FIXME: simplify | |
549 | } else if (tag("an")) { | |
550 | int val = argtoi(*args); | |
551 | if ((render_priv->state.parsed_tags & PARSED_A) == 0) { | |
552 | if (val >= 1 && val <= 9) | |
553 | render_priv->state.alignment = numpad2align(val); | |
554 | else | |
555 | render_priv->state.alignment = | |
556 | render_priv->state.style->Alignment; | |
557 | render_priv->state.parsed_tags |= PARSED_A; | |
558 | } | |
559 | } else if (tag("a")) { | |
560 | int val = argtoi(*args); | |
561 | if ((render_priv->state.parsed_tags & PARSED_A) == 0) { | |
562 | if (val >= 1 && val <= 11) | |
563 | // take care of a vsfilter quirk: | |
564 | // handle illegal \a8 and \a4 like \a5 | |
565 | render_priv->state.alignment = ((val & 3) == 0) ? 5 : val; | |
566 | else | |
567 | render_priv->state.alignment = | |
568 | render_priv->state.style->Alignment; | |
569 | render_priv->state.parsed_tags |= PARSED_A; | |
570 | } | |
571 | } else if (complex_tag("pos")) { | |
572 | double v1, v2; | |
573 | if (nargs == 2) { | |
574 | v1 = argtod(args[0]); | |
575 | v2 = argtod(args[1]); | |
576 | } else | |
577 | continue; | |
578 | if (render_priv->state.evt_type & EVENT_POSITIONED) { | |
579 | ass_msg(render_priv->library, MSGL_V, "Subtitle has a new \\pos " | |
580 | "after \\move or \\pos, ignoring"); | |
581 | } else { | |
582 | render_priv->state.evt_type |= EVENT_POSITIONED; | |
583 | render_priv->state.detect_collisions = 0; | |
584 | render_priv->state.pos_x = v1; | |
585 | render_priv->state.pos_y = v2; | |
586 | } | |
587 | } else if (complex_tag("fade") || complex_tag("fad")) { | |
588 | int a1, a2, a3; | |
589 | int32_t t1, t2, t3, t4; | |
590 | if (nargs == 2) { | |
591 | // 2-argument version (\fad, according to specs) | |
592 | a1 = 0xFF; | |
593 | a2 = 0; | |
594 | a3 = 0xFF; | |
595 | t1 = -1; | |
596 | t2 = argtoi32(args[0]); | |
597 | t3 = argtoi32(args[1]); | |
598 | t4 = -1; | |
599 | } else if (nargs == 7) { | |
600 | // 7-argument version (\fade) | |
601 | a1 = argtoi(args[0]); | |
602 | a2 = argtoi(args[1]); | |
603 | a3 = argtoi(args[2]); | |
604 | t1 = argtoi32(args[3]); | |
605 | t2 = argtoi32(args[4]); | |
606 | t3 = argtoi32(args[5]); | |
607 | t4 = argtoi32(args[6]); | |
608 | } else | |
609 | continue; | |
610 | if (t1 == -1 && t4 == -1) { | |
611 | t1 = 0; | |
612 | t4 = render_priv->state.event->Duration; | |
613 | t3 = (uint32_t) t4 - t3; | |
614 | } | |
615 | if ((render_priv->state.parsed_tags & PARSED_FADE) == 0) { | |
616 | render_priv->state.fade = | |
617 | interpolate_alpha(render_priv->time - | |
618 | render_priv->state.event->Start, t1, t2, | |
619 | t3, t4, a1, a2, a3); | |
620 | render_priv->state.parsed_tags |= PARSED_FADE; | |
621 | } | |
622 | } else if (complex_tag("org")) { | |
623 | double v1, v2; | |
624 | if (nargs == 2) { | |
625 | v1 = argtod(args[0]); | |
626 | v2 = argtod(args[1]); | |
627 | } else | |
628 | continue; | |
629 | if (!render_priv->state.have_origin) { | |
630 | render_priv->state.org_x = v1; | |
631 | render_priv->state.org_y = v2; | |
632 | render_priv->state.have_origin = 1; | |
633 | render_priv->state.detect_collisions = 0; | |
634 | } | |
635 | } else if (complex_tag("t")) { | |
636 | double accel; | |
637 | int cnt = nargs - 1; | |
638 | int32_t t1, t2, t, delta_t; | |
639 | double k; | |
640 | // VSFilter compatibility (because we can): parse the | |
641 | // timestamps differently depending on argument count. | |
642 | if (cnt == 3) { | |
643 | t1 = argtoi32(args[0]); | |
644 | t2 = argtoi32(args[1]); | |
645 | accel = argtod(args[2]); | |
646 | } else if (cnt == 2) { | |
647 | t1 = dtoi32(argtod(args[0])); | |
648 | t2 = dtoi32(argtod(args[1])); | |
649 | accel = 1.; | |
650 | } else if (cnt == 1) { | |
651 | t1 = 0; | |
652 | t2 = 0; | |
653 | accel = argtod(args[0]); | |
654 | } else { | |
655 | t1 = 0; | |
656 | t2 = 0; | |
657 | accel = 1.; | |
658 | } | |
659 | render_priv->state.detect_collisions = 0; | |
660 | if (t2 == 0) | |
661 | t2 = render_priv->state.event->Duration; | |
662 | delta_t = (uint32_t) t2 - t1; | |
663 | t = render_priv->time - render_priv->state.event->Start; // FIXME: move to render_context | |
664 | if (t < t1) | |
665 | k = 0.; | |
666 | else if (t >= t2) | |
667 | k = 1.; | |
668 | else { | |
669 | assert(delta_t != 0.); | |
670 | k = pow((double) (int32_t) ((uint32_t) t - t1) / delta_t, accel); | |
671 | } | |
672 | if (nested) | |
673 | pwr = k; | |
674 | if (cnt < 0 || cnt > 3) | |
675 | continue; | |
676 | // If there's no backslash in the arguments, there are no | |
677 | // override tags, so it's pointless to try to parse them. | |
678 | if (!has_backslash_arg) | |
679 | continue; | |
680 | p = args[cnt].start; | |
681 | if (args[cnt].end < end) { | |
682 | assert(!nested); | |
683 | p = parse_tags(render_priv, p, args[cnt].end, k, true); | |
684 | } else { | |
685 | assert(q == end); | |
686 | // No other tags can possibly follow this \t tag, | |
687 | // so we don't need to restore pwr after parsing \t. | |
688 | // The recursive call is now essentially a tail call, | |
689 | // so optimize it away. | |
690 | pwr = k; | |
691 | nested = true; | |
692 | q = p; | |
693 | } | |
694 | } else if (complex_tag("clip")) { | |
695 | if (nargs == 4) { | |
696 | int x0, y0, x1, y1; | |
697 | x0 = argtoi(args[0]); | |
698 | y0 = argtoi(args[1]); | |
699 | x1 = argtoi(args[2]); | |
700 | y1 = argtoi(args[3]); | |
701 | render_priv->state.clip_x0 = | |
702 | render_priv->state.clip_x0 * (1 - pwr) + x0 * pwr; | |
703 | render_priv->state.clip_x1 = | |
704 | render_priv->state.clip_x1 * (1 - pwr) + x1 * pwr; | |
705 | render_priv->state.clip_y0 = | |
706 | render_priv->state.clip_y0 * (1 - pwr) + y0 * pwr; | |
707 | render_priv->state.clip_y1 = | |
708 | render_priv->state.clip_y1 * (1 - pwr) + y1 * pwr; | |
709 | render_priv->state.clip_mode = 0; | |
710 | } else if (!render_priv->state.clip_drawing_text) { | |
711 | if (parse_vector_clip(render_priv, args, nargs)) | |
712 | render_priv->state.clip_drawing_mode = 0; | |
713 | } | |
714 | } else if (tag("c") || tag("1c")) { | |
715 | if (nargs) { | |
716 | uint32_t val = parse_color_tag(args->start); | |
717 | change_color(&render_priv->state.c[0], val, pwr); | |
718 | } else | |
719 | change_color(&render_priv->state.c[0], | |
720 | render_priv->state.style->PrimaryColour, 1); | |
721 | } else if (tag("2c")) { | |
722 | if (nargs) { | |
723 | uint32_t val = parse_color_tag(args->start); | |
724 | change_color(&render_priv->state.c[1], val, pwr); | |
725 | } else | |
726 | change_color(&render_priv->state.c[1], | |
727 | render_priv->state.style->SecondaryColour, 1); | |
728 | } else if (tag("3c")) { | |
729 | if (nargs) { | |
730 | uint32_t val = parse_color_tag(args->start); | |
731 | change_color(&render_priv->state.c[2], val, pwr); | |
732 | } else | |
733 | change_color(&render_priv->state.c[2], | |
734 | render_priv->state.style->OutlineColour, 1); | |
735 | } else if (tag("4c")) { | |
736 | if (nargs) { | |
737 | uint32_t val = parse_color_tag(args->start); | |
738 | change_color(&render_priv->state.c[3], val, pwr); | |
739 | } else | |
740 | change_color(&render_priv->state.c[3], | |
741 | render_priv->state.style->BackColour, 1); | |
742 | } else if (tag("1a")) { | |
743 | if (nargs) { | |
744 | uint32_t val = parse_alpha_tag(args->start); | |
745 | change_alpha(&render_priv->state.c[0], val, pwr); | |
746 | } else | |
747 | change_alpha(&render_priv->state.c[0], | |
748 | _a(render_priv->state.style->PrimaryColour), 1); | |
749 | } else if (tag("2a")) { | |
750 | if (nargs) { | |
751 | uint32_t val = parse_alpha_tag(args->start); | |
752 | change_alpha(&render_priv->state.c[1], val, pwr); | |
753 | } else | |
754 | change_alpha(&render_priv->state.c[1], | |
755 | _a(render_priv->state.style->SecondaryColour), 1); | |
756 | } else if (tag("3a")) { | |
757 | if (nargs) { | |
758 | uint32_t val = parse_alpha_tag(args->start); | |
759 | change_alpha(&render_priv->state.c[2], val, pwr); | |
760 | } else | |
761 | change_alpha(&render_priv->state.c[2], | |
762 | _a(render_priv->state.style->OutlineColour), 1); | |
763 | } else if (tag("4a")) { | |
764 | if (nargs) { | |
765 | uint32_t val = parse_alpha_tag(args->start); | |
766 | change_alpha(&render_priv->state.c[3], val, pwr); | |
767 | } else | |
768 | change_alpha(&render_priv->state.c[3], | |
769 | _a(render_priv->state.style->BackColour), 1); | |
770 | } else if (tag("r")) { | |
771 | if (nargs) { | |
772 | int len = args->end - args->start; | |
773 | reset_render_context(render_priv, | |
774 | lookup_style_strict(render_priv->track, args->start, len)); | |
775 | } else | |
776 | reset_render_context(render_priv, NULL); | |
777 | } else if (tag("be")) { | |
778 | double dval; | |
779 | if (nargs) { | |
780 | int val; | |
781 | dval = argtod(*args); | |
782 | // VSFilter always adds +0.5, even if the value is negative | |
783 | val = (int) (render_priv->state.be * (1 - pwr) + dval * pwr + 0.5); | |
784 | // Clamp to a safe upper limit, since high values need excessive CPU | |
785 | val = (val < 0) ? 0 : val; | |
786 | val = (val > MAX_BE) ? MAX_BE : val; | |
787 | render_priv->state.be = val; | |
788 | } else | |
789 | render_priv->state.be = 0; | |
790 | } else if (tag("b")) { | |
791 | int val = argtoi(*args); | |
792 | if (!nargs || !(val == 0 || val == 1 || val >= 100)) | |
793 | val = render_priv->state.style->Bold; | |
794 | render_priv->state.bold = val; | |
795 | update_font(render_priv); | |
796 | } else if (tag("i")) { | |
797 | int val = argtoi(*args); | |
798 | if (!nargs || !(val == 0 || val == 1)) | |
799 | val = render_priv->state.style->Italic; | |
800 | render_priv->state.italic = val; | |
801 | update_font(render_priv); | |
802 | } else if (tag("kf") || tag("K")) { | |
803 | double val = 100; | |
804 | if (nargs) | |
805 | val = argtod(*args); | |
806 | render_priv->state.effect_type = EF_KARAOKE_KF; | |
807 | if (render_priv->state.effect_timing) | |
808 | render_priv->state.effect_skip_timing += | |
809 | render_priv->state.effect_timing; | |
810 | render_priv->state.effect_timing = val * 10; | |
811 | } else if (tag("ko")) { | |
812 | double val = 100; | |
813 | if (nargs) | |
814 | val = argtod(*args); | |
815 | render_priv->state.effect_type = EF_KARAOKE_KO; | |
816 | if (render_priv->state.effect_timing) | |
817 | render_priv->state.effect_skip_timing += | |
818 | render_priv->state.effect_timing; | |
819 | render_priv->state.effect_timing = val * 10; | |
820 | } else if (tag("k")) { | |
821 | double val = 100; | |
822 | if (nargs) | |
823 | val = argtod(*args); | |
824 | render_priv->state.effect_type = EF_KARAOKE; | |
825 | if (render_priv->state.effect_timing) | |
826 | render_priv->state.effect_skip_timing += | |
827 | render_priv->state.effect_timing; | |
828 | render_priv->state.effect_timing = val * 10; | |
829 | } else if (tag("shad")) { | |
830 | double val, xval, yval; | |
831 | if (nargs) { | |
832 | val = argtod(*args); | |
833 | xval = render_priv->state.shadow_x * (1 - pwr) + val * pwr; | |
834 | yval = render_priv->state.shadow_y * (1 - pwr) + val * pwr; | |
835 | // VSFilter compatibility: clip for \shad but not for \[xy]shad | |
836 | xval = (xval < 0) ? 0 : xval; | |
837 | yval = (yval < 0) ? 0 : yval; | |
838 | } else | |
839 | xval = yval = render_priv->state.style->Shadow; | |
840 | render_priv->state.shadow_x = xval; | |
841 | render_priv->state.shadow_y = yval; | |
842 | } else if (tag("s")) { | |
843 | int val = argtoi(*args); | |
844 | if (!nargs || !(val == 0 || val == 1)) | |
845 | val = render_priv->state.style->StrikeOut; | |
846 | if (val) | |
847 | render_priv->state.flags |= DECO_STRIKETHROUGH; | |
848 | else | |
849 | render_priv->state.flags &= ~DECO_STRIKETHROUGH; | |
850 | } else if (tag("u")) { | |
851 | int val = argtoi(*args); | |
852 | if (!nargs || !(val == 0 || val == 1)) | |
853 | val = render_priv->state.style->Underline; | |
854 | if (val) | |
855 | render_priv->state.flags |= DECO_UNDERLINE; | |
856 | else | |
857 | render_priv->state.flags &= ~DECO_UNDERLINE; | |
858 | } else if (tag("pbo")) { | |
859 | double val = argtod(*args); | |
860 | render_priv->state.pbo = val; | |
861 | } else if (tag("p")) { | |
862 | int val = argtoi(*args); | |
300 | 863 | val = (val < 0) ? 0 : val; |
301 | } else | |
302 | val = render_priv->state.style->Outline; | |
303 | render_priv->state.border_x = val; | |
304 | } else if (tag("ybord")) { | |
305 | double val; | |
306 | if (nargs) { | |
307 | val = argtod(*args); | |
308 | val = render_priv->state.border_y * (1 - pwr) + val * pwr; | |
309 | val = (val < 0) ? 0 : val; | |
310 | } else | |
311 | val = render_priv->state.style->Outline; | |
312 | render_priv->state.border_y = val; | |
313 | } else if (tag("xshad")) { | |
314 | double val; | |
315 | if (nargs) { | |
316 | val = argtod(*args); | |
317 | val = render_priv->state.shadow_x * (1 - pwr) + val * pwr; | |
318 | } else | |
319 | val = render_priv->state.style->Shadow; | |
320 | render_priv->state.shadow_x = val; | |
321 | } else if (tag("yshad")) { | |
322 | double val; | |
323 | if (nargs) { | |
324 | val = argtod(*args); | |
325 | val = render_priv->state.shadow_y * (1 - pwr) + val * pwr; | |
326 | } else | |
327 | val = render_priv->state.style->Shadow; | |
328 | render_priv->state.shadow_y = val; | |
329 | } else if (tag("fax")) { | |
330 | double val; | |
331 | if (nargs) { | |
332 | val = argtod(*args); | |
333 | render_priv->state.fax = | |
334 | val * pwr + render_priv->state.fax * (1 - pwr); | |
335 | } else | |
336 | render_priv->state.fax = 0.; | |
337 | } else if (tag("fay")) { | |
338 | double val; | |
339 | if (nargs) { | |
340 | val = argtod(*args); | |
341 | render_priv->state.fay = | |
342 | val * pwr + render_priv->state.fay * (1 - pwr); | |
343 | } else | |
344 | render_priv->state.fay = 0.; | |
345 | } else if (complex_tag("iclip")) { | |
346 | if (nargs == 4) { | |
347 | int x0, y0, x1, y1; | |
348 | x0 = argtoi(args[0]); | |
349 | y0 = argtoi(args[1]); | |
350 | x1 = argtoi(args[2]); | |
351 | y1 = argtoi(args[3]); | |
352 | render_priv->state.clip_x0 = | |
353 | render_priv->state.clip_x0 * (1 - pwr) + x0 * pwr; | |
354 | render_priv->state.clip_x1 = | |
355 | render_priv->state.clip_x1 * (1 - pwr) + x1 * pwr; | |
356 | render_priv->state.clip_y0 = | |
357 | render_priv->state.clip_y0 * (1 - pwr) + y0 * pwr; | |
358 | render_priv->state.clip_y1 = | |
359 | render_priv->state.clip_y1 * (1 - pwr) + y1 * pwr; | |
360 | render_priv->state.clip_mode = 1; | |
361 | } else if (!render_priv->state.clip_drawing) { | |
362 | if (parse_vector_clip(render_priv, args, nargs)) | |
363 | render_priv->state.clip_drawing_mode = 1; | |
864 | render_priv->state.drawing_scale = val; | |
865 | } else if (tag("q")) { | |
866 | int val = argtoi(*args); | |
867 | if (!nargs || !(val >= 0 && val <= 3)) | |
868 | val = render_priv->track->WrapStyle; | |
869 | render_priv->state.wrap_style = val; | |
870 | } else if (tag("fe")) { | |
871 | int val; | |
872 | if (nargs) | |
873 | val = argtoi(*args); | |
874 | else | |
875 | val = render_priv->state.style->Encoding; | |
876 | render_priv->state.font_encoding = val; | |
364 | 877 | } |
365 | } else if (tag("blur")) { | |
366 | double val; | |
367 | if (nargs) { | |
368 | val = argtod(*args); | |
369 | val = render_priv->state.blur * (1 - pwr) + val * pwr; | |
370 | val = (val < 0) ? 0 : val; | |
371 | val = (val > BLUR_MAX_RADIUS) ? BLUR_MAX_RADIUS : val; | |
372 | render_priv->state.blur = val; | |
373 | } else | |
374 | render_priv->state.blur = 0.0; | |
375 | // ASS standard tags | |
376 | } else if (tag("fscx")) { | |
377 | double val; | |
378 | if (nargs) { | |
379 | val = argtod(*args) / 100; | |
380 | val = render_priv->state.scale_x * (1 - pwr) + val * pwr; | |
381 | val = (val < 0) ? 0 : val; | |
382 | } else | |
383 | val = render_priv->state.style->ScaleX; | |
384 | render_priv->state.scale_x = val; | |
385 | } else if (tag("fscy")) { | |
386 | double val; | |
387 | if (nargs) { | |
388 | val = argtod(*args) / 100; | |
389 | val = render_priv->state.scale_y * (1 - pwr) + val * pwr; | |
390 | val = (val < 0) ? 0 : val; | |
391 | } else | |
392 | val = render_priv->state.style->ScaleY; | |
393 | render_priv->state.scale_y = val; | |
394 | } else if (tag("fsc")) { | |
395 | render_priv->state.scale_x = render_priv->state.style->ScaleX; | |
396 | render_priv->state.scale_y = render_priv->state.style->ScaleY; | |
397 | } else if (tag("fsp")) { | |
398 | double val; | |
399 | if (nargs) { | |
400 | val = argtod(*args); | |
401 | render_priv->state.hspacing = | |
402 | render_priv->state.hspacing * (1 - pwr) + val * pwr; | |
403 | } else | |
404 | render_priv->state.hspacing = render_priv->state.style->Spacing; | |
405 | } else if (tag("fs")) { | |
406 | double val = 0; | |
407 | if (nargs) { | |
408 | val = argtod(*args); | |
409 | if (*args->start == '+' || *args->start == '-') | |
410 | val = render_priv->state.font_size * (1 + pwr * val / 10); | |
411 | else | |
412 | val = render_priv->state.font_size * (1 - pwr) + val * pwr; | |
413 | } | |
414 | if (val <= 0) | |
415 | val = render_priv->state.style->FontSize; | |
416 | if (render_priv->state.font) | |
417 | change_font_size(render_priv, val); | |
418 | } else if (tag("bord")) { | |
419 | double val, xval, yval; | |
420 | if (nargs) { | |
421 | val = argtod(*args); | |
422 | xval = render_priv->state.border_x * (1 - pwr) + val * pwr; | |
423 | yval = render_priv->state.border_y * (1 - pwr) + val * pwr; | |
424 | xval = (xval < 0) ? 0 : xval; | |
425 | yval = (yval < 0) ? 0 : yval; | |
426 | } else | |
427 | xval = yval = render_priv->state.style->Outline; | |
428 | render_priv->state.border_x = xval; | |
429 | render_priv->state.border_y = yval; | |
430 | } else if (complex_tag("move")) { | |
431 | double x1, x2, y1, y2; | |
432 | long long t1, t2, delta_t, t; | |
433 | double x, y; | |
434 | double k; | |
435 | if (nargs == 4 || nargs == 6) { | |
436 | x1 = argtod(args[0]); | |
437 | y1 = argtod(args[1]); | |
438 | x2 = argtod(args[2]); | |
439 | y2 = argtod(args[3]); | |
440 | t1 = t2 = 0; | |
441 | if (nargs == 6) { | |
442 | t1 = argtoll(args[4]); | |
443 | t2 = argtoll(args[5]); | |
444 | if (t1 > t2) { | |
445 | long long tmp = t2; | |
446 | t2 = t1; | |
447 | t1 = tmp; | |
448 | } | |
449 | } | |
450 | } else | |
451 | return q; | |
452 | if (t1 <= 0 && t2 <= 0) { | |
453 | t1 = 0; | |
454 | t2 = render_priv->state.event->Duration; | |
455 | } | |
456 | delta_t = t2 - t1; | |
457 | t = render_priv->time - render_priv->state.event->Start; | |
458 | if (t <= t1) | |
459 | k = 0.; | |
460 | else if (t >= t2) | |
461 | k = 1.; | |
462 | else | |
463 | k = ((double) (t - t1)) / delta_t; | |
464 | x = k * (x2 - x1) + x1; | |
465 | y = k * (y2 - y1) + y1; | |
466 | if (render_priv->state.evt_type != EVENT_POSITIONED) { | |
467 | render_priv->state.pos_x = x; | |
468 | render_priv->state.pos_y = y; | |
469 | render_priv->state.detect_collisions = 0; | |
470 | render_priv->state.evt_type = EVENT_POSITIONED; | |
471 | } | |
472 | } else if (tag("frx")) { | |
473 | double val; | |
474 | if (nargs) { | |
475 | val = argtod(*args); | |
476 | val *= M_PI / 180; | |
477 | render_priv->state.frx = | |
478 | val * pwr + render_priv->state.frx * (1 - pwr); | |
479 | } else | |
480 | render_priv->state.frx = 0.; | |
481 | } else if (tag("fry")) { | |
482 | double val; | |
483 | if (nargs) { | |
484 | val = argtod(*args); | |
485 | val *= M_PI / 180; | |
486 | render_priv->state.fry = | |
487 | val * pwr + render_priv->state.fry * (1 - pwr); | |
488 | } else | |
489 | render_priv->state.fry = 0.; | |
490 | } else if (tag("frz") || tag("fr")) { | |
491 | double val; | |
492 | if (nargs) { | |
493 | val = argtod(*args); | |
494 | val *= M_PI / 180; | |
495 | render_priv->state.frz = | |
496 | val * pwr + render_priv->state.frz * (1 - pwr); | |
497 | } else | |
498 | render_priv->state.frz = | |
499 | M_PI * render_priv->state.style->Angle / 180.; | |
500 | } else if (tag("fn")) { | |
501 | char *family; | |
502 | char *start = args->start; | |
503 | end = args->end; | |
504 | if (nargs && strncmp(start, "0", end - start)) { | |
505 | skip_spaces(&start); | |
506 | family = strndup(start, end - start); | |
507 | } else | |
508 | family = strdup(render_priv->state.style->FontName); | |
509 | free(render_priv->state.family); | |
510 | render_priv->state.family = family; | |
511 | update_font(render_priv); | |
512 | } else if (tag("alpha")) { | |
513 | int i; | |
514 | if (nargs) { | |
515 | int32_t a = parse_alpha_tag(args->start); | |
516 | for (i = 0; i < 4; ++i) | |
517 | change_alpha(&render_priv->state.c[i], a, pwr); | |
518 | } else { | |
519 | change_alpha(&render_priv->state.c[0], | |
520 | _a(render_priv->state.style->PrimaryColour), 1); | |
521 | change_alpha(&render_priv->state.c[1], | |
522 | _a(render_priv->state.style->SecondaryColour), 1); | |
523 | change_alpha(&render_priv->state.c[2], | |
524 | _a(render_priv->state.style->OutlineColour), 1); | |
525 | change_alpha(&render_priv->state.c[3], | |
526 | _a(render_priv->state.style->BackColour), 1); | |
527 | } | |
528 | // FIXME: simplify | |
529 | } else if (tag("an")) { | |
530 | int val = argtoi(*args); | |
531 | if ((render_priv->state.parsed_tags & PARSED_A) == 0) { | |
532 | if (val >= 1 && val <= 9) | |
533 | render_priv->state.alignment = numpad2align(val); | |
534 | else | |
535 | render_priv->state.alignment = | |
536 | render_priv->state.style->Alignment; | |
537 | render_priv->state.parsed_tags |= PARSED_A; | |
538 | } | |
539 | } else if (tag("a")) { | |
540 | int val = argtoi(*args); | |
541 | if ((render_priv->state.parsed_tags & PARSED_A) == 0) { | |
542 | if (val >= 1 && val <= 11) | |
543 | // take care of a vsfilter quirk: | |
544 | // handle illegal \a8 and \a4 like \a5 | |
545 | render_priv->state.alignment = ((val & 3) == 0) ? 5 : val; | |
546 | else | |
547 | render_priv->state.alignment = | |
548 | render_priv->state.style->Alignment; | |
549 | render_priv->state.parsed_tags |= PARSED_A; | |
550 | } | |
551 | } else if (complex_tag("pos")) { | |
552 | double v1, v2; | |
553 | if (nargs == 2) { | |
554 | v1 = argtod(args[0]); | |
555 | v2 = argtod(args[1]); | |
556 | } else | |
557 | return q; | |
558 | if (render_priv->state.evt_type == EVENT_POSITIONED) { | |
559 | ass_msg(render_priv->library, MSGL_V, "Subtitle has a new \\pos " | |
560 | "after \\move or \\pos, ignoring"); | |
561 | } else { | |
562 | render_priv->state.evt_type = EVENT_POSITIONED; | |
563 | render_priv->state.detect_collisions = 0; | |
564 | render_priv->state.pos_x = v1; | |
565 | render_priv->state.pos_y = v2; | |
566 | } | |
567 | } else if (complex_tag("fade") || complex_tag("fad")) { | |
568 | int a1, a2, a3; | |
569 | long long t1, t2, t3, t4; | |
570 | if (nargs == 2) { | |
571 | // 2-argument version (\fad, according to specs) | |
572 | a1 = 0xFF; | |
573 | a2 = 0; | |
574 | a3 = 0xFF; | |
575 | t1 = -1; | |
576 | t2 = argtoll(args[0]); | |
577 | t3 = argtoll(args[1]); | |
578 | t4 = -1; | |
579 | } else if (nargs == 7) { | |
580 | // 7-argument version (\fade) | |
581 | a1 = argtoi(args[0]); | |
582 | a2 = argtoi(args[1]); | |
583 | a3 = argtoi(args[2]); | |
584 | t1 = argtoll(args[3]); | |
585 | t2 = argtoll(args[4]); | |
586 | t3 = argtoll(args[5]); | |
587 | t4 = argtoll(args[6]); | |
588 | } else | |
589 | return q; | |
590 | if (t1 == -1 && t4 == -1) { | |
591 | t1 = 0; | |
592 | t4 = render_priv->state.event->Duration; | |
593 | t3 = t4 - t3; | |
594 | } | |
595 | if ((render_priv->state.parsed_tags & PARSED_FADE) == 0) { | |
596 | render_priv->state.fade = | |
597 | interpolate_alpha(render_priv->time - | |
598 | render_priv->state.event->Start, t1, t2, | |
599 | t3, t4, a1, a2, a3); | |
600 | render_priv->state.parsed_tags |= PARSED_FADE; | |
601 | } | |
602 | } else if (complex_tag("org")) { | |
603 | double v1, v2; | |
604 | if (nargs == 2) { | |
605 | v1 = argtod(args[0]); | |
606 | v2 = argtod(args[1]); | |
607 | } else | |
608 | return q; | |
609 | if (!render_priv->state.have_origin) { | |
610 | render_priv->state.org_x = v1; | |
611 | render_priv->state.org_y = v2; | |
612 | render_priv->state.have_origin = 1; | |
613 | render_priv->state.detect_collisions = 0; | |
614 | } | |
615 | } else if (complex_tag("t")) { | |
616 | double accel; | |
617 | int cnt = nargs - 1; | |
618 | long long t1, t2, t, delta_t; | |
619 | double k; | |
620 | if (cnt == 3) { | |
621 | t1 = argtoll(args[0]); | |
622 | t2 = argtoll(args[1]); | |
623 | accel = argtod(args[2]); | |
624 | } else if (cnt == 2) { | |
625 | t1 = argtoll(args[0]); | |
626 | t2 = argtoll(args[1]); | |
627 | accel = 1.; | |
628 | } else if (cnt == 1) { | |
629 | t1 = 0; | |
630 | t2 = 0; | |
631 | accel = argtod(args[0]); | |
632 | } else if (cnt == 0) { | |
633 | t1 = 0; | |
634 | t2 = 0; | |
635 | accel = 1.; | |
636 | } else | |
637 | return q; | |
638 | render_priv->state.detect_collisions = 0; | |
639 | if (t2 == 0) | |
640 | t2 = render_priv->state.event->Duration; | |
641 | delta_t = t2 - t1; | |
642 | t = render_priv->time - render_priv->state.event->Start; // FIXME: move to render_context | |
643 | if (t <= t1) | |
644 | k = 0.; | |
645 | else if (t >= t2) | |
646 | k = 1.; | |
647 | else { | |
648 | assert(delta_t != 0.); | |
649 | k = pow(((double) (t - t1)) / delta_t, accel); | |
650 | } | |
651 | p = args[cnt].start; | |
652 | while (p < args[cnt].end) | |
653 | p = parse_tag(render_priv, p, args[cnt].end, k); // maybe k*pwr ? no, specs forbid nested \t's | |
654 | } else if (complex_tag("clip")) { | |
655 | if (nargs == 4) { | |
656 | int x0, y0, x1, y1; | |
657 | x0 = argtoi(args[0]); | |
658 | y0 = argtoi(args[1]); | |
659 | x1 = argtoi(args[2]); | |
660 | y1 = argtoi(args[3]); | |
661 | render_priv->state.clip_x0 = | |
662 | render_priv->state.clip_x0 * (1 - pwr) + x0 * pwr; | |
663 | render_priv->state.clip_x1 = | |
664 | render_priv->state.clip_x1 * (1 - pwr) + x1 * pwr; | |
665 | render_priv->state.clip_y0 = | |
666 | render_priv->state.clip_y0 * (1 - pwr) + y0 * pwr; | |
667 | render_priv->state.clip_y1 = | |
668 | render_priv->state.clip_y1 * (1 - pwr) + y1 * pwr; | |
669 | render_priv->state.clip_mode = 0; | |
670 | } else if (!render_priv->state.clip_drawing) { | |
671 | if (parse_vector_clip(render_priv, args, nargs)) | |
672 | render_priv->state.clip_drawing_mode = 0; | |
673 | } | |
674 | } else if (tag("c") || tag("1c")) { | |
675 | if (nargs) { | |
676 | uint32_t val = parse_color_tag(args->start); | |
677 | change_color(&render_priv->state.c[0], val, pwr); | |
678 | } else | |
679 | change_color(&render_priv->state.c[0], | |
680 | render_priv->state.style->PrimaryColour, 1); | |
681 | } else if (tag("2c")) { | |
682 | if (nargs) { | |
683 | uint32_t val = parse_color_tag(args->start); | |
684 | change_color(&render_priv->state.c[1], val, pwr); | |
685 | } else | |
686 | change_color(&render_priv->state.c[1], | |
687 | render_priv->state.style->SecondaryColour, 1); | |
688 | } else if (tag("3c")) { | |
689 | if (nargs) { | |
690 | uint32_t val = parse_color_tag(args->start); | |
691 | change_color(&render_priv->state.c[2], val, pwr); | |
692 | } else | |
693 | change_color(&render_priv->state.c[2], | |
694 | render_priv->state.style->OutlineColour, 1); | |
695 | } else if (tag("4c")) { | |
696 | if (nargs) { | |
697 | uint32_t val = parse_color_tag(args->start); | |
698 | change_color(&render_priv->state.c[3], val, pwr); | |
699 | } else | |
700 | change_color(&render_priv->state.c[3], | |
701 | render_priv->state.style->BackColour, 1); | |
702 | } else if (tag("1a")) { | |
703 | if (nargs) { | |
704 | uint32_t val = parse_alpha_tag(args->start); | |
705 | change_alpha(&render_priv->state.c[0], val, pwr); | |
706 | } else | |
707 | change_alpha(&render_priv->state.c[0], | |
708 | _a(render_priv->state.style->PrimaryColour), 1); | |
709 | } else if (tag("2a")) { | |
710 | if (nargs) { | |
711 | uint32_t val = parse_alpha_tag(args->start); | |
712 | change_alpha(&render_priv->state.c[1], val, pwr); | |
713 | } else | |
714 | change_alpha(&render_priv->state.c[1], | |
715 | _a(render_priv->state.style->SecondaryColour), 1); | |
716 | } else if (tag("3a")) { | |
717 | if (nargs) { | |
718 | uint32_t val = parse_alpha_tag(args->start); | |
719 | change_alpha(&render_priv->state.c[2], val, pwr); | |
720 | } else | |
721 | change_alpha(&render_priv->state.c[2], | |
722 | _a(render_priv->state.style->OutlineColour), 1); | |
723 | } else if (tag("4a")) { | |
724 | if (nargs) { | |
725 | uint32_t val = parse_alpha_tag(args->start); | |
726 | change_alpha(&render_priv->state.c[3], val, pwr); | |
727 | } else | |
728 | change_alpha(&render_priv->state.c[3], | |
729 | _a(render_priv->state.style->BackColour), 1); | |
730 | } else if (tag("r")) { | |
731 | if (nargs) { | |
732 | int len = args->end - args->start; | |
733 | reset_render_context(render_priv, | |
734 | lookup_style_strict(render_priv->track, args->start, len)); | |
735 | } else | |
736 | reset_render_context(render_priv, NULL); | |
737 | } else if (tag("be")) { | |
738 | double dval; | |
739 | if (nargs) { | |
740 | int val; | |
741 | dval = argtod(*args); | |
742 | // VSFilter always adds +0.5, even if the value is negative | |
743 | val = (int) (render_priv->state.be * (1 - pwr) + dval * pwr + 0.5); | |
744 | // Clamp to a safe upper limit, since high values need excessive CPU | |
745 | val = (val < 0) ? 0 : val; | |
746 | val = (val > MAX_BE) ? MAX_BE : val; | |
747 | render_priv->state.be = val; | |
748 | } else | |
749 | render_priv->state.be = 0; | |
750 | } else if (tag("b")) { | |
751 | int val = argtoi(*args); | |
752 | if (!nargs || !(val == 0 || val == 1 || val >= 100)) | |
753 | val = render_priv->state.style->Bold; | |
754 | render_priv->state.bold = val; | |
755 | update_font(render_priv); | |
756 | } else if (tag("i")) { | |
757 | int val = argtoi(*args); | |
758 | if (!nargs || !(val == 0 || val == 1)) | |
759 | val = render_priv->state.style->Italic; | |
760 | render_priv->state.italic = val; | |
761 | update_font(render_priv); | |
762 | } else if (tag("kf") || tag("K")) { | |
763 | double val = 100; | |
764 | if (nargs) | |
765 | val = argtod(*args); | |
766 | render_priv->state.effect_type = EF_KARAOKE_KF; | |
767 | if (render_priv->state.effect_timing) | |
768 | render_priv->state.effect_skip_timing += | |
769 | render_priv->state.effect_timing; | |
770 | render_priv->state.effect_timing = val * 10; | |
771 | } else if (tag("ko")) { | |
772 | double val = 100; | |
773 | if (nargs) | |
774 | val = argtod(*args); | |
775 | render_priv->state.effect_type = EF_KARAOKE_KO; | |
776 | if (render_priv->state.effect_timing) | |
777 | render_priv->state.effect_skip_timing += | |
778 | render_priv->state.effect_timing; | |
779 | render_priv->state.effect_timing = val * 10; | |
780 | } else if (tag("k")) { | |
781 | double val = 100; | |
782 | if (nargs) | |
783 | val = argtod(*args); | |
784 | render_priv->state.effect_type = EF_KARAOKE; | |
785 | if (render_priv->state.effect_timing) | |
786 | render_priv->state.effect_skip_timing += | |
787 | render_priv->state.effect_timing; | |
788 | render_priv->state.effect_timing = val * 10; | |
789 | } else if (tag("shad")) { | |
790 | double val, xval, yval; | |
791 | if (nargs) { | |
792 | val = argtod(*args); | |
793 | xval = render_priv->state.shadow_x * (1 - pwr) + val * pwr; | |
794 | yval = render_priv->state.shadow_y * (1 - pwr) + val * pwr; | |
795 | // VSFilter compatibility: clip for \shad but not for \[xy]shad | |
796 | xval = (xval < 0) ? 0 : xval; | |
797 | yval = (yval < 0) ? 0 : yval; | |
798 | } else | |
799 | xval = yval = render_priv->state.style->Shadow; | |
800 | render_priv->state.shadow_x = xval; | |
801 | render_priv->state.shadow_y = yval; | |
802 | } else if (tag("s")) { | |
803 | int val = argtoi(*args); | |
804 | if (!nargs || !(val == 0 || val == 1)) | |
805 | val = render_priv->state.style->StrikeOut; | |
806 | if (val) | |
807 | render_priv->state.flags |= DECO_STRIKETHROUGH; | |
808 | else | |
809 | render_priv->state.flags &= ~DECO_STRIKETHROUGH; | |
810 | } else if (tag("u")) { | |
811 | int val = argtoi(*args); | |
812 | if (!nargs || !(val == 0 || val == 1)) | |
813 | val = render_priv->state.style->Underline; | |
814 | if (val) | |
815 | render_priv->state.flags |= DECO_UNDERLINE; | |
816 | else | |
817 | render_priv->state.flags &= ~DECO_UNDERLINE; | |
818 | } else if (tag("pbo")) { | |
819 | double val = argtod(*args); | |
820 | render_priv->state.pbo = val; | |
821 | } else if (tag("p")) { | |
822 | int val = argtoi(*args); | |
823 | val = (val < 0) ? 0 : val; | |
824 | render_priv->state.drawing_scale = val; | |
825 | } else if (tag("q")) { | |
826 | int val = argtoi(*args); | |
827 | if (!nargs || !(val >= 0 && val <= 3)) | |
828 | val = render_priv->track->WrapStyle; | |
829 | render_priv->state.wrap_style = val; | |
830 | } else if (tag("fe")) { | |
831 | int val; | |
832 | if (nargs) | |
833 | val = argtoi(*args); | |
834 | else | |
835 | val = render_priv->state.style->Encoding; | |
836 | render_priv->state.font_encoding = val; | |
837 | } | |
838 | ||
839 | return q; | |
878 | } | |
879 | ||
880 | return p; | |
840 | 881 | } |
841 | 882 | |
842 | 883 | void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event) |
860 | 901 | "Error parsing effect: '%s'", event->Effect); |
861 | 902 | return; |
862 | 903 | } |
863 | if (cnt >= 2 && v[1] == 0) // right-to-left | |
904 | if (cnt >= 2 && v[1]) // left-to-right | |
905 | render_priv->state.scroll_direction = SCROLL_LR; | |
906 | else // right-to-left | |
864 | 907 | render_priv->state.scroll_direction = SCROLL_RL; |
865 | else // left-to-right | |
866 | render_priv->state.scroll_direction = SCROLL_LR; | |
867 | 908 | |
868 | 909 | delay = v[0]; |
869 | 910 | if (delay == 0) |
870 | 911 | delay = 1; // ? |
871 | 912 | render_priv->state.scroll_shift = |
872 | 913 | (render_priv->time - render_priv->state.event->Start) / delay; |
873 | render_priv->state.evt_type = EVENT_HSCROLL; | |
914 | render_priv->state.evt_type |= EVENT_HSCROLL; | |
915 | render_priv->state.detect_collisions = 0; | |
916 | render_priv->state.wrap_style = 2; | |
874 | 917 | return; |
875 | 918 | } |
876 | 919 | |
904 | 947 | y0 = v[1]; |
905 | 948 | y1 = v[0]; |
906 | 949 | } |
907 | if (y1 == 0) | |
908 | y1 = render_priv->track->PlayResY; // y0=y1=0 means fullscreen scrolling | |
909 | render_priv->state.clip_y0 = y0; | |
910 | render_priv->state.clip_y1 = y1; | |
911 | render_priv->state.evt_type = EVENT_VSCROLL; | |
950 | render_priv->state.scroll_y0 = y0; | |
951 | render_priv->state.scroll_y1 = y1; | |
952 | render_priv->state.evt_type |= EVENT_VSCROLL; | |
912 | 953 | render_priv->state.detect_collisions = 0; |
913 | 954 | } |
914 | 955 | |
927 | 968 | */ |
928 | 969 | void process_karaoke_effects(ASS_Renderer *render_priv) |
929 | 970 | { |
930 | GlyphInfo *cur, *cur2; | |
931 | GlyphInfo *s1, *e1; // start and end of the current word | |
932 | GlyphInfo *s2; // start of the next word | |
933 | int i; | |
934 | int timing; // current timing | |
935 | int tm_start, tm_end; // timings at start and end of the current word | |
936 | int tm_current; | |
937 | double dt; | |
938 | int x; | |
939 | int x_start, x_end; | |
940 | ||
941 | tm_current = render_priv->time - render_priv->state.event->Start; | |
942 | timing = 0; | |
943 | s1 = s2 = 0; | |
944 | for (i = 0; i <= render_priv->text_info.length; ++i) { | |
945 | cur = render_priv->text_info.glyphs + i; | |
946 | if ((i == render_priv->text_info.length) | |
947 | || (cur->effect_type != EF_NONE)) { | |
948 | s1 = s2; | |
949 | s2 = cur; | |
950 | if (s1) { | |
951 | e1 = s2 - 1; | |
952 | tm_start = timing + s1->effect_skip_timing; | |
953 | tm_end = tm_start + s1->effect_timing; | |
954 | timing = tm_end; | |
955 | x_start = 1000000; | |
956 | x_end = -1000000; | |
957 | for (cur2 = s1; cur2 <= e1; ++cur2) { | |
958 | x_start = FFMIN(x_start, d6_to_int(cur2->bbox.x_min + cur2->pos.x)); | |
959 | x_end = FFMAX(x_end, d6_to_int(cur2->bbox.x_max + cur2->pos.x)); | |
971 | long long tm_current = render_priv->time - render_priv->state.event->Start; | |
972 | ||
973 | int timing = 0, skip_timing = 0; | |
974 | Effect effect_type = EF_NONE; | |
975 | GlyphInfo *last_boundary = NULL; | |
976 | for (int i = 0; i <= render_priv->text_info.length; i++) { | |
977 | if (i < render_priv->text_info.length && | |
978 | !render_priv->text_info.glyphs[i].starts_new_run) { | |
979 | // VSFilter compatibility: if we have \k12345\k0 without a run | |
980 | // break, subsequent text is still part of the same karaoke word, | |
981 | // the current word's starting and ending time stay unchanged, | |
982 | // but the starting time of the next karaoke word is advanced. | |
983 | skip_timing += render_priv->text_info.glyphs[i].effect_skip_timing; | |
984 | continue; | |
985 | } | |
986 | ||
987 | GlyphInfo *start = last_boundary; | |
988 | GlyphInfo *end = render_priv->text_info.glyphs + i; | |
989 | last_boundary = end; | |
990 | if (!start) | |
991 | continue; | |
992 | ||
993 | if (start->effect_type != EF_NONE) | |
994 | effect_type = start->effect_type; | |
995 | if (effect_type == EF_NONE) | |
996 | continue; | |
997 | ||
998 | long long tm_start = timing + start->effect_skip_timing; | |
999 | long long tm_end = tm_start + start->effect_timing; | |
1000 | timing = tm_end + skip_timing; | |
1001 | skip_timing = 0; | |
1002 | ||
1003 | if (effect_type != EF_KARAOKE_KF) | |
1004 | tm_end = tm_start; | |
1005 | ||
1006 | int x; | |
1007 | if (tm_current < tm_start) | |
1008 | x = -100000000; | |
1009 | else if (tm_current >= tm_end) | |
1010 | x = 100000000; | |
1011 | else { | |
1012 | GlyphInfo *first_visible = start, *last_visible = end - 1; | |
1013 | while (first_visible < last_visible && first_visible->skip) | |
1014 | ++first_visible; | |
1015 | while (first_visible < last_visible && last_visible->skip) | |
1016 | --last_visible; | |
1017 | ||
1018 | int x_start = first_visible->pos.x; | |
1019 | int x_end = last_visible->pos.x + last_visible->advance.x; | |
1020 | double dt = (double) (tm_current - tm_start) / (tm_end - tm_start); | |
1021 | double frz = fmod(start->frz, 360); | |
1022 | if (frz > 90 && frz < 270) { | |
1023 | // Fill from right to left | |
1024 | dt = 1 - dt; | |
1025 | for (GlyphInfo *info = start; info < end; info++) { | |
1026 | uint32_t tmp = info->c[0]; | |
1027 | info->c[0] = info->c[1]; | |
1028 | info->c[1] = tmp; | |
960 | 1029 | } |
961 | ||
962 | dt = (tm_current - tm_start); | |
963 | if ((s1->effect_type == EF_KARAOKE) | |
964 | || (s1->effect_type == EF_KARAOKE_KO)) { | |
965 | if (dt >= 0) | |
966 | x = x_end + 1; | |
967 | else | |
968 | x = x_start; | |
969 | } else if (s1->effect_type == EF_KARAOKE_KF) { | |
970 | dt /= (tm_end - tm_start); | |
971 | x = x_start + (x_end - x_start) * dt; | |
972 | } else { | |
973 | ass_msg(render_priv->library, MSGL_ERR, | |
974 | "Unknown effect type"); | |
975 | continue; | |
976 | } | |
977 | ||
978 | for (cur2 = s1; cur2 <= e1; ++cur2) { | |
979 | cur2->effect_type = s1->effect_type; | |
980 | cur2->effect_timing = x - d6_to_int(cur2->pos.x); | |
981 | } | |
982 | s1->effect = 1; | |
983 | } | |
1030 | } | |
1031 | x = x_start + lrint((x_end - x_start) * dt); | |
1032 | } | |
1033 | ||
1034 | for (GlyphInfo *info = start; info < end; info++) { | |
1035 | info->effect_type = effect_type; | |
1036 | info->effect_timing = x - info->pos.x; | |
984 | 1037 | } |
985 | 1038 | } |
986 | 1039 | } |
30 | 30 | void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event); |
31 | 31 | void process_karaoke_effects(ASS_Renderer *render_priv); |
32 | 32 | unsigned get_next_char(ASS_Renderer *render_priv, char **str); |
33 | char *parse_tag(ASS_Renderer *render_priv, char *p, char *end, double pwr); | |
33 | char *parse_tags(ASS_Renderer *render_priv, char *p, char *end, double pwr, | |
34 | bool nested); | |
34 | 35 | int event_has_hard_overrides(char *str); |
35 | 36 | extern void change_alpha(uint32_t *var, int32_t new, double pwr); |
36 | 37 | extern uint32_t mult_alpha(uint32_t a, uint32_t b); |
0 | /* | |
1 | * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> | |
2 | * | |
3 | * This file is part of libass. | |
4 | * | |
5 | * Permission to use, copy, modify, and distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | ||
18 | #ifndef LIBASS_PRIV_H | |
19 | #define LIBASS_PRIV_H | |
20 | ||
21 | #include <stdbool.h> | |
22 | #include <stdint.h> | |
23 | ||
24 | #include "ass_shaper.h" | |
25 | ||
26 | typedef enum { | |
27 | PST_UNKNOWN = 0, | |
28 | PST_INFO, | |
29 | PST_STYLES, | |
30 | PST_EVENTS, | |
31 | PST_FONTS | |
32 | } ParserState; | |
33 | ||
34 | typedef enum { | |
35 | SINFO_LANGUAGE = 1 << 0, | |
36 | SINFO_PLAYRESX = 1 << 1, | |
37 | SINFO_PLAYRESY = 1 << 2, | |
38 | SINFO_TIMER = 1 << 3, | |
39 | SINFO_WRAPSTYLE = 1 << 4, | |
40 | SINFO_SCALEDBORDER = 1 << 5, | |
41 | SINFO_COLOURMATRIX = 1 << 6, | |
42 | SINFO_KERNING = 1 << 7, | |
43 | // for legacy detection | |
44 | GENBY_FFMPEG = 1 << 8 | |
45 | // max 32 enumerators | |
46 | } ScriptInfo; | |
47 | ||
48 | struct parser_priv { | |
49 | ParserState state; | |
50 | char *fontname; | |
51 | char *fontdata; | |
52 | size_t fontdata_size; | |
53 | size_t fontdata_used; | |
54 | ||
55 | // contains bitmap of ReadOrder IDs of all read events | |
56 | uint32_t *read_order_bitmap; | |
57 | int read_order_elems; // size in uint32_t units of read_order_bitmap | |
58 | int check_readorder; | |
59 | ||
60 | // tracks [Script Info] headers set by the script | |
61 | uint32_t header_flags; | |
62 | ||
63 | #ifdef USE_FRIBIDI_EX_API | |
64 | bool bidi_brackets; | |
65 | #endif | |
66 | }; | |
67 | ||
68 | #endif /* LIBASS_PRIV_H */ |
268 | 268 | } |
269 | 269 | rst->size[0] = rst->n_first; |
270 | 270 | |
271 | for (size_t i = 0; i < path->n_points; i++) { | |
272 | if (path->points[i].x < OUTLINE_MIN || path->points[i].x > OUTLINE_MAX) | |
273 | return false; | |
274 | if (path->points[i].y < OUTLINE_MIN || path->points[i].y > OUTLINE_MAX) | |
275 | return false; | |
276 | } | |
271 | #ifndef NDEBUG | |
272 | for (size_t i = 0; i < path->n_points; i++) | |
273 | assert(abs(path->points[i].x) <= OUTLINE_MAX && abs(path->points[i].y) <= OUTLINE_MAX); | |
274 | #endif | |
277 | 275 | |
278 | 276 | ASS_Vector *start = path->points, *cur = start; |
279 | 277 | for (size_t i = 0; i < path->n_segments; i++) { |
26 | 26 | #include "ass_outline.h" |
27 | 27 | #include "ass_render.h" |
28 | 28 | #include "ass_parse.h" |
29 | #include "ass_priv.h" | |
29 | 30 | #include "ass_shaper.h" |
30 | 31 | |
31 | 32 | #define MAX_GLYPHS_INITIAL 1024 |
33 | 34 | #define MAX_BITMAPS_INITIAL 16 |
34 | 35 | #define MAX_SUB_BITMAPS_INITIAL 64 |
35 | 36 | #define SUBPIXEL_MASK 63 |
36 | #define SUBPIXEL_ACCURACY 7 | |
37 | #define STROKER_PRECISION 16 // stroker error in integer units, unrelated to final accuracy | |
38 | #define RASTERIZER_PRECISION 16 // rasterizer spline approximation error in 1/64 pixel units | |
39 | #define POSITION_PRECISION 8.0 // rough estimate of transform error in 1/64 pixel units | |
40 | #define MAX_PERSP_SCALE 16.0 | |
41 | #define SUBPIXEL_ORDER 3 // ~ log2(64 / POSITION_PRECISION) | |
42 | #define BLUR_PRECISION (1.0 / 256) // blur error as fraction of full input range | |
37 | 43 | |
38 | 44 | |
39 | 45 | ASS_Renderer *ass_renderer_init(ASS_Library *library) |
46 | 52 | error = FT_Init_FreeType(&ft); |
47 | 53 | if (error) { |
48 | 54 | ass_msg(library, MSGL_FATAL, "%s failed", "FT_Init_FreeType"); |
49 | goto ass_init_exit; | |
55 | goto fail; | |
50 | 56 | } |
51 | 57 | |
52 | 58 | FT_Library_Version(ft, &vmajor, &vminor, &vpatch); |
56 | 62 | priv = calloc(1, sizeof(ASS_Renderer)); |
57 | 63 | if (!priv) { |
58 | 64 | FT_Done_FreeType(ft); |
59 | goto ass_init_exit; | |
65 | goto fail; | |
60 | 66 | } |
61 | 67 | |
62 | 68 | priv->library = library; |
74 | 80 | priv->engine = &ass_bitmap_engine_c; |
75 | 81 | #endif |
76 | 82 | |
77 | if (!rasterizer_init(&priv->rasterizer, priv->engine->tile_order, 16)) { | |
78 | FT_Done_FreeType(ft); | |
79 | goto ass_init_exit; | |
80 | } | |
83 | if (!rasterizer_init(&priv->rasterizer, priv->engine->tile_order, | |
84 | RASTERIZER_PRECISION)) | |
85 | goto fail; | |
81 | 86 | |
82 | 87 | priv->cache.font_cache = ass_font_cache_create(); |
83 | 88 | priv->cache.bitmap_cache = ass_bitmap_cache_create(); |
84 | 89 | priv->cache.composite_cache = ass_composite_cache_create(); |
85 | 90 | priv->cache.outline_cache = ass_outline_cache_create(); |
91 | if (!priv->cache.font_cache || !priv->cache.bitmap_cache || !priv->cache.composite_cache || !priv->cache.outline_cache) | |
92 | goto fail; | |
93 | ||
86 | 94 | priv->cache.glyph_max = GLYPH_CACHE_MAX; |
87 | 95 | priv->cache.bitmap_max_size = BITMAP_CACHE_MAX_SIZE; |
88 | 96 | priv->cache.composite_max_size = COMPOSITE_CACHE_MAX_SIZE; |
94 | 102 | priv->text_info.combined_bitmaps = calloc(MAX_BITMAPS_INITIAL, sizeof(CombinedBitmapInfo)); |
95 | 103 | priv->text_info.glyphs = calloc(MAX_GLYPHS_INITIAL, sizeof(GlyphInfo)); |
96 | 104 | priv->text_info.lines = calloc(MAX_LINES_INITIAL, sizeof(LineInfo)); |
105 | if (!priv->text_info.combined_bitmaps || !priv->text_info.glyphs || !priv->text_info.lines) | |
106 | goto fail; | |
97 | 107 | |
98 | 108 | priv->settings.font_size_coeff = 1.; |
99 | 109 | priv->settings.selective_style_overrides = ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE; |
100 | 110 | |
101 | priv->shaper = ass_shaper_new(0); | |
111 | if (!(priv->shaper = ass_shaper_new())) | |
112 | goto fail; | |
113 | ||
102 | 114 | ass_shaper_info(library); |
103 | #ifdef CONFIG_HARFBUZZ | |
104 | 115 | priv->settings.shaper = ASS_SHAPING_COMPLEX; |
105 | #else | |
106 | priv->settings.shaper = ASS_SHAPING_SIMPLE; | |
107 | #endif | |
108 | ||
109 | ass_init_exit: | |
110 | if (priv) | |
111 | ass_msg(library, MSGL_V, "Initialized"); | |
112 | else | |
113 | ass_msg(library, MSGL_ERR, "Initialization failed"); | |
116 | ||
117 | ass_msg(library, MSGL_V, "Initialized"); | |
114 | 118 | |
115 | 119 | return priv; |
120 | ||
121 | fail: | |
122 | ass_msg(library, MSGL_ERR, "Initialization failed"); | |
123 | ass_renderer_done(priv); | |
124 | ||
125 | return NULL; | |
116 | 126 | } |
117 | 127 | |
118 | 128 | void ass_renderer_done(ASS_Renderer *render_priv) |
119 | 129 | { |
130 | if (!render_priv) | |
131 | return; | |
132 | ||
120 | 133 | ass_frame_unref(render_priv->images_root); |
121 | 134 | ass_frame_unref(render_priv->prev_images_root); |
122 | 135 | |
172 | 185 | |
173 | 186 | img->source = source; |
174 | 187 | ass_cache_inc_ref(source); |
188 | img->buffer = source ? NULL : bitmap; | |
175 | 189 | img->ref_count = 0; |
176 | 190 | |
177 | 191 | return &img->result; |
185 | 199 | return x * render_priv->orig_width / render_priv->font_scale_x / render_priv->track->PlayResX + |
186 | 200 | render_priv->settings.left_margin; |
187 | 201 | } |
188 | static double x2scr(ASS_Renderer *render_priv, double x) | |
189 | { | |
190 | if (render_priv->state.explicit) | |
202 | static double x2scr_left(ASS_Renderer *render_priv, double x) | |
203 | { | |
204 | if (render_priv->state.explicit || !render_priv->settings.use_margins) | |
191 | 205 | return x2scr_pos(render_priv, x); |
192 | return x * render_priv->orig_width_nocrop / render_priv->font_scale_x / | |
206 | return x * render_priv->fit_width / render_priv->font_scale_x / | |
207 | render_priv->track->PlayResX; | |
208 | } | |
209 | static double x2scr_right(ASS_Renderer *render_priv, double x) | |
210 | { | |
211 | if (render_priv->state.explicit || !render_priv->settings.use_margins) | |
212 | return x2scr_pos(render_priv, x); | |
213 | return x * render_priv->fit_width / render_priv->font_scale_x / | |
193 | 214 | render_priv->track->PlayResX + |
194 | FFMAX(render_priv->settings.left_margin, 0); | |
215 | (render_priv->width - render_priv->fit_width); | |
195 | 216 | } |
196 | 217 | static double x2scr_pos_scaled(ASS_Renderer *render_priv, double x) |
197 | 218 | { |
198 | 219 | return x * render_priv->orig_width / render_priv->track->PlayResX + |
199 | 220 | render_priv->settings.left_margin; |
200 | } | |
201 | static double x2scr_scaled(ASS_Renderer *render_priv, double x) | |
202 | { | |
203 | if (render_priv->state.explicit) | |
204 | return x2scr_pos_scaled(render_priv, x); | |
205 | return x * render_priv->orig_width_nocrop / | |
206 | render_priv->track->PlayResX + | |
207 | FFMAX(render_priv->settings.left_margin, 0); | |
208 | 221 | } |
209 | 222 | /** |
210 | 223 | * \brief Mapping between script and screen coordinates |
216 | 229 | } |
217 | 230 | static double y2scr(ASS_Renderer *render_priv, double y) |
218 | 231 | { |
219 | if (render_priv->state.explicit) | |
232 | if (render_priv->state.explicit || !render_priv->settings.use_margins) | |
220 | 233 | return y2scr_pos(render_priv, y); |
221 | return y * render_priv->orig_height_nocrop / | |
234 | return y * render_priv->fit_height / | |
222 | 235 | render_priv->track->PlayResY + |
223 | FFMAX(render_priv->settings.top_margin, 0); | |
236 | (render_priv->height - render_priv->fit_height) * 0.5; | |
224 | 237 | } |
225 | 238 | |
226 | 239 | // the same for toptitles |
227 | 240 | static double y2scr_top(ASS_Renderer *render_priv, double y) |
228 | 241 | { |
229 | if (render_priv->state.explicit) | |
242 | if (render_priv->state.explicit || !render_priv->settings.use_margins) | |
230 | 243 | return y2scr_pos(render_priv, y); |
231 | if (render_priv->settings.use_margins) | |
232 | return y * render_priv->orig_height_nocrop / | |
233 | render_priv->track->PlayResY; | |
234 | else | |
235 | return y * render_priv->orig_height_nocrop / | |
236 | render_priv->track->PlayResY + | |
237 | FFMAX(render_priv->settings.top_margin, 0); | |
244 | return y * render_priv->fit_height / | |
245 | render_priv->track->PlayResY; | |
238 | 246 | } |
239 | 247 | // the same for subtitles |
240 | 248 | static double y2scr_sub(ASS_Renderer *render_priv, double y) |
241 | 249 | { |
242 | if (render_priv->state.explicit) | |
250 | if (render_priv->state.explicit || !render_priv->settings.use_margins) | |
243 | 251 | return y2scr_pos(render_priv, y); |
244 | if (render_priv->settings.use_margins) | |
245 | return y * render_priv->orig_height_nocrop / | |
246 | render_priv->track->PlayResY + | |
247 | FFMAX(render_priv->settings.top_margin, 0) | |
248 | + FFMAX(render_priv->settings.bottom_margin, 0); | |
249 | else | |
250 | return y * render_priv->orig_height_nocrop / | |
251 | render_priv->track->PlayResY + | |
252 | FFMAX(render_priv->settings.top_margin, 0); | |
252 | return y * render_priv->fit_height / | |
253 | render_priv->track->PlayResY + | |
254 | (render_priv->height - render_priv->fit_height); | |
253 | 255 | } |
254 | 256 | |
255 | 257 | /* |
277 | 279 | |
278 | 280 | dst_x += bm->left; |
279 | 281 | dst_y += bm->top; |
282 | brk -= dst_x; | |
280 | 283 | |
281 | 284 | // we still need to clip against screen boundaries |
282 | 285 | zx = x2scr_pos_scaled(render_priv, 0); |
378 | 381 | return render_glyph_i(render_priv, bm, dst_x, dst_y, color, color2, |
379 | 382 | brk, tail, type, source); |
380 | 383 | |
381 | // brk is relative to dst_x | |
384 | // brk is absolute | |
382 | 385 | // color = color left of brk |
383 | 386 | // color2 = color right of brk |
384 | 387 | int b_x0, b_y0, b_x1, b_y1; // visible part of the bitmap |
388 | 391 | |
389 | 392 | dst_x += bm->left; |
390 | 393 | dst_y += bm->top; |
391 | brk -= bm->left; | |
394 | brk -= dst_x; | |
392 | 395 | |
393 | 396 | // clipping |
394 | 397 | clip_x0 = FFMINMAX(render_priv->state.clip_x0, 0, render_priv->width); |
441 | 444 | return tail; |
442 | 445 | } |
443 | 446 | |
447 | static bool quantize_transform(double m[3][3], ASS_Vector *pos, | |
448 | ASS_DVector *offset, bool first, | |
449 | BitmapHashKey *key) | |
450 | { | |
451 | // Full transform: | |
452 | // x_out = (m_xx * x + m_xy * y + m_xz) / z, | |
453 | // y_out = (m_yx * x + m_yy * y + m_yz) / z, | |
454 | // z = m_zx * x + m_zy * y + m_zz. | |
455 | ||
456 | const double max_val = 1000000; | |
457 | ||
458 | const ASS_Rect *bbox = &key->outline->cbox; | |
459 | double x0 = (bbox->x_min + bbox->x_max) / 2.0; | |
460 | double y0 = (bbox->y_min + bbox->y_max) / 2.0; | |
461 | double dx = (bbox->x_max - bbox->x_min) / 2.0 + 64; | |
462 | double dy = (bbox->y_max - bbox->y_min) / 2.0 + 64; | |
463 | ||
464 | // Change input coordinates' origin to (x0, y0), | |
465 | // after that transformation x:[-dx, dx], y:[-dy, dy], | |
466 | // max|x| = dx and max|y| = dy. | |
467 | for (int i = 0; i < 3; i++) | |
468 | m[i][2] += m[i][0] * x0 + m[i][1] * y0; | |
469 | ||
470 | if (m[2][2] <= 0) | |
471 | return false; | |
472 | ||
473 | double w = 1 / m[2][2]; | |
474 | // Transformed center of bounding box | |
475 | double center[2] = { m[0][2] * w, m[1][2] * w }; | |
476 | // Change output coordinates' origin to center, | |
477 | // m_xz and m_yz is skipped as it becomes 0 and no longer needed. | |
478 | for (int i = 0; i < 2; i++) | |
479 | for (int j = 0; j < 2; j++) | |
480 | m[i][j] -= m[2][j] * center[i]; | |
481 | ||
482 | double delta[2] = {0}; | |
483 | if (!first) { | |
484 | delta[0] = offset->x; | |
485 | delta[1] = offset->y; | |
486 | } | |
487 | ||
488 | int32_t qr[2]; // quantized center position | |
489 | for (int i = 0; i < 2; i++) { | |
490 | center[i] /= 64 >> SUBPIXEL_ORDER; | |
491 | center[i] -= delta[i]; | |
492 | if (!(fabs(center[i]) < max_val)) | |
493 | return false; | |
494 | qr[i] = lrint(center[i]); | |
495 | } | |
496 | ||
497 | // Minimal bounding box z coordinate | |
498 | double z0 = m[2][2] - fabs(m[2][0]) * dx - fabs(m[2][1]) * dy; | |
499 | // z0 clamped to z_center / MAX_PERSP_SCALE to mitigate problems with small z | |
500 | w = 1.0 / POSITION_PRECISION / FFMAX(z0, m[2][2] / MAX_PERSP_SCALE); | |
501 | double mul[2] = { dx * w, dy * w }; // 1 / q_x, 1 / q_y | |
502 | ||
503 | // z0 = m_zz - |m_zx| * dx - |m_zy| * dy, | |
504 | // m_zz = z0 + |m_zx| * dx + |m_zy| * dy, | |
505 | // z = m_zx * x + m_zy * y + m_zz | |
506 | // = m_zx * (x + sign(m_zx) * dx) + m_zy * (y + sign(m_zy) * dy) + z0. | |
507 | ||
508 | // D(f)--absolute value of error in quantity f | |
509 | // as function of error in matrix coefficients, i. e. D(m_??). | |
510 | // Error in constant is zero, i. e. D(dx) = D(dy) = D(z0) = 0. | |
511 | // In the following calculation errors are considered small | |
512 | // and second- and higher-order terms are dropped. | |
513 | // That approximation is valid as long as glyph dimensions are larger than couple of pixels. | |
514 | // Therefore standard relations for derivatives can be used for D(?): | |
515 | // D(A * B) <= D(A) * max|B| + max|A| * D(B), | |
516 | // D(1 / C) <= D(C) * max|1 / C^2|. | |
517 | ||
518 | // D(x_out) = D((m_xx * x + m_xy * y) / z) | |
519 | // <= D(m_xx * x + m_xy * y) * max|1 / z| + max|m_xx * x + m_xy * y| * D(1 / z) | |
520 | // <= (D(m_xx) * dx + D(m_xy) * dy) / z0 + (|m_xx| * dx + |m_xy| * dy) * D(z) / z0^2, | |
521 | // D(y_out) = D((m_yx * x + m_yy * y) / z) | |
522 | // <= D(m_yx * x + m_yy * y) * max|1 / z| + max|m_yx * x + m_yy * y| * D(1 / z) | |
523 | // <= (D(m_yx) * dx + D(m_yy) * dy) / z0 + (|m_yx| * dx + |m_yy| * dy) * D(z) / z0^2, | |
524 | // |m_xx| * dx + |m_xy| * dy = x_lim, | |
525 | // |m_yx| * dx + |m_yy| * dy = y_lim, | |
526 | // D(z) <= 2 * (D(m_zx) * dx + D(m_zy) * dy), | |
527 | // D(x_out) <= (D(m_xx) * dx + D(m_xy) * dy) / z0 | |
528 | // + 2 * (D(m_zx) * dx + D(m_zy) * dy) * x_lim / z0^2, | |
529 | // D(y_out) <= (D(m_yx) * dx + D(m_yy) * dy) / z0 | |
530 | // + 2 * (D(m_zx) * dx + D(m_zy) * dy) * y_lim / z0^2. | |
531 | ||
532 | // To estimate acceptable error in matrix coefficient | |
533 | // set error in all other coefficients to zero and solve system | |
534 | // D(x_out) <= ACCURACY & D(y_out) <= ACCURACY for desired D(m_??). | |
535 | // ACCURACY here is some part of total error, i. e. ACCURACY ~ POSITION_PRECISION. | |
536 | // Note that POSITION_PRECISION isn't total error, it's convenient constant. | |
537 | // True error can be up to several POSITION_PRECISION. | |
538 | ||
539 | // Quantization steps (ACCURACY ~ POSITION_PRECISION): | |
540 | // D(m_xx), D(m_yx) ~ q_x = POSITION_PRECISION * z0 / dx, | |
541 | // D(m_xy), D(m_yy) ~ q_y = POSITION_PRECISION * z0 / dy, | |
542 | // qm_xx = round(m_xx / q_x), qm_xy = round(m_xy / q_y), | |
543 | // qm_yx = round(m_yx / q_x), qm_yy = round(m_yy / q_y). | |
544 | ||
545 | int32_t qm[3][2]; | |
546 | for (int i = 0; i < 2; i++) | |
547 | for (int j = 0; j < 2; j++) { | |
548 | double val = m[i][j] * mul[j]; | |
549 | if (!(fabs(val) < max_val)) | |
550 | return false; | |
551 | qm[i][j] = lrint(val); | |
552 | } | |
553 | ||
554 | // x_lim = |m_xx| * dx + |m_xy| * dy | |
555 | // ~= |qm_xx| * q_x * dx + |qm_xy| * q_y * dy | |
556 | // = (|qm_xx| + |qm_xy|) * POSITION_PRECISION * z0, | |
557 | // y_lim = |m_yx| * dx + |m_yy| * dy | |
558 | // ~= |qm_yx| * q_x * dx + |qm_yy| * q_y * dy | |
559 | // = (|qm_yx| + |qm_yy|) * POSITION_PRECISION * z0, | |
560 | // max(x_lim, y_lim) / z0 ~= w | |
561 | // = max(|qm_xx| + |qm_xy|, |qm_yx| + |qm_yy|) * POSITION_PRECISION. | |
562 | ||
563 | // Quantization steps (ACCURACY ~ 2 * POSITION_PRECISION): | |
564 | // D(m_zx) ~ POSITION_PRECISION * z0^2 / max(x_lim, y_lim) / dx ~= q_zx = q_x / w, | |
565 | // D(m_zy) ~ POSITION_PRECISION * z0^2 / max(x_lim, y_lim) / dy ~= q_zy = q_y / w, | |
566 | // qm_zx = round(m_zx / q_zx), qm_zy = round(m_zy / q_zy). | |
567 | ||
568 | int32_t qmx = abs(qm[0][0]) + abs(qm[0][1]); | |
569 | int32_t qmy = abs(qm[1][0]) + abs(qm[1][1]); | |
570 | w = POSITION_PRECISION * FFMAX(qmx, qmy); | |
571 | mul[0] *= w; | |
572 | mul[1] *= w; | |
573 | ||
574 | for (int j = 0; j < 2; j++) { | |
575 | double val = m[2][j] * mul[j]; | |
576 | if (!(fabs(val) < max_val)) | |
577 | return false; | |
578 | qm[2][j] = lrint(val); | |
579 | } | |
580 | ||
581 | if (first && offset) { | |
582 | offset->x = center[0] - qr[0]; | |
583 | offset->y = center[1] - qr[1]; | |
584 | } | |
585 | pos->x = qr[0] >> SUBPIXEL_ORDER; | |
586 | pos->y = qr[1] >> SUBPIXEL_ORDER; | |
587 | key->offset.x = qr[0] & ((1 << SUBPIXEL_ORDER) - 1); | |
588 | key->offset.y = qr[1] & ((1 << SUBPIXEL_ORDER) - 1); | |
589 | key->matrix_x.x = qm[0][0]; key->matrix_x.y = qm[0][1]; | |
590 | key->matrix_y.x = qm[1][0]; key->matrix_y.y = qm[1][1]; | |
591 | key->matrix_z.x = qm[2][0]; key->matrix_z.y = qm[2][1]; | |
592 | return true; | |
593 | } | |
594 | ||
595 | static void restore_transform(double m[3][3], const BitmapHashKey *key) | |
596 | { | |
597 | const ASS_Rect *bbox = &key->outline->cbox; | |
598 | double x0 = (bbox->x_min + bbox->x_max) / 2.0; | |
599 | double y0 = (bbox->y_min + bbox->y_max) / 2.0; | |
600 | double dx = (bbox->x_max - bbox->x_min) / 2.0 + 64; | |
601 | double dy = (bbox->y_max - bbox->y_min) / 2.0 + 64; | |
602 | ||
603 | // Arbitrary scale has chosen so that z0 = 1 | |
604 | double q_x = POSITION_PRECISION / dx; | |
605 | double q_y = POSITION_PRECISION / dy; | |
606 | m[0][0] = key->matrix_x.x * q_x; | |
607 | m[0][1] = key->matrix_x.y * q_y; | |
608 | m[1][0] = key->matrix_y.x * q_x; | |
609 | m[1][1] = key->matrix_y.y * q_y; | |
610 | ||
611 | int32_t qmx = abs(key->matrix_x.x) + abs(key->matrix_x.y); | |
612 | int32_t qmy = abs(key->matrix_y.x) + abs(key->matrix_y.y); | |
613 | double scale_z = 1.0 / POSITION_PRECISION / FFMAX(qmx, qmy); | |
614 | m[2][0] = key->matrix_z.x * q_x * scale_z; // qm_zx * q_zx | |
615 | m[2][1] = key->matrix_z.y * q_y * scale_z; // qm_zy * q_zy | |
616 | ||
617 | m[0][2] = m[1][2] = 0; | |
618 | m[2][2] = 1 + fabs(m[2][0]) * dx + fabs(m[2][1]) * dy; | |
619 | m[2][2] = FFMIN(m[2][2], MAX_PERSP_SCALE); | |
620 | ||
621 | double center[2] = { | |
622 | key->offset.x * (64 >> SUBPIXEL_ORDER), | |
623 | key->offset.y * (64 >> SUBPIXEL_ORDER), | |
624 | }; | |
625 | for (int i = 0; i < 2; i++) | |
626 | for (int j = 0; j < 3; j++) | |
627 | m[i][j] += m[2][j] * center[i]; | |
628 | ||
629 | for (int i = 0; i < 3; i++) | |
630 | m[i][2] -= m[i][0] * x0 + m[i][1] * y0; | |
631 | } | |
632 | ||
444 | 633 | // Calculate bitmap memory footprint |
445 | static inline size_t bitmap_size(Bitmap *bm) | |
446 | { | |
447 | return bm ? sizeof(Bitmap) + bm->stride * bm->h : 0; | |
634 | static inline size_t bitmap_size(const Bitmap *bm) | |
635 | { | |
636 | return bm->stride * bm->h; | |
448 | 637 | } |
449 | 638 | |
450 | 639 | /** |
452 | 641 | * applicable. The blended bitmaps are added to a free list which is freed |
453 | 642 | * at the start of a new frame. |
454 | 643 | */ |
455 | static void blend_vector_clip(ASS_Renderer *render_priv, | |
456 | ASS_Image *head) | |
457 | { | |
458 | ASS_Drawing *drawing = render_priv->state.clip_drawing; | |
459 | if (!drawing) | |
644 | static void blend_vector_clip(ASS_Renderer *render_priv, ASS_Image *head) | |
645 | { | |
646 | if (!render_priv->state.clip_drawing_text) | |
460 | 647 | return; |
461 | 648 | |
462 | // Try to get mask from cache | |
649 | OutlineHashKey ol_key; | |
650 | ol_key.type = OUTLINE_DRAWING; | |
651 | ol_key.u.drawing.text = render_priv->state.clip_drawing_text; | |
652 | ||
653 | double m[3][3] = {{0}}; | |
654 | double w = render_priv->font_scale / (1 << (render_priv->state.clip_drawing_scale - 1)); | |
655 | m[0][0] = render_priv->font_scale_x * w; | |
656 | m[1][1] = w; | |
657 | m[2][2] = 1; | |
658 | ||
659 | m[0][2] = int_to_d6(render_priv->settings.left_margin); | |
660 | m[1][2] = int_to_d6(render_priv->settings.top_margin); | |
661 | ||
662 | ASS_Vector pos; | |
463 | 663 | BitmapHashKey key; |
464 | memset(&key, 0, sizeof(key)); | |
465 | key.type = BITMAP_CLIP; | |
466 | key.u.clip.text = drawing->text; | |
467 | ||
468 | BitmapHashValue *val; | |
469 | if (!ass_cache_get(render_priv->cache.bitmap_cache, &key, &val)) { | |
470 | if (!val) | |
471 | return; | |
472 | val->bm = val->bm_o = NULL; | |
473 | ||
474 | // Not found in cache, parse and rasterize it | |
475 | ASS_Outline *outline = ass_drawing_parse(drawing, true); | |
476 | if (!outline) { | |
477 | ass_msg(render_priv->library, MSGL_WARN, | |
478 | "Clip vector parsing failed. Skipping."); | |
479 | ass_cache_commit(val, sizeof(BitmapHashKey) + sizeof(BitmapHashValue)); | |
480 | ass_cache_dec_ref(val); | |
481 | return; | |
482 | } | |
483 | ||
484 | // We need to translate the clip according to screen borders | |
485 | if (render_priv->settings.left_margin != 0 || | |
486 | render_priv->settings.top_margin != 0) { | |
487 | ASS_Vector trans = { | |
488 | .x = int_to_d6(render_priv->settings.left_margin), | |
489 | .y = int_to_d6(render_priv->settings.top_margin), | |
490 | }; | |
491 | outline_translate(outline, trans.x, trans.y); | |
492 | } | |
493 | ||
494 | val->bm = outline_to_bitmap(render_priv, outline, NULL, 1); | |
495 | ass_cache_commit(val, bitmap_size(val->bm) + | |
496 | sizeof(BitmapHashKey) + sizeof(BitmapHashValue)); | |
497 | } | |
498 | ||
499 | Bitmap *clip_bm = val->bm; | |
500 | if (!clip_bm) { | |
501 | ass_cache_dec_ref(val); | |
664 | key.outline = ass_cache_get(render_priv->cache.outline_cache, &ol_key, render_priv); | |
665 | if (!key.outline || !key.outline->valid || | |
666 | !quantize_transform(m, &pos, NULL, true, &key)) { | |
667 | ass_cache_dec_ref(key.outline); | |
668 | return; | |
669 | } | |
670 | Bitmap *clip_bm = ass_cache_get(render_priv->cache.bitmap_cache, &key, render_priv); | |
671 | if (!clip_bm || !clip_bm->buffer) { | |
672 | ass_cache_dec_ref(clip_bm); | |
502 | 673 | return; |
503 | 674 | } |
504 | 675 | |
517 | 688 | aw = cur->w; |
518 | 689 | ah = cur->h; |
519 | 690 | as = cur->stride; |
520 | bx = clip_bm->left; | |
521 | by = clip_bm->top; | |
691 | bx = pos.x + clip_bm->left; | |
692 | by = pos.y + clip_bm->top; | |
522 | 693 | bw = clip_bm->w; |
523 | 694 | bh = clip_bm->h; |
524 | 695 | bs = clip_bm->stride; |
579 | 750 | cur->stride = ns; |
580 | 751 | } |
581 | 752 | |
582 | cur->bitmap = nbuffer; | |
583 | 753 | ASS_ImagePriv *priv = (ASS_ImagePriv *) cur; |
754 | priv->buffer = cur->bitmap = nbuffer; | |
584 | 755 | ass_cache_dec_ref(priv->source); |
585 | 756 | priv->source = NULL; |
586 | 757 | } |
587 | 758 | |
588 | ass_cache_dec_ref(val); | |
759 | ass_cache_dec_ref(clip_bm); | |
589 | 760 | } |
590 | 761 | |
591 | 762 | /** |
615 | 786 | continue; |
616 | 787 | |
617 | 788 | if ((info->effect_type == EF_KARAOKE_KO) |
618 | && (info->effect_timing <= info->first_pos_x)) { | |
789 | && (info->effect_timing <= 0)) { | |
619 | 790 | // do nothing |
620 | 791 | } else { |
621 | 792 | tail = |
631 | 802 | |
632 | 803 | if ((info->effect_type == EF_KARAOKE) |
633 | 804 | || (info->effect_type == EF_KARAOKE_KO)) { |
634 | if (info->effect_timing > info->first_pos_x) | |
805 | if (info->effect_timing > 0) | |
635 | 806 | tail = |
636 | 807 | render_glyph(render_priv, info->bm, info->x, info->y, |
637 | 808 | info->c[0], 0, 1000000, tail, |
690 | 861 | // The user style was set with ass_set_selective_style_override(). |
691 | 862 | ASS_Style *user = &render_priv->user_override_style; |
692 | 863 | ASS_Style *new = &render_priv->state.override_style_temp_storage; |
693 | int explicit = event_has_hard_overrides(render_priv->state.event->Text) || | |
694 | render_priv->state.evt_type != EVENT_NORMAL; | |
864 | int explicit = render_priv->state.explicit; | |
695 | 865 | int requested = render_priv->settings.selective_style_overrides; |
696 | 866 | double scale; |
697 | 867 | |
705 | 875 | // user_style (the user's override style). Copy only fields from the |
706 | 876 | // script's style that are deemed necessary. |
707 | 877 | *new = *rstyle; |
708 | ||
709 | render_priv->state.explicit = explicit; | |
710 | 878 | |
711 | 879 | render_priv->state.apply_font_scale = |
712 | 880 | !explicit || !(requested & ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE); |
788 | 956 | { |
789 | 957 | ASS_Settings *settings_priv = &render_priv->settings; |
790 | 958 | |
791 | render_priv->font_scale = ((double) render_priv->orig_height) / | |
792 | render_priv->track->PlayResY; | |
959 | double font_scr_h = render_priv->orig_height; | |
960 | if (!render_priv->state.explicit && render_priv->settings.use_margins) | |
961 | font_scr_h = render_priv->fit_height; | |
962 | ||
963 | render_priv->font_scale = font_scr_h / render_priv->track->PlayResY; | |
793 | 964 | if (settings_priv->storage_height) |
794 | render_priv->blur_scale = ((double) render_priv->orig_height) / | |
795 | settings_priv->storage_height; | |
965 | render_priv->blur_scale = font_scr_h / settings_priv->storage_height; | |
796 | 966 | else |
797 | render_priv->blur_scale = 1.; | |
967 | render_priv->blur_scale = font_scr_h / render_priv->track->PlayResY; | |
798 | 968 | if (render_priv->track->ScaledBorderAndShadow) |
799 | 969 | render_priv->border_scale = |
800 | ((double) render_priv->orig_height) / | |
801 | render_priv->track->PlayResY; | |
970 | font_scr_h / render_priv->track->PlayResY; | |
802 | 971 | else |
803 | 972 | render_priv->border_scale = render_priv->blur_scale; |
804 | if (!settings_priv->storage_height) | |
805 | render_priv->blur_scale = render_priv->border_scale; | |
806 | 973 | |
807 | 974 | if (render_priv->state.apply_font_scale) { |
808 | 975 | render_priv->font_scale *= settings_priv->font_size_coeff; |
830 | 997 | (style->StrikeOut ? DECO_STRIKETHROUGH : 0); |
831 | 998 | render_priv->state.font_size = style->FontSize; |
832 | 999 | |
833 | free(render_priv->state.family); | |
834 | render_priv->state.family = NULL; | |
835 | render_priv->state.family = strdup(style->FontName); | |
836 | render_priv->state.treat_family_as_pattern = | |
837 | style->treat_fontname_as_pattern; | |
1000 | char* new_family = strdup(style->FontName); | |
1001 | if (new_family) { | |
1002 | free(render_priv->state.family); | |
1003 | render_priv->state.family = new_family; | |
1004 | render_priv->state.treat_family_as_pattern = | |
1005 | style->treat_fontname_as_pattern; | |
1006 | } | |
838 | 1007 | render_priv->state.bold = style->Bold; |
839 | 1008 | render_priv->state.italic = style->Italic; |
840 | 1009 | update_font(render_priv); |
850 | 1019 | render_priv->state.shadow_x = style->Shadow; |
851 | 1020 | render_priv->state.shadow_y = style->Shadow; |
852 | 1021 | render_priv->state.frx = render_priv->state.fry = 0.; |
853 | render_priv->state.frz = M_PI * style->Angle / 180.; | |
1022 | render_priv->state.frz = style->Angle; | |
854 | 1023 | render_priv->state.fax = render_priv->state.fay = 0.; |
855 | 1024 | render_priv->state.font_encoding = style->Encoding; |
856 | 1025 | } |
865 | 1034 | render_priv->state.parsed_tags = 0; |
866 | 1035 | render_priv->state.evt_type = EVENT_NORMAL; |
867 | 1036 | |
868 | reset_render_context(render_priv, NULL); | |
869 | 1037 | render_priv->state.wrap_style = render_priv->track->WrapStyle; |
870 | 1038 | |
871 | render_priv->state.alignment = render_priv->state.style->Alignment; | |
872 | render_priv->state.justify = render_priv->state.style->Justify; | |
873 | 1039 | render_priv->state.pos_x = 0; |
874 | 1040 | render_priv->state.pos_y = 0; |
875 | 1041 | render_priv->state.org_x = 0; |
889 | 1055 | render_priv->state.effect_skip_timing = 0; |
890 | 1056 | |
891 | 1057 | apply_transition_effects(render_priv, event); |
1058 | render_priv->state.explicit = render_priv->state.evt_type != EVENT_NORMAL || | |
1059 | event_has_hard_overrides(event->Text); | |
1060 | ||
1061 | reset_render_context(render_priv, NULL); | |
1062 | render_priv->state.alignment = render_priv->state.style->Alignment; | |
1063 | render_priv->state.justify = render_priv->state.style->Justify; | |
892 | 1064 | } |
893 | 1065 | |
894 | 1066 | static void free_render_context(ASS_Renderer *render_priv) |
895 | 1067 | { |
896 | 1068 | ass_cache_dec_ref(render_priv->state.font); |
897 | 1069 | free(render_priv->state.family); |
898 | ass_drawing_free(render_priv->state.clip_drawing); | |
1070 | free(render_priv->state.clip_drawing_text); | |
899 | 1071 | |
900 | 1072 | render_priv->state.font = NULL; |
901 | 1073 | render_priv->state.family = NULL; |
902 | render_priv->state.clip_drawing = NULL; | |
1074 | render_priv->state.clip_drawing_text = NULL; | |
903 | 1075 | |
904 | 1076 | TextInfo *text_info = &render_priv->text_info; |
905 | 1077 | for (int n = 0; n < text_info->length; n++) |
906 | ass_drawing_free(text_info->glyphs[n].drawing); | |
1078 | free(text_info->glyphs[n].drawing_text); | |
907 | 1079 | text_info->length = 0; |
908 | } | |
909 | ||
910 | /* | |
911 | * Replace the outline of a glyph by a contour which makes up a simple | |
912 | * opaque rectangle. | |
913 | */ | |
914 | static void draw_opaque_box(ASS_Renderer *render_priv, GlyphInfo *info, | |
915 | int asc, int desc, ASS_Outline *ol, | |
916 | ASS_Vector advance, int sx, int sy) | |
917 | { | |
918 | int adv = advance.x; | |
919 | double scale_y = info->orig_scale_y; | |
920 | double scale_x = info->orig_scale_x; | |
921 | ||
922 | // to avoid gaps | |
923 | sx = FFMAX(64, sx); | |
924 | sy = FFMAX(64, sy); | |
925 | ||
926 | // Emulate the WTFish behavior of VSFilter, i.e. double-scale | |
927 | // the sizes of the opaque box. | |
928 | adv += double_to_d6(info->hspacing * render_priv->font_scale * scale_x); | |
929 | adv *= scale_x; | |
930 | sx *= scale_x; | |
931 | sy *= scale_y; | |
932 | desc *= scale_y; | |
933 | desc += asc * (scale_y - 1.0); | |
934 | ||
935 | ASS_Vector points[4] = { | |
936 | { .x = -sx, .y = -asc - sy }, | |
937 | { .x = adv + sx, .y = -asc - sy }, | |
938 | { .x = adv + sx, .y = desc + sy }, | |
939 | { .x = -sx, .y = desc + sy }, | |
940 | }; | |
941 | ||
942 | const char segments[4] = { | |
943 | OUTLINE_LINE_SEGMENT, | |
944 | OUTLINE_LINE_SEGMENT, | |
945 | OUTLINE_LINE_SEGMENT, | |
946 | OUTLINE_LINE_SEGMENT | OUTLINE_CONTOUR_END | |
947 | }; | |
948 | ||
949 | ol->n_points = ol->n_segments = 0; | |
950 | if (!outline_alloc(ol, 4, 4)) | |
951 | return; | |
952 | for (int i = 0; i < 4; i++) { | |
953 | ol->points[ol->n_points++] = points[i]; | |
954 | ol->segments[ol->n_segments++] = segments[i]; | |
955 | } | |
956 | } | |
957 | ||
958 | /** | |
959 | * \brief Prepare glyph hash | |
960 | */ | |
961 | static void | |
962 | fill_glyph_hash(ASS_Renderer *priv, OutlineHashKey *outline_key, | |
963 | GlyphInfo *info) | |
964 | { | |
965 | if (info->drawing) { | |
966 | DrawingHashKey *key = &outline_key->u.drawing; | |
967 | outline_key->type = OUTLINE_DRAWING; | |
968 | key->scale_x = double_to_d16(info->scale_x); | |
969 | key->scale_y = double_to_d16(info->scale_y); | |
970 | key->outline.x = double_to_d6(info->border_x * priv->border_scale); | |
971 | key->outline.y = double_to_d6(info->border_y * priv->border_scale); | |
972 | key->border_style = info->border_style; | |
973 | // hpacing only matters for opaque box borders (see draw_opaque_box), | |
974 | // so for normal borders, maximize cache utility by ignoring it | |
975 | key->hspacing = | |
976 | info->border_style == 3 ? double_to_d16(info->hspacing) : 0; | |
977 | key->hash = info->drawing->hash; | |
978 | key->text = info->drawing->text; | |
979 | key->pbo = info->drawing->pbo; | |
980 | key->scale = info->drawing->scale; | |
981 | } else { | |
982 | GlyphHashKey *key = &outline_key->u.glyph; | |
983 | outline_key->type = OUTLINE_GLYPH; | |
984 | key->font = info->font; | |
985 | key->size = info->font_size; | |
986 | key->face_index = info->face_index; | |
987 | key->glyph_index = info->glyph_index; | |
988 | key->bold = info->bold; | |
989 | key->italic = info->italic; | |
990 | key->scale_x = double_to_d16(info->scale_x); | |
991 | key->scale_y = double_to_d16(info->scale_y); | |
992 | key->outline.x = double_to_d6(info->border_x * priv->border_scale); | |
993 | key->outline.y = double_to_d6(info->border_y * priv->border_scale); | |
994 | key->flags = info->flags; | |
995 | key->border_style = info->border_style; | |
996 | key->hspacing = | |
997 | info->border_style == 3 ? double_to_d16(info->hspacing) : 0; | |
998 | } | |
999 | } | |
1000 | ||
1001 | /** | |
1002 | * \brief Prepare combined-bitmap hash | |
1003 | */ | |
1004 | static void fill_composite_hash(CompositeHashKey *hk, CombinedBitmapInfo *info) | |
1005 | { | |
1006 | hk->filter = info->filter; | |
1007 | hk->bitmap_count = info->bitmap_count; | |
1008 | hk->bitmaps = info->bitmaps; | |
1009 | 1080 | } |
1010 | 1081 | |
1011 | 1082 | /** |
1014 | 1085 | * Tries to get both glyphs from cache. |
1015 | 1086 | * If they can't be found, gets a glyph from font face, generates outline, |
1016 | 1087 | * and add them to cache. |
1017 | * The glyphs are returned in info->glyph and info->outline_glyph | |
1018 | 1088 | */ |
1019 | 1089 | static void |
1020 | 1090 | get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info) |
1021 | 1091 | { |
1022 | memset(&info->hash_key, 0, sizeof(info->hash_key)); | |
1023 | ||
1092 | OutlineHashValue *val; | |
1093 | ASS_DVector scale, offset = {0}; | |
1094 | ||
1095 | int32_t asc, desc; | |
1024 | 1096 | OutlineHashKey key; |
1025 | OutlineHashValue *val; | |
1026 | fill_glyph_hash(priv, &key, info); | |
1027 | if (!ass_cache_get(priv->cache.outline_cache, &key, &val)) { | |
1028 | if (!val) | |
1097 | if (info->drawing_text) { | |
1098 | key.type = OUTLINE_DRAWING; | |
1099 | key.u.drawing.text = info->drawing_text; | |
1100 | val = ass_cache_get(priv->cache.outline_cache, &key, priv); | |
1101 | if (!val || !val->valid) { | |
1102 | ass_cache_dec_ref(val); | |
1029 | 1103 | return; |
1030 | memset(val, 0, sizeof(*val)); | |
1031 | ||
1032 | if (info->drawing) { | |
1033 | ASS_Drawing *drawing = info->drawing; | |
1034 | ass_drawing_hash(drawing); | |
1035 | if(!ass_drawing_parse(drawing, false) || | |
1036 | !outline_copy(&val->outline, &drawing->outline)) { | |
1037 | ass_cache_commit(val, 1); | |
1038 | ass_cache_dec_ref(val); | |
1039 | return; | |
1040 | } | |
1041 | val->advance.x = drawing->advance.x; | |
1042 | val->advance.y = drawing->advance.y; | |
1043 | val->asc = drawing->asc; | |
1044 | val->desc = drawing->desc; | |
1045 | } else { | |
1046 | ass_face_set_size(info->font->faces[info->face_index], | |
1047 | info->font_size); | |
1048 | ass_font_set_transform(info->font, info->scale_x, | |
1049 | info->scale_y, NULL); | |
1104 | } | |
1105 | ||
1106 | double w = priv->font_scale / (1 << (info->drawing_scale - 1)); | |
1107 | scale.x = info->scale_x * w; | |
1108 | scale.y = info->scale_y * w; | |
1109 | desc = 64 * info->drawing_pbo; | |
1110 | asc = val->asc - desc; | |
1111 | ||
1112 | offset.y = -asc * scale.y; | |
1113 | } else { | |
1114 | key.type = OUTLINE_GLYPH; | |
1115 | GlyphHashKey *k = &key.u.glyph; | |
1116 | k->font = info->font; | |
1117 | k->size = info->font_size; | |
1118 | k->face_index = info->face_index; | |
1119 | k->glyph_index = info->glyph_index; | |
1120 | k->bold = info->bold; | |
1121 | k->italic = info->italic; | |
1122 | k->flags = info->flags; | |
1123 | ||
1124 | val = ass_cache_get(priv->cache.outline_cache, &key, priv); | |
1125 | if (!val || !val->valid) { | |
1126 | ass_cache_dec_ref(val); | |
1127 | return; | |
1128 | } | |
1129 | ||
1130 | scale.x = info->scale_x; | |
1131 | scale.y = info->scale_y; | |
1132 | asc = val->asc; | |
1133 | desc = val->desc; | |
1134 | } | |
1135 | ||
1136 | info->outline = val; | |
1137 | info->transform.scale = scale; | |
1138 | info->transform.offset = offset; | |
1139 | ||
1140 | info->bbox.x_min = lrint(val->cbox.x_min * scale.x + offset.x); | |
1141 | info->bbox.y_min = lrint(val->cbox.y_min * scale.y + offset.y); | |
1142 | info->bbox.x_max = lrint(val->cbox.x_max * scale.x + offset.x); | |
1143 | info->bbox.y_max = lrint(val->cbox.y_max * scale.y + offset.y); | |
1144 | ||
1145 | if (info->drawing_text || priv->settings.shaper == ASS_SHAPING_SIMPLE) { | |
1146 | info->cluster_advance.x = info->advance.x = lrint(val->advance * scale.x); | |
1147 | info->cluster_advance.y = info->advance.y = 0; | |
1148 | } | |
1149 | info->asc = lrint(asc * scale.y); | |
1150 | info->desc = lrint(desc * scale.y); | |
1151 | } | |
1152 | ||
1153 | size_t ass_outline_construct(void *key, void *value, void *priv) | |
1154 | { | |
1155 | ASS_Renderer *render_priv = priv; | |
1156 | OutlineHashKey *outline_key = key; | |
1157 | OutlineHashValue *v = value; | |
1158 | memset(v, 0, sizeof(*v)); | |
1159 | ||
1160 | switch (outline_key->type) { | |
1161 | case OUTLINE_GLYPH: | |
1162 | { | |
1163 | GlyphHashKey *k = &outline_key->u.glyph; | |
1164 | ass_face_set_size(k->font->faces[k->face_index], k->size); | |
1050 | 1165 | FT_Glyph glyph = |
1051 | ass_font_get_glyph(info->font, | |
1052 | info->symbol, info->face_index, info->glyph_index, | |
1053 | priv->settings.hinting, info->flags); | |
1166 | ass_font_get_glyph(k->font, k->face_index, k->glyph_index, | |
1167 | render_priv->settings.hinting, k->flags); | |
1054 | 1168 | if (glyph != NULL) { |
1055 | 1169 | FT_Outline *src = &((FT_OutlineGlyph) glyph)->outline; |
1056 | if (!outline_convert(&val->outline, src)) { | |
1057 | ass_cache_commit(val, 1); | |
1058 | ass_cache_dec_ref(val); | |
1059 | return; | |
1060 | } | |
1061 | if (priv->settings.shaper == ASS_SHAPING_SIMPLE) { | |
1062 | val->advance.x = d16_to_d6(glyph->advance.x); | |
1063 | val->advance.y = d16_to_d6(glyph->advance.y); | |
1064 | } | |
1170 | if (!outline_convert(&v->outline[0], src)) | |
1171 | return 1; | |
1172 | v->advance = d16_to_d6(glyph->advance.x); | |
1065 | 1173 | FT_Done_Glyph(glyph); |
1066 | ass_font_get_asc_desc(info->font, info->symbol, | |
1067 | &val->asc, &val->desc); | |
1068 | val->asc *= info->scale_y; | |
1069 | val->desc *= info->scale_y; | |
1174 | ass_font_get_asc_desc(k->font, k->face_index, | |
1175 | &v->asc, &v->desc); | |
1070 | 1176 | } |
1071 | } | |
1072 | val->valid = true; | |
1073 | ||
1074 | outline_get_cbox(&val->outline, &val->bbox_scaled); | |
1075 | ||
1076 | if (info->border_style == 3) { | |
1077 | ASS_Vector advance; | |
1078 | if (priv->settings.shaper == ASS_SHAPING_SIMPLE || info->drawing) | |
1079 | advance = val->advance; | |
1080 | else | |
1081 | advance = info->advance; | |
1082 | ||
1083 | draw_opaque_box(priv, info, val->asc, val->desc, &val->border[0], advance, | |
1084 | double_to_d6(info->border_x * priv->border_scale), | |
1085 | double_to_d6(info->border_y * priv->border_scale)); | |
1086 | ||
1087 | } else if (val->outline.n_points && (info->border_x > 0 || info->border_y > 0) | |
1088 | && double_to_d6(info->scale_x) && double_to_d6(info->scale_y)) { | |
1089 | const int eps = 16; | |
1090 | int xbord = double_to_d6(info->border_x * priv->border_scale); | |
1091 | int ybord = double_to_d6(info->border_y * priv->border_scale); | |
1092 | if(xbord >= eps || ybord >= eps) { | |
1093 | outline_alloc(&val->border[0], 2 * val->outline.n_points, 2 * val->outline.n_segments); | |
1094 | outline_alloc(&val->border[1], 2 * val->outline.n_points, 2 * val->outline.n_segments); | |
1095 | if (!val->border[0].max_points || !val->border[1].max_points || | |
1096 | !outline_stroke(&val->border[0], &val->border[1], | |
1097 | &val->outline, xbord, ybord, eps)) { | |
1098 | ass_msg(priv->library, MSGL_WARN, "Cannot stoke outline"); | |
1099 | outline_free(&val->border[0]); | |
1100 | outline_free(&val->border[1]); | |
1101 | } | |
1177 | break; | |
1178 | } | |
1179 | case OUTLINE_DRAWING: | |
1180 | { | |
1181 | ASS_Rect bbox; | |
1182 | const char *text = outline_key->u.drawing.text; | |
1183 | if (!ass_drawing_parse(&v->outline[0], &bbox, text, render_priv->library)) | |
1184 | return 1; | |
1185 | ||
1186 | v->advance = bbox.x_max - bbox.x_min; | |
1187 | v->asc = bbox.y_max - bbox.y_min; | |
1188 | v->desc = 0; | |
1189 | break; | |
1190 | } | |
1191 | case OUTLINE_BORDER: | |
1192 | { | |
1193 | BorderHashKey *k = &outline_key->u.border; | |
1194 | if (!k->border.x && !k->border.y) | |
1195 | break; | |
1196 | if (!k->outline->outline[0].n_points) | |
1197 | break; | |
1198 | ||
1199 | ASS_Outline src; | |
1200 | if (!outline_scale_pow2(&src, &k->outline->outline[0], | |
1201 | k->scale_ord_x, k->scale_ord_y)) | |
1202 | return 1; | |
1203 | if (!outline_stroke(&v->outline[0], &v->outline[1], &src, | |
1204 | k->border.x * STROKER_PRECISION, | |
1205 | k->border.y * STROKER_PRECISION, | |
1206 | STROKER_PRECISION)) { | |
1207 | ass_msg(render_priv->library, MSGL_WARN, "Cannot stroke outline"); | |
1208 | outline_free(&v->outline[0]); | |
1209 | outline_free(&v->outline[1]); | |
1210 | outline_free(&src); | |
1211 | return 1; | |
1102 | 1212 | } |
1103 | } | |
1104 | ||
1105 | ass_cache_commit(val, 1); | |
1106 | } else if (!val->valid) { | |
1107 | ass_cache_dec_ref(val); | |
1108 | return; | |
1109 | } | |
1110 | ||
1111 | info->hash_key.u.outline.outline = val; | |
1112 | info->outline = &val->outline; | |
1113 | info->border[0] = &val->border[0]; | |
1114 | info->border[1] = &val->border[1]; | |
1115 | info->bbox = val->bbox_scaled; | |
1116 | if (info->drawing || priv->settings.shaper == ASS_SHAPING_SIMPLE) { | |
1117 | info->cluster_advance.x = info->advance.x = val->advance.x; | |
1118 | info->cluster_advance.y = info->advance.y = val->advance.y; | |
1119 | } | |
1120 | info->asc = val->asc; | |
1121 | info->desc = val->desc; | |
1213 | outline_free(&src); | |
1214 | break; | |
1215 | } | |
1216 | case OUTLINE_BOX: | |
1217 | { | |
1218 | ASS_Outline *ol = &v->outline[0]; | |
1219 | if (!outline_alloc(ol, 4, 4)) | |
1220 | return 1; | |
1221 | ol->points[0].x = ol->points[3].x = 0; | |
1222 | ol->points[1].x = ol->points[2].x = 64; | |
1223 | ol->points[0].y = ol->points[1].y = 0; | |
1224 | ol->points[2].y = ol->points[3].y = 64; | |
1225 | ol->segments[0] = OUTLINE_LINE_SEGMENT; | |
1226 | ol->segments[1] = OUTLINE_LINE_SEGMENT; | |
1227 | ol->segments[2] = OUTLINE_LINE_SEGMENT; | |
1228 | ol->segments[3] = OUTLINE_LINE_SEGMENT | OUTLINE_CONTOUR_END; | |
1229 | ol->n_points = ol->n_segments = 4; | |
1230 | break; | |
1231 | } | |
1232 | default: | |
1233 | return 1; | |
1234 | } | |
1235 | ||
1236 | rectangle_reset(&v->cbox); | |
1237 | outline_update_cbox(&v->outline[0], &v->cbox); | |
1238 | outline_update_cbox(&v->outline[1], &v->cbox); | |
1239 | if (v->cbox.x_min > v->cbox.x_max || v->cbox.y_min > v->cbox.y_max) | |
1240 | v->cbox.x_min = v->cbox.y_min = v->cbox.x_max = v->cbox.y_max = 0; | |
1241 | v->valid = true; | |
1242 | return 1; | |
1122 | 1243 | } |
1123 | 1244 | |
1124 | 1245 | /** |
1125 | * \brief Calculate transform matrix for transform_3d() | |
1246 | * \brief Calculate outline transformation matrix | |
1126 | 1247 | */ |
1127 | static void | |
1128 | calc_transform_matrix(ASS_Vector shift, | |
1129 | double frx, double fry, double frz, | |
1130 | double fax, double fay, double scale, | |
1131 | int yshift, double m[3][3]) | |
1132 | { | |
1248 | static void calc_transform_matrix(ASS_Renderer *render_priv, | |
1249 | GlyphInfo *info, double m[3][3]) | |
1250 | { | |
1251 | double frx = M_PI / 180 * info->frx; | |
1252 | double fry = M_PI / 180 * info->fry; | |
1253 | double frz = M_PI / 180 * info->frz; | |
1254 | ||
1133 | 1255 | double sx = -sin(frx), cx = cos(frx); |
1134 | 1256 | double sy = sin(fry), cy = cos(fry); |
1135 | 1257 | double sz = -sin(frz), cz = cos(frz); |
1136 | 1258 | |
1137 | double x1[3] = { 1, fax, shift.x + fax * yshift }; | |
1138 | double y1[3] = { fay, 1, shift.y }; | |
1259 | double fax = info->fax * info->scale_x / info->scale_y; | |
1260 | double fay = info->fay * info->scale_y / info->scale_x; | |
1261 | double x1[3] = { 1, fax, info->shift.x + info->asc * fax }; | |
1262 | double y1[3] = { fay, 1, info->shift.y }; | |
1139 | 1263 | |
1140 | 1264 | double x2[3], y2[3]; |
1141 | 1265 | for (int i = 0; i < 3; i++) { |
1155 | 1279 | z4[i] = x2[i] * sy + z3[i] * cy; |
1156 | 1280 | } |
1157 | 1281 | |
1158 | double dist = 20000 * scale; | |
1282 | double dist = 20000 * render_priv->blur_scale; | |
1283 | z4[2] += dist; | |
1284 | ||
1285 | double scale_x = dist * render_priv->font_scale_x; | |
1286 | double offs_x = info->pos.x - info->shift.x * render_priv->font_scale_x; | |
1287 | double offs_y = info->pos.y - info->shift.y; | |
1159 | 1288 | for (int i = 0; i < 3; i++) { |
1160 | m[0][i] = x4[i] * dist; | |
1161 | m[1][i] = y3[i] * dist; | |
1289 | m[0][i] = z4[i] * offs_x + x4[i] * scale_x; | |
1290 | m[1][i] = z4[i] * offs_y + y3[i] * dist; | |
1162 | 1291 | m[2][i] = z4[i]; |
1163 | } | |
1164 | m[2][2] += dist; | |
1165 | } | |
1166 | ||
1167 | /** | |
1168 | * \brief Apply 3d transformation to several objects | |
1169 | * \param shift FreeType vector | |
1170 | * \param glyph FreeType glyph | |
1171 | * \param glyph2 FreeType glyph | |
1172 | * \param frx x-axis rotation angle | |
1173 | * \param fry y-axis rotation angle | |
1174 | * \param frz z-axis rotation angle | |
1175 | * Rotates both glyphs by frx, fry and frz. Shift vector is added before rotation and subtracted after it. | |
1176 | */ | |
1177 | static void | |
1178 | transform_3d(ASS_Vector shift, ASS_Outline *outline, int n_outlines, | |
1179 | double frx, double fry, double frz, double fax, double fay, | |
1180 | double scale, int yshift) | |
1181 | { | |
1182 | if (frx == 0 && fry == 0 && frz == 0 && fax == 0 && fay == 0) | |
1183 | return; | |
1184 | ||
1185 | double m[3][3]; | |
1186 | calc_transform_matrix(shift, frx, fry, frz, fax, fay, scale, yshift, m); | |
1187 | ||
1188 | for (int i = 0; i < n_outlines; i++) { | |
1189 | ASS_Vector *p = outline[i].points; | |
1190 | for (size_t j = 0; j < outline[i].n_points; ++j) { | |
1191 | double v[3]; | |
1192 | for (int k = 0; k < 3; k++) | |
1193 | v[k] = m[k][0] * p[j].x + m[k][1] * p[j].y + m[k][2]; | |
1194 | ||
1195 | double w = 1 / FFMAX(v[2], 1000); | |
1196 | p[j].x = lrint(v[0] * w) - shift.x; | |
1197 | p[j].y = lrint(v[1] * w) - shift.y; | |
1198 | } | |
1199 | 1292 | } |
1200 | 1293 | } |
1201 | 1294 | |
1205 | 1298 | * Tries to get glyph bitmaps from bitmap cache. |
1206 | 1299 | * If they can't be found, they are generated by rotating and rendering the glyph. |
1207 | 1300 | * After that, bitmaps are added to the cache. |
1208 | * They are returned in info->bm (glyph), info->bm_o (outline) and info->bm_s (shadow). | |
1301 | * They are returned in info->bm (glyph), info->bm_o (outline). | |
1209 | 1302 | */ |
1210 | 1303 | static void |
1211 | get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info) | |
1212 | { | |
1213 | if (!info->outline || info->symbol == '\n' || info->symbol == 0 || info->skip) | |
1304 | get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info, | |
1305 | int32_t *leftmost_x, | |
1306 | ASS_Vector *pos, ASS_Vector *pos_o, | |
1307 | ASS_DVector *offset, bool first, int flags) | |
1308 | { | |
1309 | if (!info->outline || info->symbol == '\n' || info->symbol == 0 || info->skip) { | |
1310 | ass_cache_dec_ref(info->outline); | |
1214 | 1311 | return; |
1215 | ||
1216 | BitmapHashValue *val; | |
1217 | OutlineBitmapHashKey *key = &info->hash_key.u.outline; | |
1218 | if (ass_cache_get(render_priv->cache.bitmap_cache, &info->hash_key, &val)) { | |
1219 | info->image = val; | |
1220 | if (!val->valid) | |
1221 | info->symbol = 0; | |
1312 | } | |
1313 | ||
1314 | double m1[3][3], m2[3][3], m[3][3]; | |
1315 | const ASS_Transform *tr = &info->transform; | |
1316 | calc_transform_matrix(render_priv, info, m1); | |
1317 | for (int i = 0; i < 3; i++) { | |
1318 | m2[i][0] = m1[i][0] * tr->scale.x; | |
1319 | m2[i][1] = m1[i][1] * tr->scale.y; | |
1320 | m2[i][2] = m1[i][0] * tr->offset.x + m1[i][1] * tr->offset.y + m1[i][2]; | |
1321 | } | |
1322 | memcpy(m, m2, sizeof(m)); | |
1323 | ||
1324 | if (info->effect_type == EF_KARAOKE_KF) | |
1325 | outline_update_min_transformed_x(&info->outline->outline[0], m, leftmost_x); | |
1326 | ||
1327 | BitmapHashKey key; | |
1328 | key.outline = info->outline; | |
1329 | if (!quantize_transform(m, pos, offset, first, &key)) { | |
1330 | ass_cache_dec_ref(info->outline); | |
1222 | 1331 | return; |
1223 | 1332 | } |
1224 | if (!val) { | |
1225 | info->symbol = 0; | |
1333 | info->bm = ass_cache_get(render_priv->cache.bitmap_cache, &key, render_priv); | |
1334 | if (!info->bm || !info->bm->buffer) { | |
1335 | ass_cache_dec_ref(info->bm); | |
1336 | info->bm = NULL; | |
1337 | } | |
1338 | *pos_o = *pos; | |
1339 | ||
1340 | OutlineHashKey ol_key; | |
1341 | if (flags & FILTER_BORDER_STYLE_3) { | |
1342 | if (!(flags & (FILTER_NONZERO_BORDER | FILTER_NONZERO_SHADOW))) | |
1343 | return; | |
1344 | ||
1345 | ol_key.type = OUTLINE_BOX; | |
1346 | ||
1347 | double w = 64 * render_priv->border_scale; | |
1348 | ASS_DVector bord = { info->border_x * w, info->border_y * w }; | |
1349 | double width = info->hspacing_scaled + info->advance.x; | |
1350 | double height = info->asc + info->desc; | |
1351 | ||
1352 | ASS_DVector orig_scale; | |
1353 | orig_scale.x = info->scale_x * info->scale_fix; | |
1354 | orig_scale.y = info->scale_y * info->scale_fix; | |
1355 | ||
1356 | // Emulate the WTFish behavior of VSFilter, i.e. double-scale | |
1357 | // the sizes of the opaque box. | |
1358 | bord.x *= orig_scale.x; | |
1359 | bord.y *= orig_scale.y; | |
1360 | width *= orig_scale.x; | |
1361 | height *= orig_scale.y; | |
1362 | ||
1363 | // to avoid gaps | |
1364 | bord.x = FFMAX(64, bord.x); | |
1365 | bord.y = FFMAX(64, bord.y); | |
1366 | ||
1367 | ASS_DVector scale = { | |
1368 | (width + 2 * bord.x) / 64, | |
1369 | (height + 2 * bord.y) / 64, | |
1370 | }; | |
1371 | ASS_DVector offset = { -bord.x, -bord.y - info->asc }; | |
1372 | for (int i = 0; i < 3; i++) { | |
1373 | m[i][0] = m1[i][0] * scale.x; | |
1374 | m[i][1] = m1[i][1] * scale.y; | |
1375 | m[i][2] = m1[i][0] * offset.x + m1[i][1] * offset.y + m1[i][2]; | |
1376 | } | |
1377 | } else { | |
1378 | if (!(flags & FILTER_NONZERO_BORDER)) | |
1379 | return; | |
1380 | ||
1381 | ol_key.type = OUTLINE_BORDER; | |
1382 | BorderHashKey *k = &ol_key.u.border; | |
1383 | k->outline = info->outline; | |
1384 | ||
1385 | double w = 64 * render_priv->border_scale; | |
1386 | double bord_x = w * info->border_x / tr->scale.x; | |
1387 | double bord_y = w * info->border_y / tr->scale.y; | |
1388 | ||
1389 | const ASS_Rect *bbox = &info->outline->cbox; | |
1390 | // Estimate bounding box half size after stroking | |
1391 | double dx = (bbox->x_max - bbox->x_min) / 2.0 + (bord_x + 64); | |
1392 | double dy = (bbox->y_max - bbox->y_min) / 2.0 + (bord_y + 64); | |
1393 | ||
1394 | // Matrix after quantize_transform() has | |
1395 | // input and output origin at bounding box center. | |
1396 | double mxx = fabs(m[0][0]), mxy = fabs(m[0][1]); | |
1397 | double myx = fabs(m[1][0]), myy = fabs(m[1][1]); | |
1398 | double mzx = fabs(m[2][0]), mzy = fabs(m[2][1]); | |
1399 | ||
1400 | double z0 = m[2][2] - mzx * dx - mzy * dy; | |
1401 | w = 1 / FFMAX(z0, m[2][2] / MAX_PERSP_SCALE); | |
1402 | ||
1403 | // Notation from quantize_transform(). | |
1404 | // Note that goal here is to estimate acceptable error for stroking, i. e. D(x) and D(y). | |
1405 | // Matrix coefficients are constants now, so D(m_??) = 0. | |
1406 | ||
1407 | // D(z) <= |m_zx| * D(x) + |m_zy| * D(y), | |
1408 | // D(x_out) = D((m_xx * x + m_xy * y) / z) | |
1409 | // <= (|m_xx| * D(x) + |m_xy| * D(y)) / z0 + x_lim * D(z) / z0^2 | |
1410 | // <= (|m_xx| / z0 + |m_zx| * x_lim / z0^2) * D(x) | |
1411 | // + (|m_xy| / z0 + |m_zy| * x_lim / z0^2) * D(y), | |
1412 | // D(y_out) = D((m_yx * x + m_yy * y) / z) | |
1413 | // <= (|m_yx| * D(x) + |m_yy| * D(y)) / z0 + y_lim * D(z) / z0^2 | |
1414 | // <= (|m_yx| / z0 + |m_zx| * y_lim / z0^2) * D(x) | |
1415 | // + (|m_yy| / z0 + |m_zy| * y_lim / z0^2) * D(y). | |
1416 | ||
1417 | // Quantization steps (ACCURACY ~ POSITION_PRECISION): | |
1418 | // STROKER_PRECISION / 2^scale_ord_x ~ D(x) ~ POSITION_PRECISION / | |
1419 | // (max(|m_xx|, |m_yx|) / z0 + |m_zx| * max(x_lim, y_lim) / z0^2), | |
1420 | // STROKER_PRECISION / 2^scale_ord_y ~ D(y) ~ POSITION_PRECISION / | |
1421 | // (max(|m_xy|, |m_yy|) / z0 + |m_zy| * max(x_lim, y_lim) / z0^2). | |
1422 | ||
1423 | double x_lim = mxx * dx + mxy * dy; | |
1424 | double y_lim = myx * dx + myy * dy; | |
1425 | double rz = FFMAX(x_lim, y_lim) * w; | |
1426 | ||
1427 | w *= STROKER_PRECISION / POSITION_PRECISION; | |
1428 | frexp(w * (FFMAX(mxx, myx) + mzx * rz), &k->scale_ord_x); | |
1429 | frexp(w * (FFMAX(mxy, myy) + mzy * rz), &k->scale_ord_y); | |
1430 | bord_x = ldexp(bord_x, k->scale_ord_x); | |
1431 | bord_y = ldexp(bord_y, k->scale_ord_y); | |
1432 | if (!(bord_x < OUTLINE_MAX && bord_y < OUTLINE_MAX)) | |
1433 | return; | |
1434 | k->border.x = lrint(bord_x / STROKER_PRECISION); | |
1435 | k->border.y = lrint(bord_y / STROKER_PRECISION); | |
1436 | if (!k->border.x && !k->border.y) { | |
1437 | ass_cache_inc_ref(info->bm); | |
1438 | info->bm_o = info->bm; | |
1439 | return; | |
1440 | } | |
1441 | ||
1442 | for (int i = 0; i < 3; i++) { | |
1443 | m[i][0] = ldexp(m2[i][0], -k->scale_ord_x); | |
1444 | m[i][1] = ldexp(m2[i][1], -k->scale_ord_y); | |
1445 | m[i][2] = m2[i][2]; | |
1446 | } | |
1447 | } | |
1448 | ||
1449 | key.outline = ass_cache_get(render_priv->cache.outline_cache, &ol_key, render_priv); | |
1450 | if (!key.outline || !key.outline->valid || | |
1451 | !quantize_transform(m, pos_o, offset, false, &key)) { | |
1452 | ass_cache_dec_ref(key.outline); | |
1226 | 1453 | return; |
1227 | 1454 | } |
1228 | if (!info->outline) { | |
1229 | memset(val, 0, sizeof(*val)); | |
1230 | ass_cache_commit(val, sizeof(BitmapHashKey) + sizeof(BitmapHashValue)); | |
1231 | info->image = val; | |
1232 | info->symbol = 0; | |
1233 | return; | |
1234 | } | |
1235 | ||
1236 | const int n_outlines = 3; | |
1237 | ASS_Outline outline[n_outlines]; | |
1238 | outline_copy(&outline[0], info->outline); | |
1239 | outline_copy(&outline[1], info->border[0]); | |
1240 | outline_copy(&outline[2], info->border[1]); | |
1241 | ||
1242 | // calculating rotation shift vector (from rotation origin to the glyph basepoint) | |
1243 | ASS_Vector shift = { key->shift_x, key->shift_y }; | |
1244 | double scale_x = render_priv->font_scale_x; | |
1245 | double fax_scaled = info->fax / info->scale_y * info->scale_x; | |
1246 | double fay_scaled = info->fay / info->scale_x * info->scale_y; | |
1247 | ||
1248 | // apply rotation | |
1249 | // use blur_scale because, like blurs, VSFilter forgets to scale this | |
1250 | transform_3d(shift, outline, n_outlines, | |
1251 | info->frx, info->fry, info->frz, fax_scaled, | |
1252 | fay_scaled, render_priv->blur_scale, info->asc); | |
1253 | ||
1254 | // PAR correction scaling + subpixel shift | |
1255 | for (int i = 0; i < n_outlines; i++) | |
1256 | outline_adjust(&outline[i], scale_x, key->advance.x, key->advance.y); | |
1257 | ||
1258 | // render glyph | |
1259 | val->valid = outline_to_bitmap2(render_priv, | |
1260 | &outline[0], &outline[1], &outline[2], | |
1261 | &val->bm, &val->bm_o); | |
1262 | if (!val->valid) | |
1263 | info->symbol = 0; | |
1264 | ||
1265 | ass_cache_commit(val, bitmap_size(val->bm) + bitmap_size(val->bm_o) + | |
1266 | sizeof(BitmapHashKey) + sizeof(BitmapHashValue)); | |
1267 | info->image = val; | |
1268 | ||
1269 | for (int i = 0; i < n_outlines; i++) | |
1270 | outline_free(&outline[i]); | |
1271 | } | |
1455 | info->bm_o = ass_cache_get(render_priv->cache.bitmap_cache, &key, render_priv); | |
1456 | if (!info->bm_o || !info->bm_o->buffer) { | |
1457 | ass_cache_dec_ref(info->bm_o); | |
1458 | info->bm_o = NULL; | |
1459 | *pos_o = *pos; | |
1460 | } else if (!info->bm) | |
1461 | *pos = *pos_o; | |
1462 | } | |
1463 | ||
1464 | size_t ass_bitmap_construct(void *key, void *value, void *priv) | |
1465 | { | |
1466 | ASS_Renderer *render_priv = priv; | |
1467 | BitmapHashKey *k = key; | |
1468 | Bitmap *bm = value; | |
1469 | ||
1470 | double m[3][3]; | |
1471 | restore_transform(m, k); | |
1472 | ||
1473 | ASS_Outline outline[2]; | |
1474 | if (k->matrix_z.x || k->matrix_z.y) { | |
1475 | outline_transform_3d(&outline[0], &k->outline->outline[0], m); | |
1476 | outline_transform_3d(&outline[1], &k->outline->outline[1], m); | |
1477 | } else { | |
1478 | outline_transform_2d(&outline[0], &k->outline->outline[0], m); | |
1479 | outline_transform_2d(&outline[1], &k->outline->outline[1], m); | |
1480 | } | |
1481 | ||
1482 | if (!outline_to_bitmap(render_priv, bm, &outline[0], &outline[1])) | |
1483 | memset(bm, 0, sizeof(*bm)); | |
1484 | outline_free(&outline[0]); | |
1485 | outline_free(&outline[1]); | |
1486 | ||
1487 | return sizeof(BitmapHashKey) + sizeof(Bitmap) + bitmap_size(bm); | |
1488 | } | |
1489 | ||
1490 | static void measure_text_on_eol(ASS_Renderer *render_priv, double scale, int cur_line, | |
1491 | int max_asc, int max_desc, | |
1492 | double max_border_x, double max_border_y) | |
1493 | { | |
1494 | render_priv->text_info.lines[cur_line].asc = scale * max_asc; | |
1495 | render_priv->text_info.lines[cur_line].desc = scale * max_desc; | |
1496 | render_priv->text_info.height += scale * max_asc + scale * max_desc; | |
1497 | // For *VSFilter compatibility do biased rounding on max_border* | |
1498 | // https://github.com/Cyberbeing/xy-VSFilter/blob/xy_sub_filter_rc4@%7B2020-05-17%7D/src/subtitles/RTS.cpp#L1465 | |
1499 | render_priv->text_info.border_bottom = (int) (render_priv->border_scale * max_border_y + 0.5); | |
1500 | if (cur_line == 0) | |
1501 | render_priv->text_info.border_top = render_priv->text_info.border_bottom; | |
1502 | // VSFilter takes max \bordx into account for collision, even if far from edge | |
1503 | render_priv->text_info.border_x = FFMAX(render_priv->text_info.border_x, | |
1504 | (int) (render_priv->border_scale * max_border_x + 0.5)); | |
1505 | } | |
1506 | ||
1272 | 1507 | |
1273 | 1508 | /** |
1274 | 1509 | * This function goes through text_info and calculates text parameters. |
1275 | 1510 | * The following text_info fields are filled: |
1276 | 1511 | * height |
1277 | * lines[].height | |
1512 | * border_top | |
1513 | * border_bottom | |
1514 | * border_x | |
1278 | 1515 | * lines[].asc |
1279 | 1516 | * lines[].desc |
1280 | 1517 | */ |
1281 | 1518 | static void measure_text(ASS_Renderer *render_priv) |
1282 | 1519 | { |
1283 | 1520 | TextInfo *text_info = &render_priv->text_info; |
1521 | text_info->height = 0; | |
1522 | ||
1284 | 1523 | int cur_line = 0; |
1285 | double max_asc = 0., max_desc = 0.; | |
1286 | GlyphInfo *last = NULL; | |
1287 | int i; | |
1288 | int empty_line = 1; | |
1289 | text_info->height = 0.; | |
1290 | for (i = 0; i < text_info->length + 1; ++i) { | |
1291 | if ((i == text_info->length) || text_info->glyphs[i].linebreak) { | |
1292 | if (empty_line && cur_line > 0 && last) { | |
1293 | max_asc = d6_to_double(last->asc) / 2.0; | |
1294 | max_desc = d6_to_double(last->desc) / 2.0; | |
1295 | } | |
1296 | text_info->lines[cur_line].asc = max_asc; | |
1297 | text_info->lines[cur_line].desc = max_desc; | |
1298 | text_info->height += max_asc + max_desc; | |
1524 | double scale = 0.5 / 64; | |
1525 | int max_asc = 0, max_desc = 0; | |
1526 | double max_border_y = 0, max_border_x = 0; | |
1527 | bool empty_trimmed_line = true; | |
1528 | for (int i = 0; i < text_info->length; i++) { | |
1529 | if (text_info->glyphs[i].linebreak) { | |
1530 | measure_text_on_eol(render_priv, scale, cur_line, | |
1531 | max_asc, max_desc, max_border_x, max_border_y); | |
1532 | empty_trimmed_line = true; | |
1533 | max_asc = max_desc = 0; | |
1534 | max_border_y = max_border_x = 0; | |
1535 | scale = 0.5 / 64; | |
1299 | 1536 | cur_line++; |
1300 | max_asc = max_desc = 0.; | |
1301 | empty_line = 1; | |
1302 | } | |
1303 | if (i < text_info->length) { | |
1304 | GlyphInfo *cur = text_info->glyphs + i; | |
1305 | if (d6_to_double(cur->asc) > max_asc) | |
1306 | max_asc = d6_to_double(cur->asc); | |
1307 | if (d6_to_double(cur->desc) > max_desc) | |
1308 | max_desc = d6_to_double(cur->desc); | |
1309 | if (cur->symbol != '\n' && cur->symbol != 0) { | |
1310 | empty_line = 0; | |
1311 | last = cur; | |
1312 | } | |
1313 | } | |
1314 | } | |
1315 | text_info->height += | |
1316 | (text_info->n_lines - | |
1317 | 1) * render_priv->settings.line_spacing; | |
1537 | } | |
1538 | GlyphInfo *cur = text_info->glyphs + i; | |
1539 | // VSFilter ignores metrics of line-leading/trailing (trimmed) | |
1540 | // whitespace, except when the line becomes empty after trimming | |
1541 | if (empty_trimmed_line && !cur->is_trimmed_whitespace) { | |
1542 | empty_trimmed_line = false; | |
1543 | // Forget metrics of line-leading whitespace | |
1544 | max_asc = max_desc = 0; | |
1545 | max_border_y = max_border_x = 0; | |
1546 | } else if (!empty_trimmed_line && cur->is_trimmed_whitespace) { | |
1547 | // Ignore metrics of line-trailing whitespace | |
1548 | continue; | |
1549 | } | |
1550 | max_asc = FFMAX(max_asc, cur->asc); | |
1551 | max_desc = FFMAX(max_desc, cur->desc); | |
1552 | max_border_y = FFMAX(max_border_y, cur->border_y); | |
1553 | max_border_x = FFMAX(max_border_x, cur->border_x); | |
1554 | if (cur->symbol != '\n') | |
1555 | scale = 1.0 / 64; | |
1556 | } | |
1557 | assert(cur_line == text_info->n_lines - 1); | |
1558 | measure_text_on_eol(render_priv, scale, cur_line, | |
1559 | max_asc, max_desc, max_border_x, max_border_y); | |
1560 | text_info->height += cur_line * render_priv->settings.line_spacing; | |
1318 | 1561 | } |
1319 | 1562 | |
1320 | 1563 | /** |
1332 | 1575 | i = ti->length - 1; |
1333 | 1576 | cur = ti->glyphs + i; |
1334 | 1577 | while (i && IS_WHITESPACE(cur)) { |
1335 | cur->skip++; | |
1578 | cur->skip = true; | |
1579 | cur->is_trimmed_whitespace = true; | |
1336 | 1580 | cur = ti->glyphs + --i; |
1337 | 1581 | } |
1338 | 1582 | |
1340 | 1584 | i = 0; |
1341 | 1585 | cur = ti->glyphs; |
1342 | 1586 | while (i < ti->length && IS_WHITESPACE(cur)) { |
1343 | cur->skip++; | |
1587 | cur->skip = true; | |
1588 | cur->is_trimmed_whitespace = true; | |
1344 | 1589 | cur = ti->glyphs + ++i; |
1345 | 1590 | } |
1591 | if (i < ti->length) | |
1592 | cur->starts_new_run = true; | |
1346 | 1593 | |
1347 | 1594 | // Mark all extraneous whitespace inbetween |
1348 | 1595 | for (i = 0; i < ti->length; ++i) { |
1352 | 1599 | j = i - 1; |
1353 | 1600 | cur = ti->glyphs + j; |
1354 | 1601 | while (j && IS_WHITESPACE(cur)) { |
1355 | cur->skip++; | |
1602 | cur->skip = true; | |
1603 | cur->is_trimmed_whitespace = true; | |
1356 | 1604 | cur = ti->glyphs + --j; |
1357 | 1605 | } |
1358 | 1606 | // A break itself can contain a whitespace, too |
1359 | 1607 | cur = ti->glyphs + i; |
1360 | 1608 | if (cur->symbol == ' ' || cur->symbol == '\n') { |
1361 | cur->skip++; | |
1609 | cur->skip = true; | |
1610 | cur->is_trimmed_whitespace = true; | |
1362 | 1611 | // Mark whitespace after |
1363 | 1612 | j = i + 1; |
1364 | 1613 | cur = ti->glyphs + j; |
1365 | 1614 | while (j < ti->length && IS_WHITESPACE(cur)) { |
1366 | cur->skip++; | |
1615 | cur->skip = true; | |
1616 | cur->is_trimmed_whitespace = true; | |
1367 | 1617 | cur = ti->glyphs + ++j; |
1368 | 1618 | } |
1369 | 1619 | i = j - 1; |
1370 | 1620 | } |
1621 | if (cur < ti->glyphs + ti->length) | |
1622 | cur->starts_new_run = true; | |
1371 | 1623 | } |
1372 | 1624 | } |
1373 | 1625 | } |
1501 | 1753 | assert(text_info->n_lines >= 1); |
1502 | 1754 | #undef DIFF |
1503 | 1755 | |
1756 | trim_whitespace(render_priv); | |
1504 | 1757 | measure_text(render_priv); |
1505 | trim_whitespace(render_priv); | |
1506 | 1758 | |
1507 | 1759 | cur_line = 1; |
1508 | 1760 | |
1580 | 1832 | } |
1581 | 1833 | |
1582 | 1834 | /** |
1583 | * Prepare bitmap hash key of a glyph | |
1584 | */ | |
1585 | static void | |
1586 | fill_bitmap_hash(ASS_Renderer *priv, GlyphInfo *info, | |
1587 | OutlineBitmapHashKey *hash_key) | |
1588 | { | |
1589 | hash_key->frx = rot_key(info->frx); | |
1590 | hash_key->fry = rot_key(info->fry); | |
1591 | hash_key->frz = rot_key(info->frz); | |
1592 | hash_key->fax = double_to_d16(info->fax); | |
1593 | hash_key->fay = double_to_d16(info->fay); | |
1594 | } | |
1595 | ||
1596 | /** | |
1597 | 1835 | * \brief Adjust the glyph's font size and scale factors to ensure smooth |
1598 | 1836 | * scaling and handle pathological font sizes. The main problem here is |
1599 | 1837 | * freetype's grid fitting, which destroys animations by font size, or will |
1615 | 1853 | // to freetype. Normalize scale_y to 1.0. |
1616 | 1854 | ft_size = glyph->scale_y * glyph->font_size; |
1617 | 1855 | } |
1618 | glyph->scale_x = glyph->scale_x * glyph->font_size / ft_size; | |
1619 | glyph->scale_y = glyph->scale_y * glyph->font_size / ft_size; | |
1856 | double mul = glyph->font_size / ft_size; | |
1857 | glyph->scale_fix = 1 / mul; | |
1858 | glyph->scale_x *= mul; | |
1859 | glyph->scale_y *= mul; | |
1620 | 1860 | glyph->font_size = ft_size; |
1621 | 1861 | } |
1622 | 1862 | |
1623 | /** | |
1624 | * \brief Checks whether a glyph should start a new bitmap run | |
1625 | * \param info Pointer to new GlyphInfo to check | |
1626 | * \param current_info Pointer to CombinedBitmapInfo for current run (may be NULL) | |
1627 | * \return 1 if a new run should be started | |
1628 | */ | |
1629 | static int is_new_bm_run(GlyphInfo *info, GlyphInfo *last) | |
1630 | { | |
1631 | // FIXME: Don't break on glyph substitutions | |
1632 | return !last || info->effect || info->drawing || last->drawing || | |
1633 | strcmp(last->font->desc.family, info->font->desc.family) || | |
1634 | last->font->desc.vertical != info->font->desc.vertical || | |
1635 | last->face_index != info->face_index || | |
1636 | last->font_size != info->font_size || | |
1637 | last->c[0] != info->c[0] || | |
1638 | last->c[1] != info->c[1] || | |
1639 | last->c[2] != info->c[2] || | |
1640 | last->c[3] != info->c[3] || | |
1641 | last->be != info->be || | |
1642 | last->blur != info->blur || | |
1643 | last->shadow_x != info->shadow_x || | |
1644 | last->shadow_y != info->shadow_y || | |
1645 | last->frx != info->frx || | |
1646 | last->fry != info->fry || | |
1647 | last->frz != info->frz || | |
1648 | last->fax != info->fax || | |
1649 | last->fay != info->fay || | |
1650 | last->scale_x != info->scale_x || | |
1651 | last->scale_y != info->scale_y || | |
1652 | last->border_style != info->border_style || | |
1653 | last->border_x != info->border_x || | |
1654 | last->border_y != info->border_y || | |
1655 | last->hspacing != info->hspacing || | |
1656 | last->italic != info->italic || | |
1657 | last->bold != info->bold || | |
1658 | last->flags != info->flags; | |
1659 | } | |
1660 | ||
1661 | static void make_shadow_bitmap(CombinedBitmapInfo *info, ASS_Renderer *render_priv) | |
1662 | { | |
1663 | if (!(info->filter.flags & FILTER_NONZERO_SHADOW)) { | |
1664 | if (info->bm && info->bm_o && !(info->filter.flags & FILTER_BORDER_STYLE_3)) { | |
1665 | fix_outline(info->bm, info->bm_o); | |
1666 | } else if (info->bm_o && !(info->filter.flags & FILTER_NONZERO_BORDER)) { | |
1667 | ass_free_bitmap(info->bm_o); | |
1668 | info->bm_o = 0; | |
1669 | } | |
1670 | return; | |
1671 | } | |
1672 | ||
1673 | // Create shadow and fix outline as needed | |
1674 | if (info->bm && info->bm_o && !(info->filter.flags & FILTER_BORDER_STYLE_3)) { | |
1675 | info->bm_s = copy_bitmap(render_priv->engine, info->bm_o); | |
1676 | fix_outline(info->bm, info->bm_o); | |
1677 | } else if (info->bm_o && (info->filter.flags & FILTER_NONZERO_BORDER)) { | |
1678 | info->bm_s = copy_bitmap(render_priv->engine, info->bm_o); | |
1679 | } else if (info->bm_o) { | |
1680 | info->bm_s = info->bm_o; | |
1681 | info->bm_o = 0; | |
1682 | } else if (info->bm) | |
1683 | info->bm_s = copy_bitmap(render_priv->engine, info->bm); | |
1684 | ||
1685 | if (!info->bm_s) | |
1686 | return; | |
1687 | ||
1688 | // Works right even for negative offsets | |
1689 | // '>>' rounds toward negative infinity, '&' returns correct remainder | |
1690 | info->bm_s->left += info->filter.shadow.x >> 6; | |
1691 | info->bm_s->top += info->filter.shadow.y >> 6; | |
1692 | shift_bitmap(info->bm_s, info->filter.shadow.x & SUBPIXEL_MASK, info->filter.shadow.y & SUBPIXEL_MASK); | |
1863 | // Initial run splitting based purely on the characters' styles | |
1864 | static void split_style_runs(ASS_Renderer *render_priv) | |
1865 | { | |
1866 | Effect last_effect_type = render_priv->text_info.glyphs[0].effect_type; | |
1867 | render_priv->text_info.glyphs[0].starts_new_run = true; | |
1868 | for (int i = 1; i < render_priv->text_info.length; i++) { | |
1869 | GlyphInfo *info = render_priv->text_info.glyphs + i; | |
1870 | GlyphInfo *last = render_priv->text_info.glyphs + (i - 1); | |
1871 | Effect effect_type = info->effect_type; | |
1872 | info->starts_new_run = | |
1873 | info->effect_timing || // but ignore effect_skip_timing | |
1874 | (effect_type != EF_NONE && effect_type != last_effect_type) || | |
1875 | info->drawing_text || | |
1876 | last->drawing_text || | |
1877 | strcmp(last->font->desc.family, info->font->desc.family) || | |
1878 | last->font->desc.vertical != info->font->desc.vertical || | |
1879 | last->font_size != info->font_size || | |
1880 | last->c[0] != info->c[0] || | |
1881 | last->c[1] != info->c[1] || | |
1882 | last->c[2] != info->c[2] || | |
1883 | last->c[3] != info->c[3] || | |
1884 | last->be != info->be || | |
1885 | last->blur != info->blur || | |
1886 | last->shadow_x != info->shadow_x || | |
1887 | last->shadow_y != info->shadow_y || | |
1888 | last->frx != info->frx || | |
1889 | last->fry != info->fry || | |
1890 | last->frz != info->frz || | |
1891 | last->fax != info->fax || | |
1892 | last->fay != info->fay || | |
1893 | last->scale_x != info->scale_x || | |
1894 | last->scale_y != info->scale_y || | |
1895 | last->border_style != info->border_style || | |
1896 | last->border_x != info->border_x || | |
1897 | last->border_y != info->border_y || | |
1898 | last->hspacing != info->hspacing || | |
1899 | last->italic != info->italic || | |
1900 | last->bold != info->bold || | |
1901 | ((last->flags ^ info->flags) & ~DECO_ROTATE); | |
1902 | if (effect_type != EF_NONE) | |
1903 | last_effect_type = effect_type; | |
1904 | } | |
1693 | 1905 | } |
1694 | 1906 | |
1695 | 1907 | // Parse event text. |
1696 | 1908 | // Fill render_priv->text_info. |
1697 | static int parse_events(ASS_Renderer *render_priv, ASS_Event *event) | |
1909 | static bool parse_events(ASS_Renderer *render_priv, ASS_Event *event) | |
1698 | 1910 | { |
1699 | 1911 | TextInfo *text_info = &render_priv->text_info; |
1700 | ASS_Drawing *drawing = NULL; | |
1701 | unsigned code; | |
1702 | char *p, *q; | |
1703 | int i; | |
1704 | ||
1705 | p = event->Text; | |
1912 | ||
1913 | char *p = event->Text, *q; | |
1914 | char *drawing_text; | |
1706 | 1915 | |
1707 | 1916 | // Event parsing. |
1708 | while (1) { | |
1917 | while (true) { | |
1918 | drawing_text = NULL; | |
1919 | ||
1709 | 1920 | // get next char, executing style override |
1710 | 1921 | // this affects render_context |
1711 | code = 0; | |
1922 | unsigned code = 0; | |
1712 | 1923 | while (*p) { |
1713 | 1924 | if ((*p == '{') && (q = strchr(p, '}'))) { |
1714 | while (p < q) | |
1715 | p = parse_tag(render_priv, p, q, 1.); | |
1925 | p = parse_tags(render_priv, p, q, 1., false); | |
1716 | 1926 | assert(*p == '}'); |
1717 | 1927 | p++; |
1718 | 1928 | } else if (render_priv->state.drawing_scale) { |
1721 | 1931 | q++; |
1722 | 1932 | while ((*q != '{') && (*q != 0)) |
1723 | 1933 | q++; |
1724 | if (!drawing) { | |
1725 | drawing = ass_drawing_new(render_priv->library); | |
1726 | if (!drawing) | |
1727 | return 1; | |
1728 | } | |
1729 | ass_drawing_set_text(drawing, p, q - p); | |
1934 | drawing_text = strndup(p, q - p); | |
1730 | 1935 | code = 0xfffc; // object replacement character |
1731 | 1936 | p = q; |
1732 | 1937 | break; |
1740 | 1945 | break; |
1741 | 1946 | |
1742 | 1947 | // face could have been changed in get_next_char |
1743 | if (!render_priv->state.font) { | |
1744 | free_render_context(render_priv); | |
1745 | ass_drawing_free(drawing); | |
1746 | return 1; | |
1747 | } | |
1948 | if (!render_priv->state.font) | |
1949 | goto fail; | |
1748 | 1950 | |
1749 | 1951 | if (text_info->length >= text_info->max_glyphs) { |
1750 | 1952 | // Raise maximum number of glyphs |
1751 | text_info->max_glyphs *= 2; | |
1752 | text_info->glyphs = | |
1753 | realloc(text_info->glyphs, | |
1754 | sizeof(GlyphInfo) * text_info->max_glyphs); | |
1953 | int new_max = 2 * FFMIN(text_info->max_glyphs, INT_MAX / 2); | |
1954 | if (text_info->length >= new_max) | |
1955 | goto fail; | |
1956 | if (!ASS_REALLOC_ARRAY(text_info->glyphs, new_max)) | |
1957 | goto fail; | |
1958 | text_info->max_glyphs = new_max; | |
1755 | 1959 | } |
1756 | 1960 | |
1757 | 1961 | GlyphInfo *info = &text_info->glyphs[text_info->length]; |
1760 | 1964 | memset(info, 0, sizeof(GlyphInfo)); |
1761 | 1965 | |
1762 | 1966 | // Parse drawing |
1763 | if (drawing && drawing->text) { | |
1764 | drawing->scale_x = render_priv->state.scale_x * | |
1765 | render_priv->font_scale; | |
1766 | drawing->scale_y = render_priv->state.scale_y * | |
1767 | render_priv->font_scale; | |
1768 | drawing->scale = render_priv->state.drawing_scale; | |
1769 | drawing->pbo = render_priv->state.pbo; | |
1770 | info->drawing = drawing; | |
1771 | drawing = NULL; | |
1967 | if (drawing_text) { | |
1968 | info->drawing_text = drawing_text; | |
1969 | info->drawing_scale = render_priv->state.drawing_scale; | |
1970 | info->drawing_pbo = render_priv->state.pbo; | |
1772 | 1971 | } |
1773 | 1972 | |
1774 | 1973 | // Fill glyph information |
1775 | 1974 | info->symbol = code; |
1776 | 1975 | info->font = render_priv->state.font; |
1777 | if (!info->drawing) | |
1976 | if (!drawing_text) | |
1778 | 1977 | ass_cache_inc_ref(info->font); |
1779 | for (i = 0; i < 4; ++i) { | |
1978 | for (int i = 0; i < 4; i++) { | |
1780 | 1979 | uint32_t clr = render_priv->state.c[i]; |
1781 | 1980 | // VSFilter compatibility: apply fade only when it's positive |
1981 | info->a_pre_fade[i] = _a(clr); | |
1782 | 1982 | if (render_priv->state.fade > 0) |
1783 | 1983 | change_alpha(&clr, |
1784 | 1984 | mult_alpha(_a(clr), render_priv->state.fade), 1.); |
1794 | 1994 | info->blur = render_priv->state.blur; |
1795 | 1995 | info->shadow_x = render_priv->state.shadow_x; |
1796 | 1996 | info->shadow_y = render_priv->state.shadow_y; |
1797 | info->scale_x = info->orig_scale_x = render_priv->state.scale_x; | |
1798 | info->scale_y = info->orig_scale_y = render_priv->state.scale_y; | |
1997 | info->scale_x = render_priv->state.scale_x; | |
1998 | info->scale_y = render_priv->state.scale_y; | |
1799 | 1999 | info->border_style = render_priv->state.border_style; |
1800 | info->border_x= render_priv->state.border_x; | |
2000 | info->border_x = render_priv->state.border_x; | |
1801 | 2001 | info->border_y = render_priv->state.border_y; |
1802 | 2002 | info->hspacing = render_priv->state.hspacing; |
1803 | 2003 | info->bold = render_priv->state.bold; |
1804 | 2004 | info->italic = render_priv->state.italic; |
1805 | 2005 | info->flags = render_priv->state.flags; |
2006 | if (info->font->desc.vertical && code >= VERTICAL_LOWER_BOUND) | |
2007 | info->flags |= DECO_ROTATE; | |
1806 | 2008 | info->frx = render_priv->state.frx; |
1807 | 2009 | info->fry = render_priv->state.fry; |
1808 | 2010 | info->frz = render_priv->state.frz; |
1809 | 2011 | info->fax = render_priv->state.fax; |
1810 | 2012 | info->fay = render_priv->state.fay; |
1811 | 2013 | |
1812 | if (!info->drawing) | |
2014 | info->hspacing_scaled = double_to_d6(info->hspacing * | |
2015 | render_priv->font_scale * info->scale_x); | |
2016 | info->scale_fix = 1; | |
2017 | ||
2018 | if (!drawing_text) | |
1813 | 2019 | fix_glyph_scaling(render_priv, info); |
1814 | 2020 | |
1815 | 2021 | text_info->length++; |
1819 | 2025 | render_priv->state.effect_skip_timing = 0; |
1820 | 2026 | } |
1821 | 2027 | |
1822 | ass_drawing_free(drawing); | |
1823 | ||
1824 | return 0; | |
2028 | return true; | |
2029 | ||
2030 | fail: | |
2031 | free_render_context(render_priv); | |
2032 | free(drawing_text); | |
2033 | return false; | |
1825 | 2034 | } |
1826 | 2035 | |
1827 | 2036 | // Process render_priv->text_info and load glyph outlines. |
1832 | 2041 | |
1833 | 2042 | for (i = 0; i < render_priv->text_info.length; i++) { |
1834 | 2043 | GlyphInfo *info = glyphs + i; |
1835 | while (info) { | |
2044 | do { | |
1836 | 2045 | get_outline_glyph(render_priv, info); |
1837 | 2046 | info = info->next; |
1838 | } | |
2047 | } while (info); | |
1839 | 2048 | info = glyphs + i; |
1840 | 2049 | |
1841 | 2050 | // Add additional space after italic to non-italic style changes |
1850 | 2059 | } |
1851 | 2060 | |
1852 | 2061 | // add horizontal letter spacing |
1853 | info->cluster_advance.x += double_to_d6(info->hspacing * | |
1854 | render_priv->font_scale * info->orig_scale_x); | |
2062 | info->cluster_advance.x += info->hspacing_scaled; | |
1855 | 2063 | |
1856 | 2064 | // add displacement for vertical shearing |
1857 | 2065 | info->cluster_advance.y += (info->fay / info->scale_x * info->scale_y) * info->cluster_advance.x; |
1865 | 2073 | for (int i = 0; i < render_priv->text_info.length; i++) { |
1866 | 2074 | GlyphInfo *info = render_priv->text_info.glyphs + i; |
1867 | 2075 | ASS_Vector cluster_pen = pen; |
1868 | while (info) { | |
2076 | do { | |
1869 | 2077 | info->pos.x = cluster_pen.x; |
1870 | 2078 | info->pos.y = cluster_pen.y; |
1871 | 2079 | |
1872 | 2080 | cluster_pen.x += info->advance.x; |
1873 | 2081 | cluster_pen.y += info->advance.y; |
1874 | 2082 | |
1875 | // fill bitmap hash | |
1876 | info->hash_key.type = BITMAP_OUTLINE; | |
1877 | fill_bitmap_hash(render_priv, info, &info->hash_key.u.outline); | |
1878 | ||
1879 | 2083 | info = info->next; |
1880 | } | |
2084 | } while (info); | |
1881 | 2085 | info = render_priv->text_info.glyphs + i; |
1882 | 2086 | pen.x += info->cluster_advance.x; |
1883 | 2087 | pen.y += info->cluster_advance.y; |
1942 | 2146 | int justify = render_priv->state.justify; |
1943 | 2147 | double max_width = 0; |
1944 | 2148 | |
1945 | if (render_priv->state.evt_type == EVENT_HSCROLL) | |
1946 | return; | |
2149 | if (render_priv->state.evt_type & EVENT_HSCROLL) { | |
2150 | justify = halign; | |
2151 | halign = HALIGN_LEFT; | |
2152 | } | |
1947 | 2153 | |
1948 | 2154 | for (i = 0; i <= text_info->length; ++i) { // (text_info->length + 1) is the end of the last line |
1949 | 2155 | if ((i == text_info->length) || glyphs[i].linebreak) { |
2005 | 2211 | { |
2006 | 2212 | ASS_DVector center; |
2007 | 2213 | if (render_priv->state.have_origin) { |
2008 | center.x = x2scr(render_priv, render_priv->state.org_x); | |
2009 | center.y = y2scr(render_priv, render_priv->state.org_y); | |
2214 | center.x = x2scr_pos(render_priv, render_priv->state.org_x); | |
2215 | center.y = y2scr_pos(render_priv, render_priv->state.org_y); | |
2010 | 2216 | } else { |
2011 | 2217 | double bx = 0., by = 0.; |
2012 | 2218 | get_base_point(bbox, render_priv->state.alignment, &bx, &by); |
2018 | 2224 | for (int i = 0; i < text_info->length; i++) { |
2019 | 2225 | GlyphInfo *info = text_info->glyphs + i; |
2020 | 2226 | while (info) { |
2021 | OutlineBitmapHashKey *key = &info->hash_key.u.outline; | |
2022 | ||
2023 | if (key->frx || key->fry || key->frz || key->fax || key->fay) { | |
2024 | key->shift_x = info->pos.x + double_to_d6(device_x - center.x); | |
2025 | key->shift_y = info->pos.y + double_to_d6(device_y - center.y); | |
2026 | } else { | |
2027 | key->shift_x = 0; | |
2028 | key->shift_y = 0; | |
2029 | } | |
2227 | info->shift.x = info->pos.x + double_to_d6(device_x - center.x + | |
2228 | info->shadow_x * render_priv->border_scale / | |
2229 | render_priv->font_scale_x); | |
2230 | info->shift.y = info->pos.y + double_to_d6(device_y - center.y + | |
2231 | info->shadow_y * render_priv->border_scale); | |
2030 | 2232 | info = info->next; |
2031 | 2233 | } |
2032 | 2234 | } |
2033 | 2235 | } |
2034 | 2236 | |
2035 | 2237 | |
2036 | static inline void rectangle_combine(ASS_Rect *rect, const Bitmap *bm, int x, int y) | |
2037 | { | |
2038 | x += bm->left; | |
2039 | y += bm->top; | |
2040 | rectangle_update(rect, x, y, x + bm->w, y + bm->h); | |
2238 | static int quantize_blur(double radius, int32_t *shadow_mask) | |
2239 | { | |
2240 | // Gaussian filter kernel (1D): | |
2241 | // G(x, r2) = exp(-x^2 / (2 * r2)) / sqrt(2 * pi * r2), | |
2242 | // position unit is 1/64th of pixel, r = 64 * radius, r2 = r^2. | |
2243 | ||
2244 | // Difference between kernels with different but near r2: | |
2245 | // G(x, r2 + dr2) - G(x, r2) ~= dr2 * G(x, r2) * (x^2 - r2) / (2 * r2^2). | |
2246 | // Maximal possible error relative to full pixel value is half of | |
2247 | // integral (from -inf to +inf) of absolute value of that difference. | |
2248 | // E_max ~= dr2 / 2 * integral(G(x, r2) * |x^2 - r2| / (2 * r2^2), x) | |
2249 | // = dr2 / (4 * r2) * integral(G(y, 1) * |y^2 - 1|, y) | |
2250 | // = dr2 / (4 * r2) * 4 / sqrt(2 * pi * e) | |
2251 | // ~ dr2 / (4 * r2) ~= dr / (2 * r). | |
2252 | // E_max ~ BLUR_PRECISION / 2 as we have 2 dimensions. | |
2253 | ||
2254 | // To get discretized blur radius solve the following | |
2255 | // differential equation (n--quantization index): | |
2256 | // dr(n) / dn = BLUR_PRECISION * r + POSITION_PRECISION, r(0) = 0, | |
2257 | // r(n) = (exp(BLUR_PRECISION * n) - 1) * POSITION_PRECISION / BLUR_PRECISION, | |
2258 | // n = log(1 + r * BLUR_PRECISION / POSITION_PRECISION) / BLUR_PRECISION. | |
2259 | ||
2260 | // To get shadow offset quantization estimate difference of | |
2261 | // G(x + dx, r2) - G(x, r2) ~= dx * G(x, r2) * (-x / r2). | |
2262 | // E_max ~= dx / 2 * integral(G(x, r2) * |x| / r2, x) | |
2263 | // = dx / sqrt(2 * pi * r2) ~ dx / (2 * r). | |
2264 | // 2^ord ~ dx ~ BLUR_PRECISION * r + POSITION_PRECISION. | |
2265 | ||
2266 | const double scale = 64 * BLUR_PRECISION / POSITION_PRECISION; | |
2267 | radius *= scale; | |
2268 | ||
2269 | int ord; | |
2270 | // ord = floor(log2(BLUR_PRECISION * r + POSITION_PRECISION)) | |
2271 | // = floor(log2(64 * radius * BLUR_PRECISION + POSITION_PRECISION)) | |
2272 | // = floor(log2((radius * scale + 1) * POSITION_PRECISION)), | |
2273 | // floor(log2(x)) = frexp(x) - 1 = frexp(x / 2). | |
2274 | frexp((1 + radius) * (POSITION_PRECISION / 2), &ord); | |
2275 | *shadow_mask = ((uint32_t) 1 << ord) - 1; | |
2276 | return lrint(log1p(radius) / BLUR_PRECISION); | |
2277 | } | |
2278 | ||
2279 | static double restore_blur(int qblur) | |
2280 | { | |
2281 | const double scale = 64 * BLUR_PRECISION / POSITION_PRECISION; | |
2282 | double sigma = expm1(BLUR_PRECISION * qblur) / scale; | |
2283 | return sigma * sigma; | |
2041 | 2284 | } |
2042 | 2285 | |
2043 | 2286 | // Convert glyphs to bitmaps, combine them, apply blur, generate shadows. |
2048 | 2291 | int left = render_priv->settings.left_margin; |
2049 | 2292 | device_x = (device_x - left) * render_priv->font_scale_x + left; |
2050 | 2293 | unsigned nb_bitmaps = 0; |
2051 | char linebreak = 0; | |
2294 | bool new_run = true; | |
2052 | 2295 | CombinedBitmapInfo *combined_info = text_info->combined_bitmaps; |
2053 | 2296 | CombinedBitmapInfo *current_info = NULL; |
2054 | GlyphInfo *last_info = NULL; | |
2297 | ASS_DVector offset; | |
2055 | 2298 | for (int i = 0; i < text_info->length; i++) { |
2056 | 2299 | GlyphInfo *info = text_info->glyphs + i; |
2057 | if (info->linebreak) linebreak = 1; | |
2300 | if (info->starts_new_run) new_run = true; | |
2058 | 2301 | if (info->skip) { |
2059 | 2302 | for (; info; info = info->next) |
2060 | ass_cache_dec_ref(info->hash_key.u.outline.outline); | |
2303 | ass_cache_dec_ref(info->outline); | |
2061 | 2304 | continue; |
2062 | 2305 | } |
2063 | 2306 | for (; info; info = info->next) { |
2064 | OutlineBitmapHashKey *key = &info->hash_key.u.outline; | |
2065 | ||
2066 | info->pos.x = double_to_d6(device_x + d6_to_double(info->pos.x) * render_priv->font_scale_x); | |
2067 | info->pos.y = double_to_d6(device_y) + info->pos.y; | |
2068 | key->advance.x = info->pos.x & (SUBPIXEL_MASK & ~SUBPIXEL_ACCURACY); | |
2069 | key->advance.y = info->pos.y & (SUBPIXEL_MASK & ~SUBPIXEL_ACCURACY); | |
2070 | int x = info->pos.x >> 6, y = info->pos.y >> 6; | |
2071 | get_bitmap_glyph(render_priv, info); | |
2072 | ||
2073 | if(linebreak || is_new_bm_run(info, last_info)) { | |
2074 | linebreak = 0; | |
2075 | last_info = NULL; | |
2307 | int flags = 0; | |
2308 | if (info->border_style == 3) | |
2309 | flags |= FILTER_BORDER_STYLE_3; | |
2310 | if (info->border_x || info->border_y) | |
2311 | flags |= FILTER_NONZERO_BORDER; | |
2312 | if (info->shadow_x || info->shadow_y) | |
2313 | flags |= FILTER_NONZERO_SHADOW; | |
2314 | if (flags & FILTER_NONZERO_SHADOW && | |
2315 | (info->effect_type == EF_KARAOKE_KF || | |
2316 | info->effect_type == EF_KARAOKE_KO || | |
2317 | (info->a_pre_fade[0]) != 0xFF || | |
2318 | info->border_style == 3)) | |
2319 | flags |= FILTER_FILL_IN_SHADOW; | |
2320 | if (!(flags & FILTER_NONZERO_BORDER) && | |
2321 | !(flags & FILTER_FILL_IN_SHADOW)) | |
2322 | flags &= ~FILTER_NONZERO_SHADOW; | |
2323 | if ((flags & FILTER_NONZERO_BORDER && | |
2324 | info->a_pre_fade[0] == 0 && | |
2325 | info->a_pre_fade[1] == 0 && | |
2326 | _a(info->c[2]) == 0) || | |
2327 | info->border_style == 3) | |
2328 | flags |= FILTER_FILL_IN_BORDER; | |
2329 | ||
2330 | if (new_run) { | |
2076 | 2331 | if (nb_bitmaps >= text_info->max_bitmaps) { |
2077 | 2332 | size_t new_size = 2 * text_info->max_bitmaps; |
2078 | 2333 | if (!ASS_REALLOC_ARRAY(text_info->combined_bitmaps, new_size)) { |
2079 | ass_cache_dec_ref(info->image); | |
2334 | ass_cache_dec_ref(info->outline); | |
2080 | 2335 | continue; |
2081 | 2336 | } |
2082 | 2337 | text_info->max_bitmaps = new_size; |
2087 | 2342 | memcpy(¤t_info->c, &info->c, sizeof(info->c)); |
2088 | 2343 | current_info->effect_type = info->effect_type; |
2089 | 2344 | current_info->effect_timing = info->effect_timing; |
2090 | current_info->first_pos_x = info->bbox.x_max >> 6; | |
2091 | ||
2092 | current_info->filter.flags = 0; | |
2093 | if (info->border_style == 3) | |
2094 | current_info->filter.flags |= FILTER_BORDER_STYLE_3; | |
2095 | if (info->border_x || info->border_y) | |
2096 | current_info->filter.flags |= FILTER_NONZERO_BORDER; | |
2097 | if (info->shadow_x || info->shadow_y) | |
2098 | current_info->filter.flags |= FILTER_NONZERO_SHADOW; | |
2099 | // VSFilter compatibility: invisible fill and no border? | |
2100 | // In this case no shadow is supposed to be rendered. | |
2101 | if (info->border[0] || info->border[1] || (info->c[0] & 0xFF) != 0xFF) | |
2102 | current_info->filter.flags |= FILTER_DRAW_SHADOW; | |
2103 | ||
2104 | current_info->filter.be = info->be; | |
2105 | current_info->filter.blur = 2 * info->blur * render_priv->blur_scale; | |
2106 | current_info->filter.shadow.x = double_to_d6(info->shadow_x * render_priv->border_scale); | |
2107 | current_info->filter.shadow.y = double_to_d6(info->shadow_y * render_priv->border_scale); | |
2345 | current_info->leftmost_x = OUTLINE_MAX; | |
2346 | ||
2347 | FilterDesc *filter = ¤t_info->filter; | |
2348 | filter->flags = flags; | |
2349 | filter->be = info->be; | |
2350 | ||
2351 | int32_t shadow_mask; | |
2352 | double blur_scale = render_priv->blur_scale * (2 / sqrt(log(256))); | |
2353 | filter->blur = quantize_blur(info->blur * blur_scale, &shadow_mask); | |
2354 | if (flags & FILTER_NONZERO_SHADOW) { | |
2355 | int32_t x = double_to_d6(info->shadow_x * render_priv->border_scale); | |
2356 | int32_t y = double_to_d6(info->shadow_y * render_priv->border_scale); | |
2357 | filter->shadow.x = (x + (shadow_mask >> 1)) & ~shadow_mask; | |
2358 | filter->shadow.y = (y + (shadow_mask >> 1)) & ~shadow_mask; | |
2359 | } else | |
2360 | filter->shadow.x = filter->shadow.y = 0; | |
2108 | 2361 | |
2109 | 2362 | current_info->x = current_info->y = INT_MAX; |
2110 | rectangle_reset(¤t_info->rect); | |
2111 | rectangle_reset(¤t_info->rect_o); | |
2112 | current_info->n_bm = current_info->n_bm_o = 0; | |
2113 | 2363 | current_info->bm = current_info->bm_o = current_info->bm_s = NULL; |
2114 | 2364 | current_info->image = NULL; |
2115 | 2365 | |
2116 | 2366 | current_info->bitmap_count = current_info->max_bitmap_count = 0; |
2117 | 2367 | current_info->bitmaps = malloc(MAX_SUB_BITMAPS_INITIAL * sizeof(BitmapRef)); |
2118 | 2368 | if (!current_info->bitmaps) { |
2119 | ass_cache_dec_ref(info->image); | |
2369 | ass_cache_dec_ref(info->outline); | |
2120 | 2370 | continue; |
2121 | 2371 | } |
2122 | 2372 | current_info->max_bitmap_count = MAX_SUB_BITMAPS_INITIAL; |
2123 | 2373 | |
2124 | 2374 | nb_bitmaps++; |
2375 | new_run = false; | |
2125 | 2376 | } |
2126 | last_info = info; | |
2127 | ||
2128 | if (!info->image || !current_info) { | |
2129 | ass_cache_dec_ref(info->image); | |
2377 | assert(current_info); | |
2378 | ||
2379 | ASS_Vector pos, pos_o; | |
2380 | info->pos.x = double_to_d6(device_x + d6_to_double(info->pos.x) * render_priv->font_scale_x); | |
2381 | info->pos.y = double_to_d6(device_y) + info->pos.y; | |
2382 | get_bitmap_glyph(render_priv, info, ¤t_info->leftmost_x, &pos, &pos_o, | |
2383 | &offset, !current_info->bitmap_count, flags); | |
2384 | ||
2385 | if (!info->bm && !info->bm_o) { | |
2386 | ass_cache_dec_ref(info->bm); | |
2387 | ass_cache_dec_ref(info->bm_o); | |
2130 | 2388 | continue; |
2131 | 2389 | } |
2132 | 2390 | |
2133 | 2391 | if (current_info->bitmap_count >= current_info->max_bitmap_count) { |
2134 | 2392 | size_t new_size = 2 * current_info->max_bitmap_count; |
2135 | 2393 | if (!ASS_REALLOC_ARRAY(current_info->bitmaps, new_size)) { |
2136 | ass_cache_dec_ref(info->image); | |
2394 | ass_cache_dec_ref(info->bm); | |
2395 | ass_cache_dec_ref(info->bm_o); | |
2137 | 2396 | continue; |
2138 | 2397 | } |
2139 | 2398 | current_info->max_bitmap_count = new_size; |
2140 | 2399 | } |
2141 | current_info->bitmaps[current_info->bitmap_count].image = info->image; | |
2142 | current_info->bitmaps[current_info->bitmap_count].x = x; | |
2143 | current_info->bitmaps[current_info->bitmap_count].y = y; | |
2400 | current_info->bitmaps[current_info->bitmap_count].bm = info->bm; | |
2401 | current_info->bitmaps[current_info->bitmap_count].bm_o = info->bm_o; | |
2402 | current_info->bitmaps[current_info->bitmap_count].pos = pos; | |
2403 | current_info->bitmaps[current_info->bitmap_count].pos_o = pos_o; | |
2144 | 2404 | current_info->bitmap_count++; |
2145 | 2405 | |
2146 | current_info->x = FFMIN(current_info->x, x); | |
2147 | current_info->y = FFMIN(current_info->y, y); | |
2148 | if (info->image->bm) { | |
2149 | rectangle_combine(¤t_info->rect, info->image->bm, x, y); | |
2150 | current_info->n_bm++; | |
2151 | } | |
2152 | if (info->image->bm_o) { | |
2153 | rectangle_combine(¤t_info->rect_o, info->image->bm_o, x, y); | |
2154 | current_info->n_bm_o++; | |
2155 | } | |
2406 | current_info->x = FFMIN(current_info->x, pos.x); | |
2407 | current_info->y = FFMIN(current_info->y, pos.y); | |
2156 | 2408 | } |
2157 | 2409 | } |
2158 | 2410 | |
2159 | 2411 | for (int i = 0; i < nb_bitmaps; i++) { |
2160 | 2412 | CombinedBitmapInfo *info = &combined_info[i]; |
2413 | if (!info->bitmap_count) { | |
2414 | free(info->bitmaps); | |
2415 | continue; | |
2416 | } | |
2417 | ||
2418 | if (info->effect_type == EF_KARAOKE_KF) | |
2419 | info->effect_timing = lround(d6_to_double(info->leftmost_x) + | |
2420 | d6_to_double(info->effect_timing) * render_priv->font_scale_x); | |
2421 | ||
2161 | 2422 | for (int j = 0; j < info->bitmap_count; j++) { |
2162 | info->bitmaps[j].x -= info->x; | |
2163 | info->bitmaps[j].y -= info->y; | |
2164 | } | |
2165 | ||
2166 | CompositeHashKey hk; | |
2167 | CompositeHashValue *hv; | |
2168 | fill_composite_hash(&hk, info); | |
2169 | if (ass_cache_get(render_priv->cache.composite_cache, &hk, &hv)) { | |
2170 | info->bm = hv->bm; | |
2171 | info->bm_o = hv->bm_o; | |
2172 | info->bm_s = hv->bm_s; | |
2173 | info->image = hv; | |
2423 | info->bitmaps[j].pos.x -= info->x; | |
2424 | info->bitmaps[j].pos.y -= info->y; | |
2425 | info->bitmaps[j].pos_o.x -= info->x; | |
2426 | info->bitmaps[j].pos_o.y -= info->y; | |
2427 | } | |
2428 | ||
2429 | CompositeHashKey key; | |
2430 | key.filter = info->filter; | |
2431 | key.bitmap_count = info->bitmap_count; | |
2432 | key.bitmaps = info->bitmaps; | |
2433 | CompositeHashValue *val = ass_cache_get(render_priv->cache.composite_cache, &key, render_priv); | |
2434 | if (!val) | |
2174 | 2435 | continue; |
2175 | } | |
2176 | if (!hv) | |
2177 | continue; | |
2178 | ||
2179 | int bord = be_padding(info->filter.be); | |
2180 | if (!bord && info->n_bm == 1) { | |
2181 | for (int j = 0; j < info->bitmap_count; j++) { | |
2182 | if (!info->bitmaps[j].image->bm) | |
2183 | continue; | |
2184 | info->bm = copy_bitmap(render_priv->engine, info->bitmaps[j].image->bm); | |
2185 | if (info->bm) { | |
2186 | info->bm->left += info->bitmaps[j].x; | |
2187 | info->bm->top += info->bitmaps[j].y; | |
2188 | } | |
2189 | break; | |
2190 | } | |
2191 | } else if (info->n_bm) { | |
2192 | info->bm = alloc_bitmap(render_priv->engine, | |
2193 | info->rect.x_max - info->rect.x_min + 2 * bord, | |
2194 | info->rect.y_max - info->rect.y_min + 2 * bord, true); | |
2195 | Bitmap *dst = info->bm; | |
2196 | if (dst) { | |
2197 | dst->left = info->rect.x_min - info->x - bord; | |
2198 | dst->top = info->rect.y_min - info->y - bord; | |
2199 | for (int j = 0; j < info->bitmap_count; j++) { | |
2200 | Bitmap *src = info->bitmaps[j].image->bm; | |
2201 | if (!src) | |
2202 | continue; | |
2203 | int x = info->bitmaps[j].x + src->left - dst->left; | |
2204 | int y = info->bitmaps[j].y + src->top - dst->top; | |
2205 | assert(x >= 0 && x + src->w <= dst->w); | |
2206 | assert(y >= 0 && y + src->h <= dst->h); | |
2207 | unsigned char *buf = dst->buffer + y * dst->stride + x; | |
2208 | render_priv->engine->add_bitmaps(buf, dst->stride, | |
2209 | src->buffer, src->stride, | |
2210 | src->h, src->w); | |
2211 | } | |
2212 | } | |
2213 | } | |
2214 | if (!bord && info->n_bm_o == 1) { | |
2215 | for (int j = 0; j < info->bitmap_count; j++) { | |
2216 | if (!info->bitmaps[j].image->bm_o) | |
2217 | continue; | |
2218 | info->bm_o = copy_bitmap(render_priv->engine, info->bitmaps[j].image->bm_o); | |
2219 | if (info->bm_o) { | |
2220 | info->bm_o->left += info->bitmaps[j].x; | |
2221 | info->bm_o->top += info->bitmaps[j].y; | |
2222 | } | |
2223 | break; | |
2224 | } | |
2225 | } else if (info->n_bm_o) { | |
2226 | info->bm_o = alloc_bitmap(render_priv->engine, | |
2227 | info->rect_o.x_max - info->rect_o.x_min + 2 * bord, | |
2228 | info->rect_o.y_max - info->rect_o.y_min + 2 * bord, | |
2229 | true); | |
2230 | Bitmap *dst = info->bm_o; | |
2231 | if (dst) { | |
2232 | dst->left = info->rect_o.x_min - info->x - bord; | |
2233 | dst->top = info->rect_o.y_min - info->y - bord; | |
2234 | for (int j = 0; j < info->bitmap_count; j++) { | |
2235 | Bitmap *src = info->bitmaps[j].image->bm_o; | |
2236 | if (!src) | |
2237 | continue; | |
2238 | int x = info->bitmaps[j].x + src->left - dst->left; | |
2239 | int y = info->bitmaps[j].y + src->top - dst->top; | |
2240 | assert(x >= 0 && x + src->w <= dst->w); | |
2241 | assert(y >= 0 && y + src->h <= dst->h); | |
2242 | unsigned char *buf = dst->buffer + y * dst->stride + x; | |
2243 | render_priv->engine->add_bitmaps(buf, dst->stride, | |
2244 | src->buffer, src->stride, | |
2245 | src->h, src->w); | |
2246 | } | |
2247 | } | |
2248 | } | |
2249 | ||
2250 | if (info->bm || info->bm_o) { | |
2251 | ass_synth_blur(render_priv->engine, info->filter.flags & FILTER_BORDER_STYLE_3, | |
2252 | info->filter.be, info->filter.blur, info->bm, info->bm_o); | |
2253 | if (info->filter.flags & FILTER_DRAW_SHADOW) | |
2254 | make_shadow_bitmap(info, render_priv); | |
2255 | } | |
2256 | ||
2257 | hv->bm = info->bm; | |
2258 | hv->bm_o = info->bm_o; | |
2259 | hv->bm_s = info->bm_s; | |
2260 | ass_cache_commit(hv, bitmap_size(hv->bm) + | |
2261 | bitmap_size(hv->bm_o) + bitmap_size(hv->bm_s) + | |
2262 | sizeof(CompositeHashKey) + sizeof(CompositeHashValue)); | |
2263 | info->image = hv; | |
2436 | ||
2437 | if (val->bm.buffer) | |
2438 | info->bm = &val->bm; | |
2439 | if (val->bm_o.buffer) | |
2440 | info->bm_o = &val->bm_o; | |
2441 | if (val->bm_s.buffer) | |
2442 | info->bm_s = &val->bm_s; | |
2443 | info->image = val; | |
2444 | continue; | |
2264 | 2445 | } |
2265 | 2446 | |
2266 | 2447 | text_info->n_bitmaps = nb_bitmaps; |
2448 | } | |
2449 | ||
2450 | static inline void rectangle_combine(ASS_Rect *rect, const Bitmap *bm, ASS_Vector pos) | |
2451 | { | |
2452 | pos.x += bm->left; | |
2453 | pos.y += bm->top; | |
2454 | rectangle_update(rect, pos.x, pos.y, pos.x + bm->w, pos.y + bm->h); | |
2455 | } | |
2456 | ||
2457 | size_t ass_composite_construct(void *key, void *value, void *priv) | |
2458 | { | |
2459 | ASS_Renderer *render_priv = priv; | |
2460 | CompositeHashKey *k = key; | |
2461 | CompositeHashValue *v = value; | |
2462 | memset(v, 0, sizeof(*v)); | |
2463 | ||
2464 | ASS_Rect rect, rect_o; | |
2465 | rectangle_reset(&rect); | |
2466 | rectangle_reset(&rect_o); | |
2467 | ||
2468 | size_t n_bm = 0, n_bm_o = 0; | |
2469 | BitmapRef *last = NULL, *last_o = NULL; | |
2470 | for (int i = 0; i < k->bitmap_count; i++) { | |
2471 | BitmapRef *ref = &k->bitmaps[i]; | |
2472 | if (ref->bm) { | |
2473 | rectangle_combine(&rect, ref->bm, ref->pos); | |
2474 | last = ref; | |
2475 | n_bm++; | |
2476 | } | |
2477 | if (ref->bm_o) { | |
2478 | rectangle_combine(&rect_o, ref->bm_o, ref->pos_o); | |
2479 | last_o = ref; | |
2480 | n_bm_o++; | |
2481 | } | |
2482 | } | |
2483 | ||
2484 | int bord = be_padding(k->filter.be); | |
2485 | if (!bord && n_bm == 1) { | |
2486 | copy_bitmap(render_priv->engine, &v->bm, last->bm); | |
2487 | v->bm.left += last->pos.x; | |
2488 | v->bm.top += last->pos.y; | |
2489 | } else if (n_bm && alloc_bitmap(render_priv->engine, &v->bm, | |
2490 | rect.x_max - rect.x_min + 2 * bord, | |
2491 | rect.y_max - rect.y_min + 2 * bord, | |
2492 | true)) { | |
2493 | Bitmap *dst = &v->bm; | |
2494 | dst->left = rect.x_min - bord; | |
2495 | dst->top = rect.y_min - bord; | |
2496 | for (int i = 0; i < k->bitmap_count; i++) { | |
2497 | Bitmap *src = k->bitmaps[i].bm; | |
2498 | if (!src) | |
2499 | continue; | |
2500 | int x = k->bitmaps[i].pos.x + src->left - dst->left; | |
2501 | int y = k->bitmaps[i].pos.y + src->top - dst->top; | |
2502 | assert(x >= 0 && x + src->w <= dst->w); | |
2503 | assert(y >= 0 && y + src->h <= dst->h); | |
2504 | unsigned char *buf = dst->buffer + y * dst->stride + x; | |
2505 | render_priv->engine->add_bitmaps(buf, dst->stride, | |
2506 | src->buffer, src->stride, | |
2507 | src->h, src->w); | |
2508 | } | |
2509 | } | |
2510 | if (!bord && n_bm_o == 1) { | |
2511 | copy_bitmap(render_priv->engine, &v->bm_o, last_o->bm_o); | |
2512 | v->bm_o.left += last_o->pos_o.x; | |
2513 | v->bm_o.top += last_o->pos_o.y; | |
2514 | } else if (n_bm_o && alloc_bitmap(render_priv->engine, &v->bm_o, | |
2515 | rect_o.x_max - rect_o.x_min + 2 * bord, | |
2516 | rect_o.y_max - rect_o.y_min + 2 * bord, | |
2517 | true)) { | |
2518 | Bitmap *dst = &v->bm_o; | |
2519 | dst->left = rect_o.x_min - bord; | |
2520 | dst->top = rect_o.y_min - bord; | |
2521 | for (int i = 0; i < k->bitmap_count; i++) { | |
2522 | Bitmap *src = k->bitmaps[i].bm_o; | |
2523 | if (!src) | |
2524 | continue; | |
2525 | int x = k->bitmaps[i].pos_o.x + src->left - dst->left; | |
2526 | int y = k->bitmaps[i].pos_o.y + src->top - dst->top; | |
2527 | assert(x >= 0 && x + src->w <= dst->w); | |
2528 | assert(y >= 0 && y + src->h <= dst->h); | |
2529 | unsigned char *buf = dst->buffer + y * dst->stride + x; | |
2530 | render_priv->engine->add_bitmaps(buf, dst->stride, | |
2531 | src->buffer, src->stride, | |
2532 | src->h, src->w); | |
2533 | } | |
2534 | } | |
2535 | ||
2536 | int flags = k->filter.flags; | |
2537 | double r2 = restore_blur(k->filter.blur); | |
2538 | if (!(flags & FILTER_NONZERO_BORDER) || (flags & FILTER_BORDER_STYLE_3)) | |
2539 | ass_synth_blur(render_priv->engine, &v->bm, k->filter.be, r2); | |
2540 | ass_synth_blur(render_priv->engine, &v->bm_o, k->filter.be, r2); | |
2541 | ||
2542 | if (!(flags & FILTER_FILL_IN_BORDER) && !(flags & FILTER_FILL_IN_SHADOW)) | |
2543 | fix_outline(&v->bm, &v->bm_o); | |
2544 | ||
2545 | if (flags & FILTER_NONZERO_SHADOW) { | |
2546 | if (flags & FILTER_NONZERO_BORDER) { | |
2547 | copy_bitmap(render_priv->engine, &v->bm_s, &v->bm_o); | |
2548 | if ((flags & FILTER_FILL_IN_BORDER) && !(flags & FILTER_FILL_IN_SHADOW)) | |
2549 | fix_outline(&v->bm, &v->bm_s); | |
2550 | } else if (flags & FILTER_BORDER_STYLE_3) { | |
2551 | v->bm_s = v->bm_o; | |
2552 | memset(&v->bm_o, 0, sizeof(v->bm_o)); | |
2553 | } else { | |
2554 | copy_bitmap(render_priv->engine, &v->bm_s, &v->bm); | |
2555 | } | |
2556 | ||
2557 | // Works right even for negative offsets | |
2558 | // '>>' rounds toward negative infinity, '&' returns correct remainder | |
2559 | v->bm_s.left += k->filter.shadow.x >> 6; | |
2560 | v->bm_s.top += k->filter.shadow.y >> 6; | |
2561 | shift_bitmap(&v->bm_s, k->filter.shadow.x & SUBPIXEL_MASK, k->filter.shadow.y & SUBPIXEL_MASK); | |
2562 | } | |
2563 | ||
2564 | if ((flags & FILTER_FILL_IN_SHADOW) && !(flags & FILTER_FILL_IN_BORDER)) | |
2565 | fix_outline(&v->bm, &v->bm_o); | |
2566 | ||
2567 | return sizeof(CompositeHashKey) + sizeof(CompositeHashValue) + | |
2568 | bitmap_size(&v->bm) + bitmap_size(&v->bm_o) + bitmap_size(&v->bm_s); | |
2267 | 2569 | } |
2268 | 2570 | |
2269 | 2571 | static void add_background(ASS_Renderer *render_priv, EventImages *event_images) |
2302 | 2604 | * \param event_images struct containing resulting images, will also be initialized |
2303 | 2605 | * Process event, appending resulting ASS_Image's to images_root. |
2304 | 2606 | */ |
2305 | static int | |
2607 | static bool | |
2306 | 2608 | ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, |
2307 | 2609 | EventImages *event_images) |
2308 | 2610 | { |
2309 | 2611 | if (event->Style >= render_priv->track->n_styles) { |
2310 | 2612 | ass_msg(render_priv->library, MSGL_WARN, "No style found"); |
2311 | return 1; | |
2613 | return false; | |
2312 | 2614 | } |
2313 | 2615 | if (!event->Text) { |
2314 | 2616 | ass_msg(render_priv->library, MSGL_WARN, "Empty event"); |
2315 | return 1; | |
2617 | return false; | |
2316 | 2618 | } |
2317 | 2619 | |
2318 | 2620 | free_render_context(render_priv); |
2319 | 2621 | init_render_context(render_priv, event); |
2320 | 2622 | |
2321 | if (parse_events(render_priv, event)) | |
2322 | return 1; | |
2623 | if (!parse_events(render_priv, event)) | |
2624 | return false; | |
2323 | 2625 | |
2324 | 2626 | TextInfo *text_info = &render_priv->text_info; |
2325 | 2627 | if (text_info->length == 0) { |
2326 | 2628 | // no valid symbols in the event; this can be smth like {comment} |
2327 | 2629 | free_render_context(render_priv); |
2328 | return 1; | |
2329 | } | |
2630 | return false; | |
2631 | } | |
2632 | ||
2633 | split_style_runs(render_priv); | |
2330 | 2634 | |
2331 | 2635 | // Find shape runs and shape text |
2332 | 2636 | ass_shaper_set_base_direction(render_priv->shaper, |
2333 | 2637 | resolve_base_direction(render_priv->state.font_encoding)); |
2334 | 2638 | ass_shaper_find_runs(render_priv->shaper, render_priv, text_info->glyphs, |
2335 | 2639 | text_info->length); |
2336 | if (ass_shaper_shape(render_priv->shaper, text_info) < 0) { | |
2640 | if (!ass_shaper_shape(render_priv->shaper, text_info)) { | |
2337 | 2641 | ass_msg(render_priv->library, MSGL_ERR, "Failed to shape text"); |
2338 | 2642 | free_render_context(render_priv); |
2339 | return 1; | |
2643 | return false; | |
2340 | 2644 | } |
2341 | 2645 | |
2342 | 2646 | retrieve_glyphs(render_priv); |
2343 | 2647 | |
2344 | 2648 | preliminary_layout(render_priv); |
2345 | ||
2346 | // depends on glyph x coordinates being monotonous, so it should be done before line wrap | |
2347 | process_karaoke_effects(render_priv); | |
2348 | 2649 | |
2349 | 2650 | int valign = render_priv->state.alignment & 12; |
2350 | 2651 | |
2357 | 2658 | |
2358 | 2659 | // calculate max length of a line |
2359 | 2660 | double max_text_width = |
2360 | x2scr(render_priv, render_priv->track->PlayResX - MarginR) - | |
2361 | x2scr(render_priv, MarginL); | |
2661 | x2scr_right(render_priv, render_priv->track->PlayResX - MarginR) - | |
2662 | x2scr_left(render_priv, MarginL); | |
2362 | 2663 | |
2363 | 2664 | // wrap lines |
2364 | if (render_priv->state.evt_type != EVENT_HSCROLL) { | |
2365 | // rearrange text in several lines | |
2366 | wrap_lines_smart(render_priv, max_text_width); | |
2367 | } else { | |
2368 | // no breaking or wrapping, everything in a single line | |
2369 | text_info->lines[0].offset = 0; | |
2370 | text_info->lines[0].len = text_info->length; | |
2371 | text_info->n_lines = 1; | |
2372 | measure_text(render_priv); | |
2373 | } | |
2665 | wrap_lines_smart(render_priv, max_text_width); | |
2666 | ||
2667 | // depends on glyph x coordinates being monotonous within runs, so it should be done before reorder | |
2668 | process_karaoke_effects(render_priv); | |
2374 | 2669 | |
2375 | 2670 | reorder_text(render_priv); |
2376 | 2671 | |
2381 | 2676 | compute_string_bbox(text_info, &bbox); |
2382 | 2677 | |
2383 | 2678 | // determine device coordinates for text |
2384 | ||
2385 | // x coordinate for everything except positioned events | |
2386 | 2679 | double device_x = 0; |
2387 | if (render_priv->state.evt_type == EVENT_NORMAL || | |
2388 | render_priv->state.evt_type == EVENT_VSCROLL) { | |
2389 | device_x = x2scr(render_priv, MarginL); | |
2390 | } else if (render_priv->state.evt_type == EVENT_HSCROLL) { | |
2680 | double device_y = 0; | |
2681 | ||
2682 | // handle positioned events first: an event can be both positioned and | |
2683 | // scrolling, and the scrolling effect overrides the position on one axis | |
2684 | if (render_priv->state.evt_type & EVENT_POSITIONED) { | |
2685 | double base_x = 0; | |
2686 | double base_y = 0; | |
2687 | get_base_point(&bbox, render_priv->state.alignment, &base_x, &base_y); | |
2688 | device_x = | |
2689 | x2scr_pos(render_priv, render_priv->state.pos_x) - base_x; | |
2690 | device_y = | |
2691 | y2scr_pos(render_priv, render_priv->state.pos_y) - base_y; | |
2692 | } | |
2693 | ||
2694 | // x coordinate | |
2695 | if (render_priv->state.evt_type & EVENT_HSCROLL) { | |
2391 | 2696 | if (render_priv->state.scroll_direction == SCROLL_RL) |
2392 | 2697 | device_x = |
2393 | x2scr(render_priv, | |
2698 | x2scr_pos(render_priv, | |
2394 | 2699 | render_priv->track->PlayResX - |
2395 | 2700 | render_priv->state.scroll_shift); |
2396 | 2701 | else if (render_priv->state.scroll_direction == SCROLL_LR) |
2397 | 2702 | device_x = |
2398 | x2scr(render_priv, render_priv->state.scroll_shift) - | |
2703 | x2scr_pos(render_priv, render_priv->state.scroll_shift) - | |
2399 | 2704 | (bbox.x_max - bbox.x_min); |
2400 | } | |
2401 | ||
2402 | // y coordinate for everything except positioned events | |
2403 | double device_y = 0; | |
2404 | if (render_priv->state.evt_type == EVENT_NORMAL || | |
2405 | render_priv->state.evt_type == EVENT_HSCROLL) { | |
2705 | } else if (!(render_priv->state.evt_type & EVENT_POSITIONED)) { | |
2706 | device_x = x2scr_left(render_priv, MarginL); | |
2707 | } | |
2708 | ||
2709 | // y coordinate | |
2710 | if (render_priv->state.evt_type & EVENT_VSCROLL) { | |
2711 | if (render_priv->state.scroll_direction == SCROLL_TB) | |
2712 | device_y = | |
2713 | y2scr(render_priv, | |
2714 | render_priv->state.scroll_y0 + | |
2715 | render_priv->state.scroll_shift) - | |
2716 | bbox.y_max; | |
2717 | else if (render_priv->state.scroll_direction == SCROLL_BT) | |
2718 | device_y = | |
2719 | y2scr(render_priv, | |
2720 | render_priv->state.scroll_y1 - | |
2721 | render_priv->state.scroll_shift) - | |
2722 | bbox.y_min; | |
2723 | } else if (!(render_priv->state.evt_type & EVENT_POSITIONED)) { | |
2406 | 2724 | if (valign == VALIGN_TOP) { // toptitle |
2407 | 2725 | device_y = |
2408 | 2726 | y2scr_top(render_priv, |
2433 | 2751 | device_y = scr_y0; |
2434 | 2752 | } |
2435 | 2753 | } |
2436 | } else if (render_priv->state.evt_type == EVENT_VSCROLL) { | |
2437 | if (render_priv->state.scroll_direction == SCROLL_TB) | |
2438 | device_y = | |
2439 | y2scr(render_priv, | |
2440 | render_priv->state.clip_y0 + | |
2441 | render_priv->state.scroll_shift) - | |
2442 | (bbox.y_max - bbox.y_min); | |
2443 | else if (render_priv->state.scroll_direction == SCROLL_BT) | |
2444 | device_y = | |
2445 | y2scr(render_priv, | |
2446 | render_priv->state.clip_y1 - | |
2447 | render_priv->state.scroll_shift); | |
2448 | } | |
2449 | ||
2450 | // positioned events are totally different | |
2451 | if (render_priv->state.evt_type == EVENT_POSITIONED) { | |
2452 | double base_x = 0; | |
2453 | double base_y = 0; | |
2454 | get_base_point(&bbox, render_priv->state.alignment, &base_x, &base_y); | |
2455 | device_x = | |
2456 | x2scr_pos(render_priv, render_priv->state.pos_x) - base_x; | |
2457 | device_y = | |
2458 | y2scr_pos(render_priv, render_priv->state.pos_y) - base_y; | |
2459 | } | |
2460 | ||
2461 | // fix clip coordinates (they depend on alignment) | |
2462 | if (render_priv->state.evt_type == EVENT_NORMAL || | |
2463 | render_priv->state.evt_type == EVENT_HSCROLL || | |
2464 | render_priv->state.evt_type == EVENT_VSCROLL) { | |
2465 | render_priv->state.clip_x0 = | |
2466 | x2scr_scaled(render_priv, render_priv->state.clip_x0); | |
2467 | render_priv->state.clip_x1 = | |
2468 | x2scr_scaled(render_priv, render_priv->state.clip_x1); | |
2469 | if (valign == VALIGN_TOP) { | |
2470 | render_priv->state.clip_y0 = | |
2471 | y2scr_top(render_priv, render_priv->state.clip_y0); | |
2472 | render_priv->state.clip_y1 = | |
2473 | y2scr_top(render_priv, render_priv->state.clip_y1); | |
2474 | } else if (valign == VALIGN_CENTER) { | |
2475 | render_priv->state.clip_y0 = | |
2476 | y2scr(render_priv, render_priv->state.clip_y0); | |
2477 | render_priv->state.clip_y1 = | |
2478 | y2scr(render_priv, render_priv->state.clip_y1); | |
2479 | } else if (valign == VALIGN_SUB) { | |
2480 | render_priv->state.clip_y0 = | |
2481 | y2scr_sub(render_priv, render_priv->state.clip_y0); | |
2482 | render_priv->state.clip_y1 = | |
2483 | y2scr_sub(render_priv, render_priv->state.clip_y1); | |
2484 | } | |
2485 | } else if (render_priv->state.evt_type == EVENT_POSITIONED) { | |
2754 | } | |
2755 | ||
2756 | // fix clip coordinates | |
2757 | if (render_priv->state.explicit || !render_priv->settings.use_margins) { | |
2486 | 2758 | render_priv->state.clip_x0 = |
2487 | 2759 | x2scr_pos_scaled(render_priv, render_priv->state.clip_x0); |
2488 | 2760 | render_priv->state.clip_x1 = |
2491 | 2763 | y2scr_pos(render_priv, render_priv->state.clip_y0); |
2492 | 2764 | render_priv->state.clip_y1 = |
2493 | 2765 | y2scr_pos(render_priv, render_priv->state.clip_y1); |
2494 | } | |
2495 | ||
2496 | if (render_priv->state.explicit) { | |
2497 | // we still need to clip against screen boundaries | |
2498 | double zx = x2scr_pos_scaled(render_priv, 0); | |
2499 | double zy = y2scr_pos(render_priv, 0); | |
2500 | double sx = x2scr_pos_scaled(render_priv, render_priv->track->PlayResX); | |
2501 | double sy = y2scr_pos(render_priv, render_priv->track->PlayResY); | |
2502 | ||
2503 | render_priv->state.clip_x0 = render_priv->state.clip_x0 < zx ? zx : render_priv->state.clip_x0; | |
2504 | render_priv->state.clip_y0 = render_priv->state.clip_y0 < zy ? zy : render_priv->state.clip_y0; | |
2505 | render_priv->state.clip_x1 = render_priv->state.clip_x1 > sx ? sx : render_priv->state.clip_x1; | |
2506 | render_priv->state.clip_y1 = render_priv->state.clip_y1 > sy ? sy : render_priv->state.clip_y1; | |
2766 | ||
2767 | if (render_priv->state.explicit) { | |
2768 | // we still need to clip against screen boundaries | |
2769 | double zx = x2scr_pos_scaled(render_priv, 0); | |
2770 | double zy = y2scr_pos(render_priv, 0); | |
2771 | double sx = x2scr_pos_scaled(render_priv, render_priv->track->PlayResX); | |
2772 | double sy = y2scr_pos(render_priv, render_priv->track->PlayResY); | |
2773 | ||
2774 | render_priv->state.clip_x0 = FFMAX(render_priv->state.clip_x0, zx); | |
2775 | render_priv->state.clip_y0 = FFMAX(render_priv->state.clip_y0, zy); | |
2776 | render_priv->state.clip_x1 = FFMIN(render_priv->state.clip_x1, sx); | |
2777 | render_priv->state.clip_y1 = FFMIN(render_priv->state.clip_y1, sy); | |
2778 | } | |
2779 | } else { | |
2780 | // no \clip (explicit==0) and use_margins => only clip to screen with margins | |
2781 | render_priv->state.clip_x0 = 0; | |
2782 | render_priv->state.clip_y0 = 0; | |
2783 | render_priv->state.clip_x1 = render_priv->settings.frame_width; | |
2784 | render_priv->state.clip_y1 = render_priv->settings.frame_height; | |
2785 | } | |
2786 | ||
2787 | if (render_priv->state.evt_type & EVENT_VSCROLL) { | |
2788 | double y0 = y2scr_pos(render_priv, render_priv->state.scroll_y0); | |
2789 | double y1 = y2scr_pos(render_priv, render_priv->state.scroll_y1); | |
2790 | ||
2791 | render_priv->state.clip_y0 = FFMAX(render_priv->state.clip_y0, y0); | |
2792 | render_priv->state.clip_y1 = FFMIN(render_priv->state.clip_y1, y1); | |
2507 | 2793 | } |
2508 | 2794 | |
2509 | 2795 | calculate_rotation_params(render_priv, &bbox, device_x, device_y); |
2511 | 2797 | render_and_combine_glyphs(render_priv, device_x, device_y); |
2512 | 2798 | |
2513 | 2799 | memset(event_images, 0, sizeof(*event_images)); |
2514 | event_images->top = device_y - text_info->lines[0].asc; | |
2515 | event_images->height = text_info->height; | |
2800 | // VSFilter does *not* shift lines with a border > margin to be within the | |
2801 | // frame, so negative values for top and left may occur | |
2802 | event_images->top = device_y - text_info->lines[0].asc - text_info->border_top; | |
2803 | event_images->height = | |
2804 | text_info->height + text_info->border_bottom + text_info->border_top; | |
2516 | 2805 | event_images->left = |
2517 | (device_x + bbox.x_min * render_priv->font_scale_x) + 0.5; | |
2806 | (device_x + bbox.x_min) * render_priv->font_scale_x - text_info->border_x + 0.5; | |
2518 | 2807 | event_images->width = |
2519 | (bbox.x_max - bbox.x_min) * render_priv->font_scale_x + 0.5; | |
2808 | (bbox.x_max - bbox.x_min) * render_priv->font_scale_x | |
2809 | + 2 * text_info->border_x + 0.5; | |
2520 | 2810 | event_images->detect_collisions = render_priv->state.detect_collisions; |
2521 | event_images->shift_direction = (valign == VALIGN_TOP) ? 1 : -1; | |
2811 | event_images->shift_direction = (valign == VALIGN_SUB) ? -1 : 1; | |
2522 | 2812 | event_images->event = event; |
2523 | 2813 | event_images->imgs = render_text(render_priv); |
2524 | 2814 | |
2528 | 2818 | ass_shaper_cleanup(render_priv->shaper, text_info); |
2529 | 2819 | free_render_context(render_priv); |
2530 | 2820 | |
2531 | return 0; | |
2821 | return true; | |
2532 | 2822 | } |
2533 | 2823 | |
2534 | 2824 | /** |
2544 | 2834 | /** |
2545 | 2835 | * \brief Start a new frame |
2546 | 2836 | */ |
2547 | static int | |
2837 | static bool | |
2548 | 2838 | ass_start_frame(ASS_Renderer *render_priv, ASS_Track *track, |
2549 | 2839 | long long now) |
2550 | 2840 | { |
2552 | 2842 | |
2553 | 2843 | if (!render_priv->settings.frame_width |
2554 | 2844 | && !render_priv->settings.frame_height) |
2555 | return 1; // library not initialized | |
2845 | return false; // library not initialized | |
2556 | 2846 | |
2557 | 2847 | if (!render_priv->fontselect) |
2558 | return 1; | |
2848 | return false; | |
2559 | 2849 | |
2560 | 2850 | if (render_priv->library != track->library) |
2561 | return 1; | |
2851 | return false; | |
2562 | 2852 | |
2563 | 2853 | if (track->n_events == 0) |
2564 | return 1; // nothing to do | |
2854 | return false; // nothing to do | |
2565 | 2855 | |
2566 | 2856 | render_priv->track = track; |
2567 | 2857 | render_priv->time = now; |
2571 | 2861 | ass_shaper_set_kerning(render_priv->shaper, track->Kerning); |
2572 | 2862 | ass_shaper_set_language(render_priv->shaper, track->Language); |
2573 | 2863 | ass_shaper_set_level(render_priv->shaper, render_priv->settings.shaper); |
2864 | #ifdef USE_FRIBIDI_EX_API | |
2865 | ass_shaper_set_bidi_brackets(render_priv->shaper, | |
2866 | track->parser_priv->bidi_brackets); | |
2867 | #endif | |
2574 | 2868 | |
2575 | 2869 | // PAR correction |
2576 | 2870 | double par = render_priv->settings.par; |
2577 | 2871 | if (par == 0.) { |
2578 | if (settings_priv->frame_width && settings_priv->frame_height && | |
2872 | if (render_priv->orig_width && render_priv->orig_height && | |
2579 | 2873 | settings_priv->storage_width && settings_priv->storage_height) { |
2580 | double dar = ((double) settings_priv->frame_width) / | |
2581 | settings_priv->frame_height; | |
2874 | double dar = ((double) render_priv->orig_width) / | |
2875 | render_priv->orig_height; | |
2582 | 2876 | double sar = ((double) settings_priv->storage_width) / |
2583 | 2877 | settings_priv->storage_height; |
2584 | par = sar / dar; | |
2878 | par = dar / sar; | |
2585 | 2879 | } else |
2586 | 2880 | par = 1.0; |
2587 | 2881 | } |
2592 | 2886 | |
2593 | 2887 | check_cache_limits(render_priv, &render_priv->cache); |
2594 | 2888 | |
2595 | return 0; | |
2889 | return true; | |
2596 | 2890 | } |
2597 | 2891 | |
2598 | 2892 | static int cmp_event_layer(const void *p1, const void *p2) |
2626 | 2920 | return event->render_priv; |
2627 | 2921 | } |
2628 | 2922 | |
2629 | static int overlap(Segment *s1, Segment *s2) | |
2630 | { | |
2631 | if (s1->a >= s2->b || s2->a >= s1->b || | |
2632 | s1->ha >= s2->hb || s2->ha >= s1->hb) | |
2923 | static int overlap(Rect *s1, Rect *s2) | |
2924 | { | |
2925 | if (s1->y0 >= s2->y1 || s2->y0 >= s1->y1 || | |
2926 | s1->x0 >= s2->x1 || s2->x0 >= s1->x1) | |
2633 | 2927 | return 0; |
2634 | 2928 | return 1; |
2635 | 2929 | } |
2636 | 2930 | |
2637 | static int cmp_segment(const void *p1, const void *p2) | |
2638 | { | |
2639 | return ((Segment *) p1)->a - ((Segment *) p2)->a; | |
2931 | static int cmp_rect_y0(const void *p1, const void *p2) | |
2932 | { | |
2933 | return ((Rect *) p1)->y0 - ((Rect *) p2)->y0; | |
2640 | 2934 | } |
2641 | 2935 | |
2642 | 2936 | static void |
2667 | 2961 | |
2668 | 2962 | // dir: 1 - move down |
2669 | 2963 | // -1 - move up |
2670 | static int fit_segment(Segment *s, Segment *fixed, int *cnt, int dir) | |
2964 | static int fit_rect(Rect *s, Rect *fixed, int *cnt, int dir) | |
2671 | 2965 | { |
2672 | 2966 | int i; |
2673 | 2967 | int shift = 0; |
2674 | 2968 | |
2675 | 2969 | if (dir == 1) // move down |
2676 | 2970 | for (i = 0; i < *cnt; ++i) { |
2677 | if (s->b + shift <= fixed[i].a || s->a + shift >= fixed[i].b || | |
2678 | s->hb <= fixed[i].ha || s->ha >= fixed[i].hb) | |
2971 | if (s->y1 + shift <= fixed[i].y0 || s->y0 + shift >= fixed[i].y1 || | |
2972 | s->x1 <= fixed[i].x0 || s->x0 >= fixed[i].x1) | |
2679 | 2973 | continue; |
2680 | shift = fixed[i].b - s->a; | |
2974 | shift = fixed[i].y1 - s->y0; | |
2681 | 2975 | } else // dir == -1, move up |
2682 | 2976 | for (i = *cnt - 1; i >= 0; --i) { |
2683 | if (s->b + shift <= fixed[i].a || s->a + shift >= fixed[i].b || | |
2684 | s->hb <= fixed[i].ha || s->ha >= fixed[i].hb) | |
2977 | if (s->y1 + shift <= fixed[i].y0 || s->y0 + shift >= fixed[i].y1 || | |
2978 | s->x1 <= fixed[i].x0 || s->x0 >= fixed[i].x1) | |
2685 | 2979 | continue; |
2686 | shift = fixed[i].a - s->b; | |
2687 | } | |
2688 | ||
2689 | fixed[*cnt].a = s->a + shift; | |
2690 | fixed[*cnt].b = s->b + shift; | |
2691 | fixed[*cnt].ha = s->ha; | |
2692 | fixed[*cnt].hb = s->hb; | |
2980 | shift = fixed[i].y0 - s->y1; | |
2981 | } | |
2982 | ||
2983 | fixed[*cnt].y0 = s->y0 + shift; | |
2984 | fixed[*cnt].y1 = s->y1 + shift; | |
2985 | fixed[*cnt].x0 = s->x0; | |
2986 | fixed[*cnt].x1 = s->x1; | |
2693 | 2987 | (*cnt)++; |
2694 | qsort(fixed, *cnt, sizeof(Segment), cmp_segment); | |
2988 | qsort(fixed, *cnt, sizeof(*fixed), cmp_rect_y0); | |
2695 | 2989 | |
2696 | 2990 | return shift; |
2697 | 2991 | } |
2699 | 2993 | static void |
2700 | 2994 | fix_collisions(ASS_Renderer *render_priv, EventImages *imgs, int cnt) |
2701 | 2995 | { |
2702 | Segment *used = ass_realloc_array(NULL, cnt, sizeof(*used)); | |
2996 | Rect *used = ass_realloc_array(NULL, cnt, sizeof(*used)); | |
2703 | 2997 | int cnt_used = 0; |
2704 | 2998 | int i, j; |
2705 | 2999 | |
2713 | 3007 | continue; |
2714 | 3008 | priv = get_render_priv(render_priv, imgs[i].event); |
2715 | 3009 | if (priv && priv->height > 0) { // it's a fixed event |
2716 | Segment s; | |
2717 | s.a = priv->top; | |
2718 | s.b = priv->top + priv->height; | |
2719 | s.ha = priv->left; | |
2720 | s.hb = priv->left + priv->width; | |
3010 | Rect s; | |
3011 | s.y0 = priv->top; | |
3012 | s.y1 = priv->top + priv->height; | |
3013 | s.x0 = priv->left; | |
3014 | s.x1 = priv->left + priv->width; | |
2721 | 3015 | if (priv->height != imgs[i].height) { // no, it's not |
2722 | 3016 | ass_msg(render_priv->library, MSGL_WARN, |
2723 | 3017 | "Event height has changed"); |
2734 | 3028 | priv->width = 0; |
2735 | 3029 | } |
2736 | 3030 | if (priv->height > 0) { // still a fixed event |
2737 | used[cnt_used].a = priv->top; | |
2738 | used[cnt_used].b = priv->top + priv->height; | |
2739 | used[cnt_used].ha = priv->left; | |
2740 | used[cnt_used].hb = priv->left + priv->width; | |
3031 | used[cnt_used].y0 = priv->top; | |
3032 | used[cnt_used].y1 = priv->top + priv->height; | |
3033 | used[cnt_used].x0 = priv->left; | |
3034 | used[cnt_used].x1 = priv->left + priv->width; | |
2741 | 3035 | cnt_used++; |
2742 | 3036 | shift_event(render_priv, imgs + i, priv->top - imgs[i].top); |
2743 | 3037 | } |
2744 | 3038 | } |
2745 | 3039 | } |
2746 | qsort(used, cnt_used, sizeof(Segment), cmp_segment); | |
3040 | qsort(used, cnt_used, sizeof(*used), cmp_rect_y0); | |
2747 | 3041 | |
2748 | 3042 | // try to fit other events in free spaces |
2749 | 3043 | for (i = 0; i < cnt; ++i) { |
2753 | 3047 | priv = get_render_priv(render_priv, imgs[i].event); |
2754 | 3048 | if (priv && priv->height == 0) { // not a fixed event |
2755 | 3049 | int shift; |
2756 | Segment s; | |
2757 | s.a = imgs[i].top; | |
2758 | s.b = imgs[i].top + imgs[i].height; | |
2759 | s.ha = imgs[i].left; | |
2760 | s.hb = imgs[i].left + imgs[i].width; | |
2761 | shift = fit_segment(&s, used, &cnt_used, imgs[i].shift_direction); | |
3050 | Rect s; | |
3051 | s.y0 = imgs[i].top; | |
3052 | s.y1 = imgs[i].top + imgs[i].height; | |
3053 | s.x0 = imgs[i].left; | |
3054 | s.x1 = imgs[i].left + imgs[i].width; | |
3055 | shift = fit_rect(&s, used, &cnt_used, imgs[i].shift_direction); | |
2762 | 3056 | if (shift) |
2763 | 3057 | shift_event(render_priv, imgs + i, shift); |
2764 | 3058 | // make it fixed |
2847 | 3141 | ASS_Image *ass_render_frame(ASS_Renderer *priv, ASS_Track *track, |
2848 | 3142 | long long now, int *detect_change) |
2849 | 3143 | { |
2850 | int i, cnt, rc; | |
2851 | EventImages *last; | |
2852 | ASS_Image **tail; | |
2853 | ||
2854 | 3144 | // init frame |
2855 | rc = ass_start_frame(priv, track, now); | |
2856 | if (rc != 0) { | |
2857 | if (detect_change) { | |
3145 | if (!ass_start_frame(priv, track, now)) { | |
3146 | if (detect_change) | |
2858 | 3147 | *detect_change = 2; |
2859 | } | |
2860 | 3148 | return NULL; |
2861 | 3149 | } |
2862 | 3150 | |
2863 | 3151 | // render events separately |
2864 | cnt = 0; | |
2865 | for (i = 0; i < track->n_events; ++i) { | |
3152 | int cnt = 0; | |
3153 | for (int i = 0; i < track->n_events; i++) { | |
2866 | 3154 | ASS_Event *event = track->events + i; |
2867 | 3155 | if ((event->Start <= now) |
2868 | 3156 | && (now < (event->Start + event->Duration))) { |
2872 | 3160 | realloc(priv->eimg, |
2873 | 3161 | priv->eimg_size * sizeof(EventImages)); |
2874 | 3162 | } |
2875 | rc = ass_render_event(priv, event, priv->eimg + cnt); | |
2876 | if (!rc) | |
2877 | ++cnt; | |
3163 | if (ass_render_event(priv, event, priv->eimg + cnt)) | |
3164 | cnt++; | |
2878 | 3165 | } |
2879 | 3166 | } |
2880 | 3167 | |
2881 | 3168 | // sort by layer |
2882 | qsort(priv->eimg, cnt, sizeof(EventImages), cmp_event_layer); | |
3169 | if (cnt > 0) | |
3170 | qsort(priv->eimg, cnt, sizeof(EventImages), cmp_event_layer); | |
2883 | 3171 | |
2884 | 3172 | // call fix_collisions for each group of events with the same layer |
2885 | last = priv->eimg; | |
2886 | for (i = 1; i < cnt; ++i) | |
3173 | EventImages *last = priv->eimg; | |
3174 | for (int i = 1; i < cnt; i++) | |
2887 | 3175 | if (last->event->Layer != priv->eimg[i].event->Layer) { |
2888 | 3176 | fix_collisions(priv, last, priv->eimg + i - last); |
2889 | 3177 | last = priv->eimg + i; |
2892 | 3180 | fix_collisions(priv, last, priv->eimg + cnt - last); |
2893 | 3181 | |
2894 | 3182 | // concat lists |
2895 | tail = &priv->images_root; | |
2896 | for (i = 0; i < cnt; ++i) { | |
3183 | ASS_Image **tail = &priv->images_root; | |
3184 | for (int i = 0; i < cnt; i++) { | |
2897 | 3185 | ASS_Image *cur = priv->eimg[i].imgs; |
2898 | 3186 | while (cur) { |
2899 | 3187 | *tail = cur; |
2935 | 3223 | do { |
2936 | 3224 | ASS_ImagePriv *priv = (ASS_ImagePriv *) img; |
2937 | 3225 | img = img->next; |
2938 | if (priv->source) | |
2939 | ass_cache_dec_ref(priv->source); | |
2940 | else | |
2941 | ass_aligned_free(priv->result.bitmap); | |
3226 | ass_cache_dec_ref(priv->source); | |
3227 | ass_aligned_free(priv->buffer); | |
2942 | 3228 | free(priv); |
2943 | 3229 | } while (img); |
2944 | 3230 | } |
20 | 20 | #define LIBASS_RENDER_H |
21 | 21 | |
22 | 22 | #include <inttypes.h> |
23 | #include <stdbool.h> | |
23 | 24 | #include <ft2build.h> |
24 | 25 | #include FT_FREETYPE_H |
25 | 26 | #include FT_GLYPH_H |
26 | 27 | #include FT_SYNTHESIS_H |
27 | #ifdef CONFIG_HARFBUZZ | |
28 | 28 | #include <hb.h> |
29 | #endif | |
30 | 29 | |
31 | 30 | #include "ass.h" |
32 | 31 | #include "ass_font.h" |
51 | 50 | typedef struct { |
52 | 51 | ASS_Image result; |
53 | 52 | CompositeHashValue *source; |
53 | unsigned char *buffer; | |
54 | 54 | size_t ref_count; |
55 | 55 | } ASS_ImagePriv; |
56 | 56 | |
62 | 62 | double font_size_coeff; // font size multiplier |
63 | 63 | double line_spacing; // additional line spacing (in frame pixels) |
64 | 64 | double line_position; // vertical position for subtitles, 0-100 (0 = no change) |
65 | int top_margin; // height of top margin. Everything except toptitles is shifted down by top_margin. | |
65 | int top_margin; // height of top margin. Video frame is shifted down by top_margin. | |
66 | 66 | int bottom_margin; // height of bottom margin. (frame_height - top_margin - bottom_margin) is original video height. |
67 | 67 | int left_margin; |
68 | 68 | int right_margin; |
69 | 69 | int use_margins; // 0 - place all subtitles inside original frame |
70 | // 1 - use margins for placing toptitles and subtitles | |
70 | // 1 - place subtitles (incl. toptitles) in full display frame incl. margins | |
71 | 71 | double par; // user defined pixel aspect ratio (0 = unset) |
72 | 72 | ASS_Hinting hinting; |
73 | 73 | ASS_ShapingLevel shaper; |
98 | 98 | FilterDesc filter; |
99 | 99 | uint32_t c[4]; // colors |
100 | 100 | Effect effect_type; |
101 | int effect_timing; // time duration of current karaoke word | |
102 | // after process_karaoke_effects: distance in pixels from the glyph origin. | |
101 | ||
102 | // during render_and_combine_glyphs: distance in subpixels from the karaoke origin. | |
103 | // after render_and_combine_glyphs: screen coordinate in pixels. | |
103 | 104 | // part of the glyph to the left of it is displayed in a different color. |
104 | ||
105 | int first_pos_x; | |
105 | int effect_timing; | |
106 | ||
107 | // karaoke origin: screen coordinate of leftmost post-transform control point x in subpixels | |
108 | int32_t leftmost_x; | |
106 | 109 | |
107 | 110 | size_t bitmap_count, max_bitmap_count; |
108 | 111 | BitmapRef *bitmaps; |
109 | 112 | |
110 | 113 | int x, y; |
111 | ASS_Rect rect, rect_o; | |
112 | size_t n_bm, n_bm_o; | |
113 | ||
114 | 114 | Bitmap *bm, *bm_o, *bm_s; // glyphs, outline, shadow bitmaps |
115 | 115 | CompositeHashValue *image; |
116 | 116 | } CombinedBitmapInfo; |
117 | ||
118 | typedef struct { | |
119 | ASS_DVector scale, offset; | |
120 | } ASS_Transform; | |
117 | 121 | |
118 | 122 | // describes a glyph |
119 | 123 | // GlyphInfo and TextInfo are used for text centering and word-wrapping operations |
120 | 124 | typedef struct glyph_info { |
121 | 125 | unsigned symbol; |
122 | unsigned skip; // skip glyph when layouting text | |
126 | bool skip; // skip glyph when layouting text | |
127 | bool is_trimmed_whitespace; | |
123 | 128 | ASS_Font *font; |
124 | 129 | int face_index; |
125 | 130 | int glyph_index; |
126 | #ifdef CONFIG_HARFBUZZ | |
127 | 131 | hb_script_t script; |
128 | #else | |
129 | int script; | |
130 | #endif | |
131 | 132 | double font_size; |
132 | ASS_Drawing *drawing; | |
133 | ASS_Outline *outline; | |
134 | ASS_Outline *border[2]; | |
133 | char *drawing_text; | |
134 | int drawing_scale; | |
135 | int drawing_pbo; | |
136 | OutlineHashValue *outline; | |
137 | ASS_Transform transform; | |
135 | 138 | ASS_Rect bbox; |
136 | 139 | ASS_Vector pos; |
137 | 140 | ASS_Vector offset; |
138 | 141 | char linebreak; // the first (leading) glyph of some line ? |
142 | bool starts_new_run; | |
139 | 143 | uint32_t c[4]; // colors |
144 | uint8_t a_pre_fade[4]; // alpha values before applying fades | |
140 | 145 | ASS_Vector advance; // 26.6 |
141 | 146 | ASS_Vector cluster_advance; |
142 | char effect; // the first (leading) glyph of some effect ? | |
143 | 147 | Effect effect_type; |
144 | 148 | int effect_timing; // time duration of current karaoke word |
145 | // after process_karaoke_effects: distance in pixels from the glyph origin. | |
149 | // after process_karaoke_effects: distance in subpixels from the karaoke origin. | |
146 | 150 | // part of the glyph to the left of it is displayed in a different color. |
147 | 151 | int effect_skip_timing; // delay after the end of last karaoke word |
148 | 152 | int asc, desc; // font max ascender and descender |
153 | 157 | double frx, fry, frz; // rotation |
154 | 158 | double fax, fay; // text shearing |
155 | 159 | double scale_x, scale_y; |
156 | double orig_scale_x, orig_scale_y; // scale_x,y before fix_glyph_scaling | |
160 | // amount of scale_x,y change due to fix_glyph_scaling | |
161 | // scale_fix = before / after | |
162 | double scale_fix; | |
157 | 163 | int border_style; |
158 | 164 | double border_x, border_y; |
159 | 165 | double hspacing; |
166 | int hspacing_scaled; // 26.6 | |
160 | 167 | unsigned italic; |
161 | 168 | unsigned bold; |
162 | 169 | int flags; |
163 | 170 | |
164 | 171 | int shape_run_id; |
165 | 172 | |
166 | BitmapHashKey hash_key; | |
167 | BitmapHashValue *image; | |
173 | ASS_Vector shift; | |
174 | Bitmap *bm, *bm_o; | |
168 | 175 | |
169 | 176 | // next glyph in this cluster |
170 | 177 | struct glyph_info *next; |
183 | 190 | CombinedBitmapInfo *combined_bitmaps; |
184 | 191 | unsigned n_bitmaps; |
185 | 192 | double height; |
193 | int border_top; | |
194 | int border_bottom; | |
195 | int border_x; | |
186 | 196 | int max_glyphs; |
187 | 197 | int max_lines; |
188 | 198 | unsigned max_bitmaps; |
193 | 203 | typedef struct { |
194 | 204 | ASS_Event *event; |
195 | 205 | ASS_Style *style; |
196 | int parsed_tags; | |
197 | 206 | |
198 | 207 | ASS_Font *font; |
199 | 208 | double font_size; |
209 | int parsed_tags; | |
200 | 210 | int flags; // decoration flags (underline/strike-through) |
201 | 211 | |
202 | 212 | int alignment; // alignment overrides go here; if zero, style value will be used |
203 | 213 | int justify; // justify instructions |
204 | 214 | double frx, fry, frz; |
205 | 215 | double fax, fay; // text shearing |
206 | enum { | |
207 | EVENT_NORMAL, // "normal" top-, sub- or mid- title | |
208 | EVENT_POSITIONED, // happens after pos(,), margins are ignored | |
209 | EVENT_HSCROLL, // "Banner" transition effect, text_width is unlimited | |
210 | EVENT_VSCROLL // "Scroll up", "Scroll down" transition effects | |
211 | } evt_type; | |
212 | 216 | double pos_x, pos_y; // position |
213 | 217 | double org_x, org_y; // origin |
214 | char have_origin; // origin is explicitly defined; if 0, get_base_point() is used | |
215 | 218 | double scale_x, scale_y; |
216 | 219 | double hspacing; // distance between letters, in pixels |
217 | int border_style; | |
218 | 220 | double border_x; // outline width |
219 | 221 | double border_y; |
222 | enum { | |
223 | EVENT_NORMAL = 0, // "normal" top-, sub- or mid- title | |
224 | EVENT_POSITIONED = 1, // happens after \pos or \move, margins are ignored | |
225 | EVENT_HSCROLL = 2, // "Banner" transition effect, text_width is unlimited | |
226 | EVENT_VSCROLL = 4 // "Scroll up", "Scroll down" transition effects | |
227 | } evt_type; | |
228 | int border_style; | |
220 | 229 | uint32_t c[4]; // colors(Primary, Secondary, so on) in RGBA |
221 | 230 | int clip_x0, clip_y0, clip_x1, clip_y1; |
231 | char have_origin; // origin is explicitly defined; if 0, get_base_point() is used | |
222 | 232 | char clip_mode; // 1 = iclip |
223 | 233 | char detect_collisions; |
234 | char be; // blur edges | |
224 | 235 | int fade; // alpha from \fad |
225 | char be; // blur edges | |
226 | 236 | double blur; // gaussian blur |
227 | 237 | double shadow_x; |
228 | 238 | double shadow_y; |
239 | double pbo; // drawing baseline offset | |
240 | char *clip_drawing_text; | |
241 | ||
242 | // used to store RenderContext.style when doing selective style overrides | |
243 | ASS_Style override_style_temp_storage; | |
244 | ||
229 | 245 | int drawing_scale; // currently reading: regular text if 0, drawing otherwise |
230 | double pbo; // drawing baseline offset | |
231 | ASS_Drawing *clip_drawing; // clip vector | |
246 | int clip_drawing_scale; | |
232 | 247 | int clip_drawing_mode; // 0 = regular clip, 1 = inverse clip |
233 | 248 | |
234 | 249 | Effect effect_type; |
242 | 257 | SCROLL_BT |
243 | 258 | } scroll_direction; // for EVENT_HSCROLL, EVENT_VSCROLL |
244 | 259 | int scroll_shift; |
260 | int scroll_y0, scroll_y1; | |
245 | 261 | |
246 | 262 | // face properties |
247 | 263 | char *family; |
257 | 273 | int apply_font_scale; |
258 | 274 | // whether this is assumed to be explicitly positioned |
259 | 275 | int explicit; |
260 | ||
261 | // used to store RenderContext.style when doing selective style overrides | |
262 | ASS_Style override_style_temp_storage; | |
263 | 276 | } RenderContext; |
264 | 277 | |
265 | 278 | typedef struct { |
292 | 305 | int width, height; // screen dimensions |
293 | 306 | int orig_height; // frame height ( = screen height - margins ) |
294 | 307 | int orig_width; // frame width ( = screen width - margins ) |
295 | int orig_height_nocrop; // frame height ( = screen height - margins + cropheight) | |
296 | int orig_width_nocrop; // frame width ( = screen width - margins + cropwidth) | |
308 | double fit_height; // frame height without zoom & pan (fit to screen & letterboxed) | |
309 | double fit_width; // frame width without zoom & pan (fit to screen & letterboxed) | |
297 | 310 | ASS_Track *track; |
298 | 311 | long long time; // frame's timestamp, ms |
299 | 312 | double font_scale; |
323 | 336 | int y1; |
324 | 337 | } Rect; |
325 | 338 | |
326 | typedef struct { | |
327 | int a, b; // top and height | |
328 | int ha, hb; // left and width | |
329 | } Segment; | |
330 | ||
331 | 339 | void reset_render_context(ASS_Renderer *render_priv, ASS_Style *style); |
332 | 340 | void ass_frame_ref(ASS_Image *img); |
333 | 341 | void ass_frame_unref(ASS_Image *img); |
36 | 36 | settings->right_margin; |
37 | 37 | priv->orig_height = settings->frame_height - settings->top_margin - |
38 | 38 | settings->bottom_margin; |
39 | priv->orig_width_nocrop = | |
40 | settings->frame_width - FFMAX(settings->left_margin, 0) - | |
41 | FFMAX(settings->right_margin, 0); | |
42 | priv->orig_height_nocrop = | |
43 | settings->frame_height - FFMAX(settings->top_margin, 0) - | |
44 | FFMAX(settings->bottom_margin, 0); | |
39 | priv->fit_width = | |
40 | (long long) priv->orig_width * priv->height >= | |
41 | (long long) priv->orig_height * priv->width ? | |
42 | priv->width : | |
43 | (double) priv->orig_width * priv->height / priv->orig_height; | |
44 | priv->fit_height = | |
45 | (long long) priv->orig_width * priv->height <= | |
46 | (long long) priv->orig_height * priv->width ? | |
47 | priv->height : | |
48 | (double) priv->orig_height * priv->width / priv->orig_width; | |
45 | 49 | } |
46 | 50 | |
47 | 51 | void ass_set_frame_size(ASS_Renderer *priv, int w, int h) |
65 | 69 | |
66 | 70 | void ass_set_shaper(ASS_Renderer *priv, ASS_ShapingLevel level) |
67 | 71 | { |
68 | #ifdef CONFIG_HARFBUZZ | |
69 | 72 | // select the complex shaper for illegal values |
70 | 73 | if (level == ASS_SHAPING_SIMPLE || level == ASS_SHAPING_COMPLEX) |
71 | 74 | priv->settings.shaper = level; |
72 | 75 | else |
73 | 76 | priv->settings.shaper = ASS_SHAPING_COMPLEX; |
74 | #endif | |
75 | 77 | } |
76 | 78 | |
77 | 79 | void ass_set_margins(ASS_Renderer *priv, int t, int b, int l, int r) |
26 | 26 | #include <limits.h> |
27 | 27 | #include <stdbool.h> |
28 | 28 | |
29 | #ifdef CONFIG_HARFBUZZ | |
30 | #include <hb-ft.h> | |
29 | #include <ft2build.h> | |
30 | #include FT_FREETYPE_H | |
31 | #include FT_TRUETYPE_TABLES_H | |
31 | 32 | enum { |
32 | 33 | VERT = 0, |
33 | 34 | VKNA, |
36 | 37 | CLIG |
37 | 38 | }; |
38 | 39 | #define NUM_FEATURES 5 |
39 | #endif | |
40 | 40 | |
41 | 41 | struct ass_shaper { |
42 | 42 | ASS_ShapingLevel shaping_level; |
49 | 49 | FriBidiStrIndex *cmap; |
50 | 50 | FriBidiParType base_direction; |
51 | 51 | |
52 | #ifdef CONFIG_HARFBUZZ | |
53 | 52 | // OpenType features |
54 | 53 | int n_features; |
55 | 54 | hb_feature_t *features; |
57 | 56 | |
58 | 57 | // Glyph metrics cache, to speed up shaping |
59 | 58 | Cache *metrics_cache; |
59 | ||
60 | #ifdef USE_FRIBIDI_EX_API | |
61 | FriBidiBracketType *btypes; | |
62 | bool bidi_brackets; | |
60 | 63 | #endif |
61 | 64 | }; |
62 | 65 | |
63 | #ifdef CONFIG_HARFBUZZ | |
64 | 66 | struct ass_shaper_metrics_data { |
65 | 67 | Cache *metrics_cache; |
66 | 68 | GlyphMetricsHashKey hash_key; |
72 | 74 | hb_font_funcs_t *font_funcs[ASS_FONT_MAX_FACES]; |
73 | 75 | struct ass_shaper_metrics_data *metrics_data[ASS_FONT_MAX_FACES]; |
74 | 76 | }; |
75 | #endif | |
76 | 77 | |
77 | 78 | /** |
78 | 79 | * \brief Print version information |
81 | 82 | { |
82 | 83 | ass_msg(lib, MSGL_INFO, "Shaper: FriBidi " |
83 | 84 | FRIBIDI_VERSION " (SIMPLE)" |
84 | #ifdef CONFIG_HARFBUZZ | |
85 | 85 | " HarfBuzz-ng %s (COMPLEX)", hb_version_string() |
86 | #endif | |
87 | 86 | ); |
88 | 87 | } |
89 | 88 | |
96 | 95 | if (new_size > shaper->n_glyphs) { |
97 | 96 | if (!ASS_REALLOC_ARRAY(shaper->event_text, new_size) || |
98 | 97 | !ASS_REALLOC_ARRAY(shaper->ctypes, new_size) || |
98 | #ifdef USE_FRIBIDI_EX_API | |
99 | (shaper->bidi_brackets && !ASS_REALLOC_ARRAY(shaper->btypes, new_size)) || | |
100 | #endif | |
99 | 101 | !ASS_REALLOC_ARRAY(shaper->emblevels, new_size) || |
100 | 102 | !ASS_REALLOC_ARRAY(shaper->cmap, new_size)) |
101 | 103 | return false; |
109 | 111 | */ |
110 | 112 | void ass_shaper_free(ASS_Shaper *shaper) |
111 | 113 | { |
112 | #ifdef CONFIG_HARFBUZZ | |
113 | 114 | ass_cache_done(shaper->metrics_cache); |
114 | 115 | free(shaper->features); |
115 | #endif | |
116 | 116 | free(shaper->event_text); |
117 | 117 | free(shaper->ctypes); |
118 | #ifdef USE_FRIBIDI_EX_API | |
119 | free(shaper->btypes); | |
120 | #endif | |
118 | 121 | free(shaper->emblevels); |
119 | 122 | free(shaper->cmap); |
120 | 123 | free(shaper); |
122 | 125 | |
123 | 126 | void ass_shaper_empty_cache(ASS_Shaper *shaper) |
124 | 127 | { |
125 | #ifdef CONFIG_HARFBUZZ | |
126 | 128 | ass_cache_empty(shaper->metrics_cache); |
127 | #endif | |
128 | 129 | } |
129 | 130 | |
130 | 131 | void ass_shaper_font_data_free(ASS_ShaperFontData *priv) |
131 | 132 | { |
132 | #ifdef CONFIG_HARFBUZZ | |
133 | 133 | int i; |
134 | 134 | for (i = 0; i < ASS_FONT_MAX_FACES; i++) |
135 | 135 | if (priv->fonts[i]) { |
138 | 138 | hb_font_funcs_destroy(priv->font_funcs[i]); |
139 | 139 | } |
140 | 140 | free(priv); |
141 | #endif | |
142 | } | |
143 | ||
144 | #ifdef CONFIG_HARFBUZZ | |
141 | } | |
142 | ||
145 | 143 | /** |
146 | 144 | * \brief set up the HarfBuzz OpenType feature list with some |
147 | 145 | * standard features. |
209 | 207 | * |
210 | 208 | */ |
211 | 209 | |
212 | GlyphMetricsHashValue * | |
213 | get_cached_metrics(struct ass_shaper_metrics_data *metrics, FT_Face face, | |
210 | FT_Glyph_Metrics * | |
211 | get_cached_metrics(struct ass_shaper_metrics_data *metrics, | |
214 | 212 | hb_codepoint_t unicode, hb_codepoint_t glyph) |
215 | 213 | { |
216 | GlyphMetricsHashValue *val; | |
217 | metrics->hash_key.glyph_index = glyph; | |
218 | if (ass_cache_get(metrics->metrics_cache, &metrics->hash_key, &val)) { | |
219 | if (val->metrics.width >= 0) | |
220 | return val; | |
221 | ass_cache_dec_ref(val); | |
222 | return NULL; | |
223 | } | |
224 | if (!val) | |
225 | return NULL; | |
226 | ||
227 | int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | |
228 | | FT_LOAD_IGNORE_TRANSFORM; | |
229 | ||
230 | if (FT_Load_Glyph(face, glyph, load_flags)) { | |
231 | val->metrics.width = -1; | |
232 | ass_cache_commit(val, 1); | |
233 | ass_cache_dec_ref(val); | |
234 | return NULL; | |
235 | } | |
236 | ||
237 | memcpy(&val->metrics, &face->glyph->metrics, sizeof(FT_Glyph_Metrics)); | |
238 | ||
214 | bool rotate = false; | |
239 | 215 | // if @font rendering is enabled and the glyph should be rotated, |
240 | 216 | // make cached_h_advance pick up the right advance later |
241 | 217 | if (metrics->vertical && unicode >= VERTICAL_LOWER_BOUND) |
242 | val->metrics.horiAdvance = val->metrics.vertAdvance; | |
243 | ||
244 | ass_cache_commit(val, 1); | |
245 | return val; | |
218 | rotate = true; | |
219 | ||
220 | metrics->hash_key.glyph_index = glyph; | |
221 | FT_Glyph_Metrics *val = ass_cache_get(metrics->metrics_cache, &metrics->hash_key, | |
222 | rotate ? metrics : NULL); | |
223 | if (!val) | |
224 | return NULL; | |
225 | if (val->width >= 0) | |
226 | return val; | |
227 | ass_cache_dec_ref(val); | |
228 | return NULL; | |
229 | } | |
230 | ||
231 | size_t ass_glyph_metrics_construct(void *key, void *value, void *priv) | |
232 | { | |
233 | GlyphMetricsHashKey *k = key; | |
234 | FT_Glyph_Metrics *v = value; | |
235 | ||
236 | int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | |
237 | | FT_LOAD_IGNORE_TRANSFORM; | |
238 | ||
239 | FT_Face face = k->font->faces[k->face_index]; | |
240 | if (FT_Load_Glyph(face, k->glyph_index, load_flags)) { | |
241 | v->width = -1; | |
242 | return 1; | |
243 | } | |
244 | ||
245 | memcpy(v, &face->glyph->metrics, sizeof(FT_Glyph_Metrics)); | |
246 | ||
247 | if (priv) // rotate | |
248 | v->horiAdvance = v->vertAdvance; | |
249 | ||
250 | return 1; | |
251 | } | |
252 | ||
253 | static hb_blob_t* | |
254 | get_reference_table(hb_face_t *hbface, hb_tag_t tag, void *font_data) | |
255 | { | |
256 | FT_Face face = font_data; | |
257 | FT_ULong len = 0; | |
258 | ||
259 | if (FT_Load_Sfnt_Table(face, tag, 0, NULL, &len) != FT_Err_Ok) | |
260 | return NULL; | |
261 | ||
262 | char *buf = malloc(len); | |
263 | if (!buf) | |
264 | return NULL; | |
265 | ||
266 | if (FT_Load_Sfnt_Table(face, tag, 0, (FT_Byte*)buf, &len) != FT_Err_Ok) { | |
267 | free(buf); | |
268 | return NULL; | |
269 | } | |
270 | ||
271 | hb_blob_t *blob = hb_blob_create(buf, len, HB_MEMORY_MODE_WRITABLE, buf, free); | |
272 | if (!blob) | |
273 | free(buf); | |
274 | ||
275 | return blob; | |
246 | 276 | } |
247 | 277 | |
248 | 278 | static hb_bool_t |
249 | get_glyph(hb_font_t *font, void *font_data, hb_codepoint_t unicode, | |
250 | hb_codepoint_t variation, hb_codepoint_t *glyph, void *user_data) | |
279 | get_glyph_nominal(hb_font_t *font, void *font_data, hb_codepoint_t unicode, | |
280 | hb_codepoint_t *glyph, void *user_data) | |
251 | 281 | { |
252 | 282 | FT_Face face = font_data; |
253 | 283 | struct ass_shaper_metrics_data *metrics_priv = user_data; |
254 | 284 | |
255 | if (variation) | |
256 | *glyph = FT_Face_GetCharVariantIndex(face, ass_font_index_magic(face, unicode), variation); | |
257 | else | |
258 | *glyph = FT_Get_Char_Index(face, ass_font_index_magic(face, unicode)); | |
285 | *glyph = FT_Get_Char_Index(face, ass_font_index_magic(face, unicode)); | |
259 | 286 | if (!*glyph) |
260 | 287 | return false; |
261 | 288 | |
262 | 289 | // rotate glyph advances for @fonts while we still know the Unicode codepoints |
263 | GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, unicode, *glyph); | |
290 | FT_Glyph_Metrics *metrics = get_cached_metrics(metrics_priv, unicode, *glyph); | |
291 | ass_cache_dec_ref(metrics); | |
292 | return true; | |
293 | } | |
294 | ||
295 | static hb_bool_t | |
296 | get_glyph_variation(hb_font_t *font, void *font_data, hb_codepoint_t unicode, | |
297 | hb_codepoint_t variation, hb_codepoint_t *glyph, void *user_data) | |
298 | { | |
299 | FT_Face face = font_data; | |
300 | struct ass_shaper_metrics_data *metrics_priv = user_data; | |
301 | ||
302 | *glyph = FT_Face_GetCharVariantIndex(face, ass_font_index_magic(face, unicode), variation); | |
303 | if (!*glyph) | |
304 | return false; | |
305 | ||
306 | // rotate glyph advances for @fonts while we still know the Unicode codepoints | |
307 | FT_Glyph_Metrics *metrics = get_cached_metrics(metrics_priv, unicode, *glyph); | |
264 | 308 | ass_cache_dec_ref(metrics); |
265 | 309 | return true; |
266 | 310 | } |
269 | 313 | cached_h_advance(hb_font_t *font, void *font_data, hb_codepoint_t glyph, |
270 | 314 | void *user_data) |
271 | 315 | { |
272 | FT_Face face = font_data; | |
273 | 316 | struct ass_shaper_metrics_data *metrics_priv = user_data; |
274 | GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, 0, glyph); | |
317 | FT_Glyph_Metrics *metrics = get_cached_metrics(metrics_priv, 0, glyph); | |
275 | 318 | if (!metrics) |
276 | 319 | return 0; |
277 | 320 | |
278 | hb_position_t advance = metrics->metrics.horiAdvance; | |
321 | hb_position_t advance = metrics->horiAdvance; | |
279 | 322 | ass_cache_dec_ref(metrics); |
280 | 323 | return advance; |
281 | 324 | } |
284 | 327 | cached_v_advance(hb_font_t *font, void *font_data, hb_codepoint_t glyph, |
285 | 328 | void *user_data) |
286 | 329 | { |
287 | FT_Face face = font_data; | |
288 | 330 | struct ass_shaper_metrics_data *metrics_priv = user_data; |
289 | GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, 0, glyph); | |
331 | FT_Glyph_Metrics *metrics = get_cached_metrics(metrics_priv, 0, glyph); | |
290 | 332 | if (!metrics) |
291 | 333 | return 0; |
292 | 334 | |
293 | hb_position_t advance = metrics->metrics.vertAdvance; | |
335 | hb_position_t advance = metrics->vertAdvance; | |
294 | 336 | ass_cache_dec_ref(metrics); |
295 | 337 | return advance; |
296 | 338 | } |
306 | 348 | cached_v_origin(hb_font_t *font, void *font_data, hb_codepoint_t glyph, |
307 | 349 | hb_position_t *x, hb_position_t *y, void *user_data) |
308 | 350 | { |
309 | FT_Face face = font_data; | |
310 | 351 | struct ass_shaper_metrics_data *metrics_priv = user_data; |
311 | GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, 0, glyph); | |
352 | FT_Glyph_Metrics *metrics = get_cached_metrics(metrics_priv, 0, glyph); | |
312 | 353 | if (!metrics) |
313 | 354 | return false; |
314 | 355 | |
315 | *x = metrics->metrics.horiBearingX - metrics->metrics.vertBearingX; | |
316 | *y = metrics->metrics.horiBearingY - (-metrics->metrics.vertBearingY); | |
356 | *x = metrics->horiBearingX - metrics->vertBearingX; | |
357 | *y = metrics->horiBearingY + metrics->vertBearingY; | |
317 | 358 | ass_cache_dec_ref(metrics); |
318 | 359 | return true; |
319 | 360 | } |
342 | 383 | cached_extents(hb_font_t *font, void *font_data, hb_codepoint_t glyph, |
343 | 384 | hb_glyph_extents_t *extents, void *user_data) |
344 | 385 | { |
345 | FT_Face face = font_data; | |
346 | 386 | struct ass_shaper_metrics_data *metrics_priv = user_data; |
347 | GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, 0, glyph); | |
387 | FT_Glyph_Metrics *metrics = get_cached_metrics(metrics_priv, 0, glyph); | |
348 | 388 | if (!metrics) |
349 | 389 | return false; |
350 | 390 | |
351 | extents->x_bearing = metrics->metrics.horiBearingX; | |
352 | extents->y_bearing = metrics->metrics.horiBearingY; | |
353 | extents->width = metrics->metrics.width; | |
354 | extents->height = -metrics->metrics.height; | |
391 | extents->x_bearing = metrics->horiBearingX; | |
392 | extents->y_bearing = metrics->horiBearingY; | |
393 | extents->width = metrics->width; | |
394 | extents->height = -metrics->height; | |
355 | 395 | ass_cache_dec_ref(metrics); |
356 | 396 | return true; |
357 | 397 | } |
389 | 429 | |
390 | 430 | if (!font->shaper_priv) |
391 | 431 | font->shaper_priv = calloc(sizeof(ASS_ShaperFontData), 1); |
392 | ||
432 | if (!font->shaper_priv) | |
433 | return NULL; | |
393 | 434 | |
394 | 435 | hb_fonts = font->shaper_priv->fonts; |
395 | 436 | if (!hb_fonts[info->face_index]) { |
396 | hb_fonts[info->face_index] = | |
397 | hb_ft_font_create(font->faces[info->face_index], NULL); | |
437 | FT_Face face = font->faces[info->face_index]; | |
438 | hb_face_t *hb_face = hb_face_create_for_tables(get_reference_table, face, NULL); | |
439 | if (!hb_face) | |
440 | return NULL; | |
441 | hb_face_set_index(hb_face, face->face_index); | |
442 | hb_face_set_upem(hb_face, face->units_per_EM); | |
443 | ||
444 | hb_font_t *hb_font = hb_fonts[info->face_index] = hb_font_create(hb_face); | |
445 | hb_face_destroy(hb_face); | |
446 | if (!hb_font) | |
447 | return NULL; | |
448 | ||
449 | hb_font_set_scale(hb_font, | |
450 | (int)(((uint64_t)face->size->metrics.x_scale * face->units_per_EM + (1<<15)) >> 16), | |
451 | (int)(((uint64_t)face->size->metrics.y_scale * face->units_per_EM + (1<<15)) >> 16)); | |
398 | 452 | |
399 | 453 | // set up cached metrics access |
400 | font->shaper_priv->metrics_data[info->face_index] = | |
401 | calloc(sizeof(struct ass_shaper_metrics_data), 1); | |
402 | 454 | struct ass_shaper_metrics_data *metrics = |
403 | font->shaper_priv->metrics_data[info->face_index]; | |
455 | font->shaper_priv->metrics_data[info->face_index] = | |
456 | calloc(sizeof(struct ass_shaper_metrics_data), 1); | |
457 | if (!metrics) | |
458 | return NULL; | |
404 | 459 | metrics->metrics_cache = shaper->metrics_cache; |
405 | 460 | metrics->vertical = info->font->desc.vertical; |
406 | 461 | |
407 | 462 | hb_font_funcs_t *funcs = hb_font_funcs_create(); |
463 | if (!funcs) | |
464 | return NULL; | |
408 | 465 | font->shaper_priv->font_funcs[info->face_index] = funcs; |
409 | hb_font_funcs_set_glyph_func(funcs, get_glyph, | |
466 | hb_font_funcs_set_nominal_glyph_func(funcs, get_glyph_nominal, | |
467 | metrics, NULL); | |
468 | hb_font_funcs_set_variation_glyph_func(funcs, get_glyph_variation, | |
410 | 469 | metrics, NULL); |
411 | 470 | hb_font_funcs_set_glyph_h_advance_func(funcs, cached_h_advance, |
412 | 471 | metrics, NULL); |
424 | 483 | metrics, NULL); |
425 | 484 | hb_font_funcs_set_glyph_contour_point_func(funcs, get_contour_point, |
426 | 485 | metrics, NULL); |
427 | hb_font_set_funcs(hb_fonts[info->face_index], funcs, | |
428 | font->faces[info->face_index], NULL); | |
486 | hb_font_set_funcs(hb_font, funcs, face, NULL); | |
429 | 487 | } |
430 | 488 | |
431 | 489 | ass_face_set_size(font->faces[info->face_index], info->font_size); |
437 | 495 | metrics->hash_key.font = info->font; |
438 | 496 | metrics->hash_key.face_index = info->face_index; |
439 | 497 | metrics->hash_key.size = info->font_size; |
440 | metrics->hash_key.scale_x = double_to_d6(info->scale_x); | |
441 | metrics->hash_key.scale_y = double_to_d6(info->scale_y); | |
442 | 498 | |
443 | 499 | return hb_fonts[info->face_index]; |
444 | 500 | } |
566 | 622 | |
567 | 623 | // if we have more than one glyph per cluster, allocate a new one |
568 | 624 | // and attach to the root glyph |
569 | if (info->skip == 0) { | |
625 | if (!info->skip) { | |
570 | 626 | while (info->next) |
571 | 627 | info = info->next; |
572 | 628 | info->next = malloc(sizeof(GlyphInfo)); |
579 | 635 | } |
580 | 636 | |
581 | 637 | // set position and advance |
582 | info->skip = 0; | |
638 | info->skip = false; | |
583 | 639 | info->glyph_index = glyph_info[j].codepoint; |
584 | 640 | info->offset.x = pos[j].x_offset * info->scale_x; |
585 | 641 | info->offset.y = -pos[j].y_offset * info->scale_y; |
597 | 653 | * \param glyphs glyph clusters |
598 | 654 | * \param len number of clusters |
599 | 655 | */ |
600 | static void shape_harfbuzz(ASS_Shaper *shaper, GlyphInfo *glyphs, size_t len) | |
656 | static bool shape_harfbuzz(ASS_Shaper *shaper, GlyphInfo *glyphs, size_t len) | |
601 | 657 | { |
602 | 658 | int i; |
603 | 659 | hb_buffer_t *buf = hb_buffer_create(); |
605 | 661 | |
606 | 662 | // Initialize: skip all glyphs, this is undone later as needed |
607 | 663 | for (i = 0; i < len; i++) |
608 | glyphs[i].skip = 1; | |
664 | glyphs[i].skip = true; | |
609 | 665 | |
610 | 666 | for (i = 0; i < len; i++) { |
667 | if (glyphs[i].drawing_text) { | |
668 | glyphs[i].skip = false; | |
669 | continue; | |
670 | } | |
671 | ||
611 | 672 | int offset = i; |
612 | 673 | hb_font_t *font = get_hb_font(shaper, glyphs + offset); |
613 | int level = glyphs[offset].shape_run_id; | |
614 | int direction = shaper->emblevels[offset] % 2; | |
674 | if (!font) | |
675 | return false; | |
676 | int run_id = glyphs[offset].shape_run_id; | |
677 | int level = shaper->emblevels[offset]; | |
615 | 678 | |
616 | 679 | // advance in text until end of run |
617 | while (i < (len - 1) && level == glyphs[i+1].shape_run_id) | |
680 | while (i < (len - 1) && run_id == glyphs[i + 1].shape_run_id && | |
681 | level == shaper->emblevels[i + 1]) | |
618 | 682 | i++; |
619 | 683 | |
620 | 684 | hb_buffer_pre_allocate(buf, i - offset + 1); |
621 | 685 | hb_buffer_add_utf32(buf, shaper->event_text + offset, i - offset + 1, |
622 | 686 | 0, i - offset + 1); |
623 | 687 | |
624 | props.direction = direction ? HB_DIRECTION_RTL : HB_DIRECTION_LTR; | |
688 | props.direction = FRIBIDI_LEVEL_IS_RTL(level) ? | |
689 | HB_DIRECTION_RTL : HB_DIRECTION_LTR; | |
625 | 690 | props.script = glyphs[offset].script; |
626 | 691 | props.language = hb_shaper_get_run_language(shaper, props.script); |
627 | 692 | hb_buffer_set_segment_properties(buf, &props); |
634 | 699 | } |
635 | 700 | |
636 | 701 | hb_buffer_destroy(buf); |
702 | ||
703 | return true; | |
637 | 704 | } |
638 | 705 | |
639 | 706 | /** |
685 | 752 | } |
686 | 753 | } |
687 | 754 | } |
688 | #endif | |
689 | 755 | |
690 | 756 | /** |
691 | 757 | * \brief Shape event text with FriBidi. Does mirroring and simple |
719 | 785 | * \param shaper shaper instance |
720 | 786 | * \param kern toggle kerning |
721 | 787 | */ |
722 | void ass_shaper_set_kerning(ASS_Shaper *shaper, int kern) | |
723 | { | |
724 | #ifdef CONFIG_HARFBUZZ | |
725 | shaper->features[KERN].value = !!kern; | |
726 | #endif | |
788 | void ass_shaper_set_kerning(ASS_Shaper *shaper, bool kern) | |
789 | { | |
790 | shaper->features[KERN].value = kern; | |
727 | 791 | } |
728 | 792 | |
729 | 793 | /** |
735 | 799 | int i; |
736 | 800 | int shape_run = 0; |
737 | 801 | |
738 | #ifdef CONFIG_HARFBUZZ | |
739 | 802 | ass_shaper_determine_script(shaper, glyphs, len); |
740 | #endif | |
741 | 803 | |
742 | 804 | // find appropriate fonts for the shape runs |
743 | 805 | for (i = 0; i < len; i++) { |
744 | GlyphInfo *last = glyphs + i - 1; | |
745 | 806 | GlyphInfo *info = glyphs + i; |
746 | // skip drawings | |
747 | if (info->symbol == 0xfffc) | |
748 | continue; | |
749 | // set size and get glyph index | |
750 | ass_font_get_index(render_priv->fontselect, info->font, | |
751 | info->symbol, &info->face_index, &info->glyph_index); | |
752 | // shape runs break on: xbord, ybord, xshad, yshad, | |
753 | // all four colors, all four alphas, be, blur, fn, fs, | |
754 | // fscx, fscy, fsp, bold, italic, underline, strikeout, | |
755 | // frx, fry, frz, fax, fay, karaoke start, karaoke type, | |
756 | // and on every line break | |
757 | if (i > 0 && (last->font != info->font || | |
807 | if (!info->drawing_text) { | |
808 | // set size and get glyph index | |
809 | ass_font_get_index(render_priv->fontselect, info->font, | |
810 | info->symbol, &info->face_index, &info->glyph_index); | |
811 | } | |
812 | if (i > 0) { | |
813 | GlyphInfo *last = glyphs + i - 1; | |
814 | if ((last->font != info->font || | |
758 | 815 | last->face_index != info->face_index || |
759 | 816 | last->script != info->script || |
760 | last->font_size != info->font_size || | |
761 | last->c[0] != info->c[0] || | |
762 | last->c[1] != info->c[1] || | |
763 | last->c[2] != info->c[2] || | |
764 | last->c[3] != info->c[3] || | |
765 | last->be != info->be || | |
766 | last->blur != info->blur || | |
767 | last->shadow_x != info->shadow_x || | |
768 | last->shadow_y != info->shadow_y || | |
769 | last->frx != info->frx || | |
770 | last->fry != info->fry || | |
771 | last->frz != info->frz || | |
772 | last->fax != info->fax || | |
773 | last->fay != info->fay || | |
774 | last->scale_x != info->scale_x || | |
775 | last->scale_y != info->scale_y || | |
776 | last->border_style != info->border_style || | |
777 | last->border_x != info->border_x || | |
778 | last->border_y != info->border_y || | |
779 | last->hspacing != info->hspacing || | |
780 | last->italic != info->italic || | |
781 | last->bold != info->bold || | |
817 | info->starts_new_run || | |
782 | 818 | last->flags != info->flags)) |
783 | shape_run++; | |
819 | shape_run++; | |
820 | } | |
784 | 821 | info->shape_run_id = shape_run; |
785 | 822 | } |
786 | 823 | } |
801 | 838 | */ |
802 | 839 | void ass_shaper_set_language(ASS_Shaper *shaper, const char *code) |
803 | 840 | { |
804 | #ifdef CONFIG_HARFBUZZ | |
805 | 841 | hb_language_t lang; |
806 | 842 | |
807 | 843 | if (code) |
810 | 846 | lang = HB_LANGUAGE_INVALID; |
811 | 847 | |
812 | 848 | shaper->language = lang; |
849 | } | |
850 | ||
851 | /** | |
852 | * Set shaping level. Essentially switches between FriBidi and HarfBuzz. | |
853 | */ | |
854 | void ass_shaper_set_level(ASS_Shaper *shaper, ASS_ShapingLevel level) | |
855 | { | |
856 | shaper->shaping_level = level; | |
857 | } | |
858 | ||
859 | #ifdef USE_FRIBIDI_EX_API | |
860 | void ass_shaper_set_bidi_brackets(ASS_Shaper *shaper, bool match_brackets) | |
861 | { | |
862 | shaper->bidi_brackets = match_brackets; | |
863 | } | |
813 | 864 | #endif |
814 | } | |
815 | ||
816 | /** | |
817 | * Set shaping level. Essentially switches between FriBidi and HarfBuzz. | |
818 | */ | |
819 | void ass_shaper_set_level(ASS_Shaper *shaper, ASS_ShapingLevel level) | |
820 | { | |
821 | shaper->shaping_level = level; | |
822 | } | |
823 | 865 | |
824 | 866 | /** |
825 | 867 | * \brief Remove all zero-width invisible characters from the text. |
834 | 876 | // Skip direction override control characters |
835 | 877 | if ((glyphs[i].symbol <= 0x202e && glyphs[i].symbol >= 0x202a) |
836 | 878 | || (glyphs[i].symbol <= 0x200f && glyphs[i].symbol >= 0x200b) |
837 | || (glyphs[i].symbol <= 0x2063 && glyphs[i].symbol >= 0x2060) | |
879 | || (glyphs[i].symbol <= 0x206f && glyphs[i].symbol >= 0x2060) | |
880 | || (glyphs[i].symbol <= 0xfe0f && glyphs[i].symbol >= 0xfe00) | |
881 | || (glyphs[i].symbol <= 0xe01ef && glyphs[i].symbol >= 0xe0100) | |
882 | || (glyphs[i].symbol <= 0x180f && glyphs[i].symbol >= 0x180b) | |
883 | || glyphs[i].symbol == 0x061c | |
838 | 884 | || glyphs[i].symbol == 0xfeff |
839 | 885 | || glyphs[i].symbol == 0x00ad |
840 | 886 | || glyphs[i].symbol == 0x034f) { |
841 | 887 | glyphs[i].symbol = 0; |
842 | glyphs[i].skip++; | |
888 | glyphs[i].skip = true; | |
843 | 889 | } |
844 | 890 | } |
845 | 891 | } |
849 | 895 | * \param text_info event's text |
850 | 896 | * \return success, when 0 |
851 | 897 | */ |
852 | int ass_shaper_shape(ASS_Shaper *shaper, TextInfo *text_info) | |
898 | bool ass_shaper_shape(ASS_Shaper *shaper, TextInfo *text_info) | |
853 | 899 | { |
854 | 900 | int i, ret, last_break; |
855 | 901 | FriBidiParType dir; |
856 | 902 | GlyphInfo *glyphs = text_info->glyphs; |
857 | 903 | |
858 | 904 | if (!check_allocations(shaper, text_info->length)) |
859 | return -1; | |
905 | return false; | |
860 | 906 | |
861 | 907 | // Get bidi character types and embedding levels |
862 | 908 | last_break = 0; |
867 | 913 | dir = shaper->base_direction; |
868 | 914 | fribidi_get_bidi_types(shaper->event_text + last_break, |
869 | 915 | i - last_break + 1, shaper->ctypes + last_break); |
916 | #ifdef USE_FRIBIDI_EX_API | |
917 | FriBidiBracketType *btypes = NULL; | |
918 | if (shaper->bidi_brackets) { | |
919 | btypes = shaper->btypes + last_break; | |
920 | fribidi_get_bracket_types(shaper->event_text + last_break, | |
921 | i - last_break + 1, shaper->ctypes + last_break, | |
922 | btypes); | |
923 | } | |
924 | ret = fribidi_get_par_embedding_levels_ex( | |
925 | shaper->ctypes + last_break, btypes, | |
926 | i - last_break + 1, &dir, shaper->emblevels + last_break); | |
927 | #else | |
870 | 928 | ret = fribidi_get_par_embedding_levels(shaper->ctypes + last_break, |
871 | 929 | i - last_break + 1, &dir, shaper->emblevels + last_break); |
930 | #endif | |
872 | 931 | if (ret == 0) |
873 | return -1; | |
932 | return false; | |
874 | 933 | last_break = i + 1; |
875 | 934 | } |
876 | 935 | } |
877 | 936 | |
878 | // add embedding levels to shape runs for final runs | |
879 | for (i = 0; i < text_info->length; i++) { | |
880 | glyphs[i].shape_run_id += shaper->emblevels[i]; | |
881 | } | |
882 | ||
883 | #ifdef CONFIG_HARFBUZZ | |
884 | 937 | switch (shaper->shaping_level) { |
885 | 938 | case ASS_SHAPING_SIMPLE: |
886 | 939 | shape_fribidi(shaper, glyphs, text_info->length); |
887 | 940 | ass_shaper_skip_characters(text_info); |
888 | break; | |
941 | return true; | |
889 | 942 | case ASS_SHAPING_COMPLEX: |
890 | shape_harfbuzz(shaper, glyphs, text_info->length); | |
891 | break; | |
892 | } | |
893 | #else | |
894 | shape_fribidi(shaper, glyphs, text_info->length); | |
895 | ass_shaper_skip_characters(text_info); | |
896 | #endif | |
897 | ||
898 | return 0; | |
899 | } | |
900 | ||
901 | /** | |
902 | * \brief Create a new shaper instance and preallocate data structures | |
903 | * \param prealloc preallocation size | |
904 | */ | |
905 | ASS_Shaper *ass_shaper_new(size_t prealloc) | |
943 | default: | |
944 | return shape_harfbuzz(shaper, glyphs, text_info->length); | |
945 | } | |
946 | } | |
947 | ||
948 | /** | |
949 | * \brief Create a new shaper instance | |
950 | */ | |
951 | ASS_Shaper *ass_shaper_new(void) | |
906 | 952 | { |
907 | 953 | ASS_Shaper *shaper = calloc(sizeof(*shaper), 1); |
908 | 954 | if (!shaper) |
909 | 955 | return NULL; |
910 | 956 | |
911 | 957 | shaper->base_direction = FRIBIDI_PAR_ON; |
912 | if (!check_allocations(shaper, prealloc)) | |
913 | goto error; | |
914 | ||
915 | #ifdef CONFIG_HARFBUZZ | |
958 | ||
916 | 959 | if (!init_features(shaper)) |
917 | 960 | goto error; |
918 | 961 | shaper->metrics_cache = ass_glyph_metrics_cache_create(); |
919 | 962 | if (!shaper->metrics_cache) |
920 | 963 | goto error; |
921 | #endif | |
922 | 964 | |
923 | 965 | return shaper; |
924 | 966 |
21 | 21 | typedef struct ass_shaper ASS_Shaper; |
22 | 22 | |
23 | 23 | #include <fribidi.h> |
24 | #include <stdbool.h> | |
24 | 25 | #include "ass_render.h" |
25 | 26 | |
27 | #if FRIBIDI_MAJOR_VERSION >= 1 | |
28 | #define USE_FRIBIDI_EX_API | |
29 | #endif | |
30 | ||
26 | 31 | void ass_shaper_info(ASS_Library *lib); |
27 | ASS_Shaper *ass_shaper_new(size_t prealloc); | |
32 | ASS_Shaper *ass_shaper_new(void); | |
28 | 33 | void ass_shaper_free(ASS_Shaper *shaper); |
29 | 34 | void ass_shaper_empty_cache(ASS_Shaper *shaper); |
30 | void ass_shaper_set_kerning(ASS_Shaper *shaper, int kern); | |
35 | void ass_shaper_set_kerning(ASS_Shaper *shaper, bool kern); | |
31 | 36 | void ass_shaper_find_runs(ASS_Shaper *shaper, ASS_Renderer *render_priv, |
32 | 37 | GlyphInfo *glyphs, size_t len); |
33 | 38 | void ass_shaper_set_base_direction(ASS_Shaper *shaper, FriBidiParType dir); |
34 | 39 | void ass_shaper_set_language(ASS_Shaper *shaper, const char *code); |
35 | 40 | void ass_shaper_set_level(ASS_Shaper *shaper, ASS_ShapingLevel level); |
36 | int ass_shaper_shape(ASS_Shaper *shaper, TextInfo *text_info); | |
41 | #ifdef USE_FRIBIDI_EX_API | |
42 | void ass_shaper_set_bidi_brackets(ASS_Shaper *shaper, bool match_brackets); | |
43 | #endif | |
44 | bool ass_shaper_shape(ASS_Shaper *shaper, TextInfo *text_info); | |
37 | 45 | void ass_shaper_cleanup(ASS_Shaper *shaper, TextInfo *text_info); |
38 | 46 | FriBidiStrIndex *ass_shaper_reorder(ASS_Shaper *shaper, TextInfo *text_info); |
39 | 47 | FriBidiParType resolve_base_direction(int font_encoding); |
258 | 258 | } else if (exp > ((size_t) -1 - (*p - '0')) / 10) { |
259 | 259 | expWraparound = 1; |
260 | 260 | } |
261 | exp = exp * 10 + (*p - '0'); | |
261 | exp = exp * 10u + (*p - '0'); | |
262 | 262 | p += 1; |
263 | 263 | } |
264 | 264 | if (expSign == fracExpSign) { |
165 | 165 | YCBCR_SMPTE240M_PC, |
166 | 166 | YCBCR_FCC_TV, |
167 | 167 | YCBCR_FCC_PC |
168 | // New enum values can be added here in new ABI-compatible library releases. | |
168 | 169 | } ASS_YCbCrMatrix; |
169 | 170 | |
170 | 171 | /* |
204 | 205 | |
205 | 206 | ASS_Library *library; |
206 | 207 | ASS_ParserPriv *parser_priv; |
208 | ||
209 | // New fields can be added here in new ABI-compatible library releases. | |
207 | 210 | } ASS_Track; |
208 | 211 | |
209 | 212 | #endif /* LIBASS_TYPES_H */ |
45 | 45 | { |
46 | 46 | uint32_t eax = 1, ebx, ecx, edx; |
47 | 47 | ass_get_cpuid(&eax, &ebx, &ecx, &edx); |
48 | if(!(ecx & (1 << 27))) // not OSXSAVE | |
48 | if (!(ecx & (1 << 27))) // not OSXSAVE | |
49 | 49 | return 0; |
50 | 50 | uint32_t misc = ecx; |
51 | 51 | ass_get_xgetbv(0, &eax, &edx); |
52 | if((eax & 0x6) != 0x6) | |
52 | if ((eax & 0x6) != 0x6) | |
53 | 53 | return 0; |
54 | 54 | eax = 0; |
55 | 55 | ass_get_cpuid(&eax, &ebx, &ecx, &edx); |
153 | 153 | *str = p; |
154 | 154 | } |
155 | 155 | |
156 | int mystrtoi(char **p, int *res) | |
157 | { | |
158 | char *start = *p; | |
159 | double temp_res = ass_strtod(*p, p); | |
160 | *res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5)); | |
161 | return *p != start; | |
162 | } | |
163 | ||
164 | int mystrtoll(char **p, long long *res) | |
165 | { | |
166 | char *start = *p; | |
167 | double temp_res = ass_strtod(*p, p); | |
168 | *res = (long long) (temp_res + (temp_res > 0 ? 0.5 : -0.5)); | |
169 | return *p != start; | |
170 | } | |
171 | ||
172 | int mystrtod(char **p, double *res) | |
173 | { | |
174 | char *start = *p; | |
175 | *res = ass_strtod(*p, p); | |
176 | return *p != start; | |
177 | } | |
178 | ||
179 | int mystrtoi32(char **p, int base, int32_t *res) | |
180 | { | |
181 | char *start = *p; | |
182 | long long temp_res = strtoll(*p, p, base); | |
183 | *res = FFMINMAX(temp_res, INT32_MIN, INT32_MAX); | |
184 | return *p != start; | |
185 | } | |
186 | ||
187 | static int read_digits(char **str, int base, uint32_t *res) | |
156 | static int read_digits(char **str, unsigned base, uint32_t *res) | |
188 | 157 | { |
189 | 158 | char *p = *str; |
190 | 159 | char *start = p; |
191 | 160 | uint32_t val = 0; |
192 | 161 | |
193 | 162 | while (1) { |
194 | int digit; | |
163 | unsigned digit; | |
195 | 164 | if (*p >= '0' && *p < FFMIN(base, 10) + '0') |
196 | 165 | digit = *p - '0'; |
197 | 166 | else if (*p >= 'a' && *p < base - 10 + 'a') |
214 | 183 | * Follows the rules for strtoul but reduces the number modulo 2**32 |
215 | 184 | * instead of saturating it to 2**32 - 1. |
216 | 185 | */ |
217 | static int mystrtou32_modulo(char **p, int base, uint32_t *res) | |
186 | static int mystrtou32_modulo(char **p, unsigned base, uint32_t *res) | |
218 | 187 | { |
219 | 188 | // This emulates scanf with %d or %x format as it works on |
220 | 189 | // Windows, because that's what is used by VSFilter. In practice, |
270 | 239 | uint32_t parse_color_header(char *str) |
271 | 240 | { |
272 | 241 | uint32_t color = 0; |
273 | int base; | |
242 | unsigned base; | |
274 | 243 | |
275 | 244 | if (!ass_strncasecmp(str, "&h", 2) || !ass_strncasecmp(str, "0x", 2)) { |
276 | 245 | str += 2; |
77 | 77 | |
78 | 78 | void skip_spaces(char **str); |
79 | 79 | void rskip_spaces(char **str, char *limit); |
80 | int mystrtoi(char **p, int *res); | |
81 | int mystrtoll(char **p, long long *res); | |
82 | int mystrtod(char **p, double *res); | |
83 | int mystrtoi32(char **p, int base, int32_t *res); | |
84 | 80 | int32_t parse_alpha_tag(char *str); |
85 | 81 | uint32_t parse_color_tag(char *str); |
86 | 82 | uint32_t parse_color_header(char *str); |
163 | 159 | return (int) (x * 0x400000); |
164 | 160 | } |
165 | 161 | |
166 | // Calculate cache key for a rotational angle in radians | |
167 | static inline int rot_key(double a) | |
168 | { | |
169 | return double_to_d22(remainder(a, 2 * M_PI)); | |
170 | } | |
171 | ||
172 | 162 | #define FNV1_32A_INIT 0x811c9dc5U |
173 | 163 | #define FNV1_32A_PRIME 16777619U |
174 | 164 | |
175 | static inline unsigned fnv_32a_buf(void *buf, size_t len, unsigned hval) | |
176 | { | |
177 | unsigned char *bp = (unsigned char*)buf; | |
165 | static inline uint32_t fnv_32a_buf(void *buf, size_t len, uint32_t hval) | |
166 | { | |
167 | unsigned char *bp = (unsigned char *) buf; | |
178 | 168 | size_t n = (len + 3) / 4; |
179 | 169 | |
180 | 170 | switch (len % 4) { |
181 | case 0: do { hval ^= (unsigned) *bp++; hval *= FNV1_32A_PRIME; | |
182 | case 3: hval ^= (unsigned) *bp++; hval *= FNV1_32A_PRIME; | |
183 | case 2: hval ^= (unsigned) *bp++; hval *= FNV1_32A_PRIME; | |
184 | case 1: hval ^= (unsigned) *bp++; hval *= FNV1_32A_PRIME; | |
171 | case 0: do { hval ^= *bp++; hval *= FNV1_32A_PRIME; //-fallthrough | |
172 | case 3: hval ^= *bp++; hval *= FNV1_32A_PRIME; //-fallthrough | |
173 | case 2: hval ^= *bp++; hval *= FNV1_32A_PRIME; //-fallthrough | |
174 | case 1: hval ^= *bp++; hval *= FNV1_32A_PRIME; | |
185 | 175 | } while (--n > 0); |
186 | 176 | } |
187 | 177 | |
188 | 178 | return hval; |
189 | 179 | } |
190 | static inline unsigned fnv_32a_str(char *str, unsigned hval) | |
180 | static inline uint32_t fnv_32a_str(const char *str, uint32_t hval) | |
191 | 181 | { |
192 | 182 | unsigned char *s = (unsigned char *) str; |
193 | 183 | while (*s) { |
194 | hval ^= (unsigned) *s++; | |
184 | hval ^= *s++; | |
195 | 185 | hval *= FNV1_32A_PRIME; |
196 | 186 | } |
197 | 187 | return hval; |
198 | 188 | } |
199 | 189 | |
190 | static inline int mystrtoi(char **p, int *res) | |
191 | { | |
192 | char *start = *p; | |
193 | double temp_res = ass_strtod(*p, p); | |
194 | *res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5)); | |
195 | return *p != start; | |
196 | } | |
197 | ||
198 | static inline int mystrtoll(char **p, long long *res) | |
199 | { | |
200 | char *start = *p; | |
201 | double temp_res = ass_strtod(*p, p); | |
202 | *res = (long long) (temp_res + (temp_res > 0 ? 0.5 : -0.5)); | |
203 | return *p != start; | |
204 | } | |
205 | ||
206 | static inline int mystrtod(char **p, double *res) | |
207 | { | |
208 | char *start = *p; | |
209 | *res = ass_strtod(*p, p); | |
210 | return *p != start; | |
211 | } | |
212 | ||
213 | static inline int mystrtoi32(char **p, int base, int32_t *res) | |
214 | { | |
215 | char *start = *p; | |
216 | long long temp_res = strtoll(*p, p, base); | |
217 | *res = FFMINMAX(temp_res, INT32_MIN, INT32_MAX); | |
218 | return *p != start; | |
219 | } | |
220 | ||
200 | 221 | #endif /* LIBASS_UTILS_H */ |
55 | 55 | |
56 | 56 | typedef enum DWRITE_FACTORY_TYPE { |
57 | 57 | DWRITE_FACTORY_TYPE_SHARED = 0, |
58 | DWRITE_FACTORY_TYPE_ISOLATED | |
58 | DWRITE_FACTORY_TYPE_ISOLATED | |
59 | 59 | } DWRITE_FACTORY_TYPE; |
60 | 60 | |
61 | 61 | typedef enum DWRITE_FONT_FACE_TYPE { |
72 | 72 | typedef enum DWRITE_FONT_SIMULATIONS { |
73 | 73 | DWRITE_FONT_SIMULATIONS_NONE = 0x0000, |
74 | 74 | DWRITE_FONT_SIMULATIONS_BOLD = 0x0001, |
75 | DWRITE_FONT_SIMULATIONS_OBLIQUE = 0x0002 | |
75 | DWRITE_FONT_SIMULATIONS_OBLIQUE = 0x0002 | |
76 | 76 | } DWRITE_FONT_SIMULATIONS; |
77 | 77 | |
78 | 78 | typedef enum DWRITE_FONT_STRETCH { |
86 | 86 | DWRITE_FONT_STRETCH_SEMI_EXPANDED = 6, |
87 | 87 | DWRITE_FONT_STRETCH_EXPANDED = 7, |
88 | 88 | DWRITE_FONT_STRETCH_EXTRA_EXPANDED = 8, |
89 | DWRITE_FONT_STRETCH_ULTRA_EXPANDED = 9 | |
89 | DWRITE_FONT_STRETCH_ULTRA_EXPANDED = 9 | |
90 | 90 | } DWRITE_FONT_STRETCH; |
91 | 91 | |
92 | 92 | typedef enum DWRITE_FONT_STYLE { |
93 | 93 | DWRITE_FONT_STYLE_NORMAL = 0, |
94 | 94 | DWRITE_FONT_STYLE_OBLIQUE, |
95 | DWRITE_FONT_STYLE_ITALIC | |
95 | DWRITE_FONT_STYLE_ITALIC | |
96 | 96 | } DWRITE_FONT_STYLE; |
97 | 97 | |
98 | 98 | typedef enum DWRITE_FONT_WEIGHT { |
42 | 42 | ass_set_selective_style_override_enabled |
43 | 43 | ass_set_selective_style_override |
44 | 44 | ass_set_check_readorder |
45 | ass_track_set_feature |
0 | 0 | ;****************************************************************************** |
1 | 1 | ;* be_blur.asm: SSE2 \be blur |
2 | 2 | ;****************************************************************************** |
3 | ;* Copyright (C) 2013 Rodger Combs <rcombs@rcombs.me> | |
3 | ;* Copyright (C) 2013 rcombs <rcombs@rcombs.me> | |
4 | 4 | ;* |
5 | 5 | ;* This file is part of libass. |
6 | 6 | ;* |
0 | 0 | ;****************************************************************************** |
1 | 1 | ;* add_bitmaps.asm: SSE2 and x86 add_bitmaps |
2 | 2 | ;****************************************************************************** |
3 | ;* Copyright (C) 2013 Rodger Combs <rcombs@rcombs.me> | |
3 | ;* Copyright (C) 2013 rcombs <rcombs@rcombs.me> | |
4 | 4 | ;* |
5 | 5 | ;* This file is part of libass. |
6 | 6 | ;* |
202 | 202 | lea %6, [%5] |
203 | 203 | cmp %6, %3 |
204 | 204 | cmovae %6, %4 |
205 | %if (mmsize != 32) || (%0 < 7) | |
205 | %if mmsize != 32 || %0 < 7 | |
206 | 206 | mova m%1, [%2 + %6] |
207 | 207 | %elifidn %7, left |
208 | 208 | mova xm%1, [%2 + %6] |
218 | 218 | sub %5, %2 |
219 | 219 | cmp %4, %3 |
220 | 220 | cmovb %5, %4 |
221 | %if (mmsize != 32) || (%0 < 6) | |
221 | %if mmsize != 32 || %0 < 6 | |
222 | 222 | mova m%1, [%2 + %5] |
223 | 223 | %elifidn %6, left |
224 | 224 | mova xm%1, [%2 + %5] |
285 | 285 | mova m3, m0 |
286 | 286 | mova m4, m1 |
287 | 287 | %endif |
288 | psrldq m3, 10 | |
289 | psrldq m4, 10 | |
290 | pslldq m6, m1, 6 | |
291 | por m3, m6 | |
292 | pslldq m6, m2, 6 | |
293 | por m4, m6 | |
288 | PALIGNR m3,m1,m3, m6, 10 | |
289 | PALIGNR m4,m2,m4, m6, 10 | |
294 | 290 | paddw m3, m1 |
295 | 291 | paddw m4, m2 |
296 | 292 | pand m3, m7 |
309 | 305 | %if mmsize == 32 |
310 | 306 | vperm2i128 m0, m0, m1, 0x20 |
311 | 307 | %endif |
312 | psrldq m0, 8 | |
313 | pslldq m6, m1, 8 | |
314 | por m0, m6 | |
315 | paddd m5, m0, m1 | |
308 | PALIGNR m5,m1,m0, m6, 8 | |
309 | paddd m5, m1 | |
316 | 310 | psrld m5, 1 |
317 | psrldq m0, 4 | |
318 | pslldq m6, m1, 4 | |
319 | por m0, m6 | |
311 | PALIGNR m0,m1,m0, m6, 12 | |
320 | 312 | paddd m5, m0 |
321 | 313 | psrld m5, 1 |
322 | 314 | paddd m5, m3 |
326 | 318 | %if mmsize == 32 |
327 | 319 | vperm2i128 m1, m1, m2, 0x21 |
328 | 320 | %endif |
329 | psrldq m1, 8 | |
330 | pslldq m6, m2, 8 | |
331 | por m1, m6 | |
332 | paddd m5, m1, m2 | |
321 | PALIGNR m5,m2,m1, m6, 8 | |
322 | paddd m5, m2 | |
333 | 323 | psrld m5, 1 |
334 | psrldq m1, 4 | |
335 | pslldq m6, m2, 4 | |
336 | por m1, m6 | |
324 | PALIGNR m1,m2,m1, m6, 12 | |
337 | 325 | paddd m5, m1 |
338 | 326 | psrld m5, 1 |
339 | 327 | paddd m5, m4 |
500 | 488 | %endif |
501 | 489 | .main_loop: |
502 | 490 | %if ARCH_X86_64 |
503 | LOAD_LINE 0, r1,r2,r7, r4 + 0 * r3, r6, right | |
491 | LOAD_LINE 2, r1,r2,r7, r4 + 0 * r3, r6, right | |
504 | 492 | LOAD_LINE 1, r1,r2,r7, r4 + 1 * r3, r6 |
505 | 493 | %else |
506 | LOAD_LINE_COMPACT 0, r1,r2,r4, r6, right | |
494 | LOAD_LINE_COMPACT 2, r1,r2,r4, r6, right | |
507 | 495 | add r4, r3 |
508 | 496 | LOAD_LINE_COMPACT 1, r1,r2,r4, r6 |
509 | 497 | sub r4, r3 |
510 | 498 | %endif |
511 | 499 | |
512 | 500 | %if mmsize == 32 |
513 | vperm2i128 m0, m0, m1, 0x20 | |
514 | %endif | |
515 | psrldq m0, 12 | |
516 | pslldq m3, m1, 4 | |
517 | por m0, m3 | |
518 | psrldq m2, m0, 2 | |
519 | pslldq m3, m1, 2 | |
520 | por m2, m3 | |
521 | ||
501 | vperm2i128 m2, m2, m1, 0x20 | |
502 | %endif | |
503 | PALIGNR m0,m1,m2, m3, 12 | |
504 | PALIGNR m2,m1,m2, m3, 14 | |
522 | 505 | paddw m3, m0, m1 |
523 | 506 | psrlw m3, 1 |
524 | 507 | paddw m3, m2 |
563 | 546 | |
564 | 547 | .odd_stripe: |
565 | 548 | %if ARCH_X86_64 |
566 | LOAD_LINE 0, r1,r2,r7, r4 + 0 * r3, r6, right | |
549 | LOAD_LINE 2, r1,r2,r7, r4 + 0 * r3, r6, right | |
567 | 550 | LOAD_LINE 1, r1,r2,r7, r4 + 1 * r3, r6, left |
568 | 551 | %else |
569 | LOAD_LINE_COMPACT 0, r1,r2,r4, r6, right | |
552 | LOAD_LINE_COMPACT 2, r1,r2,r4, r6, right | |
570 | 553 | add r4, r3 |
571 | 554 | LOAD_LINE_COMPACT 1, r1,r2,r4, r6, left |
572 | 555 | sub r4, r3 |
573 | 556 | %endif |
574 | 557 | |
575 | psrldq xm0, 12 | |
576 | pslldq xm3, xm1, 4 | |
577 | por xm0, xm3 | |
578 | psrldq xm2, xm0, 2 | |
579 | pslldq xm3, xm1, 2 | |
580 | por xm2, xm3 | |
581 | ||
558 | PALIGNR xm0,xm1,xm2, xm3, 12 | |
559 | PALIGNR xm2,xm1,xm2, xm3, 14 | |
582 | 560 | paddw xm3, xm0, xm1 |
583 | 561 | psrlw xm3, 1 |
584 | 562 | paddw xm3, xm2 |
673 | 651 | EXPAND_VERT |
674 | 652 | |
675 | 653 | ;------------------------------------------------------------------------------ |
676 | ; PRE_BLUR1_HORZ | |
677 | ; void pre_blur1_horz(int16_t *dst, const int16_t *src, | |
678 | ; uintptr_t src_width, uintptr_t src_height); | |
679 | ;------------------------------------------------------------------------------ | |
680 | ||
681 | %macro PRE_BLUR1_HORZ 0 | |
682 | %if ARCH_X86_64 | |
683 | cglobal pre_blur1_horz, 4,8,4 | |
684 | %else | |
685 | cglobal pre_blur1_horz, 4,7,4 | |
686 | %endif | |
687 | lea r5, [2 * r2 + mmsize + 3] | |
654 | ; LOAD_MULTIPLIER 1:n, 2:m_mul, 3:src, 4:tmp | |
655 | ; Load blur parameters into xmm/ymm registers | |
656 | ;------------------------------------------------------------------------------ | |
657 | ||
658 | %macro LOAD_MULTIPLIER 4 | |
659 | %if ARCH_X86_64 | |
660 | %assign %%t %2 + (%1 - 1) / 2 | |
661 | %else | |
662 | %assign %%t %2 | |
663 | %endif | |
664 | movu xm %+ %%t, [%3] | |
665 | %if %1 % 2 | |
666 | pextrw %4d, xm %+ %%t, 0 | |
667 | pslldq xm %+ %%t, 2 | |
668 | pinsrw xm %+ %%t, %4d, 0 | |
669 | %endif | |
670 | %if mmsize == 32 | |
671 | vpermq m %+ %%t, m %+ %%t, q1010 | |
672 | %endif | |
673 | %if ARCH_X86_64 | |
674 | %assign %%i 0 | |
675 | %rep (%1 + 1) / 2 | |
676 | %assign %%c %2 + %%i | |
677 | pshufd m %+ %%c, m %+ %%t, q1111 * %%i | |
678 | %assign %%i %%i + 1 | |
679 | %endrep | |
680 | %endif | |
681 | %endmacro | |
682 | ||
683 | ;------------------------------------------------------------------------------ | |
684 | ; FILTER_PAIR 1-2:m_acc[2], 3-4:m_line[2], 5:m_tmp, 6:m_mul, 7:pos | |
685 | ; Calculate acc += line[0] * mul[odd] + line[1] * mul[even] | |
686 | ;------------------------------------------------------------------------------ | |
687 | ||
688 | %macro FILTER_PAIR 7 | |
689 | punpcklwd m%5, m%4, m%3 | |
690 | punpckhwd m%4, m%3 | |
691 | %assign %%p ((%7) - 1) / 2 | |
692 | %if ARCH_X86_64 | |
693 | %assign %%p %6 + %%p | |
694 | %else | |
695 | pshufd m%3, m%6, q1111 * %%p | |
696 | %assign %%p %3 | |
697 | %endif | |
698 | pmaddwd m%5, m %+ %%p | |
699 | pmaddwd m%4, m %+ %%p | |
700 | %ifidn %1, %5 | |
701 | paddd m%1, m%2 | |
702 | %else | |
703 | paddd m%1, m%5 | |
704 | %endif | |
705 | paddd m%2, m%4 | |
706 | %endmacro | |
707 | ||
708 | ;------------------------------------------------------------------------------ | |
709 | ; NEXT_DIFF 1:m_res, 2:m_side, 3:m_center, 4:position, 5:left/right | |
710 | ; Calculate difference between next offset line and center line | |
711 | ;------------------------------------------------------------------------------ | |
712 | ||
713 | %macro NEXT_DIFF 5 | |
714 | %ifidn %5, left | |
715 | ||
716 | %if cpuflag(ssse3) | |
717 | palignr m%1, m%3, m%2, 16 - (%4) | |
718 | %else | |
719 | psrldq m%2, 2 | |
720 | pslldq m%1, m%3, %4 | |
721 | por m%1, m%2 | |
722 | %endif | |
723 | ||
724 | %elifidn %5, right | |
725 | ||
726 | %if cpuflag(ssse3) | |
727 | palignr m%1, m%2, m%3, %4 | |
728 | %else | |
729 | pslldq m%2, 2 | |
730 | psrldq m%1, m%3, %4 | |
731 | por m%1, m%2 | |
732 | %endif | |
733 | ||
734 | %else | |
735 | %error "left/right expected" | |
736 | %endif | |
737 | psubw m%1, m%3 | |
738 | %endmacro | |
739 | ||
740 | ;------------------------------------------------------------------------------ | |
741 | ; BLUR_HORZ 1:radius | |
742 | ; void blurN_horz(int16_t *dst, const int16_t *src, | |
743 | ; uintptr_t src_width, uintptr_t src_height, | |
744 | ; const int16_t *param); | |
745 | ;------------------------------------------------------------------------------ | |
746 | ||
747 | %macro BLUR_HORZ 1 | |
748 | %if ARCH_X86_64 | |
749 | %assign %%narg 9 + (%1 + 1) / 2 | |
750 | cglobal blur%1_horz, 5,8,%%narg | |
751 | %else | |
752 | cglobal blur%1_horz, 5,7,8 | |
753 | SWAP 7, 9 | |
754 | %endif | |
755 | LOAD_MULTIPLIER %1, 9, r4, r5 | |
756 | lea r5, [2 * r2 + mmsize + 4 * %1 - 1] | |
688 | 757 | lea r2, [2 * r2 + mmsize - 1] |
689 | 758 | and r5, ~(mmsize - 1) |
690 | 759 | and r2, ~(mmsize - 1) |
693 | 762 | add r5, r0 |
694 | 763 | xor r4, r4 |
695 | 764 | MUL r3, mmsize |
765 | %if mmsize != 32 && %1 > 4 | |
696 | 766 | sub r4, r3 |
697 | mova m3, [words_one] | |
698 | %if ARCH_X86_64 | |
767 | %endif | |
768 | sub r4, r3 | |
769 | %if ARCH_X86_64 | |
770 | mova m7, [dwords_round] | |
699 | 771 | lea r7, [words_zero] |
700 | 772 | sub r7, r1 |
701 | 773 | %endif |
702 | 774 | |
703 | 775 | .main_loop: |
704 | 776 | %if ARCH_X86_64 |
705 | LOAD_LINE 0, r1,r2,r7, r4 + 0 * r3, r6, right | |
706 | LOAD_LINE 1, r1,r2,r7, r4 + 1 * r3, r6 | |
707 | %else | |
708 | LOAD_LINE_COMPACT 0, r1,r2,r4, r6, right | |
777 | %if %1 > 4 | |
778 | LOAD_LINE 1, r1,r2,r7, r4 + 0 * r3, r6 | |
779 | %else | |
780 | LOAD_LINE 1, r1,r2,r7, r4 + 0 * r3, r6, right | |
781 | %endif | |
782 | LOAD_LINE 2, r1,r2,r7, r4 + 1 * r3, r6 | |
783 | %if mmsize != 32 && %1 > 4 | |
784 | LOAD_LINE 0, r1,r2,r7, r4 + 2 * r3, r6 | |
785 | SWAP 0, 2 | |
786 | %endif | |
787 | %else | |
788 | %if %1 > 4 | |
789 | LOAD_LINE_COMPACT 1, r1,r2,r4, r6 | |
790 | %else | |
791 | LOAD_LINE_COMPACT 1, r1,r2,r4, r6, right | |
792 | %endif | |
709 | 793 | add r4, r3 |
710 | LOAD_LINE_COMPACT 1, r1,r2,r4, r6 | |
794 | LOAD_LINE_COMPACT 2, r1,r2,r4, r6 | |
795 | %if mmsize != 32 && %1 > 4 | |
796 | add r4, r3 | |
797 | LOAD_LINE_COMPACT 0, r1,r2,r4, r6 | |
798 | SWAP 0, 2 | |
711 | 799 | sub r4, r3 |
712 | 800 | %endif |
713 | ||
714 | %if mmsize == 32 | |
715 | vperm2i128 m0, m0, m1, 0x20 | |
716 | %endif | |
717 | psrldq m0, 12 | |
718 | pslldq m2, m1, 4 | |
719 | por m0, m2 | |
720 | psrldq m2, m0, 2 | |
721 | paddw m0, m1 | |
722 | pslldq m1, 2 | |
723 | psrlw m0, 1 | |
724 | por m1, m2 | |
725 | paddw m0, m1 | |
726 | paddw m0, m3 | |
727 | psrlw m0, 1 | |
728 | ||
801 | sub r4, r3 | |
802 | %endif | |
803 | ||
804 | %if %1 > 4 | |
805 | %if mmsize == 32 | |
806 | vperm2i128 m0, m1, m2, 0x21 | |
807 | %endif | |
808 | %if cpuflag(ssse3) | |
809 | PALIGNR m1,m0,m1, m3, 16 - 2 * %1 | |
810 | %else | |
811 | PALIGNR m1,m0,m1, m3, 32 - 4 * %1 | |
812 | %endif | |
813 | PALIGNR m0,m2,m0, m3, 16 - 2 * %1 | |
814 | %else | |
815 | %if mmsize == 32 | |
816 | vperm2i128 m1, m1, m2, 0x20 | |
817 | %endif | |
818 | %if cpuflag(ssse3) | |
819 | palignr m0, m2, m1, 8 | |
820 | pslldq m1, 8 | |
821 | %else | |
822 | shufpd m0, m1, m2, 5 | |
823 | %endif | |
824 | %endif | |
825 | ||
826 | %if ARCH_X86_64 | |
827 | mova m6, m7 | |
828 | %else | |
829 | mova m6, [dwords_round] | |
830 | mova [r0], m1 | |
831 | SWAP 1, 8 | |
832 | %endif | |
833 | ||
834 | %assign %%i %1 | |
835 | psubw m3, m2, m0 | |
836 | %if cpuflag(ssse3) && %1 < 8 | |
837 | psrldq m2, 16 - 2 * %1 | |
838 | %endif | |
839 | NEXT_DIFF 4,2,0, 2 * %%i - 2, right | |
840 | FILTER_PAIR 5,6, 3,4, 5, 9,%%i | |
841 | %rep %1 / 2 - 1 | |
842 | %assign %%i %%i - 2 | |
843 | NEXT_DIFF 3,2,0, 2 * %%i, right | |
844 | NEXT_DIFF 4,2,0, 2 * %%i - 2, right | |
845 | FILTER_PAIR 5,6, 3,4, 8, 9,%%i | |
846 | %endrep | |
847 | ||
848 | %if ARCH_X86_64 == 0 | |
849 | SWAP 1, 8 | |
850 | mova m1, [r0] | |
851 | %if %1 % 2 | |
852 | mova [r0], m2 | |
853 | %endif | |
854 | SWAP 2, 8 | |
855 | %endif | |
856 | ||
857 | %assign %%i %1 | |
858 | %if cpuflag(ssse3) && %1 < 8 | |
859 | NEXT_DIFF 3,1,0, 2 * %%i, left | |
860 | %else | |
861 | psubw m3, m1, m0 | |
862 | %endif | |
863 | NEXT_DIFF 4,1,0, 2 * %%i - 2, left | |
864 | FILTER_PAIR 5,6, 3,4, 8, 9,%%i | |
865 | %rep %1 / 2 - 1 | |
866 | %assign %%i %%i - 2 | |
867 | NEXT_DIFF 3,1,0, 2 * %%i, left | |
868 | NEXT_DIFF 4,1,0, 2 * %%i - 2, left | |
869 | FILTER_PAIR 5,6, 3,4, 8, 9,%%i | |
870 | %endrep | |
871 | ||
872 | %if %%i > 2 | |
873 | %assign %%i %%i - 2 | |
874 | %if ARCH_X86_64 == 0 | |
875 | SWAP 2, 8 | |
876 | mova m2, [r0] | |
877 | %endif | |
878 | NEXT_DIFF 3,1,0, 2 * %%i, left | |
879 | NEXT_DIFF 4,2,0, 2 * %%i, right | |
880 | FILTER_PAIR 5,6, 3,4, 1, 9,%%i | |
881 | %endif | |
882 | ||
883 | psrad m5, 16 | |
884 | psrad m6, 16 | |
885 | packssdw m5, m6 | |
886 | paddw m0, m5 | |
729 | 887 | mova [r0], m0 |
730 | 888 | add r0, mmsize |
731 | 889 | add r4, mmsize |
735 | 893 | %endmacro |
736 | 894 | |
737 | 895 | INIT_XMM sse2 |
738 | PRE_BLUR1_HORZ | |
896 | BLUR_HORZ 4 | |
897 | BLUR_HORZ 5 | |
898 | BLUR_HORZ 6 | |
899 | BLUR_HORZ 7 | |
900 | BLUR_HORZ 8 | |
739 | 901 | INIT_YMM avx2 |
740 | PRE_BLUR1_HORZ | |
741 | ||
742 | ;------------------------------------------------------------------------------ | |
743 | ; PRE_BLUR1_VERT | |
744 | ; void pre_blur1_vert(int16_t *dst, const int16_t *src, | |
745 | ; uintptr_t src_width, uintptr_t src_height); | |
746 | ;------------------------------------------------------------------------------ | |
747 | ||
748 | %macro PRE_BLUR1_VERT 0 | |
749 | cglobal pre_blur1_vert, 4,7,4 | |
902 | BLUR_HORZ 4 | |
903 | BLUR_HORZ 5 | |
904 | BLUR_HORZ 6 | |
905 | BLUR_HORZ 7 | |
906 | BLUR_HORZ 8 | |
907 | ||
908 | ;------------------------------------------------------------------------------ | |
909 | ; BLUR_VERT 1:radius | |
910 | ; void blurN_vert(int16_t *dst, const int16_t *src, | |
911 | ; uintptr_t src_width, uintptr_t src_height, | |
912 | ; const int16_t *param); | |
913 | ;------------------------------------------------------------------------------ | |
914 | ||
915 | %macro BLUR_VERT 1 | |
916 | %if ARCH_X86_64 | |
917 | %assign %%narg 7 + (%1 + 1) / 2 | |
918 | cglobal blur%1_vert, 5,7,%%narg | |
919 | %else | |
920 | cglobal blur%1_vert, 5,7,8 | |
921 | %endif | |
922 | LOAD_MULTIPLIER %1, 7, r4, r5 | |
750 | 923 | lea r2, [2 * r2 + mmsize - 1] |
751 | lea r5, [r3 + 2] | |
924 | lea r5, [r3 + 2 * %1] | |
752 | 925 | and r2, ~(mmsize - 1) |
753 | 926 | imul r2, r5 |
754 | 927 | MUL r3, mmsize |
755 | 928 | add r2, r0 |
756 | mova m3, [words_one] | |
929 | mova m4, [dwords_round] | |
757 | 930 | lea r6, [words_zero] |
758 | 931 | sub r6, r1 |
759 | 932 | |
760 | 933 | .col_loop: |
761 | mov r4, -2 * mmsize | |
762 | pxor m0, m0 | |
763 | pxor m1, m1 | |
934 | mov r4, -2 * %1 * mmsize | |
764 | 935 | .row_loop: |
765 | LOAD_LINE 2, r1,r3,r6, r4 + 2 * mmsize, r5 | |
766 | ||
767 | paddw m0, m2 | |
768 | psrlw m0, 1 | |
769 | paddw m0, m1 | |
770 | paddw m0, m3 | |
771 | psrlw m0, 1 | |
772 | ||
773 | mova [r0], m0 | |
774 | add r4, mmsize | |
775 | add r0, mmsize | |
776 | mova m0, m1 | |
777 | mova m1, m2 | |
778 | cmp r4, r3 | |
779 | jl .row_loop | |
780 | add r1, r3 | |
781 | sub r6, r3 | |
782 | cmp r0, r2 | |
783 | jb .col_loop | |
784 | RET | |
785 | %endmacro | |
786 | ||
787 | INIT_XMM sse2 | |
788 | PRE_BLUR1_VERT | |
789 | INIT_YMM avx2 | |
790 | PRE_BLUR1_VERT | |
791 | ||
792 | ;------------------------------------------------------------------------------ | |
793 | ; PRE_BLUR2_HORZ | |
794 | ; void pre_blur2_horz(int16_t *dst, const int16_t *src, | |
795 | ; uintptr_t src_width, uintptr_t src_height); | |
796 | ;------------------------------------------------------------------------------ | |
797 | ||
798 | %macro PRE_BLUR2_HORZ 0 | |
799 | %if ARCH_X86_64 | |
800 | cglobal pre_blur2_horz, 4,8,7 | |
801 | %else | |
802 | cglobal pre_blur2_horz, 4,7,7 | |
803 | %endif | |
804 | lea r5, [2 * r2 + mmsize + 7] | |
805 | lea r2, [2 * r2 + mmsize - 1] | |
806 | and r5, ~(mmsize - 1) | |
807 | and r2, ~(mmsize - 1) | |
808 | imul r5, r3 | |
809 | imul r2, r3 | |
810 | add r5, r0 | |
811 | xor r4, r4 | |
812 | MUL r3, mmsize | |
813 | sub r4, r3 | |
814 | mova m5, [words_one] | |
815 | mova m6, [words_sign] | |
816 | %if ARCH_X86_64 | |
817 | lea r7, [words_zero] | |
818 | sub r7, r1 | |
819 | %endif | |
820 | ||
821 | .main_loop: | |
822 | %if ARCH_X86_64 | |
823 | LOAD_LINE 0, r1,r2,r7, r4 + 0 * r3, r6, right | |
824 | LOAD_LINE 1, r1,r2,r7, r4 + 1 * r3, r6 | |
825 | %else | |
826 | LOAD_LINE_COMPACT 0, r1,r2,r4, r6, right | |
827 | add r4, r3 | |
828 | LOAD_LINE_COMPACT 1, r1,r2,r4, r6 | |
829 | sub r4, r3 | |
830 | %endif | |
831 | ||
832 | %if mmsize == 32 | |
833 | vperm2i128 m0, m0, m1, 0x20 | |
834 | %endif | |
835 | psrldq m0, 8 | |
836 | pslldq m2, m1, 8 | |
837 | por m2, m0 | |
838 | paddw m2, m1 | |
839 | psrlw m2, 1 | |
840 | psrldq m0, 2 | |
841 | pslldq m3, m1, 6 | |
842 | por m3, m0 | |
843 | psrldq m0, 2 | |
844 | pslldq m4, m1, 4 | |
845 | por m4, m0 | |
846 | paddw m2, m4 | |
847 | psrlw m2, 1 | |
848 | paddw m2, m4 | |
849 | psrldq m0, 2 | |
850 | pslldq m1, 2 | |
851 | por m0, m1 | |
852 | paddw m0, m3 | |
853 | mova m1, m6 | |
854 | pand m1, m0 | |
855 | pand m1, m2 | |
856 | paddw m0, m2 | |
857 | psrlw m0, 1 | |
858 | por m0, m1 | |
859 | paddw m0, m5 | |
860 | psrlw m0, 1 | |
861 | ||
862 | mova [r0], m0 | |
863 | add r0, mmsize | |
864 | add r4, mmsize | |
865 | cmp r0, r5 | |
866 | jb .main_loop | |
867 | RET | |
868 | %endmacro | |
869 | ||
870 | INIT_XMM sse2 | |
871 | PRE_BLUR2_HORZ | |
872 | INIT_YMM avx2 | |
873 | PRE_BLUR2_HORZ | |
874 | ||
875 | ;------------------------------------------------------------------------------ | |
876 | ; PRE_BLUR2_VERT | |
877 | ; void pre_blur2_vert(int16_t *dst, const int16_t *src, | |
878 | ; uintptr_t src_width, uintptr_t src_height); | |
879 | ;------------------------------------------------------------------------------ | |
880 | ||
881 | %macro PRE_BLUR2_VERT 0 | |
882 | %if ARCH_X86_64 | |
883 | cglobal pre_blur2_vert, 4,7,9 | |
884 | %else | |
885 | cglobal pre_blur2_vert, 4,7,8 | |
886 | %endif | |
887 | lea r2, [2 * r2 + mmsize - 1] | |
888 | lea r5, [r3 + 4] | |
889 | and r2, ~(mmsize - 1) | |
890 | imul r2, r5 | |
891 | MUL r3, mmsize | |
892 | add r2, r0 | |
893 | mova m7, [words_one] | |
894 | %if ARCH_X86_64 | |
895 | mova m8, [words_sign] | |
896 | %endif | |
897 | lea r6, [words_zero] | |
898 | sub r6, r1 | |
899 | ||
900 | .col_loop: | |
901 | mov r4, -4 * mmsize | |
902 | pxor m0, m0 | |
903 | pxor m1, m1 | |
904 | pxor m2, m2 | |
905 | pxor m3, m3 | |
906 | .row_loop: | |
907 | LOAD_LINE 4, r1,r3,r6, r4 + 4 * mmsize, r5 | |
908 | ||
909 | %if ARCH_X86_64 | |
910 | mova m6, m8 | |
911 | %else | |
912 | psllw m6, m7, 15 | |
913 | %endif | |
914 | paddw m0, m4 | |
915 | psrlw m0, 1 | |
916 | paddw m0, m2 | |
917 | psrlw m0, 1 | |
918 | paddw m0, m2 | |
919 | paddw m5, m1, m3 | |
920 | pand m6, m0 | |
921 | pand m6, m5 | |
922 | paddw m0, m5 | |
923 | psrlw m0, 1 | |
924 | por m0, m6 | |
925 | paddw m0, m7 | |
926 | psrlw m0, 1 | |
927 | ||
928 | mova [r0], m0 | |
929 | add r4, mmsize | |
930 | add r0, mmsize | |
931 | mova m0, m1 | |
932 | mova m1, m2 | |
933 | mova m2, m3 | |
934 | mova m3, m4 | |
935 | cmp r4, r3 | |
936 | jl .row_loop | |
937 | add r1, r3 | |
938 | sub r6, r3 | |
939 | cmp r0, r2 | |
940 | jb .col_loop | |
941 | RET | |
942 | %endmacro | |
943 | ||
944 | INIT_XMM sse2 | |
945 | PRE_BLUR2_VERT | |
946 | INIT_YMM avx2 | |
947 | PRE_BLUR2_VERT | |
948 | ||
949 | ;------------------------------------------------------------------------------ | |
950 | ; ADD_LINE 1:m_acc1, 2:m_acc2, 3:m_line, 4-5:m_tmp | |
951 | ; Calculate acc += line | |
952 | ;------------------------------------------------------------------------------ | |
953 | ||
954 | %macro ADD_LINE 5 | |
955 | psraw m%4, m%3, 15 | |
956 | punpcklwd m%5, m%3, m%4 | |
957 | punpckhwd m%3, m%4 | |
958 | %ifidn %1, %5 | |
959 | paddd m%1, m%2 | |
960 | %else | |
961 | paddd m%1, m%5 | |
962 | %endif | |
963 | paddd m%2, m%3 | |
964 | %endmacro | |
965 | ||
966 | ;------------------------------------------------------------------------------ | |
967 | ; FILTER_PAIR 1:m_acc1, 2:m_acc2, 3:m_line1, 4:m_line2, | |
968 | ; 5:m_tmp, 6:m_mul64, [7:m_mul32, 8:swizzle] | |
969 | ; Calculate acc += line1 * mul[odd] + line2 * mul[even] | |
970 | ;------------------------------------------------------------------------------ | |
971 | ||
972 | %macro FILTER_PAIR 6-8 | |
973 | punpcklwd m%5, m%4, m%3 | |
974 | punpckhwd m%4, m%3 | |
975 | %if ARCH_X86_64 || (%0 < 8) | |
976 | pmaddwd m%5, m%6 | |
977 | pmaddwd m%4, m%6 | |
978 | %else | |
979 | pshufd m%3, m%7, %8 | |
980 | pmaddwd m%5, m%3 | |
981 | pmaddwd m%4, m%3 | |
982 | %endif | |
983 | %ifidn %1, %5 | |
984 | paddd m%1, m%2 | |
985 | %else | |
986 | paddd m%1, m%5 | |
987 | %endif | |
988 | paddd m%2, m%4 | |
989 | %endmacro | |
990 | ||
991 | ;------------------------------------------------------------------------------ | |
992 | ; PRE_BLUR3_HORZ | |
993 | ; void pre_blur3_horz(int16_t *dst, const int16_t *src, | |
994 | ; uintptr_t src_width, uintptr_t src_height); | |
995 | ;------------------------------------------------------------------------------ | |
996 | ||
997 | %macro PRE_BLUR3_HORZ 0 | |
998 | %if ARCH_X86_64 | |
999 | cglobal pre_blur3_horz, 4,8,9 | |
1000 | %else | |
1001 | cglobal pre_blur3_horz, 4,7,8 | |
1002 | %endif | |
1003 | lea r5, [2 * r2 + mmsize + 11] | |
1004 | lea r2, [2 * r2 + mmsize - 1] | |
1005 | and r5, ~(mmsize - 1) | |
1006 | and r2, ~(mmsize - 1) | |
1007 | imul r5, r3 | |
1008 | imul r2, r3 | |
1009 | add r5, r0 | |
1010 | xor r4, r4 | |
1011 | MUL r3, mmsize | |
1012 | sub r4, r3 | |
1013 | mova m5, [words_15_6] | |
1014 | %if ARCH_X86_64 | |
1015 | mova m8, [dwords_32] | |
1016 | lea r7, [words_zero] | |
1017 | sub r7, r1 | |
1018 | %endif | |
1019 | ||
1020 | .main_loop: | |
1021 | %if ARCH_X86_64 | |
1022 | LOAD_LINE 0, r1,r2,r7, r4 + 0 * r3, r6, right | |
1023 | LOAD_LINE 1, r1,r2,r7, r4 + 1 * r3, r6 | |
1024 | %else | |
1025 | LOAD_LINE_COMPACT 0, r1,r2,r4, r6, right | |
1026 | add r4, r3 | |
1027 | LOAD_LINE_COMPACT 1, r1,r2,r4, r6 | |
1028 | sub r4, r3 | |
1029 | %endif | |
1030 | ||
1031 | %if ARCH_X86_64 | |
1032 | mova m7, m8 | |
1033 | %else | |
1034 | mova m7, [dwords_32] | |
1035 | %endif | |
1036 | %if mmsize == 32 | |
1037 | vperm2i128 m0, m0, m1, 0x20 | |
1038 | %endif | |
1039 | psrldq m2, m0, 10 | |
1040 | pslldq m3, m1, 6 | |
1041 | por m2, m3 | |
1042 | ||
1043 | psrldq m0, 4 | |
1044 | pslldq m3, m2, 6 | |
1045 | por m3, m0 | |
1046 | psubw m3, m2 | |
1047 | ADD_LINE 6,7, 3,4, 6 | |
1048 | ||
1049 | psrldq m0, 2 | |
1050 | pslldq m3, m2, 4 | |
1051 | por m3, m0 | |
1052 | psubw m3, m2 | |
1053 | psrldq m0, 2 | |
1054 | pslldq m4, m2, 2 | |
1055 | por m4, m0 | |
1056 | psubw m4, m2 | |
1057 | FILTER_PAIR 6,7, 3,4, 0, 5 | |
1058 | ||
1059 | psubw m3, m1, m2 | |
1060 | ADD_LINE 6,7, 3,4, 0 | |
1061 | ||
1062 | pslldq m1, 2 | |
1063 | psrldq m3, m2, 4 | |
1064 | por m3, m1 | |
1065 | psubw m3, m2 | |
1066 | pslldq m1, 2 | |
1067 | psrldq m4, m2, 2 | |
1068 | por m4, m1 | |
1069 | psubw m4, m2 | |
1070 | FILTER_PAIR 6,7, 3,4, 0, 5 | |
1071 | ||
1072 | psrad m6, 6 | |
1073 | psrad m7, 6 | |
1074 | packssdw m6, m7 | |
1075 | paddw m2, m6 | |
1076 | mova [r0], m2 | |
1077 | add r0, mmsize | |
1078 | add r4, mmsize | |
1079 | cmp r0, r5 | |
1080 | jb .main_loop | |
1081 | RET | |
1082 | %endmacro | |
1083 | ||
1084 | INIT_XMM sse2 | |
1085 | PRE_BLUR3_HORZ | |
1086 | INIT_YMM avx2 | |
1087 | PRE_BLUR3_HORZ | |
1088 | ||
1089 | ;------------------------------------------------------------------------------ | |
1090 | ; PRE_BLUR3_VERT | |
1091 | ; void pre_blur3_vert(int16_t *dst, const int16_t *src, | |
1092 | ; uintptr_t src_width, uintptr_t src_height); | |
1093 | ;------------------------------------------------------------------------------ | |
1094 | ||
1095 | %macro PRE_BLUR3_VERT 0 | |
1096 | %if ARCH_X86_64 | |
1097 | cglobal pre_blur3_vert, 4,7,8 | |
1098 | %else | |
1099 | cglobal pre_blur3_vert, 4,7,8 | |
1100 | %endif | |
1101 | lea r2, [2 * r2 + mmsize - 1] | |
1102 | lea r5, [r3 + 6] | |
1103 | and r2, ~(mmsize - 1) | |
1104 | imul r2, r5 | |
1105 | MUL r3, mmsize | |
1106 | add r2, r0 | |
1107 | mova m4, [dwords_32] | |
1108 | mova m5, [words_15_6] | |
1109 | lea r6, [words_zero] | |
1110 | sub r6, r1 | |
1111 | ||
1112 | .col_loop: | |
1113 | mov r4, -6 * mmsize | |
1114 | .row_loop: | |
936 | mova m5, m4 | |
1115 | 937 | mova m6, m4 |
1116 | mova m7, m4 | |
1117 | LOAD_LINE 0, r1,r3,r6, r4 + 3 * mmsize, r5 | |
1118 | ||
1119 | LOAD_LINE 1, r1,r3,r6, r4 + 0 * mmsize, r5 | |
1120 | psubw m1, m0 | |
1121 | ADD_LINE 6,7, 1,2, 3 | |
1122 | ||
1123 | LOAD_LINE 1, r1,r3,r6, r4 + 1 * mmsize, r5 | |
1124 | LOAD_LINE 2, r1,r3,r6, r4 + 2 * mmsize, r5 | |
938 | LOAD_LINE 0, r1,r3,r6, r4 + %1 * mmsize, r5 | |
939 | ||
940 | %assign %%i %1 | |
941 | %rep %1 / 2 | |
942 | ||
943 | LOAD_LINE 1, r1,r3,r6, r4 + (%1 - %%i) * mmsize, r5 | |
944 | LOAD_LINE 2, r1,r3,r6, r4 + (%1 - %%i + 1) * mmsize, r5 | |
1125 | 945 | psubw m1, m0 |
1126 | 946 | psubw m2, m0 |
1127 | FILTER_PAIR 6,7, 1,2, 3, 5 | |
1128 | ||
1129 | LOAD_LINE 1, r1,r3,r6, r4 + 6 * mmsize, r5 | |
1130 | psubw m1, m0 | |
1131 | ADD_LINE 6,7, 1,2, 3 | |
1132 | ||
1133 | LOAD_LINE 1, r1,r3,r6, r4 + 5 * mmsize, r5 | |
1134 | LOAD_LINE 2, r1,r3,r6, r4 + 4 * mmsize, r5 | |
947 | FILTER_PAIR 5,6, 1,2, 3, 7,%%i | |
948 | ||
949 | LOAD_LINE 1, r1,r3,r6, r4 + (%1 + %%i) * mmsize, r5 | |
950 | LOAD_LINE 2, r1,r3,r6, r4 + (%1 + %%i - 1) * mmsize, r5 | |
1135 | 951 | psubw m1, m0 |
1136 | 952 | psubw m2, m0 |
1137 | FILTER_PAIR 6,7, 1,2, 3, 5 | |
1138 | ||
1139 | psrad m6, 6 | |
1140 | psrad m7, 6 | |
1141 | packssdw m6, m7 | |
1142 | paddw m0, m6 | |
953 | FILTER_PAIR 5,6, 1,2, 3, 7,%%i | |
954 | ||
955 | %assign %%i %%i - 2 | |
956 | %endrep | |
957 | ||
958 | %if %%i > 0 | |
959 | LOAD_LINE 1, r1,r3,r6, r4 + (%1 - %%i) * mmsize, r5 | |
960 | LOAD_LINE 2, r1,r3,r6, r4 + (%1 + %%i) * mmsize, r5 | |
961 | psubw m1, m0 | |
962 | psubw m2, m0 | |
963 | FILTER_PAIR 5,6, 1,2, 3, 7,%%i | |
964 | %endif | |
965 | ||
966 | psrad m5, 16 | |
967 | psrad m6, 16 | |
968 | packssdw m5, m6 | |
969 | paddw m0, m5 | |
1143 | 970 | mova [r0], m0 |
1144 | 971 | add r4, mmsize |
1145 | 972 | add r0, mmsize |
1153 | 980 | %endmacro |
1154 | 981 | |
1155 | 982 | INIT_XMM sse2 |
1156 | PRE_BLUR3_VERT | |
983 | BLUR_VERT 4 | |
984 | BLUR_VERT 5 | |
985 | BLUR_VERT 6 | |
986 | BLUR_VERT 7 | |
987 | BLUR_VERT 8 | |
1157 | 988 | INIT_YMM avx2 |
1158 | PRE_BLUR3_VERT | |
1159 | ||
1160 | ;------------------------------------------------------------------------------ | |
1161 | ; LOAD_MULTIPLIER 1:m_mul1, 2:m_mul2, 3:src, 4:tmp | |
1162 | ; Load blur parameters into xmm/ymm registers | |
1163 | ;------------------------------------------------------------------------------ | |
1164 | ||
1165 | %macro LOAD_MULTIPLIER 4 | |
1166 | mov %4, [%3] | |
1167 | movd xm%1, %4d | |
1168 | %if ARCH_X86_64 | |
1169 | shr %4, 32 | |
1170 | %else | |
1171 | mov %4, [%3 + 4] | |
1172 | %endif | |
1173 | movd xm%2, %4d | |
1174 | %if ARCH_X86_64 == 0 | |
1175 | punpckldq xm%1, xm%2 | |
1176 | %if mmsize == 32 | |
1177 | vpbroadcastq m%1, xm%1 | |
1178 | %endif | |
1179 | %elif mmsize == 32 | |
1180 | vpbroadcastd m%1, xm%1 | |
1181 | vpbroadcastd m%2, xm%2 | |
1182 | %else | |
1183 | pshufd m%1, m%1, q0000 | |
1184 | pshufd m%2, m%2, q0000 | |
1185 | %endif | |
1186 | %endmacro | |
1187 | ||
1188 | ;------------------------------------------------------------------------------ | |
1189 | ; BLUR_HORZ 1:pattern | |
1190 | ; void blurNNNN_horz(int16_t *dst, const int16_t *src, | |
1191 | ; uintptr_t src_width, uintptr_t src_height, | |
1192 | ; const int16_t *param); | |
1193 | ;------------------------------------------------------------------------------ | |
1194 | ||
1195 | %macro BLUR_HORZ 1 | |
1196 | %assign %%i1 %1 / 1000 % 10 | |
1197 | %assign %%i2 %1 / 100 % 10 | |
1198 | %assign %%i3 %1 / 10 % 10 | |
1199 | %assign %%i4 %1 / 1 % 10 | |
1200 | %if ARCH_X86_64 | |
1201 | cglobal blur%1_horz, 5,8,10 | |
1202 | %else | |
1203 | cglobal blur%1_horz, 5,7,8 | |
1204 | %endif | |
1205 | %if ARCH_X86_64 | |
1206 | LOAD_MULTIPLIER 8,9, r4, r5 | |
1207 | %else | |
1208 | LOAD_MULTIPLIER 5,0, r4, r5 | |
1209 | %endif | |
1210 | lea r5, [2 * r2 + mmsize + 4 * %%i4 - 1] | |
1211 | lea r2, [2 * r2 + mmsize - 1] | |
1212 | and r5, ~(mmsize - 1) | |
1213 | and r2, ~(mmsize - 1) | |
1214 | imul r5, r3 | |
1215 | imul r2, r3 | |
1216 | add r5, r0 | |
1217 | xor r4, r4 | |
1218 | MUL r3, mmsize | |
1219 | %if (mmsize != 32) && (%%i4 > 4) | |
1220 | sub r4, r3 | |
1221 | %endif | |
1222 | sub r4, r3 | |
1223 | %if ARCH_X86_64 | |
1224 | mova m5, [dwords_round] | |
1225 | lea r7, [words_zero] | |
1226 | sub r7, r1 | |
1227 | %endif | |
1228 | ||
1229 | .main_loop: | |
1230 | %if ARCH_X86_64 | |
1231 | %if %%i4 > 4 | |
1232 | LOAD_LINE 0, r1,r2,r7, r4 + 0 * r3, r6 | |
1233 | %else | |
1234 | LOAD_LINE 0, r1,r2,r7, r4 + 0 * r3, r6, right | |
1235 | %endif | |
1236 | LOAD_LINE 1, r1,r2,r7, r4 + 1 * r3, r6 | |
1237 | %if (mmsize != 32) && (%%i4 > 4) | |
1238 | LOAD_LINE 2, r1,r2,r7, r4 + 2 * r3, r6 | |
1239 | SWAP 1, 2 | |
1240 | %endif | |
1241 | %else | |
1242 | %if %%i4 > 4 | |
1243 | LOAD_LINE_COMPACT 0, r1,r2,r4, r6 | |
1244 | %else | |
1245 | LOAD_LINE_COMPACT 0, r1,r2,r4, r6, right | |
1246 | %endif | |
1247 | add r4, r3 | |
1248 | LOAD_LINE_COMPACT 1, r1,r2,r4, r6 | |
1249 | %if (mmsize != 32) && (%%i4 > 4) | |
1250 | add r4, r3 | |
1251 | LOAD_LINE_COMPACT 2, r1,r2,r4, r6 | |
1252 | SWAP 1, 2 | |
1253 | sub r4, r3 | |
1254 | %endif | |
1255 | sub r4, r3 | |
1256 | %endif | |
1257 | ||
1258 | %if ARCH_X86_64 | |
1259 | mova m7, m5 | |
1260 | %else | |
1261 | mova m7, [dwords_round] | |
1262 | %endif | |
1263 | %if %%i4 > 4 | |
1264 | %if mmsize == 32 | |
1265 | vperm2i128 m2, m0, m1, 0x21 | |
1266 | %endif | |
1267 | psrldq m0, 32 - 4 * %%i4 | |
1268 | pslldq m3, m2, 4 * %%i4 - 16 | |
1269 | por m0, m3 | |
1270 | psrldq m2, 16 - 2 * %%i4 | |
1271 | %else | |
1272 | %if mmsize == 32 | |
1273 | vperm2i128 m0, m0, m1, 0x20 | |
1274 | %endif | |
1275 | psrldq m2, m0, 16 - 2 * %%i4 | |
1276 | %endif | |
1277 | pslldq m3, m1, 2 * %%i4 | |
1278 | por m2, m3 | |
1279 | ||
1280 | psubw m3, m1, m2 | |
1281 | pslldq m1, 2 * (%%i4 - %%i3) | |
1282 | psrldq m4, m2, 2 * %%i3 | |
1283 | por m4, m1 | |
1284 | psubw m4, m2 | |
1285 | FILTER_PAIR 6,7, 3,4, 6, 9,5,q1111 | |
1286 | ||
1287 | pslldq m1, 2 * (%%i3 - %%i2) | |
1288 | psrldq m3, m2, 2 * %%i2 | |
1289 | por m3, m1 | |
1290 | psubw m3, m2 | |
1291 | pslldq m1, 2 * (%%i2 - %%i1) | |
1292 | psrldq m4, m2, 2 * %%i1 | |
1293 | por m4, m1 | |
1294 | psubw m4, m2 | |
1295 | FILTER_PAIR 6,7, 3,4, 1, 8,5,q0000 | |
1296 | ||
1297 | psubw m3, m0, m2 | |
1298 | psrldq m0, 2 * (%%i4 - %%i3) | |
1299 | pslldq m4, m2, 2 * %%i3 | |
1300 | por m4, m0 | |
1301 | psubw m4, m2 | |
1302 | FILTER_PAIR 6,7, 3,4, 1, 9,5,q1111 | |
1303 | ||
1304 | psrldq m0, 2 * (%%i3 - %%i2) | |
1305 | pslldq m3, m2, 2 * %%i2 | |
1306 | por m3, m0 | |
1307 | psubw m3, m2 | |
1308 | psrldq m0, 2 * (%%i2 - %%i1) | |
1309 | pslldq m4, m2, 2 * %%i1 | |
1310 | por m4, m0 | |
1311 | psubw m4, m2 | |
1312 | FILTER_PAIR 6,7, 3,4, 1, 8,5,q0000 | |
1313 | ||
1314 | psrad m6, 16 | |
1315 | psrad m7, 16 | |
1316 | packssdw m6, m7 | |
1317 | paddw m2, m6 | |
1318 | mova [r0], m2 | |
1319 | add r0, mmsize | |
1320 | add r4, mmsize | |
1321 | cmp r0, r5 | |
1322 | jb .main_loop | |
1323 | RET | |
1324 | %endmacro | |
1325 | ||
1326 | INIT_XMM sse2 | |
1327 | BLUR_HORZ 1234 | |
1328 | BLUR_HORZ 1235 | |
1329 | BLUR_HORZ 1246 | |
1330 | INIT_YMM avx2 | |
1331 | BLUR_HORZ 1234 | |
1332 | BLUR_HORZ 1235 | |
1333 | BLUR_HORZ 1246 | |
1334 | ||
1335 | ;------------------------------------------------------------------------------ | |
1336 | ; BLUR_VERT 1:pattern | |
1337 | ; void blurNNNN_vert(int16_t *dst, const int16_t *src, | |
1338 | ; uintptr_t src_width, uintptr_t src_height, | |
1339 | ; const int16_t *param); | |
1340 | ;------------------------------------------------------------------------------ | |
1341 | ||
1342 | %macro BLUR_VERT 1 | |
1343 | %assign %%i1 %1 / 1000 % 10 | |
1344 | %assign %%i2 %1 / 100 % 10 | |
1345 | %assign %%i3 %1 / 10 % 10 | |
1346 | %assign %%i4 %1 / 1 % 10 | |
1347 | %if ARCH_X86_64 | |
1348 | cglobal blur%1_vert, 5,7,9 | |
1349 | %else | |
1350 | cglobal blur%1_vert, 5,7,8 | |
1351 | %endif | |
1352 | %if ARCH_X86_64 | |
1353 | LOAD_MULTIPLIER 4,5, r4, r5 | |
1354 | %else | |
1355 | LOAD_MULTIPLIER 5,0, r4, r5 | |
1356 | SWAP 4, 8 | |
1357 | %endif | |
1358 | lea r2, [2 * r2 + mmsize - 1] | |
1359 | lea r5, [r3 + 2 * %%i4] | |
1360 | and r2, ~(mmsize - 1) | |
1361 | imul r2, r5 | |
1362 | MUL r3, mmsize | |
1363 | add r2, r0 | |
1364 | mova m8, [dwords_round] | |
1365 | lea r6, [words_zero] | |
1366 | sub r6, r1 | |
1367 | ||
1368 | .col_loop: | |
1369 | mov r4, -2 * %%i4 * mmsize | |
1370 | .row_loop: | |
1371 | mova m6, m8 | |
1372 | mova m7, m8 | |
1373 | LOAD_LINE 0, r1,r3,r6, r4 + %%i4 * mmsize, r5 | |
1374 | ||
1375 | LOAD_LINE 1, r1,r3,r6, r4 + (%%i4 - %%i4) * mmsize, r5 | |
1376 | LOAD_LINE 2, r1,r3,r6, r4 + (%%i4 - %%i3) * mmsize, r5 | |
1377 | psubw m1, m0 | |
1378 | psubw m2, m0 | |
1379 | FILTER_PAIR 6,7, 1,2, 3, 5,5,q1111 | |
1380 | ||
1381 | LOAD_LINE 1, r1,r3,r6, r4 + (%%i4 - %%i2) * mmsize, r5 | |
1382 | LOAD_LINE 2, r1,r3,r6, r4 + (%%i4 - %%i1) * mmsize, r5 | |
1383 | psubw m1, m0 | |
1384 | psubw m2, m0 | |
1385 | FILTER_PAIR 6,7, 1,2, 3, 4,5,q0000 | |
1386 | ||
1387 | LOAD_LINE 1, r1,r3,r6, r4 + (%%i4 + %%i4) * mmsize, r5 | |
1388 | LOAD_LINE 2, r1,r3,r6, r4 + (%%i4 + %%i3) * mmsize, r5 | |
1389 | psubw m1, m0 | |
1390 | psubw m2, m0 | |
1391 | FILTER_PAIR 6,7, 1,2, 3, 5,5,q1111 | |
1392 | ||
1393 | LOAD_LINE 1, r1,r3,r6, r4 + (%%i4 + %%i2) * mmsize, r5 | |
1394 | LOAD_LINE 2, r1,r3,r6, r4 + (%%i4 + %%i1) * mmsize, r5 | |
1395 | psubw m1, m0 | |
1396 | psubw m2, m0 | |
1397 | FILTER_PAIR 6,7, 1,2, 3, 4,5,q0000 | |
1398 | ||
1399 | psrad m6, 16 | |
1400 | psrad m7, 16 | |
1401 | packssdw m6, m7 | |
1402 | paddw m0, m6 | |
1403 | mova [r0], m0 | |
1404 | add r4, mmsize | |
1405 | add r0, mmsize | |
1406 | cmp r4, r3 | |
1407 | jl .row_loop | |
1408 | add r1, r3 | |
1409 | sub r6, r3 | |
1410 | cmp r0, r2 | |
1411 | jb .col_loop | |
1412 | RET | |
1413 | %endmacro | |
1414 | ||
1415 | INIT_XMM sse2 | |
1416 | BLUR_VERT 1234 | |
1417 | BLUR_VERT 1235 | |
1418 | BLUR_VERT 1246 | |
1419 | INIT_YMM avx2 | |
1420 | BLUR_VERT 1234 | |
1421 | BLUR_VERT 1235 | |
1422 | BLUR_VERT 1246 | |
989 | BLUR_VERT 4 | |
990 | BLUR_VERT 5 | |
991 | BLUR_VERT 6 | |
992 | BLUR_VERT 7 | |
993 | BLUR_VERT 8 |
0 | 0 | ;****************************************************************************** |
1 | 1 | ;* add_bitmaps.asm: SSE2 and x86 add_bitmaps |
2 | 2 | ;****************************************************************************** |
3 | ;* Copyright (C) 2013 Rodger Combs <rcombs@rcombs.me> | |
3 | ;* Copyright (C) 2013 rcombs <rcombs@rcombs.me> | |
4 | 4 | ;* |
5 | 5 | ;* This file is part of libass. |
6 | 6 | ;* |
0 | 0 | /* |
1 | * Copyright (C) 2013 Rodger Combs <rcombs@rcombs.me> | |
1 | * Copyright (C) 2013 rcombs <rcombs@rcombs.me> | |
2 | 2 | * |
3 | 3 | * This file is part of libass. |
4 | 4 | * |
18 | 18 | #ifndef INTEL_CPUID_H |
19 | 19 | #define INTEL_CPUID_H |
20 | 20 | |
21 | #include <stdint.h> | |
22 | ||
21 | 23 | void ass_get_cpuid( uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); |
22 | 24 | void ass_get_xgetbv( uint32_t op, uint32_t *eax, uint32_t *edx ); |
23 | 25 |
82 | 82 | pmaxsw m%1, m%2 |
83 | 83 | %endif |
84 | 84 | %endmacro |
85 | ||
86 | ;------------------------------------------------------------------------------ | |
87 | ; PALIGNR 1:m_dst, 2:m_src1, 3:m_src2, 4:m_tmp, 5:amount | |
88 | ;------------------------------------------------------------------------------ | |
89 | ||
90 | %macro PALIGNR 5 | |
91 | %if (%5) == 0 | |
92 | %ifnidn %1, %3 | |
93 | mova %1, %3 | |
94 | %endif | |
95 | %elif mmsize == 32 | |
96 | palignr %1, %2, %3, %5 | |
97 | %elif cpuflag(ssse3) | |
98 | ||
99 | %ifnidn %1, %3 | |
100 | palignr %1, %2, %3, %5 | |
101 | %elifidn %2, %4 | |
102 | palignr %2, %3, %5 | |
103 | mova %1, %2 | |
104 | %else | |
105 | mova %4, %3 | |
106 | palignr %1, %2, %4, %5 | |
107 | %endif | |
108 | ||
109 | %elif (%5) == 8 | |
110 | ||
111 | %ifnidn %1, %2 | |
112 | shufpd %1, %3, %2, 5 | |
113 | %elifidn %3, %4 | |
114 | shufpd %3, %2, 5 | |
115 | mova %1, %3 | |
116 | %else | |
117 | mova %4, %2 | |
118 | shufpd %1, %3, %4, 5 | |
119 | %endif | |
120 | ||
121 | %else | |
122 | ||
123 | %assign %%flip 0 | |
124 | %ifidn %1, %3 | |
125 | %assign %%flip 1 | |
126 | %endif | |
127 | %ifidn %2, %4 | |
128 | %assign %%flip 1 | |
129 | %endif | |
130 | %if %%flip | |
131 | pslldq %4, %2, 16 - (%5) | |
132 | psrldq %1, %3, %5 | |
133 | %else | |
134 | pslldq %1, %2, 16 - (%5) | |
135 | psrldq %4, %3, %5 | |
136 | %endif | |
137 | por %1, %4 | |
138 | ||
139 | %endif | |
140 | %endmacro |
1066 | 1066 | _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; |
1067 | 1067 | darwin1.*) |
1068 | 1068 | _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; |
1069 | darwin*) # darwin 5.x on | |
1070 | # if running on 10.5 or later, the deployment target defaults | |
1071 | # to the OS version, if on x86, and 10.4, the deployment | |
1072 | # target defaults to 10.4. Don't you love it? | |
1073 | case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in | |
1074 | 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) | |
1075 | _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; | |
1076 | 10.[[012]][[,.]]*) | |
1069 | darwin*) | |
1070 | case ${MACOSX_DEPLOYMENT_TARGET},$host in | |
1071 | 10.[[012]],*|,*powerpc*) | |
1077 | 1072 | _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; |
1078 | 10.*) | |
1073 | *) | |
1079 | 1074 | _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; |
1080 | 1075 | esac |
1081 | 1076 | ;; |
0 | 0 | #! /bin/sh |
1 | 1 | # Common wrapper for a few potentially missing GNU programs. |
2 | 2 | |
3 | scriptversion=2013-10-28.13; # UTC | |
4 | ||
5 | # Copyright (C) 1996-2014 Free Software Foundation, Inc. | |
3 | scriptversion=2018-03-07.03; # UTC | |
4 | ||
5 | # Copyright (C) 1996-2018 Free Software Foundation, Inc. | |
6 | 6 | # Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996. |
7 | 7 | |
8 | 8 | # This program is free software; you can redistribute it and/or modify |
16 | 16 | # GNU General Public License for more details. |
17 | 17 | |
18 | 18 | # You should have received a copy of the GNU General Public License |
19 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | # along with this program. If not, see <https://www.gnu.org/licenses/>. | |
20 | 20 | |
21 | 21 | # As a special exception to the GNU General Public License, if you |
22 | 22 | # distribute this file as part of a program that contains a |
100 | 100 | exit $st |
101 | 101 | fi |
102 | 102 | |
103 | perl_URL=http://www.perl.org/ | |
104 | flex_URL=http://flex.sourceforge.net/ | |
105 | gnu_software_URL=http://www.gnu.org/software | |
103 | perl_URL=https://www.perl.org/ | |
104 | flex_URL=https://github.com/westes/flex | |
105 | gnu_software_URL=https://www.gnu.org/software | |
106 | 106 | |
107 | 107 | program_details () |
108 | 108 | { |
206 | 206 | exit $st |
207 | 207 | |
208 | 208 | # Local variables: |
209 | # eval: (add-hook 'write-file-hooks 'time-stamp) | |
209 | # eval: (add-hook 'before-save-hook 'time-stamp) | |
210 | 210 | # time-stamp-start: "scriptversion=" |
211 | 211 | # time-stamp-format: "%:y-%02m-%02d.%02H" |
212 | # time-stamp-time-zone: "UTC" | |
212 | # time-stamp-time-zone: "UTC0" | |
213 | 213 | # time-stamp-end: "; # UTC" |
214 | 214 | # End: |
0 | # Makefile.in generated by automake 1.15 from Makefile.am. | |
0 | # Makefile.in generated by automake 1.16.1 from Makefile.am. | |
1 | 1 | # @configure_input@ |
2 | 2 | |
3 | # Copyright (C) 1994-2014 Free Software Foundation, Inc. | |
3 | # Copyright (C) 1994-2018 Free Software Foundation, Inc. | |
4 | 4 | |
5 | 5 | # This Makefile.in is free software; the Free Software Foundation |
6 | 6 | # gives unlimited permission to copy and/or distribute it, |
126 | 126 | am__v_at_1 = |
127 | 127 | DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) |
128 | 128 | depcomp = $(SHELL) $(top_srcdir)/depcomp |
129 | am__depfiles_maybe = depfiles | |
129 | am__maybe_remake_depfiles = depfiles | |
130 | am__depfiles_remade = ./$(DEPDIR)/profile-profile.Po | |
130 | 131 | am__mv = mv -f |
131 | 132 | COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ |
132 | 133 | $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) |
330 | 331 | exit 1;; \ |
331 | 332 | esac; \ |
332 | 333 | done; \ |
333 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu profile/Makefile'; \ | |
334 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign profile/Makefile'; \ | |
334 | 335 | $(am__cd) $(top_srcdir) && \ |
335 | $(AUTOMAKE) --gnu profile/Makefile | |
336 | $(AUTOMAKE) --foreign profile/Makefile | |
336 | 337 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status |
337 | 338 | @case '$?' in \ |
338 | 339 | *config.status*) \ |
339 | 340 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ |
340 | 341 | *) \ |
341 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ | |
342 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ | |
342 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ | |
343 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ | |
343 | 344 | esac; |
344 | 345 | |
345 | 346 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) |
370 | 371 | distclean-compile: |
371 | 372 | -rm -f *.tab.c |
372 | 373 | |
373 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profile-profile.Po@am__quote@ | |
374 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profile-profile.Po@am__quote@ # am--include-marker | |
375 | ||
376 | $(am__depfiles_remade): | |
377 | @$(MKDIR_P) $(@D) | |
378 | @echo '# dummy' >$@-t && $(am__mv) $@-t $@ | |
379 | ||
380 | am--depfiles: $(am__depfiles_remade) | |
374 | 381 | |
375 | 382 | .c.o: |
376 | 383 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< |
465 | 472 | distclean-tags: |
466 | 473 | -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags |
467 | 474 | |
468 | distdir: $(DISTFILES) | |
475 | distdir: $(BUILT_SOURCES) | |
476 | $(MAKE) $(AM_MAKEFLAGS) distdir-am | |
477 | ||
478 | distdir-am: $(DISTFILES) | |
469 | 479 | @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ |
470 | 480 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ |
471 | 481 | list='$(DISTFILES)'; \ |
535 | 545 | mostlyclean-am |
536 | 546 | |
537 | 547 | distclean: distclean-am |
538 | -rm -rf ./$(DEPDIR) | |
548 | -rm -f ./$(DEPDIR)/profile-profile.Po | |
539 | 549 | -rm -f Makefile |
540 | 550 | distclean-am: clean-am distclean-compile distclean-generic \ |
541 | 551 | distclean-tags |
581 | 591 | installcheck-am: |
582 | 592 | |
583 | 593 | maintainer-clean: maintainer-clean-am |
584 | -rm -rf ./$(DEPDIR) | |
594 | -rm -f ./$(DEPDIR)/profile-profile.Po | |
585 | 595 | -rm -f Makefile |
586 | 596 | maintainer-clean-am: distclean-am maintainer-clean-generic |
587 | 597 | |
602 | 612 | |
603 | 613 | .MAKE: install-am install-strip |
604 | 614 | |
605 | .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ | |
606 | clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \ | |
607 | ctags-am distclean distclean-compile distclean-generic \ | |
615 | .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ | |
616 | clean-generic clean-libtool clean-noinstPROGRAMS cscopelist-am \ | |
617 | ctags ctags-am distclean distclean-compile distclean-generic \ | |
608 | 618 | distclean-libtool distclean-tags distdir dvi dvi-am html \ |
609 | 619 | html-am info info-am install install-am install-data \ |
610 | 620 | install-data-am install-dvi install-dvi-am install-exec \ |
0 | 0 | /* |
1 | 1 | * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> |
2 | 2 | * Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org> |
3 | * Copyright (C) 2013 Rodger Combs <rcombs@rcombs.me> | |
3 | * Copyright (C) 2013 rcombs <rcombs@rcombs.me> | |
4 | 4 | * |
5 | 5 | * This file is part of libass. |
6 | 6 | * |
65 | 65 | const int frame_h = 720; |
66 | 66 | |
67 | 67 | if (argc < 5) { |
68 | printf("usage: %s <subtitle file> <start time> <fps> <time to render>\n", argv[0]); | |
68 | printf("usage: %s <subtitle file> <start time> <fps> <end time>\n", argv[0]); | |
69 | 69 | exit(1); |
70 | 70 | } |
71 | 71 | char *subfile = argv[1]; |
72 | 72 | double tm = strtod(argv[2], 0); |
73 | 73 | double fps = strtod(argv[3], 0); |
74 | double time = strtod(argv[4], 0); | |
75 | ||
76 | if(fps == 0){ | |
74 | double end_time = strtod(argv[4], 0); | |
75 | ||
76 | if (fps == 0) { | |
77 | 77 | printf("fps cannot equal 0\n"); |
78 | 78 | exit(1); |
79 | 79 | } |
85 | 85 | exit(1); |
86 | 86 | } |
87 | 87 | |
88 | while(tm < time){ | |
88 | while (tm < end_time) { | |
89 | 89 | ass_render_frame(ass_renderer, track, (int) (tm * 1000), NULL); |
90 | 90 | tm += 1 / fps; |
91 | 91 | } |
0 | # Makefile.in generated by automake 1.15 from Makefile.am. | |
0 | # Makefile.in generated by automake 1.16.1 from Makefile.am. | |
1 | 1 | # @configure_input@ |
2 | 2 | |
3 | # Copyright (C) 1994-2014 Free Software Foundation, Inc. | |
3 | # Copyright (C) 1994-2018 Free Software Foundation, Inc. | |
4 | 4 | |
5 | 5 | # This Makefile.in is free software; the Free Software Foundation |
6 | 6 | # gives unlimited permission to copy and/or distribute it, |
126 | 126 | am__v_at_1 = |
127 | 127 | DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) |
128 | 128 | depcomp = $(SHELL) $(top_srcdir)/depcomp |
129 | am__depfiles_maybe = depfiles | |
129 | am__maybe_remake_depfiles = depfiles | |
130 | am__depfiles_remade = ./$(DEPDIR)/test-test.Po | |
130 | 131 | am__mv = mv -f |
131 | 132 | COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ |
132 | 133 | $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) |
330 | 331 | exit 1;; \ |
331 | 332 | esac; \ |
332 | 333 | done; \ |
333 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/Makefile'; \ | |
334 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/Makefile'; \ | |
334 | 335 | $(am__cd) $(top_srcdir) && \ |
335 | $(AUTOMAKE) --gnu test/Makefile | |
336 | $(AUTOMAKE) --foreign test/Makefile | |
336 | 337 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status |
337 | 338 | @case '$?' in \ |
338 | 339 | *config.status*) \ |
339 | 340 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ |
340 | 341 | *) \ |
341 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ | |
342 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ | |
342 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ | |
343 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ | |
343 | 344 | esac; |
344 | 345 | |
345 | 346 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) |
370 | 371 | distclean-compile: |
371 | 372 | -rm -f *.tab.c |
372 | 373 | |
373 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-test.Po@am__quote@ | |
374 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-test.Po@am__quote@ # am--include-marker | |
375 | ||
376 | $(am__depfiles_remade): | |
377 | @$(MKDIR_P) $(@D) | |
378 | @echo '# dummy' >$@-t && $(am__mv) $@-t $@ | |
379 | ||
380 | am--depfiles: $(am__depfiles_remade) | |
374 | 381 | |
375 | 382 | .c.o: |
376 | 383 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< |
465 | 472 | distclean-tags: |
466 | 473 | -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags |
467 | 474 | |
468 | distdir: $(DISTFILES) | |
475 | distdir: $(BUILT_SOURCES) | |
476 | $(MAKE) $(AM_MAKEFLAGS) distdir-am | |
477 | ||
478 | distdir-am: $(DISTFILES) | |
469 | 479 | @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ |
470 | 480 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ |
471 | 481 | list='$(DISTFILES)'; \ |
535 | 545 | mostlyclean-am |
536 | 546 | |
537 | 547 | distclean: distclean-am |
538 | -rm -rf ./$(DEPDIR) | |
548 | -rm -f ./$(DEPDIR)/test-test.Po | |
539 | 549 | -rm -f Makefile |
540 | 550 | distclean-am: clean-am distclean-compile distclean-generic \ |
541 | 551 | distclean-tags |
581 | 591 | installcheck-am: |
582 | 592 | |
583 | 593 | maintainer-clean: maintainer-clean-am |
584 | -rm -rf ./$(DEPDIR) | |
594 | -rm -f ./$(DEPDIR)/test-test.Po | |
585 | 595 | -rm -f Makefile |
586 | 596 | maintainer-clean-am: distclean-am maintainer-clean-generic |
587 | 597 | |
602 | 612 | |
603 | 613 | .MAKE: install-am install-strip |
604 | 614 | |
605 | .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ | |
606 | clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \ | |
607 | ctags-am distclean distclean-compile distclean-generic \ | |
615 | .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ | |
616 | clean-generic clean-libtool clean-noinstPROGRAMS cscopelist-am \ | |
617 | ctags ctags-am distclean distclean-compile distclean-generic \ | |
608 | 618 | distclean-libtool distclean-tags distdir dvi dvi-am html \ |
609 | 619 | html-am info info-am install install-am install-data \ |
610 | 620 | install-data-am install-dvi install-dvi-am install-exec \ |