mirror of https://gitee.com/openkylin/libass.git
Import Upstream version 0.14.0
This commit is contained in:
commit
6db9427a94
|
@ -0,0 +1,15 @@
|
|||
ISC License
|
||||
|
||||
Copyright (C) 2006-2016 libass contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
@ -0,0 +1,353 @@
|
|||
libass (0.14.0)
|
||||
* Brand new, faster and better outline stroker (replaces FreeType stroker)
|
||||
* Remove option to use the FreeType rasterizer
|
||||
* Fix spots of missing border around self-intersecting shapes
|
||||
* Switch from Yasm to NASM for building hand-written assembler code
|
||||
* Support Core Text font provider on Mac OS X 10.6 and 10.7
|
||||
* Clear font cache in ass_set_fonts(). This fixes potentially incorrect
|
||||
font choices and an occasional crash if this function is called midway
|
||||
through rendering a file.
|
||||
|
||||
libass (0.13.7)
|
||||
* Fix invalid memory accesses with BorderStyle=4
|
||||
* Fix change detection bug on frame resizes
|
||||
* Fix cache bugs with border size
|
||||
* Reduce precision of border width in font outline caching
|
||||
* Don't treat :;<=>? as hexadecimal digits in color headers
|
||||
* Fix parsing of unusual Alignment values in ASS style definitions
|
||||
* Fix potential truncation in timestamp parsing
|
||||
* Treat negative PlayResX/PlayResY like VSFilter
|
||||
* Fixes to parsing of embedded fonts
|
||||
* Remove arbitrary bitmap limit (fixes issues with subtitle rendering at 4K)
|
||||
* Allow using shadow offset to adjust size of background with BorderStyle=4
|
||||
* Fix TrueType/OpenType font collection handling with the DirectWrite backend
|
||||
|
||||
libass (0.13.6)
|
||||
* Bump ABI version to account for the new Justify field in ASS_Style
|
||||
that was added in 0.13.5.
|
||||
|
||||
libass (0.13.5)
|
||||
* Add Justify style override that changes text justification
|
||||
(left/right/center) without affecting event positioning.
|
||||
* Fix ass_set_cache_limits() to affect total bitmap cache size
|
||||
including composite bitmap cache.
|
||||
* Number parsing fixes
|
||||
* Fix illegal read when parsing some numbers in scientific notation
|
||||
with huge exponents.
|
||||
* Correctly evaluate numbers in scientific notation with large exponents.
|
||||
* Correctly evaluate numbers with many leading zeros.
|
||||
* Bug fixes found with fuzzing
|
||||
* Fix a small memory leak in the parser.
|
||||
* Fix illegal read in the parser on specially crafted input with \t tags.
|
||||
|
||||
libass (0.13.4)
|
||||
* Bug fixes found with fuzzing
|
||||
* Fix memory reallocation in the shaper. (CVE-2016-7972)
|
||||
* Fix two small memory leaks in the parser and test program.
|
||||
* Fix illegal read in Gaussian blur coefficient calculations.
|
||||
(CVE-2016-7970)
|
||||
* Fix mode 0/3 line wrapping equalization in specific cases which could
|
||||
result in illegal reads while laying out and shaping text.
|
||||
(CVE-2016-7969)
|
||||
|
||||
libass (0.13.3)
|
||||
* Improve compatibility/portablility of build system,
|
||||
should fix e.g. compilation on Solaris.
|
||||
* Fix memory leak in DirectWrite font provider.
|
||||
* Fix the rasterizer when rendering some large outlines.
|
||||
* Remove hack that forced RTL base direction depending on font encoding.
|
||||
* Greatly improve the internal caches with refcounting and gradual clearing.
|
||||
|
||||
libass (0.13.2)
|
||||
* Add ass_set_check_readorder() API function to disable use of the ReadOrder
|
||||
field for duplicate checking in ass_process_chunk().
|
||||
* ass_step_sub(track, now, 0) now finds the start of the subtitle at "now".
|
||||
* Bug fixes
|
||||
* Fix an issue with the new duplicate checking, which could lead to
|
||||
missing subtitles after seeking.
|
||||
* Fix a crash with CoreText under specific circumstances
|
||||
|
||||
libass (0.13.1)
|
||||
* Much faster duplicate event check in ass_process_chunk. This can
|
||||
bring a large speedup for embedded subtitles with lots of events.
|
||||
To make this possible, it is now forbidden to combine calls to
|
||||
ass_process_chunk with any other method of manipulating the event
|
||||
list, namely, manual manipulation and calls to ass_process_data,
|
||||
ass_read_memory and ass_read_file.
|
||||
* Interpret negative timestamp components as actual negative numbers.
|
||||
This change increases compatibility with VSFilter.
|
||||
* Font matching changes for VSFilter compatibility
|
||||
* Look up fonts that contain PostScript outlines by their PostScript
|
||||
name instead of their full names. Family names continue to be used
|
||||
for all fonts.
|
||||
* Keep spaces in font names
|
||||
* Drop support for Fontconfig < 2.10.92 to ensure correct font matching
|
||||
* Bug fixes
|
||||
* Fix building the assembler code for the x32 ABI (GH #200)
|
||||
* Fix static linking against libass through pkg-config when libass
|
||||
uses libiconv
|
||||
* Fix some small memory leaks, potential crashes and bad data uses
|
||||
|
||||
libass (0.13.0)
|
||||
* Add native font selection backends for OSX (CoreText) and Windows
|
||||
(DirectWrite). You can now run libass without fontconfig on these
|
||||
platforms. This fixes problems with fontconfig behaving badly on
|
||||
these platforms (it could take minutes to scan all system fonts).
|
||||
Even on Linux, this speeds up loading of embedded fonts (such as
|
||||
provided by ass_add_font()).
|
||||
The DirectWrite backend only works on Windows Vista and later. On
|
||||
XP, fontconfig is still needed. libass can be compiled with both
|
||||
DirectWrite and fontconfig, and then it will fallback to fontconfig
|
||||
automatically if DirectWrite is not available at runtime.
|
||||
* Add ass_get_available_font_providers() API function.
|
||||
* Change the 4th parameter of ass_set_fonts(). This now selects the
|
||||
font provider. This is somewhat backwards compatible with the old
|
||||
behavior, but if you ever passed values other than 0 or 1, your
|
||||
application might break with this libass release.
|
||||
* The ass_fonts_update() function now does nothing. It's kept for
|
||||
backward compatibility only.
|
||||
* Much faster gaussian blur. This can bring a large speedup with big
|
||||
blurred signs and such.
|
||||
* Drop ENCA support
|
||||
* Bug fixes
|
||||
* Fix compilation of the freetype rasterizer (disabled by default)
|
||||
* Fix rendering with some cases of consecutive line breaks (\N\N).
|
||||
* Fix some memory allocation failure checks
|
||||
* Avoid system locale dependent behavior by reinventing some standard
|
||||
C functions
|
||||
* Fix rendering errors with strikes (GH #193)
|
||||
* MSVC compilation fixes
|
||||
|
||||
libass (0.12.3)
|
||||
* VSFilter blur compatibility changes
|
||||
* VSFilter color/alpha parsing compatibility changes
|
||||
* Bugfixes
|
||||
* Fix some potential memory leaks and crashes
|
||||
* Fix large timestamps (larger than about 600 hours)
|
||||
* Fix a potential crash with the new rasterizer and complex fonts
|
||||
* Do not apply user-configured line position to non-dialog events
|
||||
* Strictly clip non-dialog events to the video rectangle
|
||||
|
||||
libass (0.12.2)
|
||||
* Add extern "C" guards to the public headers for C++ compatibility
|
||||
* Improvements to style override API and implementation
|
||||
* Bugfixes
|
||||
* Fix some rasterizer bugs of unknown severity
|
||||
* Fix a broken memset() of unknown severity
|
||||
* Make timestamp parsing more lenient, which makes libass accept invalid
|
||||
files accepted by most other ASS parsers
|
||||
* Increase compatibility with broken ASS drawings accepted by VSFilter
|
||||
|
||||
libass (0.12.1)
|
||||
* Make ASS drawings with an extremely high number of control points work
|
||||
This change increases compatibility with VSFilter.
|
||||
* Bugfixes
|
||||
* Fix a crash when using newer harfbuzz versions (GH #155)
|
||||
* Load embedded memory fonts correctly
|
||||
* Large shadow offsets rendered incorrectly (GH #142)
|
||||
* Fix incorrect closing of last drawing contour
|
||||
* Fix issues with undefined behavior in shifts
|
||||
* Lots of of malloc() error checking
|
||||
|
||||
libass (0.12.0)
|
||||
* Implement fast quad-tree rasterizer in C and SSE2/AVX2 assembly
|
||||
* Make \be animatable
|
||||
* Add BorderStyle=4 (GH #105)
|
||||
* Add selective style override functionality
|
||||
* ass_set_selective_style_override()
|
||||
* ass_set_selective_style_override_enabled()
|
||||
* Support for assembly on DragonFly BSD
|
||||
* Bugfixes
|
||||
* Various parser fixes
|
||||
* Fix premature parser exit on }{ in drawing mode (GH #75)
|
||||
* Reset clipping mode on every rectangle clip
|
||||
* Improved error handling for FriBidi and FreeType (GH #131)
|
||||
* Fix bitmap combining cache
|
||||
|
||||
libass (0.11.2)
|
||||
* Improve yasm version check
|
||||
* Fix \fscx0 crashes
|
||||
* Actually export ass_library_version
|
||||
* Fix change detection with vector clips
|
||||
* SIMD assembly bugfixes
|
||||
* Parse drawing numbers as floats (GH #63)
|
||||
* Fix shaper sign bug (GH #68)
|
||||
* Initialize \pbo correctly (GH #74)
|
||||
|
||||
libass (0.11.1)
|
||||
* Fix distfile generation
|
||||
* No functional changes
|
||||
|
||||
libass (0.11.0)
|
||||
* Add bitmap run combining/compositing
|
||||
This changes the text rendering model and increases compatibility with
|
||||
VSFilter. It may make rendering faster or slower in certain cases.
|
||||
* Add AVX/SSE2 implementations for \be and compositing
|
||||
This adds yasm as (optional) build dependency.
|
||||
* Add ass_library_version() API funcion (GC #113)
|
||||
* Add 'profile' program for benchmarks
|
||||
* Improve gaussian blur
|
||||
* Fix compilation with MSVC 2013
|
||||
* Speed up HarfBuzz shaper
|
||||
* Speed up cache
|
||||
* Notable compatibility bugfixes
|
||||
* Reset origin on \fay changes (GC #88)
|
||||
* Tons of parser fixes
|
||||
* Fix ascender/descender metrics (GH #8)
|
||||
* Fix \pbo sign and scaling
|
||||
* Don't reset wrap style on \r (GC #116, GH #45)
|
||||
* Notable bugfixes:
|
||||
* Correctly handle @font advance (GC #94)
|
||||
* Disable ligatures for non-zero \fsp
|
||||
* Make sure to release vector clip (GH #22)
|
||||
|
||||
libass (0.10.2)
|
||||
* API additions and some ABI changes, bumped SONAME
|
||||
* Expose header field for VSFilter color mangling (GC #87)
|
||||
* Add functions for explicit scaling hints (GC #6)
|
||||
* Add 'type' field to ASS_Image (GC #31)
|
||||
* Workaround Freetype's font size grid-fitting where appropriate
|
||||
* Apply blur to both glyph and border when using opaque box
|
||||
* Parser bugfixes
|
||||
* Parse angles in style as number
|
||||
* Fix fallback event formats
|
||||
* Make closing ')' optional for some tags
|
||||
* Fix crazy VSFilter behaviour for \move (GC #90)
|
||||
* Make \r fall back to line style (GC #104)
|
||||
* Parse style name like VSFilter
|
||||
* Ignore junk in nested \t tags
|
||||
* Make \clip tag arguments mandatory
|
||||
* Properly handle script and language in the HarfBuzz shaper
|
||||
* Allow ASS_Track and ASS_Renderer to have different ASS_Library
|
||||
* Fix stroking in some rare cases
|
||||
* Correctly handle @font advance (GC #94)
|
||||
* Fix ascent/descent for some fonts (GC #106)
|
||||
* Fix ass_step_sub to not require sorted events
|
||||
* Fix blur scaling
|
||||
* Don't mutate input strings (GC #88)
|
||||
* Remove/change some error messages
|
||||
* Fix various small memory leaks
|
||||
|
||||
libass (0.10.1)
|
||||
* Fix letter spacing
|
||||
* Add \rSTYLENAME syntax support (GC #43)
|
||||
* Fix border generation and border style reset (GC #56)
|
||||
* Fix various issues with bug-for-bug compatibility of
|
||||
transformations (\fax, \fay, etc.) to VSFilter (GC #46, GC #42)
|
||||
* Fix drawing parsing (GC #47)
|
||||
* Various fixes to shaper (GC #54, GC #55, GC#59)
|
||||
* Fix change detection
|
||||
* Add ass_set_line_position API to set a vertical subtitle offset
|
||||
* Fix scaling of drawing baseline offset (\pbo) values
|
||||
* Fix skipping of zero-width characters for FriBiDi shaper
|
||||
* Use LTR text base direction by default, similar to VSFilter
|
||||
|
||||
libass (0.10.0)
|
||||
* Bidirectional layout and Arabic shaping via FriBidi (GC #13)
|
||||
* OpenType shaping via HarfBuzz-ng (GC #13)
|
||||
* Add API for shaper configuration
|
||||
* Add support for `Language' Script Info property, this can be used for
|
||||
hinting the text language
|
||||
* Vertical layout improvements
|
||||
* Use `vert' and `vkna' OpenType features for vertical glyph variants
|
||||
* Position rotated glyphs onto baseline
|
||||
* Parse font encoding property for base text direction hinting
|
||||
* Refactor cache system
|
||||
* Use generic outlines in place of FreeType glyphs
|
||||
* Direct outline bitmap rendering
|
||||
* Fix whitespace trimming (GC #35)
|
||||
* Do not render border if there's no shadow or glyph (GC #29)
|
||||
* Adjust spacing after a italic to non-italic style change (GC #37)
|
||||
* Fix fade timing
|
||||
* Fix x positioning with borders (GC #27)
|
||||
* Build system tweaks
|
||||
|
||||
libass (0.9.12)
|
||||
* Switch to permissive (ISC) license
|
||||
* Support \fs+ and \fs- syntax for modifying font size
|
||||
* Fix word-wrapping
|
||||
* Improved charmap fallback matching
|
||||
* Handle a few more VSFilter quirks correctly
|
||||
* Add a sensible default style
|
||||
* Fix compilation against libpng 1.5
|
||||
|
||||
libass (0.9.11)
|
||||
* Fix serious memory leaks
|
||||
* Reduce frame/drawing initialization overhead
|
||||
|
||||
libass (0.9.10)
|
||||
* Basic (incorrect, but working) support for @font vertical text layout
|
||||
* Fix multiple faces per font attachment
|
||||
* charmap selection fixes
|
||||
* Add ass_flush_events API function
|
||||
* Improve fullname font matching
|
||||
* Better PAR correction if text transforms are used
|
||||
* Calculate drawing bounding box like VSFilter
|
||||
* Performance improvements
|
||||
* Cache vector clip masks
|
||||
* Avoid unnecessary glyph copies
|
||||
* Various rendering fixes
|
||||
|
||||
libass (0.9.9)
|
||||
* Parse numbers in a locale-independent way
|
||||
* Remove support for freetype < 2.2.1, fontconfig < 2.4.1; this especially
|
||||
means libass will not extract fonts into the file system anymore
|
||||
* Disable script file size limit
|
||||
* Match fonts against the full name ("name for humans")
|
||||
* Reset clip mode after \iclip
|
||||
* Improve VSFilter compatibility
|
||||
* Update API documentation
|
||||
* A couple of smaller fixes and cleanups
|
||||
|
||||
libass (0.9.8)
|
||||
* Support \q override tag
|
||||
* Support wrap style 1 (i.e. wrap, but do not equalize line lengths)
|
||||
* Support border style 3 (opaque box)
|
||||
* Use the event bounding box (instead of vertical position and height) for
|
||||
collision detection
|
||||
* Embold glyphs if no bold variant is available, but was requested
|
||||
* Modify \fax to be similar to VSFilter
|
||||
* Trim spaces after line wrapping
|
||||
* Fix border/shadow overlap combining in some cases
|
||||
* Disable kerning by default. Use "Kerning=yes" style override or
|
||||
"Kerning: yes" in [Script Info] to enable it
|
||||
* Slight bitmap handling optimizations
|
||||
* Various bugfixes
|
||||
|
||||
libass (0.9.7)
|
||||
* Build system fixes
|
||||
* Fixed cache lookup and overload problems
|
||||
* All globals have been eliminated, libass is reentrant
|
||||
* Dynamically allocate glyph and line buffers
|
||||
* Fix up stroking of big borders
|
||||
* Support empty lines (\N\N)
|
||||
* Support for the following override tags:
|
||||
\fax, \fay, \xshad, \yshad, \ybord, \xbord, \iclip, \u, \s, \p, \pbo
|
||||
* Full subpixel accuracy for positioning
|
||||
* PAR and rotation correction for EOSD rendering
|
||||
* Drawing mode (including vector \clip and \iclip)
|
||||
* Fixed a few memory leaks
|
||||
* Removed MPlayer compatibility code
|
||||
* Introduced message handling callback
|
||||
* Various fixes to match VSFilter quirks and Windows font metrics
|
||||
* Lots of bugfixes
|
||||
|
||||
LibASS (0.9.6)
|
||||
* Various fixes and updates to match VSFilter renderer.
|
||||
* Support \blur tag and ScaledBordersAndShadow property.
|
||||
* Fractional arguments and subpixel accuracy.
|
||||
* Keep positions when pan-and-scan is used.
|
||||
* Lots of bugfixes and other changes.
|
||||
|
||||
LibASS (0.9.5)
|
||||
* Support '=' and '.' in style name in arguments to ass_set_style_overrides().
|
||||
* Allow overriding [Script Info] parameters with ass_set_style_overrides().
|
||||
* Add workarounds for some buggy fonts.
|
||||
* Remove buggy workarounds for some other fonts.
|
||||
* Fixed ass_set_line_spacing() (was broken before).
|
||||
* Negative margin sizes are now used for image cropping.
|
||||
* Better handling of behind-the-camera objects.
|
||||
* Case insensitive parsing of SSA/ASS section headers.
|
||||
* Improved font matching.
|
||||
* When 2 styles have the same name, the later one is used.
|
||||
* Fixed several other bugs.
|
|
@ -0,0 +1,17 @@
|
|||
ACLOCAL_AMFLAGS = -I m4
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
EXTRA_DIST = libass.pc.in Changelog
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libass.pc
|
||||
|
||||
if HAVE_LIBPNG
|
||||
test = test
|
||||
endif
|
||||
|
||||
if ENABLE_PROFILE
|
||||
profile = profile
|
||||
endif
|
||||
|
||||
SUBDIRS = libass $(test) $(profile)
|
||||
|
|
@ -0,0 +1,895 @@
|
|||
# Makefile.in generated by automake 1.15 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2014 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
*) echo "am__make_running_with_option: internal error: invalid" \
|
||||
"target option '$${target_option-}' specified" >&2; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
has_opt=no; \
|
||||
sane_makeflags=$$MAKEFLAGS; \
|
||||
if $(am__is_gnu_make); then \
|
||||
sane_makeflags=$$MFLAGS; \
|
||||
else \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
bs=\\; \
|
||||
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
|
||||
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
|
||||
esac; \
|
||||
fi; \
|
||||
skip_next=no; \
|
||||
strip_trailopt () \
|
||||
{ \
|
||||
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
|
||||
}; \
|
||||
for flg in $$sane_makeflags; do \
|
||||
test $$skip_next = yes && { skip_next=no; continue; }; \
|
||||
case $$flg in \
|
||||
*=*|--*) continue;; \
|
||||
-*I) strip_trailopt 'I'; skip_next=yes;; \
|
||||
-*I?*) strip_trailopt 'I';; \
|
||||
-*O) strip_trailopt 'O'; skip_next=yes;; \
|
||||
-*O?*) strip_trailopt 'O';; \
|
||||
-*l) strip_trailopt 'l'; skip_next=yes;; \
|
||||
-*l?*) strip_trailopt 'l';; \
|
||||
-[dEDm]) skip_next=yes;; \
|
||||
-[JT]) skip_next=yes;; \
|
||||
esac; \
|
||||
case $$flg in \
|
||||
*$$target_option*) has_opt=yes; break;; \
|
||||
esac; \
|
||||
done; \
|
||||
test $$has_opt = yes
|
||||
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
|
||||
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
subdir = .
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
|
||||
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
|
||||
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
|
||||
$(am__configure_deps) $(am__DIST_COMMON)
|
||||
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
|
||||
configure.lineno config.status.lineno
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = config.h
|
||||
CONFIG_CLEAN_FILES = libass.pc
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
|
||||
am__v_P_0 = false
|
||||
am__v_P_1 = :
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_GEN_1 =
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
am__v_at_1 =
|
||||
SOURCES =
|
||||
DIST_SOURCES =
|
||||
RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
|
||||
ctags-recursive dvi-recursive html-recursive info-recursive \
|
||||
install-data-recursive install-dvi-recursive \
|
||||
install-exec-recursive install-html-recursive \
|
||||
install-info-recursive install-pdf-recursive \
|
||||
install-ps-recursive install-recursive installcheck-recursive \
|
||||
installdirs-recursive pdf-recursive ps-recursive \
|
||||
tags-recursive uninstall-recursive
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||
am__install_max = 40
|
||||
am__nobase_strip_setup = \
|
||||
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||
am__nobase_strip = \
|
||||
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||
am__nobase_list = $(am__nobase_strip_setup); \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||
if (++n[$$2] == $(am__install_max)) \
|
||||
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||
END { for (dir in files) print dir, files[dir] }'
|
||||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__uninstall_files_from_dir = { \
|
||||
test -z "$$files" \
|
||||
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
am__installdirs = "$(DESTDIR)$(pkgconfigdir)"
|
||||
DATA = $(pkgconfig_DATA)
|
||||
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
|
||||
distclean-recursive maintainer-clean-recursive
|
||||
am__recursive_targets = \
|
||||
$(RECURSIVE_TARGETS) \
|
||||
$(RECURSIVE_CLEAN_TARGETS) \
|
||||
$(am__extra_recursive_targets)
|
||||
AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
|
||||
cscope distdir dist dist-all distcheck
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
|
||||
$(LISP)config.h.in
|
||||
# Read a list of newline-separated strings from the standard input,
|
||||
# and print each of them once, without duplicates. Input order is
|
||||
# *not* preserved.
|
||||
am__uniquify_input = $(AWK) '\
|
||||
BEGIN { nonempty = 0; } \
|
||||
{ items[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in items) print i; }; } \
|
||||
'
|
||||
# Make sure the list of sources is unique. This is necessary because,
|
||||
# e.g., the same source file might be shared among _SOURCES variables
|
||||
# for different programs/libraries.
|
||||
am__define_uniq_tagged_files = \
|
||||
list='$(am__tagged_files)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | $(am__uniquify_input)`
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
CSCOPE = cscope
|
||||
DIST_SUBDIRS = libass test profile
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
|
||||
$(srcdir)/libass.pc.in COPYING compile config.guess config.sub \
|
||||
install-sh ltmain.sh missing
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
distdir = $(PACKAGE)-$(VERSION)
|
||||
top_distdir = $(distdir)
|
||||
am__remove_distdir = \
|
||||
if test -d "$(distdir)"; then \
|
||||
find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
|
||||
&& rm -rf "$(distdir)" \
|
||||
|| { sleep 5 && rm -rf "$(distdir)"; }; \
|
||||
else :; fi
|
||||
am__post_remove_distdir = $(am__remove_distdir)
|
||||
am__relativize = \
|
||||
dir0=`pwd`; \
|
||||
sed_first='s,^\([^/]*\)/.*$$,\1,'; \
|
||||
sed_rest='s,^[^/]*/*,,'; \
|
||||
sed_last='s,^.*/\([^/]*\)$$,\1,'; \
|
||||
sed_butlast='s,/*[^/]*$$,,'; \
|
||||
while test -n "$$dir1"; do \
|
||||
first=`echo "$$dir1" | sed -e "$$sed_first"`; \
|
||||
if test "$$first" != "."; then \
|
||||
if test "$$first" = ".."; then \
|
||||
dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
|
||||
dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
|
||||
else \
|
||||
first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
|
||||
if test "$$first2" = "$$first"; then \
|
||||
dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
|
||||
else \
|
||||
dir2="../$$dir2"; \
|
||||
fi; \
|
||||
dir0="$$dir0"/"$$first"; \
|
||||
fi; \
|
||||
fi; \
|
||||
dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
|
||||
done; \
|
||||
reldir="$$dir2"
|
||||
DIST_ARCHIVES = $(distdir).tar.gz
|
||||
GZIP_ENV = --best
|
||||
DIST_TARGETS = dist-gzip
|
||||
distuninstallcheck_listfiles = find . -type f -print
|
||||
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
|
||||
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
|
||||
distcleancheck_listfiles = find . -type f -print
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
AS = @AS@
|
||||
ASFLAGS = @ASFLAGS@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCAS = @CCAS@
|
||||
CCASDEPMODE = @CCASDEPMODE@
|
||||
CCASFLAGS = @CCASFLAGS@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
|
||||
FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
|
||||
FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
|
||||
FREETYPE_LIBS = @FREETYPE_LIBS@
|
||||
FRIBIDI_CFLAGS = @FRIBIDI_CFLAGS@
|
||||
FRIBIDI_LIBS = @FRIBIDI_LIBS@
|
||||
GREP = @GREP@
|
||||
HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@
|
||||
HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
|
||||
LIBPNG_LIBS = @LIBPNG_LIBS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PKG_CONFIG = @PKG_CONFIG@
|
||||
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
|
||||
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
|
||||
PKG_LIBS_DEFAULT = @PKG_LIBS_DEFAULT@
|
||||
PKG_LIBS_PRIVATE = @PKG_LIBS_PRIVATE@
|
||||
PKG_REQUIRES_DEFAULT = @PKG_REQUIRES_DEFAULT@
|
||||
PKG_REQUIRES_PRIVATE = @PKG_REQUIRES_PRIVATE@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
nasm_check = @nasm_check@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
EXTRA_DIST = libass.pc.in Changelog
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libass.pc
|
||||
@HAVE_LIBPNG_TRUE@test = test
|
||||
@ENABLE_PROFILE_TRUE@profile = profile
|
||||
SUBDIRS = libass $(test) $(profile)
|
||||
all: config.h
|
||||
$(MAKE) $(AM_MAKEFLAGS) all-recursive
|
||||
|
||||
.SUFFIXES:
|
||||
am--refresh: Makefile
|
||||
@:
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
|
||||
$(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
|
||||
&& exit 0; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
echo ' $(SHELL) ./config.status'; \
|
||||
$(SHELL) ./config.status;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
$(am__cd) $(srcdir) && $(AUTOCONF)
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
config.h: stamp-h1
|
||||
@test -f $@ || rm -f stamp-h1
|
||||
@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
|
||||
|
||||
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
|
||||
@rm -f stamp-h1
|
||||
cd $(top_builddir) && $(SHELL) ./config.status config.h
|
||||
$(srcdir)/config.h.in: $(am__configure_deps)
|
||||
($(am__cd) $(top_srcdir) && $(AUTOHEADER))
|
||||
rm -f stamp-h1
|
||||
touch $@
|
||||
|
||||
distclean-hdr:
|
||||
-rm -f config.h stamp-h1
|
||||
libass.pc: $(top_builddir)/config.status $(srcdir)/libass.pc.in
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $@
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
distclean-libtool:
|
||||
-rm -f libtool config.lt
|
||||
install-pkgconfigDATA: $(pkgconfig_DATA)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; \
|
||||
done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \
|
||||
done
|
||||
|
||||
uninstall-pkgconfigDATA:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
|
||||
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
|
||||
dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir)
|
||||
|
||||
# This directory's subdirectories are mostly independent; you can cd
|
||||
# into them and run 'make' without going through this Makefile.
|
||||
# To change the values of 'make' variables: instead of editing Makefiles,
|
||||
# (1) if the variable is set in 'config.status', edit 'config.status'
|
||||
# (which will cause the Makefiles to be regenerated when you run 'make');
|
||||
# (2) otherwise, pass the desired values on the 'make' command line.
|
||||
$(am__recursive_targets):
|
||||
@fail=; \
|
||||
if $(am__make_keepgoing); then \
|
||||
failcom='fail=yes'; \
|
||||
else \
|
||||
failcom='exit 1'; \
|
||||
fi; \
|
||||
dot_seen=no; \
|
||||
target=`echo $@ | sed s/-recursive//`; \
|
||||
case "$@" in \
|
||||
distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
|
||||
*) list='$(SUBDIRS)' ;; \
|
||||
esac; \
|
||||
for subdir in $$list; do \
|
||||
echo "Making $$target in $$subdir"; \
|
||||
if test "$$subdir" = "."; then \
|
||||
dot_seen=yes; \
|
||||
local_target="$$target-am"; \
|
||||
else \
|
||||
local_target="$$target"; \
|
||||
fi; \
|
||||
($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|
||||
|| eval $$failcom; \
|
||||
done; \
|
||||
if test "$$dot_seen" = "no"; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
|
||||
fi; test -z "$$fail"
|
||||
|
||||
ID: $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); mkid -fID $$unique
|
||||
tags: tags-recursive
|
||||
TAGS: tags
|
||||
|
||||
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
|
||||
include_option=--etags-include; \
|
||||
empty_fix=.; \
|
||||
else \
|
||||
include_option=--include; \
|
||||
empty_fix=; \
|
||||
fi; \
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
test ! -f $$subdir/TAGS || \
|
||||
set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
|
||||
fi; \
|
||||
done; \
|
||||
$(am__define_uniq_tagged_files); \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: ctags-recursive
|
||||
|
||||
CTAGS: ctags
|
||||
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
cscope: cscope.files
|
||||
test ! -s cscope.files \
|
||||
|| $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
|
||||
clean-cscope:
|
||||
-rm -f cscope.files
|
||||
cscope.files: clean-cscope cscopelist
|
||||
cscopelist: cscopelist-recursive
|
||||
|
||||
cscopelist-am: $(am__tagged_files)
|
||||
list='$(am__tagged_files)'; \
|
||||
case "$(srcdir)" in \
|
||||
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
|
||||
*) sdir=$(subdir)/$(srcdir) ;; \
|
||||
esac; \
|
||||
for i in $$list; do \
|
||||
if test -f "$$i"; then \
|
||||
echo "$(subdir)/$$i"; \
|
||||
else \
|
||||
echo "$$sdir/$$i"; \
|
||||
fi; \
|
||||
done >> $(top_builddir)/cscope.files
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
$(am__remove_distdir)
|
||||
test -d "$(distdir)" || mkdir "$(distdir)"
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
$(am__make_dryrun) \
|
||||
|| test -d "$(distdir)/$$subdir" \
|
||||
|| $(MKDIR_P) "$(distdir)/$$subdir" \
|
||||
|| exit 1; \
|
||||
dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
|
||||
$(am__relativize); \
|
||||
new_distdir=$$reldir; \
|
||||
dir1=$$subdir; dir2="$(top_distdir)"; \
|
||||
$(am__relativize); \
|
||||
new_top_distdir=$$reldir; \
|
||||
echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
|
||||
echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
|
||||
($(am__cd) $$subdir && \
|
||||
$(MAKE) $(AM_MAKEFLAGS) \
|
||||
top_distdir="$$new_top_distdir" \
|
||||
distdir="$$new_distdir" \
|
||||
am__remove_distdir=: \
|
||||
am__skip_length_check=: \
|
||||
am__skip_mode_fix=: \
|
||||
distdir) \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
-test -n "$(am__skip_mode_fix)" \
|
||||
|| find "$(distdir)" -type d ! -perm -755 \
|
||||
-exec chmod u+rwx,go+rx {} \; -o \
|
||||
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
|
||||
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
|
||||
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|
||||
|| chmod -R a+r "$(distdir)"
|
||||
dist-gzip: distdir
|
||||
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-bzip2: distdir
|
||||
tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-lzip: distdir
|
||||
tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-xz: distdir
|
||||
tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-tarZ: distdir
|
||||
@echo WARNING: "Support for distribution archives compressed with" \
|
||||
"legacy program 'compress' is deprecated." >&2
|
||||
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
|
||||
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-shar: distdir
|
||||
@echo WARNING: "Support for shar distribution archives is" \
|
||||
"deprecated." >&2
|
||||
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
|
||||
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-zip: distdir
|
||||
-rm -f $(distdir).zip
|
||||
zip -rq $(distdir).zip $(distdir)
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist dist-all:
|
||||
$(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
# This target untars the dist file and tries a VPATH configuration. Then
|
||||
# it guarantees that the distribution is self-contained by making another
|
||||
# tarfile.
|
||||
distcheck: dist
|
||||
case '$(DIST_ARCHIVES)' in \
|
||||
*.tar.gz*) \
|
||||
GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
|
||||
*.tar.bz2*) \
|
||||
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
|
||||
*.tar.lz*) \
|
||||
lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
|
||||
*.tar.xz*) \
|
||||
xz -dc $(distdir).tar.xz | $(am__untar) ;;\
|
||||
*.tar.Z*) \
|
||||
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
|
||||
*.shar.gz*) \
|
||||
GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
|
||||
*.zip*) \
|
||||
unzip $(distdir).zip ;;\
|
||||
esac
|
||||
chmod -R a-w $(distdir)
|
||||
chmod u+w $(distdir)
|
||||
mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
|
||||
chmod a-w $(distdir)
|
||||
test -d $(distdir)/_build || exit 0; \
|
||||
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
|
||||
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
|
||||
&& am__cwd=`pwd` \
|
||||
&& $(am__cd) $(distdir)/_build/sub \
|
||||
&& ../../configure \
|
||||
$(AM_DISTCHECK_CONFIGURE_FLAGS) \
|
||||
$(DISTCHECK_CONFIGURE_FLAGS) \
|
||||
--srcdir=../.. --prefix="$$dc_install_base" \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) check \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) install \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) uninstall \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
|
||||
distuninstallcheck \
|
||||
&& chmod -R a-w "$$dc_install_base" \
|
||||
&& ({ \
|
||||
(cd ../.. && umask 077 && mkdir "$$dc_destdir") \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
|
||||
distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
|
||||
} || { rm -rf "$$dc_destdir"; exit 1; }) \
|
||||
&& rm -rf "$$dc_destdir" \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) dist \
|
||||
&& rm -rf $(DIST_ARCHIVES) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
|
||||
&& cd "$$am__cwd" \
|
||||
|| exit 1
|
||||
$(am__post_remove_distdir)
|
||||
@(echo "$(distdir) archives ready for distribution: "; \
|
||||
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
|
||||
sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
|
||||
distuninstallcheck:
|
||||
@test -n '$(distuninstallcheck_dir)' || { \
|
||||
echo 'ERROR: trying to run $@ with an empty' \
|
||||
'$$(distuninstallcheck_dir)' >&2; \
|
||||
exit 1; \
|
||||
}; \
|
||||
$(am__cd) '$(distuninstallcheck_dir)' || { \
|
||||
echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
|
||||
exit 1; \
|
||||
}; \
|
||||
test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
|
||||
|| { echo "ERROR: files left after uninstall:" ; \
|
||||
if test -n "$(DESTDIR)"; then \
|
||||
echo " (check DESTDIR support)"; \
|
||||
fi ; \
|
||||
$(distuninstallcheck_listfiles) ; \
|
||||
exit 1; } >&2
|
||||
distcleancheck: distclean
|
||||
@if test '$(srcdir)' = . ; then \
|
||||
echo "ERROR: distcleancheck can only run from a VPATH build" ; \
|
||||
exit 1 ; \
|
||||
fi
|
||||
@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
|
||||
|| { echo "ERROR: files left in build directory after distclean:" ; \
|
||||
$(distcleancheck_listfiles) ; \
|
||||
exit 1; } >&2
|
||||
check-am: all-am
|
||||
check: check-recursive
|
||||
all-am: Makefile $(DATA) config.h
|
||||
installdirs: installdirs-recursive
|
||||
installdirs-am:
|
||||
for dir in "$(DESTDIR)$(pkgconfigdir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-recursive
|
||||
install-exec: install-exec-recursive
|
||||
install-data: install-data-recursive
|
||||
uninstall: uninstall-recursive
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-recursive
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-recursive
|
||||
|
||||
clean-am: clean-generic clean-libtool mostlyclean-am
|
||||
|
||||
distclean: distclean-recursive
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-generic distclean-hdr \
|
||||
distclean-libtool distclean-tags
|
||||
|
||||
dvi: dvi-recursive
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-recursive
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-recursive
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am: install-pkgconfigDATA
|
||||
|
||||
install-dvi: install-dvi-recursive
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-recursive
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-recursive
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-recursive
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-recursive
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-recursive
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -rf $(top_srcdir)/autom4te.cache
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-recursive
|
||||
|
||||
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
|
||||
|
||||
pdf: pdf-recursive
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-recursive
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-pkgconfigDATA
|
||||
|
||||
.MAKE: $(am__recursive_targets) all install-am install-strip
|
||||
|
||||
.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
|
||||
am--refresh check check-am clean clean-cscope clean-generic \
|
||||
clean-libtool cscope cscopelist-am ctags ctags-am dist \
|
||||
dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \
|
||||
dist-xz dist-zip distcheck distclean distclean-generic \
|
||||
distclean-hdr distclean-libtool distclean-tags distcleancheck \
|
||||
distdir distuninstallcheck dvi dvi-am html html-am info \
|
||||
info-am install install-am install-data install-data-am \
|
||||
install-dvi install-dvi-am install-exec install-exec-am \
|
||||
install-html install-html-am install-info install-info-am \
|
||||
install-man install-pdf install-pdf-am install-pkgconfigDATA \
|
||||
install-ps install-ps-am install-strip installcheck \
|
||||
installcheck-am installdirs installdirs-am maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-generic \
|
||||
mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
|
||||
uninstall-am uninstall-pkgconfigDATA
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,347 @@
|
|||
#! /bin/sh
|
||||
# Wrapper for compilers which do not understand '-c -o'.
|
||||
|
||||
scriptversion=2012-10-14.11; # UTC
|
||||
|
||||
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
nl='
|
||||
'
|
||||
|
||||
# We need space, tab and new line, in precisely that order. Quoting is
|
||||
# there to prevent tools from complaining about whitespace usage.
|
||||
IFS=" "" $nl"
|
||||
|
||||
file_conv=
|
||||
|
||||
# func_file_conv build_file lazy
|
||||
# Convert a $build file to $host form and store it in $file
|
||||
# Currently only supports Windows hosts. If the determined conversion
|
||||
# type is listed in (the comma separated) LAZY, no conversion will
|
||||
# take place.
|
||||
func_file_conv ()
|
||||
{
|
||||
file=$1
|
||||
case $file in
|
||||
/ | /[!/]*) # absolute file, and not a UNC file
|
||||
if test -z "$file_conv"; then
|
||||
# lazily determine how to convert abs files
|
||||
case `uname -s` in
|
||||
MINGW*)
|
||||
file_conv=mingw
|
||||
;;
|
||||
CYGWIN*)
|
||||
file_conv=cygwin
|
||||
;;
|
||||
*)
|
||||
file_conv=wine
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
case $file_conv/,$2, in
|
||||
*,$file_conv,*)
|
||||
;;
|
||||
mingw/*)
|
||||
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
|
||||
;;
|
||||
cygwin/*)
|
||||
file=`cygpath -m "$file" || echo "$file"`
|
||||
;;
|
||||
wine/*)
|
||||
file=`winepath -w "$file" || echo "$file"`
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# func_cl_dashL linkdir
|
||||
# Make cl look for libraries in LINKDIR
|
||||
func_cl_dashL ()
|
||||
{
|
||||
func_file_conv "$1"
|
||||
if test -z "$lib_path"; then
|
||||
lib_path=$file
|
||||
else
|
||||
lib_path="$lib_path;$file"
|
||||
fi
|
||||
linker_opts="$linker_opts -LIBPATH:$file"
|
||||
}
|
||||
|
||||
# func_cl_dashl library
|
||||
# Do a library search-path lookup for cl
|
||||
func_cl_dashl ()
|
||||
{
|
||||
lib=$1
|
||||
found=no
|
||||
save_IFS=$IFS
|
||||
IFS=';'
|
||||
for dir in $lib_path $LIB
|
||||
do
|
||||
IFS=$save_IFS
|
||||
if $shared && test -f "$dir/$lib.dll.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.dll.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/$lib.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/lib$lib.a"; then
|
||||
found=yes
|
||||
lib=$dir/lib$lib.a
|
||||
break
|
||||
fi
|
||||
done
|
||||
IFS=$save_IFS
|
||||
|
||||
if test "$found" != yes; then
|
||||
lib=$lib.lib
|
||||
fi
|
||||
}
|
||||
|
||||
# func_cl_wrapper cl arg...
|
||||
# Adjust compile command to suit cl
|
||||
func_cl_wrapper ()
|
||||
{
|
||||
# Assume a capable shell
|
||||
lib_path=
|
||||
shared=:
|
||||
linker_opts=
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.[oO][bB][jJ])
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fo"$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fe"$file"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
-I)
|
||||
eat=1
|
||||
func_file_conv "$2" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-I*)
|
||||
func_file_conv "${1#-I}" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-l)
|
||||
eat=1
|
||||
func_cl_dashl "$2"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-l*)
|
||||
func_cl_dashl "${1#-l}"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-L)
|
||||
eat=1
|
||||
func_cl_dashL "$2"
|
||||
;;
|
||||
-L*)
|
||||
func_cl_dashL "${1#-L}"
|
||||
;;
|
||||
-static)
|
||||
shared=false
|
||||
;;
|
||||
-Wl,*)
|
||||
arg=${1#-Wl,}
|
||||
save_ifs="$IFS"; IFS=','
|
||||
for flag in $arg; do
|
||||
IFS="$save_ifs"
|
||||
linker_opts="$linker_opts $flag"
|
||||
done
|
||||
IFS="$save_ifs"
|
||||
;;
|
||||
-Xlinker)
|
||||
eat=1
|
||||
linker_opts="$linker_opts $2"
|
||||
;;
|
||||
-*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
|
||||
func_file_conv "$1"
|
||||
set x "$@" -Tp"$file"
|
||||
shift
|
||||
;;
|
||||
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
|
||||
func_file_conv "$1" mingw
|
||||
set x "$@" "$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
if test -n "$linker_opts"; then
|
||||
linker_opts="-link$linker_opts"
|
||||
fi
|
||||
exec "$@" $linker_opts
|
||||
exit 1
|
||||
}
|
||||
|
||||
eat=
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: compile [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Wrapper for compilers which do not understand '-c -o'.
|
||||
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
|
||||
arguments, and rename the output as expected.
|
||||
|
||||
If you are trying to build a whole package this is not the
|
||||
right script to run: please start by reading the file 'INSTALL'.
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "compile $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
|
||||
func_cl_wrapper "$@" # Doesn't return...
|
||||
;;
|
||||
esac
|
||||
|
||||
ofile=
|
||||
cfile=
|
||||
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
# So we strip '-o arg' only if arg is an object.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.obj)
|
||||
ofile=$2
|
||||
;;
|
||||
*)
|
||||
set x "$@" -o "$2"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*.c)
|
||||
cfile=$1
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
if test -z "$ofile" || test -z "$cfile"; then
|
||||
# If no '-o' option was seen then we might have been invoked from a
|
||||
# pattern rule where we don't need one. That is ok -- this is a
|
||||
# normal compilation that the losing compiler can handle. If no
|
||||
# '.c' file was seen then we are probably linking. That is also
|
||||
# ok.
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
# Name of file we expect compiler to create.
|
||||
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
|
||||
|
||||
# Create the lock directory.
|
||||
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
|
||||
# that we are using for the .o file. Also, base the name on the expected
|
||||
# object file name, since that is what matters with a parallel build.
|
||||
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
|
||||
while true; do
|
||||
if mkdir "$lockdir" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
# FIXME: race condition here if user kills between mkdir and trap.
|
||||
trap "rmdir '$lockdir'; exit 1" 1 2 15
|
||||
|
||||
# Run the compile.
|
||||
"$@"
|
||||
ret=$?
|
||||
|
||||
if test -f "$cofile"; then
|
||||
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
|
||||
elif test -f "${cofile}bj"; then
|
||||
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
|
||||
fi
|
||||
|
||||
rmdir "$lockdir"
|
||||
exit $ret
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,109 @@
|
|||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* ASM enabled */
|
||||
#undef CONFIG_ASM
|
||||
|
||||
/* found CoreText framework */
|
||||
#undef CONFIG_CORETEXT
|
||||
|
||||
/* found DirectWrite */
|
||||
#undef CONFIG_DIRECTWRITE
|
||||
|
||||
/* found fontconfig via pkg-config */
|
||||
#undef CONFIG_FONTCONFIG
|
||||
|
||||
/* found freetype2 via pkg-config */
|
||||
#undef CONFIG_FREETYPE
|
||||
|
||||
/* found fribidi via pkg-config */
|
||||
#undef CONFIG_FRIBIDI
|
||||
|
||||
/* found harfbuzz-ng via pkg-config */
|
||||
#undef CONFIG_HARFBUZZ
|
||||
|
||||
/* use iconv */
|
||||
#undef CONFIG_ICONV
|
||||
|
||||
/* use small tiles */
|
||||
#undef CONFIG_LARGE_TILES
|
||||
|
||||
/* found libpng via pkg-config */
|
||||
#undef CONFIG_LIBPNG
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the <iconv.h> header file. */
|
||||
#undef HAVE_ICONV_H
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `m' library (-lm). */
|
||||
#undef HAVE_LIBM
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if stdbool.h conforms to C99. */
|
||||
#undef HAVE_STDBOOL_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `strdup' function. */
|
||||
#undef HAVE_STRDUP
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the `strndup' function. */
|
||||
#undef HAVE_STRNDUP
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if the system has the type `_Bool'. */
|
||||
#undef HAVE__BOOL
|
||||
|
||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,269 @@
|
|||
AC_INIT(libass, 0.14.0)
|
||||
AM_INIT_AUTOMAKE
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
# Disable Fortran checks
|
||||
define([AC_LIBTOOL_LANG_F77_CONFIG], [:])
|
||||
LT_INIT
|
||||
AC_CONFIG_SRCDIR([libass/ass.c])
|
||||
AC_CONFIG_HEADER([config.h])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AM_PROG_CC_C_O
|
||||
AM_PROG_AS
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_STDBOOL
|
||||
AC_CHECK_HEADERS([stdint.h iconv.h])
|
||||
|
||||
# Checks for library functions.
|
||||
AC_CHECK_FUNCS([strdup strndup])
|
||||
|
||||
# Checks for libraries.
|
||||
# Add them to pkg-config for static linking.
|
||||
OLDLIBS="$LIBS"
|
||||
LIBS=
|
||||
use_libiconv=false
|
||||
AC_SEARCH_LIBS([libiconv_open], [iconv], use_libiconv=true)
|
||||
AC_SEARCH_LIBS([iconv_open], [iconv], use_libiconv=true)
|
||||
AC_CHECK_LIB([m], [fabs])
|
||||
pkg_libs="$LIBS"
|
||||
LIBS="$OLDLIBS $LIBS"
|
||||
|
||||
# Check for libraries via pkg-config
|
||||
AC_ARG_ENABLE([test], AS_HELP_STRING([--enable-test],
|
||||
[enable test program (requires libpng) @<:@default=no@:>@]))
|
||||
AC_ARG_ENABLE([profile], AS_HELP_STRING([--enable-profile],
|
||||
[enable profiling program @<:@default=no@:>@]))
|
||||
AC_ARG_ENABLE([fontconfig], AS_HELP_STRING([--disable-fontconfig],
|
||||
[disable fontconfig support @<:@default=enabled@:>@]))
|
||||
AC_ARG_ENABLE([directwrite], AS_HELP_STRING([--disable-directwrite],
|
||||
[disable DirectWrite support (win32 only) @<:@default=check@:>@]))
|
||||
AC_ARG_ENABLE([coretext], AS_HELP_STRING([--disable-coretext],
|
||||
[disable CoreText support (OSX only) @<:@default=check@:>@]))
|
||||
AC_ARG_ENABLE([require-system-font-provider], AS_HELP_STRING([--disable-require-system-font-provider],
|
||||
[allow compilation even if no system font provider was found @<:@default=enabled:>@]))
|
||||
AC_ARG_ENABLE([harfbuzz], AS_HELP_STRING([--disable-harfbuzz],
|
||||
[disable HarfBuzz support @<:@default=check@:>@]))
|
||||
AC_ARG_ENABLE([asm], AS_HELP_STRING([--disable-asm],
|
||||
[disable compiling with ASM @<:@default=check@:>@]))
|
||||
AC_ARG_ENABLE([large-tiles], AS_HELP_STRING([--enable-large-tiles],
|
||||
[use larger tiles in the rasterizer (better performance, slightly worse quality) @<:@default=disabled@:>@]))
|
||||
|
||||
AS_IF([test x$enable_asm != xno], [
|
||||
AS_CASE([$host],
|
||||
[i?86-*], [
|
||||
INTEL=true
|
||||
AS=nasm
|
||||
X86=true
|
||||
BITS=32
|
||||
BITTYPE=32
|
||||
ASFLAGS="$ASFLAGS -DARCH_X86_64=0" ],
|
||||
[x86_64-*-gnux32|amd64-*-gnux32], [
|
||||
AS=nasm
|
||||
INTEL=true
|
||||
X64=true
|
||||
BITS=64
|
||||
BITTYPE=x32
|
||||
ASFLAGS="$ASFLAGS -DARCH_X86_64=1 -DPIC" ],
|
||||
[x86_64-*|amd64-*], [
|
||||
AS=nasm
|
||||
INTEL=true
|
||||
X64=true
|
||||
BITS=64
|
||||
BITTYPE=64
|
||||
ASFLAGS="$ASFLAGS -DARCH_X86_64=1 -DPIC" ],
|
||||
)
|
||||
AS_IF([test x$INTEL = xtrue], [
|
||||
AC_CHECK_PROG([nasm_check], [$AS], [yes])
|
||||
AS_IF([test x$nasm_check != xyes], [
|
||||
AC_MSG_WARN(nasm was not found; ASM functions are disabled.)
|
||||
AC_MSG_WARN(Install nasm for a significantly faster libass build.)
|
||||
enable_asm=no
|
||||
], [
|
||||
AS_CASE([$host],
|
||||
[*darwin*], [
|
||||
ASFLAGS="$ASFLAGS -f macho$BITTYPE -DPREFIX -DHAVE_ALIGNED_STACK=1" ],
|
||||
[*linux*|*dragonfly*|*bsd*|*solaris*], [
|
||||
ASFLAGS="$ASFLAGS -f elf$BITTYPE -DHAVE_ALIGNED_STACK=1" ],
|
||||
[*cygwin*|*mingw*], [
|
||||
ASFLAGS="$ASFLAGS -f win$BITTYPE"
|
||||
AS_IF([test x$BITS = x64], [
|
||||
ASFLAGS="$ASFLAGS -DHAVE_ALIGNED_STACK=1"
|
||||
], [
|
||||
ASFLAGS="$ASFLAGS -DHAVE_ALIGNED_STACK=0 -DPREFIX"
|
||||
])
|
||||
])
|
||||
ASFLAGS="$ASFLAGS -DHAVE_CPUNOP=0 -Dprivate_prefix=ass"
|
||||
AC_MSG_CHECKING([if $AS supports vpmovzxwd])
|
||||
echo "vpmovzxwd ymm0, xmm0" > conftest.asm
|
||||
AS_IF([$AS conftest.asm $ASFLAGS -o conftest.o >conftest.log 2>&1], [
|
||||
AC_MSG_RESULT([yes])
|
||||
], [
|
||||
AC_MSG_RESULT([no])
|
||||
VER=`($AS --version || echo no assembler) 2>/dev/null | head -n 1`
|
||||
AC_MSG_WARN([nasm is too old (found $VER); ASM functions are disabled.])
|
||||
AC_MSG_WARN([Install nasm-2.10 or later for a significantly faster libass build.])
|
||||
enable_asm=no
|
||||
])
|
||||
rm conftest.asm conftest.o > /dev/null 2>&1
|
||||
])
|
||||
])
|
||||
])
|
||||
|
||||
AC_SUBST([ASFLAGS], ["$ASFLAGS"])
|
||||
AC_SUBST([AS], ["$AS"])
|
||||
|
||||
AM_CONDITIONAL([ASM], [test x$enable_asm != xno])
|
||||
AM_CONDITIONAL([INTEL], [test x$INTEL = xtrue])
|
||||
AM_CONDITIONAL([X86], [test x$X86 = xtrue])
|
||||
AM_CONDITIONAL([X64], [test x$X64 = xtrue])
|
||||
|
||||
AM_COND_IF([ASM],
|
||||
[AC_DEFINE(CONFIG_ASM, 1, [ASM enabled])],
|
||||
[AC_DEFINE(CONFIG_ASM, 0, [ASM enabled])]
|
||||
)
|
||||
|
||||
AM_CONDITIONAL([ENABLE_LARGE_TILES], [test x$enable_large_tiles = xyes])
|
||||
|
||||
AM_COND_IF([ENABLE_LARGE_TILES],
|
||||
[AC_DEFINE(CONFIG_LARGE_TILES, 1, [use large tiles])]
|
||||
[AC_DEFINE(CONFIG_LARGE_TILES, 0, [use small tiles])],
|
||||
)
|
||||
|
||||
PKG_CHECK_MODULES([FREETYPE], freetype2 >= 9.10.3, [
|
||||
CFLAGS="$CFLAGS $FREETYPE_CFLAGS"
|
||||
CXXFLAGS="$CFLAGS $FREETYPE_CFLAGS"
|
||||
LIBS="$LIBS $FREETYPE_LIBS"
|
||||
AC_DEFINE(CONFIG_FREETYPE, 1, [found freetype2 via pkg-config])
|
||||
])
|
||||
|
||||
PKG_CHECK_MODULES([FRIBIDI], fribidi >= 0.19.0, [
|
||||
CFLAGS="$CFLAGS $FRIBIDI_CFLAGS"
|
||||
LIBS="$LIBS $FRIBIDI_LIBS"
|
||||
AC_DEFINE(CONFIG_FRIBIDI, 1, [found fribidi via pkg-config])
|
||||
])
|
||||
|
||||
if test x$enable_fontconfig != xno; then
|
||||
PKG_CHECK_MODULES([FONTCONFIG], fontconfig >= 2.10.92, [
|
||||
CFLAGS="$CFLAGS $FONTCONFIG_CFLAGS"
|
||||
LIBS="$LIBS $FONTCONFIG_LIBS"
|
||||
AC_DEFINE(CONFIG_FONTCONFIG, 1, [found fontconfig via pkg-config])
|
||||
fontconfig=true
|
||||
], [fontconfig=false])
|
||||
fi
|
||||
AM_CONDITIONAL([FONTCONFIG], [test x$fontconfig = xtrue])
|
||||
|
||||
if test x$enable_coretext != xno; then
|
||||
# Linking to CoreText directly only works from Mountain Lion and iOS.
|
||||
# In earlier OS X releases CoreText was part of the ApplicationServices
|
||||
# umbrella framework.
|
||||
AC_MSG_CHECKING([for CORETEXT])
|
||||
AC_COMPILE_IFELSE([
|
||||
AC_LANG_PROGRAM(
|
||||
[[#include <ApplicationServices/ApplicationServices.h>]],
|
||||
[[CTFontDescriptorCopyAttribute(NULL, kCTFontURLAttribute);]])
|
||||
], [
|
||||
LIBS="$LIBS -framework ApplicationServices -framework CoreFoundation"
|
||||
AC_DEFINE(CONFIG_CORETEXT, 1, [found CoreText in ApplicationServices framework])
|
||||
coretext=true
|
||||
AC_MSG_RESULT([yes])
|
||||
], [
|
||||
AC_COMPILE_IFELSE([
|
||||
AC_LANG_PROGRAM(
|
||||
[[#include <CoreText/CoreText.h>]],
|
||||
[[CTFontDescriptorCopyAttribute(NULL, kCTFontURLAttribute);]])
|
||||
], [
|
||||
LIBS="$LIBS -framework CoreText -framework CoreFoundation"
|
||||
AC_DEFINE(CONFIG_CORETEXT, 1, [found CoreText framework])
|
||||
coretext=true
|
||||
AC_MSG_RESULT([yes])
|
||||
], [
|
||||
coretext=false
|
||||
AC_MSG_RESULT([no])
|
||||
])
|
||||
])
|
||||
fi
|
||||
AM_CONDITIONAL([CORETEXT], [test x$coretext = xtrue])
|
||||
|
||||
|
||||
|
||||
if test x$enable_directwrite != xno; then
|
||||
# Linking to DirectWrite directly only works from Windows
|
||||
AC_MSG_CHECKING([for DIRECTWRITE])
|
||||
AC_LINK_IFELSE([
|
||||
AC_LANG_PROGRAM(
|
||||
[[#include <windows.h>]],
|
||||
[[;]],)
|
||||
], [
|
||||
AC_DEFINE(CONFIG_DIRECTWRITE, 1, [found DirectWrite])
|
||||
directwrite=true
|
||||
AC_MSG_RESULT([yes])
|
||||
], [
|
||||
directwrite=false
|
||||
AC_MSG_RESULT([no])
|
||||
])
|
||||
fi
|
||||
AM_CONDITIONAL([DIRECTWRITE], [test x$directwrite = xtrue])
|
||||
|
||||
if test x$enable_harfbuzz != xno; then
|
||||
PKG_CHECK_MODULES([HARFBUZZ], harfbuzz >= 0.9.5, [
|
||||
CFLAGS="$CFLAGS $HARFBUZZ_CFLAGS"
|
||||
LIBS="$LIBS $HARFBUZZ_LIBS"
|
||||
AC_DEFINE(CONFIG_HARFBUZZ, 1, [found harfbuzz-ng via pkg-config])
|
||||
harfbuzz=true
|
||||
], [harfbuzz=false])
|
||||
fi
|
||||
|
||||
libpng=false
|
||||
if test x$enable_test = xyes; then
|
||||
PKG_CHECK_MODULES([LIBPNG], libpng >= 1.2.0, [
|
||||
CFLAGS="$CFLAGS $LIBPNG_CFLAGS"
|
||||
AC_DEFINE(CONFIG_LIBPNG, 1, [found libpng via pkg-config])
|
||||
libpng=true])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([HAVE_LIBPNG], [test x$libpng = xtrue])
|
||||
|
||||
AM_CONDITIONAL([ENABLE_PROFILE], [test x$enable_profile = xyes])
|
||||
|
||||
# add packages to pkg-config for static linking
|
||||
if test "$use_libiconv" = true; then
|
||||
AC_DEFINE(CONFIG_ICONV, 1, [use iconv])
|
||||
if test x"$ac_cv_search_libiconv_open" != x"none required" &&
|
||||
test x"$ac_cv_search_iconv_open" != x"none required"; then
|
||||
pkg_libs="${pkg_libs} -liconv"
|
||||
fi
|
||||
fi
|
||||
pkg_requires="freetype2 >= 9.10.3"
|
||||
pkg_requires="fribidi >= 0.19.0, ${pkg_requires}"
|
||||
if test x$fontconfig = xtrue; then
|
||||
pkg_requires="fontconfig >= 2.10.92, ${pkg_requires}"
|
||||
fi
|
||||
if test x$harfbuzz = xtrue; then
|
||||
pkg_requires="harfbuzz >= 0.9.5, ${pkg_requires}"
|
||||
fi
|
||||
|
||||
if test x$enable_require_system_font_provider != xno &&
|
||||
test x$fontconfig != xtrue &&
|
||||
test x$directwrite != xtrue &&
|
||||
test x$coretext != xtrue
|
||||
then
|
||||
AC_MSG_ERROR([\
|
||||
Either DirectWrite (on Windows), CoreText (on OSX), or Fontconfig \
|
||||
(Linux, other) is required. If you really want to compile without \
|
||||
a system font provider, add --disable-require-system-font-provider])
|
||||
fi
|
||||
|
||||
AC_SUBST([PKG_LIBS_DEFAULT], [$(test x$enable_shared = xno && echo ${pkg_libs})])
|
||||
AC_SUBST([PKG_REQUIRES_DEFAULT], [$(test x$enable_shared = xno && echo ${pkg_requires})])
|
||||
AC_SUBST([PKG_LIBS_PRIVATE], [$(test x$enable_shared = xno || echo ${pkg_libs})])
|
||||
AC_SUBST([PKG_REQUIRES_PRIVATE], [$(test x$enable_shared = xno || echo ${pkg_requires})])
|
||||
|
||||
# Setup output beautifier.
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
AC_CONFIG_FILES([Makefile libass/Makefile test/Makefile profile/Makefile libass.pc])
|
||||
AC_OUTPUT
|
|
@ -0,0 +1,791 @@
|
|||
#! /bin/sh
|
||||
# depcomp - compile a program generating dependencies as side-effects
|
||||
|
||||
scriptversion=2013-05-30.07; # UTC
|
||||
|
||||
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Run PROGRAMS ARGS to compile a file, generating dependencies
|
||||
as side-effects.
|
||||
|
||||
Environment variables:
|
||||
depmode Dependency tracking mode.
|
||||
source Source file read by 'PROGRAMS ARGS'.
|
||||
object Object file output by 'PROGRAMS ARGS'.
|
||||
DEPDIR directory where to store dependencies.
|
||||
depfile Dependency file to output.
|
||||
tmpdepfile Temporary file to use when outputting dependencies.
|
||||
libtool Whether libtool is used (yes/no).
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "depcomp $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
|
||||
# Get the directory component of the given path, and save it in the
|
||||
# global variables '$dir'. Note that this directory component will
|
||||
# be either empty or ending with a '/' character. This is deliberate.
|
||||
set_dir_from ()
|
||||
{
|
||||
case $1 in
|
||||
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
|
||||
*) dir=;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Get the suffix-stripped basename of the given path, and save it the
|
||||
# global variable '$base'.
|
||||
set_base_from ()
|
||||
{
|
||||
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
|
||||
}
|
||||
|
||||
# If no dependency file was actually created by the compiler invocation,
|
||||
# we still have to create a dummy depfile, to avoid errors with the
|
||||
# Makefile "include basename.Plo" scheme.
|
||||
make_dummy_depfile ()
|
||||
{
|
||||
echo "#dummy" > "$depfile"
|
||||
}
|
||||
|
||||
# Factor out some common post-processing of the generated depfile.
|
||||
# Requires the auxiliary global variable '$tmpdepfile' to be set.
|
||||
aix_post_process_depfile ()
|
||||
{
|
||||
# If the compiler actually managed to produce a dependency file,
|
||||
# post-process it.
|
||||
if test -f "$tmpdepfile"; then
|
||||
# Each line is of the form 'foo.o: dependency.h'.
|
||||
# Do two passes, one to just change these to
|
||||
# $object: dependency.h
|
||||
# and one to simply output
|
||||
# dependency.h:
|
||||
# which is needed to avoid the deleted-header problem.
|
||||
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
|
||||
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
|
||||
} > "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
}
|
||||
|
||||
# A tabulation character.
|
||||
tab=' '
|
||||
# A newline character.
|
||||
nl='
|
||||
'
|
||||
# Character ranges might be problematic outside the C locale.
|
||||
# These definitions help.
|
||||
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
lower=abcdefghijklmnopqrstuvwxyz
|
||||
digits=0123456789
|
||||
alpha=${upper}${lower}
|
||||
|
||||
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
|
||||
echo "depcomp: Variables source, object and depmode must be set" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
|
||||
depfile=${depfile-`echo "$object" |
|
||||
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
|
||||
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
|
||||
|
||||
rm -f "$tmpdepfile"
|
||||
|
||||
# Avoid interferences from the environment.
|
||||
gccflag= dashmflag=
|
||||
|
||||
# Some modes work just like other modes, but use different flags. We
|
||||
# parameterize here, but still list the modes in the big case below,
|
||||
# to make depend.m4 easier to write. Note that we *cannot* use a case
|
||||
# here, because this file can only contain one case statement.
|
||||
if test "$depmode" = hp; then
|
||||
# HP compiler uses -M and no extra arg.
|
||||
gccflag=-M
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
if test "$depmode" = dashXmstdout; then
|
||||
# This is just like dashmstdout with a different argument.
|
||||
dashmflag=-xM
|
||||
depmode=dashmstdout
|
||||
fi
|
||||
|
||||
cygpath_u="cygpath -u -f -"
|
||||
if test "$depmode" = msvcmsys; then
|
||||
# This is just like msvisualcpp but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvisualcpp
|
||||
fi
|
||||
|
||||
if test "$depmode" = msvc7msys; then
|
||||
# This is just like msvc7 but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvc7
|
||||
fi
|
||||
|
||||
if test "$depmode" = xlc; then
|
||||
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
|
||||
gccflag=-qmakedep=gcc,-MF
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
case "$depmode" in
|
||||
gcc3)
|
||||
## gcc 3 implements dependency tracking that does exactly what
|
||||
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
|
||||
## it if -MD -MP comes after the -MF stuff. Hmm.
|
||||
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
|
||||
## the command line argument order; so add the flags where they
|
||||
## appear in depend2.am. Note that the slowdown incurred here
|
||||
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
|
||||
*) set fnord "$@" "$arg" ;;
|
||||
esac
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
done
|
||||
"$@"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
mv "$tmpdepfile" "$depfile"
|
||||
;;
|
||||
|
||||
gcc)
|
||||
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
|
||||
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
|
||||
## (see the conditional assignment to $gccflag above).
|
||||
## There are various ways to get dependency output from gcc. Here's
|
||||
## why we pick this rather obscure method:
|
||||
## - Don't want to use -MD because we'd like the dependencies to end
|
||||
## up in a subdir. Having to rename by hand is ugly.
|
||||
## (We might end up doing this anyway to support other compilers.)
|
||||
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
|
||||
## -MM, not -M (despite what the docs say). Also, it might not be
|
||||
## supported by the other compilers which use the 'gcc' depmode.
|
||||
## - Using -M directly means running the compiler twice (even worse
|
||||
## than renaming).
|
||||
if test -z "$gccflag"; then
|
||||
gccflag=-MD,
|
||||
fi
|
||||
"$@" -Wp,"$gccflag$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The second -e expression handles DOS-style file names with drive
|
||||
# letters.
|
||||
sed -e 's/^[^:]*: / /' \
|
||||
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
|
||||
## This next piece of magic avoids the "deleted header file" problem.
|
||||
## The problem is that when a header file which appears in a .P file
|
||||
## is deleted, the dependency causes make to die (because there is
|
||||
## typically no way to rebuild the header). We avoid this by adding
|
||||
## dummy dependencies for each header file. Too bad gcc doesn't do
|
||||
## this for us directly.
|
||||
## Some versions of gcc put a space before the ':'. On the theory
|
||||
## that the space means something, we add a space to the output as
|
||||
## well. hp depmode also adds that space, but also prefixes the VPATH
|
||||
## to the object. Take care to not repeat it in the output.
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
sgi)
|
||||
if test "$libtool" = yes; then
|
||||
"$@" "-Wp,-MDupdate,$tmpdepfile"
|
||||
else
|
||||
"$@" -MDupdate "$tmpdepfile"
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
|
||||
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
|
||||
echo "$object : \\" > "$depfile"
|
||||
# Clip off the initial element (the dependent). Don't try to be
|
||||
# clever and replace this with sed code, as IRIX sed won't handle
|
||||
# lines with more than a fixed number of characters (4096 in
|
||||
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
|
||||
# the IRIX cc adds comments like '#:fec' to the end of the
|
||||
# dependency line.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
|
||||
| tr "$nl" ' ' >> "$depfile"
|
||||
echo >> "$depfile"
|
||||
# The second pass generates a dummy entry for each header file.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
|
||||
>> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
xlc)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
aix)
|
||||
# The C for AIX Compiler uses -M and outputs the dependencies
|
||||
# in a .u file. In older versions, this file always lives in the
|
||||
# current directory. Also, the AIX compiler puts '$object:' at the
|
||||
# start of each line; $object doesn't have directory information.
|
||||
# Version 6 uses the directory in both cases.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$base.u
|
||||
tmpdepfile3=$dir.libs/$base.u
|
||||
"$@" -Wc,-M
|
||||
else
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$dir$base.u
|
||||
tmpdepfile3=$dir$base.u
|
||||
"$@" -M
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
tcc)
|
||||
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
|
||||
# FIXME: That version still under development at the moment of writing.
|
||||
# Make that this statement remains true also for stable, released
|
||||
# versions.
|
||||
# It will wrap lines (doesn't matter whether long or short) with a
|
||||
# trailing '\', as in:
|
||||
#
|
||||
# foo.o : \
|
||||
# foo.c \
|
||||
# foo.h \
|
||||
#
|
||||
# It will put a trailing '\' even on the last line, and will use leading
|
||||
# spaces rather than leading tabs (at least since its commit 0394caf7
|
||||
# "Emit spaces for -MD").
|
||||
"$@" -MD -MF "$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
|
||||
# We have to change lines of the first kind to '$object: \'.
|
||||
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
|
||||
# And for each line of the second kind, we have to emit a 'dep.h:'
|
||||
# dummy dependency, to avoid the deleted-header problem.
|
||||
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
## The order of this option in the case statement is important, since the
|
||||
## shell code in configure will try each of these formats in the order
|
||||
## listed in this file. A plain '-MD' option would be understood by many
|
||||
## compilers, so we must ensure this comes after the gcc and icc options.
|
||||
pgcc)
|
||||
# Portland's C compiler understands '-MD'.
|
||||
# Will always output deps to 'file.d' where file is the root name of the
|
||||
# source file under compilation, even if file resides in a subdirectory.
|
||||
# The object file name does not affect the name of the '.d' file.
|
||||
# pgcc 10.2 will output
|
||||
# foo.o: sub/foo.c sub/foo.h
|
||||
# and will wrap long lines using '\' :
|
||||
# foo.o: sub/foo.c ... \
|
||||
# sub/foo.h ... \
|
||||
# ...
|
||||
set_dir_from "$object"
|
||||
# Use the source, not the object, to determine the base name, since
|
||||
# that's sadly what pgcc will do too.
|
||||
set_base_from "$source"
|
||||
tmpdepfile=$base.d
|
||||
|
||||
# For projects that build the same source file twice into different object
|
||||
# files, the pgcc approach of using the *source* file root name can cause
|
||||
# problems in parallel builds. Use a locking strategy to avoid stomping on
|
||||
# the same $tmpdepfile.
|
||||
lockdir=$base.d-lock
|
||||
trap "
|
||||
echo '$0: caught signal, cleaning up...' >&2
|
||||
rmdir '$lockdir'
|
||||
exit 1
|
||||
" 1 2 13 15
|
||||
numtries=100
|
||||
i=$numtries
|
||||
while test $i -gt 0; do
|
||||
# mkdir is a portable test-and-set.
|
||||
if mkdir "$lockdir" 2>/dev/null; then
|
||||
# This process acquired the lock.
|
||||
"$@" -MD
|
||||
stat=$?
|
||||
# Release the lock.
|
||||
rmdir "$lockdir"
|
||||
break
|
||||
else
|
||||
# If the lock is being held by a different process, wait
|
||||
# until the winning process is done or we timeout.
|
||||
while test -d "$lockdir" && test $i -gt 0; do
|
||||
sleep 1
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
fi
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
trap - 1 2 13 15
|
||||
if test $i -le 0; then
|
||||
echo "$0: failed to acquire lock after $numtries attempts" >&2
|
||||
echo "$0: check lockdir '$lockdir'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each line is of the form `foo.o: dependent.h',
|
||||
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp2)
|
||||
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
|
||||
# compilers, which have integrated preprocessors. The correct option
|
||||
# to use with these is +Maked; it writes dependencies to a file named
|
||||
# 'foo.d', which lands next to the object file, wherever that
|
||||
# happens to be.
|
||||
# Much of this is similar to the tru64 case; see comments there.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir.libs/$base.d
|
||||
"$@" -Wc,+Maked
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
"$@" +Maked
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
|
||||
# Add 'dependent.h:' lines.
|
||||
sed -ne '2,${
|
||||
s/^ *//
|
||||
s/ \\*$//
|
||||
s/$/:/
|
||||
p
|
||||
}' "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile" "$tmpdepfile2"
|
||||
;;
|
||||
|
||||
tru64)
|
||||
# The Tru64 compiler uses -MD to generate dependencies as a side
|
||||
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
|
||||
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
|
||||
# dependencies in 'foo.d' instead, so we check for that too.
|
||||
# Subdirectories are respected.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
|
||||
if test "$libtool" = yes; then
|
||||
# Libtool generates 2 separate objects for the 2 libraries. These
|
||||
# two compilations output dependencies in $dir.libs/$base.o.d and
|
||||
# in $dir$base.o.d. We have to check for both files, because
|
||||
# one of the two compilations can be disabled. We should prefer
|
||||
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
|
||||
# automatically cleaned when .libs/ is deleted, while ignoring
|
||||
# the former would cause a distcleancheck panic.
|
||||
tmpdepfile1=$dir$base.o.d # libtool 1.5
|
||||
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
|
||||
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
|
||||
"$@" -Wc,-MD
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
tmpdepfile3=$dir$base.d
|
||||
"$@" -MD
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
# Same post-processing that is required for AIX mode.
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
msvc7)
|
||||
if test "$libtool" = yes; then
|
||||
showIncludes=-Wc,-showIncludes
|
||||
else
|
||||
showIncludes=-showIncludes
|
||||
fi
|
||||
"$@" $showIncludes > "$tmpdepfile"
|
||||
stat=$?
|
||||
grep -v '^Note: including file: ' "$tmpdepfile"
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The first sed program below extracts the file names and escapes
|
||||
# backslashes for cygpath. The second sed program outputs the file
|
||||
# name when reading, but also accumulates all include files in the
|
||||
# hold buffer in order to output them again at the end. This only
|
||||
# works with sed implementations that can handle large buffers.
|
||||
sed < "$tmpdepfile" -n '
|
||||
/^Note: including file: *\(.*\)/ {
|
||||
s//\1/
|
||||
s/\\/\\\\/g
|
||||
p
|
||||
}' | $cygpath_u | sort -u | sed -n '
|
||||
s/ /\\ /g
|
||||
s/\(.*\)/'"$tab"'\1 \\/p
|
||||
s/.\(.*\) \\/\1:/
|
||||
H
|
||||
$ {
|
||||
s/.*/'"$tab"'/
|
||||
G
|
||||
p
|
||||
}' >> "$depfile"
|
||||
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvc7msys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
#nosideeffect)
|
||||
# This comment above is used by automake to tell side-effect
|
||||
# dependency tracking mechanisms from slower ones.
|
||||
|
||||
dashmstdout)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout, regardless of -o.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
test -z "$dashmflag" && dashmflag=-M
|
||||
# Require at least two characters before searching for ':'
|
||||
# in the target name. This is to cope with DOS-style filenames:
|
||||
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
|
||||
"$@" $dashmflag |
|
||||
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this sed invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
dashXmstdout)
|
||||
# This case only exists to satisfy depend.m4. It is never actually
|
||||
# run, as this mode is specially recognized in the preamble.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
makedepend)
|
||||
"$@" || exit $?
|
||||
# Remove any Libtool call
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
# X makedepend
|
||||
shift
|
||||
cleared=no eat=no
|
||||
for arg
|
||||
do
|
||||
case $cleared in
|
||||
no)
|
||||
set ""; shift
|
||||
cleared=yes ;;
|
||||
esac
|
||||
if test $eat = yes; then
|
||||
eat=no
|
||||
continue
|
||||
fi
|
||||
case "$arg" in
|
||||
-D*|-I*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
# Strip any option that makedepend may not understand. Remove
|
||||
# the object too, otherwise makedepend will parse it as a source file.
|
||||
-arch)
|
||||
eat=yes ;;
|
||||
-*|$object)
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
esac
|
||||
done
|
||||
obj_suffix=`echo "$object" | sed 's/^.*\././'`
|
||||
touch "$tmpdepfile"
|
||||
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
|
||||
rm -f "$depfile"
|
||||
# makedepend may prepend the VPATH from the source file name to the object.
|
||||
# No need to regex-escape $object, excess matching of '.' is harmless.
|
||||
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process the last invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed '1,2d' "$tmpdepfile" \
|
||||
| tr ' ' "$nl" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile" "$tmpdepfile".bak
|
||||
;;
|
||||
|
||||
cpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
"$@" -E \
|
||||
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
| sed '$ s: \\$::' > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
cat < "$tmpdepfile" >> "$depfile"
|
||||
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvisualcpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case "$arg" in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
|
||||
set fnord "$@"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
"$@" -E 2>/dev/null |
|
||||
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
|
||||
echo "$tab" >> "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvcmsys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
none)
|
||||
exec "$@"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown depmode $depmode" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
|
@ -0,0 +1,501 @@
|
|||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2013-12-25.23; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# 'make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
tab=' '
|
||||
nl='
|
||||
'
|
||||
IFS=" $tab$nl"
|
||||
|
||||
# Set DOITPROG to "echo" to test this script.
|
||||
|
||||
doit=${DOITPROG-}
|
||||
doit_exec=${doit:-exec}
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
is_target_a_directory=possibly
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t)
|
||||
is_target_a_directory=always
|
||||
dst_arg=$2
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) is_target_a_directory=never;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# We allow the use of options -d and -T together, by making -d
|
||||
# take the precedence; this is for compatibility with GNU install.
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
if test -n "$dst_arg"; then
|
||||
echo "$0: target directory not allowed when installing a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call 'install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
if test $# -gt 1 || test "$is_target_a_directory" = always; then
|
||||
if test ! -d "$dst_arg"; then
|
||||
echo "$0: $dst_arg: Is not a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
if test -d "$dst"; then
|
||||
if test "$is_target_a_directory" = never; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dst=$dstdir/`basename "$src"`
|
||||
dstdir_status=0
|
||||
else
|
||||
dstdir=`dirname "$dst"`
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
if (umask $mkdir_umask &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/d" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
rmtmp=$dstdir/_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
set +f &&
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
|
@ -0,0 +1,13 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: libass
|
||||
Description: LibASS is an SSA/ASS subtitles rendering library
|
||||
Version: @PACKAGE_VERSION@
|
||||
Requires: @PKG_REQUIRES_DEFAULT@
|
||||
Requires.private: @PKG_REQUIRES_PRIVATE@
|
||||
Libs: -L${libdir} -lass @PKG_LIBS_DEFAULT@
|
||||
Libs.private: @PKG_LIBS_PRIVATE@
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,63 @@
|
|||
AM_CFLAGS = -std=gnu99 -Wall -Wextra -Wno-sign-compare -Wno-unused-parameter \
|
||||
-Werror-implicit-function-declaration -Wstrict-prototypes \
|
||||
-Wpointer-arith -Wredundant-decls -Wno-missing-field-initializers\
|
||||
-D_GNU_SOURCE
|
||||
|
||||
LIBASS_LT_CURRENT = 9
|
||||
LIBASS_LT_REVISION = 2
|
||||
LIBASS_LT_AGE = 0
|
||||
|
||||
nasm_verbose = $(nasm_verbose_$(V))
|
||||
nasm_verbose_ = $(nasm_verbose_$(AM_DEFAULT_VERBOSITY))
|
||||
nasm_verbose_0 = @echo " NASM " $@;
|
||||
|
||||
.asm.lo:
|
||||
$(nasm_verbose)$(LIBTOOL) $(AM_V_lt) --tag=CC --mode=compile $(AS) $(ASFLAGS) -I$(srcdir)/ -o $@ $< -prefer-non-pic
|
||||
|
||||
SRC_INTEL = x86/rasterizer.asm x86/blend_bitmaps.asm x86/blur.asm x86/cpuid.asm \
|
||||
x86/cpuid.h
|
||||
SRC_INTEL64 = x86/be_blur.asm
|
||||
|
||||
SRC_FONTCONFIG = ass_fontconfig.c ass_fontconfig.h
|
||||
SRC_DIRECTWRITE = ass_directwrite.c ass_directwrite.h dwrite_c.h
|
||||
SRC_CORETEXT = ass_coretext.c ass_coretext.h
|
||||
|
||||
lib_LTLIBRARIES = libass.la
|
||||
libass_la_SOURCES = ass.h ass.c ass_types.h ass_utils.h ass_utils.c \
|
||||
ass_compat.h ass_string.h ass_string.c ass_strtod.c \
|
||||
ass_library.h ass_library.c ass_cache.h ass_cache.c ass_cache_template.h \
|
||||
ass_font.h ass_font.c ass_fontselect.h ass_fontselect.c \
|
||||
ass_render.h ass_render.c ass_render_api.c \
|
||||
ass_parse.h ass_parse.c ass_shaper.h ass_shaper.c \
|
||||
ass_outline.h ass_outline.c ass_drawing.h ass_drawing.c \
|
||||
ass_rasterizer.h ass_rasterizer.c ass_rasterizer_c.c \
|
||||
ass_bitmap.h ass_bitmap.c ass_blur.c ass_func_template.h
|
||||
|
||||
libass_la_LDFLAGS = -no-undefined -version-info $(LIBASS_LT_CURRENT):$(LIBASS_LT_REVISION):$(LIBASS_LT_AGE)
|
||||
libass_la_LDFLAGS += -export-symbols $(srcdir)/libass.sym
|
||||
|
||||
if FONTCONFIG
|
||||
libass_la_SOURCES += $(SRC_FONTCONFIG)
|
||||
endif
|
||||
|
||||
if DIRECTWRITE
|
||||
libass_la_SOURCES += $(SRC_DIRECTWRITE)
|
||||
endif
|
||||
|
||||
if CORETEXT
|
||||
libass_la_SOURCES += $(SRC_CORETEXT)
|
||||
endif
|
||||
|
||||
if ASM
|
||||
if INTEL
|
||||
libass_la_SOURCES += $(SRC_INTEL)
|
||||
if X64
|
||||
libass_la_SOURCES += $(SRC_INTEL64)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
assheadersdir = $(includedir)/ass
|
||||
dist_assheaders_HEADERS = ass.h ass_types.h
|
||||
|
||||
EXTRA_DIST = libass.sym x86/x86inc.asm x86/utils.asm
|
|
@ -0,0 +1,800 @@
|
|||
# Makefile.in generated by automake 1.15 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2014 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
*) echo "am__make_running_with_option: internal error: invalid" \
|
||||
"target option '$${target_option-}' specified" >&2; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
has_opt=no; \
|
||||
sane_makeflags=$$MAKEFLAGS; \
|
||||
if $(am__is_gnu_make); then \
|
||||
sane_makeflags=$$MFLAGS; \
|
||||
else \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
bs=\\; \
|
||||
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
|
||||
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
|
||||
esac; \
|
||||
fi; \
|
||||
skip_next=no; \
|
||||
strip_trailopt () \
|
||||
{ \
|
||||
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
|
||||
}; \
|
||||
for flg in $$sane_makeflags; do \
|
||||
test $$skip_next = yes && { skip_next=no; continue; }; \
|
||||
case $$flg in \
|
||||
*=*|--*) continue;; \
|
||||
-*I) strip_trailopt 'I'; skip_next=yes;; \
|
||||
-*I?*) strip_trailopt 'I';; \
|
||||
-*O) strip_trailopt 'O'; skip_next=yes;; \
|
||||
-*O?*) strip_trailopt 'O';; \
|
||||
-*l) strip_trailopt 'l'; skip_next=yes;; \
|
||||
-*l?*) strip_trailopt 'l';; \
|
||||
-[dEDm]) skip_next=yes;; \
|
||||
-[JT]) skip_next=yes;; \
|
||||
esac; \
|
||||
case $$flg in \
|
||||
*$$target_option*) has_opt=yes; break;; \
|
||||
esac; \
|
||||
done; \
|
||||
test $$has_opt = yes
|
||||
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
|
||||
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
@FONTCONFIG_TRUE@am__append_1 = $(SRC_FONTCONFIG)
|
||||
@DIRECTWRITE_TRUE@am__append_2 = $(SRC_DIRECTWRITE)
|
||||
@CORETEXT_TRUE@am__append_3 = $(SRC_CORETEXT)
|
||||
@ASM_TRUE@@INTEL_TRUE@am__append_4 = $(SRC_INTEL)
|
||||
@ASM_TRUE@@INTEL_TRUE@@X64_TRUE@am__append_5 = $(SRC_INTEL64)
|
||||
subdir = libass
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
|
||||
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
|
||||
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(dist_assheaders_HEADERS) \
|
||||
$(am__DIST_COMMON)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||
am__install_max = 40
|
||||
am__nobase_strip_setup = \
|
||||
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||
am__nobase_strip = \
|
||||
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||
am__nobase_list = $(am__nobase_strip_setup); \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||
if (++n[$$2] == $(am__install_max)) \
|
||||
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||
END { for (dir in files) print dir, files[dir] }'
|
||||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__uninstall_files_from_dir = { \
|
||||
test -z "$$files" \
|
||||
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(assheadersdir)"
|
||||
LTLIBRARIES = $(lib_LTLIBRARIES)
|
||||
libass_la_LIBADD =
|
||||
am__libass_la_SOURCES_DIST = ass.h ass.c ass_types.h ass_utils.h \
|
||||
ass_utils.c ass_compat.h ass_string.h ass_string.c \
|
||||
ass_strtod.c ass_library.h ass_library.c ass_cache.h \
|
||||
ass_cache.c ass_cache_template.h ass_font.h ass_font.c \
|
||||
ass_fontselect.h ass_fontselect.c ass_render.h ass_render.c \
|
||||
ass_render_api.c ass_parse.h ass_parse.c ass_shaper.h \
|
||||
ass_shaper.c ass_outline.h ass_outline.c ass_drawing.h \
|
||||
ass_drawing.c ass_rasterizer.h ass_rasterizer.c \
|
||||
ass_rasterizer_c.c ass_bitmap.h ass_bitmap.c ass_blur.c \
|
||||
ass_func_template.h ass_fontconfig.c ass_fontconfig.h \
|
||||
ass_directwrite.c ass_directwrite.h dwrite_c.h ass_coretext.c \
|
||||
ass_coretext.h x86/rasterizer.asm x86/blend_bitmaps.asm \
|
||||
x86/blur.asm x86/cpuid.asm x86/cpuid.h x86/be_blur.asm
|
||||
am__objects_1 = ass_fontconfig.lo
|
||||
@FONTCONFIG_TRUE@am__objects_2 = $(am__objects_1)
|
||||
am__objects_3 = ass_directwrite.lo
|
||||
@DIRECTWRITE_TRUE@am__objects_4 = $(am__objects_3)
|
||||
am__objects_5 = ass_coretext.lo
|
||||
@CORETEXT_TRUE@am__objects_6 = $(am__objects_5)
|
||||
am__dirstamp = $(am__leading_dot)dirstamp
|
||||
am__objects_7 = x86/rasterizer.lo x86/blend_bitmaps.lo x86/blur.lo \
|
||||
x86/cpuid.lo
|
||||
@ASM_TRUE@@INTEL_TRUE@am__objects_8 = $(am__objects_7)
|
||||
am__objects_9 = x86/be_blur.lo
|
||||
@ASM_TRUE@@INTEL_TRUE@@X64_TRUE@am__objects_10 = $(am__objects_9)
|
||||
am_libass_la_OBJECTS = ass.lo ass_utils.lo ass_string.lo ass_strtod.lo \
|
||||
ass_library.lo ass_cache.lo ass_font.lo ass_fontselect.lo \
|
||||
ass_render.lo ass_render_api.lo ass_parse.lo ass_shaper.lo \
|
||||
ass_outline.lo ass_drawing.lo ass_rasterizer.lo \
|
||||
ass_rasterizer_c.lo ass_bitmap.lo ass_blur.lo $(am__objects_2) \
|
||||
$(am__objects_4) $(am__objects_6) $(am__objects_8) \
|
||||
$(am__objects_10)
|
||||
libass_la_OBJECTS = $(am_libass_la_OBJECTS)
|
||||
AM_V_lt = $(am__v_lt_@AM_V@)
|
||||
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
|
||||
am__v_lt_0 = --silent
|
||||
am__v_lt_1 =
|
||||
libass_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(libass_la_LDFLAGS) $(LDFLAGS) -o $@
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
|
||||
am__v_P_0 = false
|
||||
am__v_P_1 = :
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_GEN_1 =
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
am__v_at_1 =
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
|
||||
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
am__mv = mv -f
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
|
||||
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
|
||||
$(AM_CFLAGS) $(CFLAGS)
|
||||
AM_V_CC = $(am__v_CC_@AM_V@)
|
||||
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
|
||||
am__v_CC_0 = @echo " CC " $@;
|
||||
am__v_CC_1 =
|
||||
CCLD = $(CC)
|
||||
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
|
||||
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
|
||||
am__v_CCLD_0 = @echo " CCLD " $@;
|
||||
am__v_CCLD_1 =
|
||||
SOURCES = $(libass_la_SOURCES)
|
||||
DIST_SOURCES = $(am__libass_la_SOURCES_DIST)
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
HEADERS = $(dist_assheaders_HEADERS)
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
|
||||
# Read a list of newline-separated strings from the standard input,
|
||||
# and print each of them once, without duplicates. Input order is
|
||||
# *not* preserved.
|
||||
am__uniquify_input = $(AWK) '\
|
||||
BEGIN { nonempty = 0; } \
|
||||
{ items[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in items) print i; }; } \
|
||||
'
|
||||
# Make sure the list of sources is unique. This is necessary because,
|
||||
# e.g., the same source file might be shared among _SOURCES variables
|
||||
# for different programs/libraries.
|
||||
am__define_uniq_tagged_files = \
|
||||
list='$(am__tagged_files)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | $(am__uniquify_input)`
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
AS = @AS@
|
||||
ASFLAGS = @ASFLAGS@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCAS = @CCAS@
|
||||
CCASDEPMODE = @CCASDEPMODE@
|
||||
CCASFLAGS = @CCASFLAGS@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
|
||||
FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
|
||||
FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
|
||||
FREETYPE_LIBS = @FREETYPE_LIBS@
|
||||
FRIBIDI_CFLAGS = @FRIBIDI_CFLAGS@
|
||||
FRIBIDI_LIBS = @FRIBIDI_LIBS@
|
||||
GREP = @GREP@
|
||||
HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@
|
||||
HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
|
||||
LIBPNG_LIBS = @LIBPNG_LIBS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PKG_CONFIG = @PKG_CONFIG@
|
||||
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
|
||||
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
|
||||
PKG_LIBS_DEFAULT = @PKG_LIBS_DEFAULT@
|
||||
PKG_LIBS_PRIVATE = @PKG_LIBS_PRIVATE@
|
||||
PKG_REQUIRES_DEFAULT = @PKG_REQUIRES_DEFAULT@
|
||||
PKG_REQUIRES_PRIVATE = @PKG_REQUIRES_PRIVATE@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
nasm_check = @nasm_check@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
AM_CFLAGS = -std=gnu99 -Wall -Wextra -Wno-sign-compare -Wno-unused-parameter \
|
||||
-Werror-implicit-function-declaration -Wstrict-prototypes \
|
||||
-Wpointer-arith -Wredundant-decls -Wno-missing-field-initializers\
|
||||
-D_GNU_SOURCE
|
||||
|
||||
LIBASS_LT_CURRENT = 9
|
||||
LIBASS_LT_REVISION = 2
|
||||
LIBASS_LT_AGE = 0
|
||||
nasm_verbose = $(nasm_verbose_$(V))
|
||||
nasm_verbose_ = $(nasm_verbose_$(AM_DEFAULT_VERBOSITY))
|
||||
nasm_verbose_0 = @echo " NASM " $@;
|
||||
SRC_INTEL = x86/rasterizer.asm x86/blend_bitmaps.asm x86/blur.asm x86/cpuid.asm \
|
||||
x86/cpuid.h
|
||||
|
||||
SRC_INTEL64 = x86/be_blur.asm
|
||||
SRC_FONTCONFIG = ass_fontconfig.c ass_fontconfig.h
|
||||
SRC_DIRECTWRITE = ass_directwrite.c ass_directwrite.h dwrite_c.h
|
||||
SRC_CORETEXT = ass_coretext.c ass_coretext.h
|
||||
lib_LTLIBRARIES = libass.la
|
||||
libass_la_SOURCES = ass.h ass.c ass_types.h ass_utils.h ass_utils.c \
|
||||
ass_compat.h ass_string.h ass_string.c ass_strtod.c \
|
||||
ass_library.h ass_library.c ass_cache.h ass_cache.c \
|
||||
ass_cache_template.h ass_font.h ass_font.c ass_fontselect.h \
|
||||
ass_fontselect.c ass_render.h ass_render.c ass_render_api.c \
|
||||
ass_parse.h ass_parse.c ass_shaper.h ass_shaper.c \
|
||||
ass_outline.h ass_outline.c ass_drawing.h ass_drawing.c \
|
||||
ass_rasterizer.h ass_rasterizer.c ass_rasterizer_c.c \
|
||||
ass_bitmap.h ass_bitmap.c ass_blur.c ass_func_template.h \
|
||||
$(am__append_1) $(am__append_2) $(am__append_3) \
|
||||
$(am__append_4) $(am__append_5)
|
||||
libass_la_LDFLAGS = -no-undefined -version-info \
|
||||
$(LIBASS_LT_CURRENT):$(LIBASS_LT_REVISION):$(LIBASS_LT_AGE) \
|
||||
-export-symbols $(srcdir)/libass.sym
|
||||
assheadersdir = $(includedir)/ass
|
||||
dist_assheaders_HEADERS = ass.h ass_types.h
|
||||
EXTRA_DIST = libass.sym x86/x86inc.asm x86/utils.asm
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .asm .c .lo .o .obj
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libass/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --gnu libass/Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
|
||||
list2=; for p in $$list; do \
|
||||
if test -f $$p; then \
|
||||
list2="$$list2 $$p"; \
|
||||
else :; fi; \
|
||||
done; \
|
||||
test -z "$$list2" || { \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
|
||||
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
|
||||
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
|
||||
}
|
||||
|
||||
uninstall-libLTLIBRARIES:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
|
||||
for p in $$list; do \
|
||||
$(am__strip_dir) \
|
||||
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
|
||||
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
|
||||
done
|
||||
|
||||
clean-libLTLIBRARIES:
|
||||
-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
|
||||
@list='$(lib_LTLIBRARIES)'; \
|
||||
locs=`for p in $$list; do echo $$p; done | \
|
||||
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
|
||||
sort -u`; \
|
||||
test -z "$$locs" || { \
|
||||
echo rm -f $${locs}; \
|
||||
rm -f $${locs}; \
|
||||
}
|
||||
x86/$(am__dirstamp):
|
||||
@$(MKDIR_P) x86
|
||||
@: > x86/$(am__dirstamp)
|
||||
x86/$(DEPDIR)/$(am__dirstamp):
|
||||
@$(MKDIR_P) x86/$(DEPDIR)
|
||||
@: > x86/$(DEPDIR)/$(am__dirstamp)
|
||||
x86/rasterizer.lo: x86/$(am__dirstamp) x86/$(DEPDIR)/$(am__dirstamp)
|
||||
x86/blend_bitmaps.lo: x86/$(am__dirstamp) \
|
||||
x86/$(DEPDIR)/$(am__dirstamp)
|
||||
x86/blur.lo: x86/$(am__dirstamp) x86/$(DEPDIR)/$(am__dirstamp)
|
||||
x86/cpuid.lo: x86/$(am__dirstamp) x86/$(DEPDIR)/$(am__dirstamp)
|
||||
x86/be_blur.lo: x86/$(am__dirstamp) x86/$(DEPDIR)/$(am__dirstamp)
|
||||
|
||||
libass.la: $(libass_la_OBJECTS) $(libass_la_DEPENDENCIES) $(EXTRA_libass_la_DEPENDENCIES)
|
||||
$(AM_V_CCLD)$(libass_la_LINK) -rpath $(libdir) $(libass_la_OBJECTS) $(libass_la_LIBADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
-rm -f x86/*.$(OBJEXT)
|
||||
-rm -f x86/*.lo
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_bitmap.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_blur.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_cache.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_coretext.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_directwrite.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_drawing.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_font.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_fontconfig.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_fontselect.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_library.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_outline.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_parse.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_rasterizer.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_rasterizer_c.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_render.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_render_api.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_shaper.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_string.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_strtod.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ass_utils.Plo@am__quote@
|
||||
|
||||
.c.o:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
|
||||
|
||||
.c.obj:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
|
||||
.c.lo:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
-rm -rf x86/.libs x86/_libs
|
||||
install-dist_assheadersHEADERS: $(dist_assheaders_HEADERS)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(dist_assheaders_HEADERS)'; test -n "$(assheadersdir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(assheadersdir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(assheadersdir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; \
|
||||
done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(assheadersdir)'"; \
|
||||
$(INSTALL_HEADER) $$files "$(DESTDIR)$(assheadersdir)" || exit $$?; \
|
||||
done
|
||||
|
||||
uninstall-dist_assheadersHEADERS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(dist_assheaders_HEADERS)'; test -n "$(assheadersdir)" || list=; \
|
||||
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
|
||||
dir='$(DESTDIR)$(assheadersdir)'; $(am__uninstall_files_from_dir)
|
||||
|
||||
ID: $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); mkid -fID $$unique
|
||||
tags: tags-am
|
||||
TAGS: tags
|
||||
|
||||
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
$(am__define_uniq_tagged_files); \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: ctags-am
|
||||
|
||||
CTAGS: ctags
|
||||
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
cscopelist: cscopelist-am
|
||||
|
||||
cscopelist-am: $(am__tagged_files)
|
||||
list='$(am__tagged_files)'; \
|
||||
case "$(srcdir)" in \
|
||||
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
|
||||
*) sdir=$(subdir)/$(srcdir) ;; \
|
||||
esac; \
|
||||
for i in $$list; do \
|
||||
if test -f "$$i"; then \
|
||||
echo "$(subdir)/$$i"; \
|
||||
else \
|
||||
echo "$$sdir/$$i"; \
|
||||
fi; \
|
||||
done >> $(top_builddir)/cscope.files
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(LTLIBRARIES) $(HEADERS)
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(assheadersdir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
-rm -f x86/$(DEPDIR)/$(am__dirstamp)
|
||||
-rm -f x86/$(am__dirstamp)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
|
||||
mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am: install-dist_assheadersHEADERS
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am: install-libLTLIBRARIES
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-dist_assheadersHEADERS \
|
||||
uninstall-libLTLIBRARIES
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
|
||||
clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \
|
||||
ctags-am distclean distclean-compile distclean-generic \
|
||||
distclean-libtool distclean-tags distdir dvi dvi-am html \
|
||||
html-am info info-am install install-am install-data \
|
||||
install-data-am install-dist_assheadersHEADERS install-dvi \
|
||||
install-dvi-am install-exec install-exec-am install-html \
|
||||
install-html-am install-info install-info-am \
|
||||
install-libLTLIBRARIES install-man install-pdf install-pdf-am \
|
||||
install-ps install-ps-am install-strip installcheck \
|
||||
installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
tags tags-am uninstall uninstall-am \
|
||||
uninstall-dist_assheadersHEADERS uninstall-libLTLIBRARIES
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
.asm.lo:
|
||||
$(nasm_verbose)$(LIBTOOL) $(AM_V_lt) --tag=CC --mode=compile $(AS) $(ASFLAGS) -I$(srcdir)/ -o $@ $< -prefer-non-pic
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,659 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
||||
* Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBASS_ASS_H
|
||||
#define LIBASS_ASS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "ass_types.h"
|
||||
|
||||
#define LIBASS_VERSION 0x01400000
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A linked list of images produced by an ass renderer.
|
||||
*
|
||||
* These images have to be rendered in-order for the correct screen
|
||||
* composition. The libass renderer clips these bitmaps to the frame size.
|
||||
* w/h can be zero, in this case the bitmap should not be rendered at all.
|
||||
* The last bitmap row is not guaranteed to be padded up to stride size,
|
||||
* e.g. in the worst case a bitmap has the size stride * (h - 1) + w.
|
||||
*/
|
||||
typedef struct ass_image {
|
||||
int w, h; // Bitmap width/height
|
||||
int stride; // Bitmap stride
|
||||
unsigned char *bitmap; // 1bpp stride*h alpha buffer
|
||||
// Note: the last row may not be padded to
|
||||
// bitmap stride!
|
||||
uint32_t color; // Bitmap color and alpha, RGBA
|
||||
int dst_x, dst_y; // Bitmap placement inside the video frame
|
||||
|
||||
struct ass_image *next; // Next image, or NULL
|
||||
|
||||
enum {
|
||||
IMAGE_TYPE_CHARACTER,
|
||||
IMAGE_TYPE_OUTLINE,
|
||||
IMAGE_TYPE_SHADOW
|
||||
} type;
|
||||
|
||||
} ASS_Image;
|
||||
|
||||
/*
|
||||
* Hinting type. (see ass_set_hinting below)
|
||||
*
|
||||
* Setting hinting to anything but ASS_HINTING_NONE will put libass in a mode
|
||||
* that reduces compatibility with vsfilter and many ASS scripts. The main
|
||||
* problem is that hinting conflicts with smooth scaling, which precludes
|
||||
* animations and precise positioning.
|
||||
*
|
||||
* In other words, enabling hinting might break some scripts severely.
|
||||
*
|
||||
* FreeType's native hinter is still buggy sometimes and it is recommended
|
||||
* to use the light autohinter, ASS_HINTING_LIGHT, instead. For best
|
||||
* compatibility with problematic fonts, disable hinting.
|
||||
*/
|
||||
typedef enum {
|
||||
ASS_HINTING_NONE = 0,
|
||||
ASS_HINTING_LIGHT,
|
||||
ASS_HINTING_NORMAL,
|
||||
ASS_HINTING_NATIVE
|
||||
} ASS_Hinting;
|
||||
|
||||
/**
|
||||
* \brief Text shaping levels.
|
||||
*
|
||||
* SIMPLE is a fast, font-agnostic shaper that can do only substitutions.
|
||||
* COMPLEX is a slower shaper using OpenType for substitutions and positioning.
|
||||
*
|
||||
* libass uses the best shaper available by default.
|
||||
*/
|
||||
typedef enum {
|
||||
ASS_SHAPING_SIMPLE = 0,
|
||||
ASS_SHAPING_COMPLEX
|
||||
} ASS_ShapingLevel;
|
||||
|
||||
/**
|
||||
* \brief Style override options. See
|
||||
* ass_set_selective_style_override_enabled() for details.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* Default mode (with no other bits set). All selective override features
|
||||
* as well as the style set with ass_set_selective_style_override() are
|
||||
* disabled, but traditional overrides like ass_set_font_scale() are
|
||||
* applied unconditionally.
|
||||
*/
|
||||
ASS_OVERRIDE_DEFAULT = 0,
|
||||
/**
|
||||
* Apply the style as set with ass_set_selective_style_override() on events
|
||||
* which look like dialogue. Other style overrides are also applied this
|
||||
* way, except ass_set_font_scale(). How ass_set_font_scale() is applied
|
||||
* depends on the ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE flag.
|
||||
*
|
||||
* This is equivalent to setting all of the following bits:
|
||||
*
|
||||
* ASS_OVERRIDE_BIT_FONT_NAME
|
||||
* ASS_OVERRIDE_BIT_FONT_SIZE_FIELDS
|
||||
* ASS_OVERRIDE_BIT_COLORS
|
||||
* ASS_OVERRIDE_BIT_BORDER
|
||||
* ASS_OVERRIDE_BIT_ATTRIBUTES
|
||||
*/
|
||||
ASS_OVERRIDE_BIT_STYLE = 1 << 0,
|
||||
/**
|
||||
* Apply ass_set_font_scale() only on events which look like dialogue.
|
||||
* If not set, the font scale is applied to all events. (The behavior and
|
||||
* name of this flag are unintuitive, but exist for compatibility)
|
||||
*/
|
||||
ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE = 1 << 1,
|
||||
/**
|
||||
* Old alias for ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE. Deprecated. Do not use.
|
||||
*/
|
||||
ASS_OVERRIDE_BIT_FONT_SIZE = 1 << 1,
|
||||
/**
|
||||
* On dialogue events override: FontSize, Spacing, Blur, ScaleX, ScaleY
|
||||
*/
|
||||
ASS_OVERRIDE_BIT_FONT_SIZE_FIELDS = 1 << 2,
|
||||
/**
|
||||
* On dialogue events override: FontName, treat_fontname_as_pattern
|
||||
*/
|
||||
ASS_OVERRIDE_BIT_FONT_NAME = 1 << 3,
|
||||
/**
|
||||
* On dialogue events override: PrimaryColour, SecondaryColour, OutlineColour, BackColour
|
||||
*/
|
||||
ASS_OVERRIDE_BIT_COLORS = 1 << 4,
|
||||
/**
|
||||
* On dialogue events override: Bold, Italic, Underline, StrikeOut
|
||||
*/
|
||||
ASS_OVERRIDE_BIT_ATTRIBUTES = 1 << 5,
|
||||
/**
|
||||
* On dialogue events override: BorderStyle, Outline, Shadow
|
||||
*/
|
||||
ASS_OVERRIDE_BIT_BORDER = 1 << 6,
|
||||
/**
|
||||
* On dialogue events override: Alignment
|
||||
*/
|
||||
ASS_OVERRIDE_BIT_ALIGNMENT = 1 << 7,
|
||||
/**
|
||||
* On dialogue events override: MarginL, MarginR, MarginV
|
||||
*/
|
||||
ASS_OVERRIDE_BIT_MARGINS = 1 << 8,
|
||||
/**
|
||||
* Unconditionally replace all fields of all styles with the one provided
|
||||
* with ass_set_selective_style_override().
|
||||
* Does not apply ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE.
|
||||
* Add ASS_OVERRIDE_BIT_FONT_SIZE_FIELDS and ASS_OVERRIDE_BIT_BORDER if
|
||||
* you want FontSize, Spacing, Outline, Shadow to be scaled to the script
|
||||
* resolution given by the ASS_Track.
|
||||
*/
|
||||
ASS_OVERRIDE_FULL_STYLE = 1 << 9,
|
||||
/**
|
||||
* On dialogue events override: Justify
|
||||
*/
|
||||
ASS_OVERRIDE_BIT_JUSTIFY = 1 << 10,
|
||||
} ASS_OverrideBits;
|
||||
|
||||
/**
|
||||
* \brief Return the version of library. This returns the value LIBASS_VERSION
|
||||
* was set to when the library was compiled.
|
||||
* \return library version
|
||||
*/
|
||||
int ass_library_version(void);
|
||||
|
||||
/**
|
||||
* \brief Default Font provider to load fonts in libass' database
|
||||
*
|
||||
* NONE don't use any default font provider for font lookup
|
||||
* AUTODETECT use the first available font provider
|
||||
* CORETEXT force a CoreText based font provider (OS X only)
|
||||
* FONTCONFIG force a Fontconfig based font provider
|
||||
*
|
||||
* libass uses the best shaper available by default.
|
||||
*/
|
||||
typedef enum {
|
||||
ASS_FONTPROVIDER_NONE = 0,
|
||||
ASS_FONTPROVIDER_AUTODETECT = 1,
|
||||
ASS_FONTPROVIDER_CORETEXT,
|
||||
ASS_FONTPROVIDER_FONTCONFIG,
|
||||
ASS_FONTPROVIDER_DIRECTWRITE,
|
||||
} ASS_DefaultFontProvider;
|
||||
|
||||
/**
|
||||
* \brief Initialize the library.
|
||||
* \return library handle or NULL if failed
|
||||
*/
|
||||
ASS_Library *ass_library_init(void);
|
||||
|
||||
/**
|
||||
* \brief Finalize the library
|
||||
* \param priv library handle
|
||||
*/
|
||||
void ass_library_done(ASS_Library *priv);
|
||||
|
||||
/**
|
||||
* \brief Set additional fonts directory.
|
||||
* Optional directory that will be scanned for fonts recursively. The fonts
|
||||
* found are used for font lookup.
|
||||
* NOTE: A valid font directory is not needed to support embedded fonts.
|
||||
*
|
||||
* \param priv library handle
|
||||
* \param fonts_dir directory with additional fonts
|
||||
*/
|
||||
void ass_set_fonts_dir(ASS_Library *priv, const char *fonts_dir);
|
||||
|
||||
/**
|
||||
* \brief Whether fonts should be extracted from track data.
|
||||
* \param priv library handle
|
||||
* \param extract whether to extract fonts
|
||||
*/
|
||||
void ass_set_extract_fonts(ASS_Library *priv, int extract);
|
||||
|
||||
/**
|
||||
* \brief Register style overrides with a library instance.
|
||||
* The overrides should have the form [Style.]Param=Value, e.g.
|
||||
* SomeStyle.Font=Arial
|
||||
* ScaledBorderAndShadow=yes
|
||||
*
|
||||
* \param priv library handle
|
||||
* \param list NULL-terminated list of strings
|
||||
*/
|
||||
void ass_set_style_overrides(ASS_Library *priv, char **list);
|
||||
|
||||
/**
|
||||
* \brief Explicitly process style overrides for a track.
|
||||
* \param track track handle
|
||||
*/
|
||||
void ass_process_force_style(ASS_Track *track);
|
||||
|
||||
/**
|
||||
* \brief Register a callback for debug/info messages.
|
||||
* If a callback is registered, it is called for every message emitted by
|
||||
* libass. The callback receives a format string and a list of arguments,
|
||||
* to be used for the printf family of functions. Additionally, a log level
|
||||
* from 0 (FATAL errors) to 7 (verbose DEBUG) is passed. Usually, level 5
|
||||
* should be used by applications.
|
||||
* If no callback is set, all messages level < 5 are printed to stderr,
|
||||
* prefixed with [ass].
|
||||
*
|
||||
* \param priv library handle
|
||||
* \param msg_cb pointer to callback function
|
||||
* \param data additional data, will be passed to callback
|
||||
*/
|
||||
void ass_set_message_cb(ASS_Library *priv, void (*msg_cb)
|
||||
(int level, const char *fmt, va_list args, void *data),
|
||||
void *data);
|
||||
|
||||
/**
|
||||
* \brief Initialize the renderer.
|
||||
* \param priv library handle
|
||||
* \return renderer handle or NULL if failed
|
||||
*/
|
||||
ASS_Renderer *ass_renderer_init(ASS_Library *);
|
||||
|
||||
/**
|
||||
* \brief Finalize the renderer.
|
||||
* \param priv renderer handle
|
||||
*/
|
||||
void ass_renderer_done(ASS_Renderer *priv);
|
||||
|
||||
/**
|
||||
* \brief Set the frame size in pixels, including margins.
|
||||
* The renderer will never return images that are outside of the frame area.
|
||||
* The value set with this function can influence the pixel aspect ratio used
|
||||
* for rendering. If the frame size doesn't equal to the video size, you may
|
||||
* have to use ass_set_pixel_aspect().
|
||||
* @see ass_set_pixel_aspect()
|
||||
* @see ass_set_margins()
|
||||
* \param priv renderer handle
|
||||
* \param w width
|
||||
* \param h height
|
||||
*/
|
||||
void ass_set_frame_size(ASS_Renderer *priv, int w, int h);
|
||||
|
||||
/**
|
||||
* \brief Set the source image size in pixels.
|
||||
* This is used to calculate the source aspect ratio and the blur scale.
|
||||
* The source image size can be reset to default by setting w and h to 0.
|
||||
* The value set with this function can influence the pixel aspect ratio used
|
||||
* for rendering.
|
||||
* @see ass_set_pixel_aspect()
|
||||
* \param priv renderer handle
|
||||
* \param w width
|
||||
* \param h height
|
||||
*/
|
||||
void ass_set_storage_size(ASS_Renderer *priv, int w, int h);
|
||||
|
||||
/**
|
||||
* \brief Set shaping level. This is merely a hint, the renderer will use
|
||||
* whatever is available if the request cannot be fulfilled.
|
||||
* \param level shaping level
|
||||
*/
|
||||
void ass_set_shaper(ASS_Renderer *priv, ASS_ShapingLevel level);
|
||||
|
||||
/**
|
||||
* \brief Set frame margins. These values may be negative if pan-and-scan
|
||||
* is used. The margins are in pixels. Each value specifies the distance from
|
||||
* the video rectangle to the renderer frame. If a given margin value is
|
||||
* positive, there will be free space between renderer frame and video area.
|
||||
* If a given margin value is negative, the frame is inside the video, i.e.
|
||||
* the video has been cropped.
|
||||
*
|
||||
* The renderer will try to keep subtitles inside the frame area. If possible,
|
||||
* text is layout so that it is inside the cropped area. Subtitle events
|
||||
* that can't be moved are cropped against the frame area.
|
||||
*
|
||||
* ass_set_use_margins() can be used to allow libass to render subtitles into
|
||||
* the empty areas if margins are positive, i.e. the video area is smaller than
|
||||
* the frame. (Traditionally, this has been used to show subtitles in
|
||||
* the bottom "black bar" between video bottom screen border when playing 16:9
|
||||
* video on a 4:3 screen.)
|
||||
*
|
||||
* When using this function, it is recommended to calculate and set your own
|
||||
* aspect ratio with ass_set_pixel_aspect(), as the defaults won't make any
|
||||
* sense.
|
||||
* @see ass_set_pixel_aspect()
|
||||
* \param priv renderer handle
|
||||
* \param t top margin
|
||||
* \param b bottom margin
|
||||
* \param l left margin
|
||||
* \param r right margin
|
||||
*/
|
||||
void ass_set_margins(ASS_Renderer *priv, int t, int b, int l, int r);
|
||||
|
||||
/**
|
||||
* \brief Whether margins should be used for placing regular events.
|
||||
* \param priv renderer handle
|
||||
* \param use whether to use the margins
|
||||
*/
|
||||
void ass_set_use_margins(ASS_Renderer *priv, int use);
|
||||
|
||||
/**
|
||||
* \brief Set pixel aspect ratio correction.
|
||||
* This is the ratio of pixel width to pixel height.
|
||||
*
|
||||
* Generally, this is (s_w / s_h) / (d_w / d_h), where s_w and s_h is the
|
||||
* video storage size, and d_w and d_h is the video display size. (Display
|
||||
* and storage size can be different for anamorphic video, such as DVDs.)
|
||||
*
|
||||
* If the pixel aspect ratio is 0, or if the aspect ratio has never been set
|
||||
* by calling this function, libass will calculate a default pixel aspect ratio
|
||||
* out of values set with ass_set_frame_size() and ass_set_storage_size(). Note
|
||||
* that this is useful only if the frame size corresponds to the video display
|
||||
* size. Keep in mind that the margins set with ass_set_margins() are ignored
|
||||
* for aspect ratio calculations as well.
|
||||
* If the storage size has not been set, a pixel aspect ratio of 1 is assumed.
|
||||
* \param priv renderer handle
|
||||
* \param par pixel aspect ratio (1.0 means square pixels, 0 means default)
|
||||
*/
|
||||
void ass_set_pixel_aspect(ASS_Renderer *priv, double par);
|
||||
|
||||
/**
|
||||
* \brief Set aspect ratio parameters.
|
||||
* This calls ass_set_pixel_aspect(priv, dar / sar).
|
||||
* @deprecated New code should use ass_set_pixel_aspect().
|
||||
* \param priv renderer handle
|
||||
* \param dar display aspect ratio (DAR), prescaled for output PAR
|
||||
* \param sar storage aspect ratio (SAR)
|
||||
*/
|
||||
void ass_set_aspect_ratio(ASS_Renderer *priv, double dar, double sar);
|
||||
|
||||
/**
|
||||
* \brief Set a fixed font scaling factor.
|
||||
* \param priv renderer handle
|
||||
* \param font_scale scaling factor, default is 1.0
|
||||
*/
|
||||
void ass_set_font_scale(ASS_Renderer *priv, double font_scale);
|
||||
|
||||
/**
|
||||
* \brief Set font hinting method.
|
||||
* \param priv renderer handle
|
||||
* \param ht hinting method
|
||||
*/
|
||||
void ass_set_hinting(ASS_Renderer *priv, ASS_Hinting ht);
|
||||
|
||||
/**
|
||||
* \brief Set line spacing. Will not be scaled with frame size.
|
||||
* \param priv renderer handle
|
||||
* \param line_spacing line spacing in pixels
|
||||
*/
|
||||
void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing);
|
||||
|
||||
/**
|
||||
* \brief Set vertical line position.
|
||||
* \param priv renderer handle
|
||||
* \param line_position vertical line position of subtitles in percent
|
||||
* (0-100: 0 = on the bottom (default), 100 = on top)
|
||||
*/
|
||||
void ass_set_line_position(ASS_Renderer *priv, double line_position);
|
||||
|
||||
/**
|
||||
* \brief Get the list of available font providers. The output array
|
||||
* is allocated with malloc and can be released with free(). If an
|
||||
* allocation error occurs, size is set to (size_t)-1.
|
||||
* \param priv library handle
|
||||
* \param providers output, list of default providers (malloc'ed array)
|
||||
* \param size output, number of providers
|
||||
* \return list of available font providers (user owns the returned array)
|
||||
*/
|
||||
void ass_get_available_font_providers(ASS_Library *priv,
|
||||
ASS_DefaultFontProvider **providers,
|
||||
size_t *size);
|
||||
|
||||
/**
|
||||
* \brief Set font lookup defaults.
|
||||
* \param default_font path to default font to use. Must be supplied if
|
||||
* fontconfig is disabled or unavailable.
|
||||
* \param default_family fallback font family for fontconfig, or NULL
|
||||
* \param dfp which font provider to use (one of ASS_DefaultFontProvider). In
|
||||
* older libass version, this could be 0 or 1, where 1 enabled fontconfig.
|
||||
* Newer relases also accept 0 (ASS_FONTPROVIDER_NONE) and 1
|
||||
* (ASS_FONTPROVIDER_AUTODETECT), which is almost backward-compatible.
|
||||
* If the requested fontprovider does not exist or fails to initialize, the
|
||||
* behavior is the same as when ASS_FONTPROVIDER_NONE was passed.
|
||||
* \param config path to fontconfig configuration file, or NULL. Only relevant
|
||||
* if fontconfig is used.
|
||||
* \param update whether fontconfig cache should be built/updated now. Only
|
||||
* relevant if fontconfig is used.
|
||||
*
|
||||
* NOTE: font lookup must be configured before an ASS_Renderer can be used.
|
||||
*/
|
||||
void ass_set_fonts(ASS_Renderer *priv, const char *default_font,
|
||||
const char *default_family, int dfp,
|
||||
const char *config, int update);
|
||||
|
||||
/**
|
||||
* \brief Set selective style override mode.
|
||||
* If enabled, the renderer attempts to override the ASS script's styling of
|
||||
* normal subtitles, without affecting explicitly positioned text. If an event
|
||||
* looks like a normal subtitle, parts of the font style are copied from the
|
||||
* user style set with ass_set_selective_style_override().
|
||||
* Warning: the heuristic used for deciding when to override the style is rather
|
||||
* rough, and enabling this option can lead to incorrectly rendered
|
||||
* subtitles. Since the ASS format doesn't have any support for
|
||||
* allowing end-users to customize subtitle styling, this feature can
|
||||
* only be implemented on "best effort" basis, and has to rely on
|
||||
* heuristics that can easily break.
|
||||
* \param priv renderer handle
|
||||
* \param bits bit mask comprised of ASS_OverrideBits values.
|
||||
*/
|
||||
void ass_set_selective_style_override_enabled(ASS_Renderer *priv, int bits);
|
||||
|
||||
/**
|
||||
* \brief Set style for selective style override.
|
||||
* See ass_set_selective_style_override_enabled().
|
||||
* \param style style settings to use if override is enabled. Applications
|
||||
* should initialize it with {0} before setting fields. Strings will be copied
|
||||
* by the function.
|
||||
*/
|
||||
void ass_set_selective_style_override(ASS_Renderer *priv, ASS_Style *style);
|
||||
|
||||
/**
|
||||
* \brief This is a stub and does nothing. Old documentation: Update/build font
|
||||
* cache. This needs to be called if it was disabled when ass_set_fonts was set.
|
||||
*
|
||||
* \param priv renderer handle
|
||||
* \return success
|
||||
*/
|
||||
int ass_fonts_update(ASS_Renderer *priv);
|
||||
|
||||
/**
|
||||
* \brief Set hard cache limits. Do not set, or set to zero, for reasonable
|
||||
* defaults.
|
||||
*
|
||||
* \param priv renderer handle
|
||||
* \param glyph_max maximum number of cached glyphs
|
||||
* \param bitmap_max_size maximum bitmap cache size (in MB)
|
||||
*/
|
||||
void ass_set_cache_limits(ASS_Renderer *priv, int glyph_max,
|
||||
int bitmap_max_size);
|
||||
|
||||
/**
|
||||
* \brief Render a frame, producing a list of ASS_Image.
|
||||
* \param priv renderer handle
|
||||
* \param track subtitle track
|
||||
* \param now video timestamp in milliseconds
|
||||
* \param detect_change compare to the previous call and set to 1
|
||||
* if positions changed, or set to 2 if content changed.
|
||||
*/
|
||||
ASS_Image *ass_render_frame(ASS_Renderer *priv, ASS_Track *track,
|
||||
long long now, int *detect_change);
|
||||
|
||||
|
||||
/*
|
||||
* The following functions operate on track objects and do not need
|
||||
* an ass_renderer
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Allocate a new empty track object.
|
||||
* \param library handle
|
||||
* \return pointer to empty track
|
||||
*/
|
||||
ASS_Track *ass_new_track(ASS_Library *);
|
||||
|
||||
/**
|
||||
* \brief Deallocate track and all its child objects (styles and events).
|
||||
* \param track track to deallocate
|
||||
*/
|
||||
void ass_free_track(ASS_Track *track);
|
||||
|
||||
/**
|
||||
* \brief Allocate new style.
|
||||
* \param track track
|
||||
* \return newly allocated style id
|
||||
*/
|
||||
int ass_alloc_style(ASS_Track *track);
|
||||
|
||||
/**
|
||||
* \brief Allocate new event.
|
||||
* \param track track
|
||||
* \return newly allocated event id
|
||||
*/
|
||||
int ass_alloc_event(ASS_Track *track);
|
||||
|
||||
/**
|
||||
* \brief Delete a style.
|
||||
* \param track track
|
||||
* \param sid style id
|
||||
* Deallocates style data. Does not modify track->n_styles.
|
||||
*/
|
||||
void ass_free_style(ASS_Track *track, int sid);
|
||||
|
||||
/**
|
||||
* \brief Delete an event.
|
||||
* \param track track
|
||||
* \param eid event id
|
||||
* Deallocates event data. Does not modify track->n_events.
|
||||
*/
|
||||
void ass_free_event(ASS_Track *track, int eid);
|
||||
|
||||
/**
|
||||
* \brief Parse a chunk of subtitle stream data.
|
||||
* \param track track
|
||||
* \param data string to parse
|
||||
* \param size length of data
|
||||
*/
|
||||
void ass_process_data(ASS_Track *track, char *data, int size);
|
||||
|
||||
/**
|
||||
* \brief Parse Codec Private section of the subtitle stream, in Matroska
|
||||
* format. See the Matroska specification for details.
|
||||
* \param track target track
|
||||
* \param data string to parse
|
||||
* \param size length of data
|
||||
*/
|
||||
void ass_process_codec_private(ASS_Track *track, char *data, int size);
|
||||
|
||||
/**
|
||||
* \brief Parse a chunk of subtitle stream data. A chunk contains exactly one
|
||||
* event in Matroska format. See the Matroska specification for details.
|
||||
* In later libass versions (since LIBASS_VERSION==0x01300001), using this
|
||||
* function means you agree not to modify events manually, or using other
|
||||
* functions manipulating the event list like ass_process_data(). If you do
|
||||
* anyway, the internal duplicate checking might break. Calling
|
||||
* ass_flush_events() is still allowed.
|
||||
* \param track track
|
||||
* \param data string to parse
|
||||
* \param size length of data
|
||||
* \param timecode starting time of the event (milliseconds)
|
||||
* \param duration duration of the event (milliseconds)
|
||||
*/
|
||||
void ass_process_chunk(ASS_Track *track, char *data, int size,
|
||||
long long timecode, long long duration);
|
||||
|
||||
/**
|
||||
* \brief Set whether the ReadOrder field when processing a packet with
|
||||
* ass_process_chunk() should be used for eliminating duplicates.
|
||||
* \param check_readorder 0 means do not try to eliminate duplicates; 1 means
|
||||
* use the ReadOrder field embedded in the packet as unique identifier, and
|
||||
* discard the packet if there was already a packet with the same ReadOrder.
|
||||
* Other values are undefined.
|
||||
* If this function is not called, the default value is 1.
|
||||
*/
|
||||
void ass_set_check_readorder(ASS_Track *track, int check_readorder);
|
||||
|
||||
/**
|
||||
* \brief Flush buffered events.
|
||||
* \param track track
|
||||
*/
|
||||
void ass_flush_events(ASS_Track *track);
|
||||
|
||||
/**
|
||||
* \brief Read subtitles from file.
|
||||
* \param library library handle
|
||||
* \param fname file name
|
||||
* \param codepage encoding (iconv format)
|
||||
* \return newly allocated track
|
||||
*/
|
||||
ASS_Track *ass_read_file(ASS_Library *library, char *fname,
|
||||
char *codepage);
|
||||
|
||||
/**
|
||||
* \brief Read subtitles from memory.
|
||||
* \param library library handle
|
||||
* \param buf pointer to subtitles text
|
||||
* \param bufsize size of buffer
|
||||
* \param codepage encoding (iconv format)
|
||||
* \return newly allocated track
|
||||
*/
|
||||
ASS_Track *ass_read_memory(ASS_Library *library, char *buf,
|
||||
size_t bufsize, char *codepage);
|
||||
/**
|
||||
* \brief Read styles from file into already initialized track.
|
||||
* \param fname file name
|
||||
* \param codepage encoding (iconv format)
|
||||
* \return 0 on success
|
||||
*/
|
||||
int ass_read_styles(ASS_Track *track, char *fname, char *codepage);
|
||||
|
||||
/**
|
||||
* \brief Add a memory font.
|
||||
* \param library library handle
|
||||
* \param name attachment name
|
||||
* \param data binary font data
|
||||
* \param data_size data size
|
||||
*/
|
||||
void ass_add_font(ASS_Library *library, char *name, char *data,
|
||||
int data_size);
|
||||
|
||||
/**
|
||||
* \brief Remove all fonts stored in an ass_library object.
|
||||
* \param library library handle
|
||||
*/
|
||||
void ass_clear_fonts(ASS_Library *library);
|
||||
|
||||
/**
|
||||
* \brief Calculates timeshift from now to the start of some other subtitle
|
||||
* event, depending on movement parameter.
|
||||
* \param track subtitle track
|
||||
* \param now current time in milliseconds
|
||||
* \param movement how many events to skip from the one currently displayed
|
||||
* +2 means "the one after the next", -1 means "previous"
|
||||
* \return timeshift in milliseconds
|
||||
*/
|
||||
long long ass_step_sub(ASS_Track *track, long long now, int movement);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LIBASS_ASS_H */
|
|
@ -0,0 +1,517 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
||||
* Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx>
|
||||
* Copyright (c) 2011-2014, Yu Zhuohuang <yuzhuohuang@qq.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ass_compat.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_GLYPH_H
|
||||
#include FT_OUTLINE_H
|
||||
|
||||
#include "ass_utils.h"
|
||||
#include "ass_outline.h"
|
||||
#include "ass_bitmap.h"
|
||||
#include "ass_render.h"
|
||||
|
||||
|
||||
#define ALIGN C_ALIGN_ORDER
|
||||
#define DECORATE(func) ass_##func##_c
|
||||
#include "ass_func_template.h"
|
||||
#undef ALIGN
|
||||
#undef DECORATE
|
||||
|
||||
#if (defined(__i386__) || defined(__x86_64__)) && CONFIG_ASM
|
||||
|
||||
#define ALIGN 4
|
||||
#define DECORATE(func) ass_##func##_sse2
|
||||
#include "ass_func_template.h"
|
||||
#undef ALIGN
|
||||
#undef DECORATE
|
||||
|
||||
#define ALIGN 5
|
||||
#define DECORATE(func) ass_##func##_avx2
|
||||
#include "ass_func_template.h"
|
||||
#undef ALIGN
|
||||
#undef DECORATE
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void ass_synth_blur(const BitmapEngine *engine, int opaque_box, int be,
|
||||
double blur_radius, Bitmap *bm_g, Bitmap *bm_o)
|
||||
{
|
||||
bool blur_g = !bm_o || opaque_box;
|
||||
if (blur_g && !bm_g)
|
||||
return;
|
||||
|
||||
// Apply gaussian blur
|
||||
double r2 = blur_radius * blur_radius / log(256);
|
||||
if (r2 > 0.001) {
|
||||
if (bm_o)
|
||||
ass_gaussian_blur(engine, bm_o, r2);
|
||||
if (blur_g)
|
||||
ass_gaussian_blur(engine, bm_g, r2);
|
||||
}
|
||||
|
||||
// Apply box blur (multiple passes, if requested)
|
||||
if (be) {
|
||||
size_t size_o = 0, size_g = 0;
|
||||
if (bm_o)
|
||||
size_o = sizeof(uint16_t) * bm_o->stride * 2;
|
||||
if (blur_g)
|
||||
size_g = sizeof(uint16_t) * bm_g->stride * 2;
|
||||
size_t size = FFMAX(size_o, size_g);
|
||||
uint16_t *tmp = size ? ass_aligned_alloc(32, size, false) : NULL;
|
||||
if (!tmp)
|
||||
return;
|
||||
if (bm_o) {
|
||||
unsigned passes = be;
|
||||
unsigned w = bm_o->w;
|
||||
unsigned h = bm_o->h;
|
||||
unsigned stride = bm_o->stride;
|
||||
unsigned char *buf = bm_o->buffer;
|
||||
if(w && h){
|
||||
if(passes > 1){
|
||||
be_blur_pre(buf, w, h, stride);
|
||||
while(--passes){
|
||||
memset(tmp, 0, stride * 2);
|
||||
engine->be_blur(buf, w, h, stride, tmp);
|
||||
}
|
||||
be_blur_post(buf, w, h, stride);
|
||||
}
|
||||
memset(tmp, 0, stride * 2);
|
||||
engine->be_blur(buf, w, h, stride, tmp);
|
||||
}
|
||||
}
|
||||
if (blur_g) {
|
||||
unsigned passes = be;
|
||||
unsigned w = bm_g->w;
|
||||
unsigned h = bm_g->h;
|
||||
unsigned stride = bm_g->stride;
|
||||
unsigned char *buf = bm_g->buffer;
|
||||
if(w && h){
|
||||
if(passes > 1){
|
||||
be_blur_pre(buf, w, h, stride);
|
||||
while(--passes){
|
||||
memset(tmp, 0, stride * 2);
|
||||
engine->be_blur(buf, w, h, stride, tmp);
|
||||
}
|
||||
be_blur_post(buf, w, h, stride);
|
||||
}
|
||||
memset(tmp, 0, stride * 2);
|
||||
engine->be_blur(buf, w, h, stride, tmp);
|
||||
}
|
||||
}
|
||||
ass_aligned_free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static bool alloc_bitmap_buffer(const BitmapEngine *engine, Bitmap *bm, int w, int h,
|
||||
bool zero)
|
||||
{
|
||||
unsigned align = 1 << engine->align_order;
|
||||
size_t s = ass_align(align, w);
|
||||
// Too often we use ints as offset for bitmaps => use INT_MAX.
|
||||
if (s > (INT_MAX - 32) / FFMAX(h, 1))
|
||||
return false;
|
||||
uint8_t *buf = ass_aligned_alloc(align, s * h + 32, zero);
|
||||
if (!buf)
|
||||
return false;
|
||||
bm->w = w;
|
||||
bm->h = h;
|
||||
bm->stride = s;
|
||||
bm->buffer = buf;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bitmap *alloc_bitmap(const BitmapEngine *engine, int w, int h, bool zero)
|
||||
{
|
||||
Bitmap *bm = malloc(sizeof(Bitmap));
|
||||
if (!bm)
|
||||
return NULL;
|
||||
if (!alloc_bitmap_buffer(engine, bm, w, h, zero)) {
|
||||
free(bm);
|
||||
return NULL;
|
||||
}
|
||||
bm->left = bm->top = 0;
|
||||
return bm;
|
||||
}
|
||||
|
||||
bool realloc_bitmap(const BitmapEngine *engine, Bitmap *bm, int w, int h)
|
||||
{
|
||||
uint8_t *old = bm->buffer;
|
||||
if (!alloc_bitmap_buffer(engine, bm, w, h, false))
|
||||
return false;
|
||||
ass_aligned_free(old);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ass_free_bitmap(Bitmap *bm)
|
||||
{
|
||||
if (bm)
|
||||
ass_aligned_free(bm->buffer);
|
||||
free(bm);
|
||||
}
|
||||
|
||||
Bitmap *copy_bitmap(const BitmapEngine *engine, const Bitmap *src)
|
||||
{
|
||||
Bitmap *dst = alloc_bitmap(engine, src->w, src->h, false);
|
||||
if (!dst)
|
||||
return NULL;
|
||||
dst->left = src->left;
|
||||
dst->top = src->top;
|
||||
memcpy(dst->buffer, src->buffer, src->stride * src->h);
|
||||
return dst;
|
||||
}
|
||||
|
||||
Bitmap *outline_to_bitmap(ASS_Renderer *render_priv,
|
||||
ASS_Outline *outline1, ASS_Outline *outline2,
|
||||
int bord)
|
||||
{
|
||||
RasterizerData *rst = &render_priv->rasterizer;
|
||||
if (outline1 && !rasterizer_set_outline(rst, outline1, false)) {
|
||||
ass_msg(render_priv->library, MSGL_WARN, "Failed to process glyph outline!\n");
|
||||
return NULL;
|
||||
}
|
||||
if (outline2 && !rasterizer_set_outline(rst, outline2, !!outline1)) {
|
||||
ass_msg(render_priv->library, MSGL_WARN, "Failed to process glyph outline!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bord < 0 || bord > INT_MAX / 2)
|
||||
return NULL;
|
||||
if (rst->bbox.x_max > INT_MAX - 63 || rst->bbox.y_max > INT_MAX - 63)
|
||||
return NULL;
|
||||
|
||||
int x_min = rst->bbox.x_min >> 6;
|
||||
int y_min = rst->bbox.y_min >> 6;
|
||||
int x_max = (rst->bbox.x_max + 63) >> 6;
|
||||
int y_max = (rst->bbox.y_max + 63) >> 6;
|
||||
int w = x_max - x_min;
|
||||
int h = y_max - y_min;
|
||||
|
||||
int mask = (1 << render_priv->engine->tile_order) - 1;
|
||||
|
||||
if (w < 0 || h < 0 ||
|
||||
w > INT_MAX - (2 * bord + mask) || h > INT_MAX - (2 * bord + mask)) {
|
||||
ass_msg(render_priv->library, MSGL_WARN, "Glyph bounding box too large: %dx%dpx",
|
||||
w, h);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int tile_w = (w + 2 * bord + mask) & ~mask;
|
||||
int tile_h = (h + 2 * bord + mask) & ~mask;
|
||||
Bitmap *bm = alloc_bitmap(render_priv->engine, tile_w, tile_h, false);
|
||||
if (!bm)
|
||||
return NULL;
|
||||
bm->left = x_min - bord;
|
||||
bm->top = y_min - bord;
|
||||
|
||||
if (!rasterizer_fill(render_priv->engine, rst, bm->buffer,
|
||||
x_min - bord, y_min - bord,
|
||||
bm->stride, tile_h, bm->stride)) {
|
||||
ass_msg(render_priv->library, MSGL_WARN, "Failed to rasterize glyph!\n");
|
||||
ass_free_bitmap(bm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return bm;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief fix outline bitmap
|
||||
*
|
||||
* The glyph bitmap is subtracted from outline bitmap. This way looks much
|
||||
* better in some cases.
|
||||
*/
|
||||
void fix_outline(Bitmap *bm_g, Bitmap *bm_o)
|
||||
{
|
||||
int x, y;
|
||||
const int l = bm_o->left > bm_g->left ? bm_o->left : bm_g->left;
|
||||
const int t = bm_o->top > bm_g->top ? bm_o->top : bm_g->top;
|
||||
const int r =
|
||||
bm_o->left + bm_o->stride <
|
||||
bm_g->left + bm_g->stride ? bm_o->left + bm_o->stride : bm_g->left + bm_g->stride;
|
||||
const int b =
|
||||
bm_o->top + bm_o->h <
|
||||
bm_g->top + bm_g->h ? bm_o->top + bm_o->h : bm_g->top + bm_g->h;
|
||||
|
||||
unsigned char *g =
|
||||
bm_g->buffer + (t - bm_g->top) * bm_g->stride + (l - bm_g->left);
|
||||
unsigned char *o =
|
||||
bm_o->buffer + (t - bm_o->top) * bm_o->stride + (l - bm_o->left);
|
||||
|
||||
for (y = 0; y < b - t; ++y) {
|
||||
for (x = 0; x < r - l; ++x) {
|
||||
unsigned char c_g, c_o;
|
||||
c_g = g[x];
|
||||
c_o = o[x];
|
||||
o[x] = (c_o > c_g) ? c_o - (c_g / 2) : 0;
|
||||
}
|
||||
g += bm_g->stride;
|
||||
o += bm_o->stride;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Shift a bitmap by the fraction of a pixel in x and y direction
|
||||
* expressed in 26.6 fixed point
|
||||
*/
|
||||
void shift_bitmap(Bitmap *bm, int shift_x, int shift_y)
|
||||
{
|
||||
int x, y, b;
|
||||
int w = bm->w;
|
||||
int h = bm->h;
|
||||
int s = bm->stride;
|
||||
unsigned char *buf = bm->buffer;
|
||||
|
||||
assert((shift_x & ~63) == 0 && (shift_y & ~63) == 0);
|
||||
|
||||
// Shift in x direction
|
||||
for (y = 0; y < h; y++) {
|
||||
for (x = w - 1; x > 0; x--) {
|
||||
b = (buf[x + y * s - 1] * shift_x) >> 6;
|
||||
buf[x + y * s - 1] -= b;
|
||||
buf[x + y * s] += b;
|
||||
}
|
||||
}
|
||||
|
||||
// Shift in y direction
|
||||
for (x = 0; x < w; x++) {
|
||||
for (y = h - 1; y > 0; y--) {
|
||||
b = (buf[x + (y - 1) * s] * shift_y) >> 6;
|
||||
buf[x + (y - 1) * s] -= b;
|
||||
buf[x + y * s] += b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Blur with [[1,2,1], [2,4,2], [1,2,1]] kernel
|
||||
* This blur is the same as the one employed by vsfilter.
|
||||
* Pure C implementation.
|
||||
*/
|
||||
void ass_be_blur_c(uint8_t *buf, intptr_t w, intptr_t h,
|
||||
intptr_t stride, uint16_t *tmp)
|
||||
{
|
||||
uint16_t *col_pix_buf = tmp;
|
||||
uint16_t *col_sum_buf = tmp + w;
|
||||
unsigned x, y, old_pix, old_sum, temp1, temp2;
|
||||
uint8_t *src, *dst;
|
||||
memset(tmp, 0, sizeof(uint16_t) * w * 2);
|
||||
y = 0;
|
||||
|
||||
{
|
||||
src=buf+y*stride;
|
||||
|
||||
x = 1;
|
||||
old_pix = src[x-1];
|
||||
old_sum = old_pix;
|
||||
for ( ; x < w; x++) {
|
||||
temp1 = src[x];
|
||||
temp2 = old_pix + temp1;
|
||||
old_pix = temp1;
|
||||
temp1 = old_sum + temp2;
|
||||
old_sum = temp2;
|
||||
col_pix_buf[x-1] = temp1;
|
||||
col_sum_buf[x-1] = temp1;
|
||||
}
|
||||
temp1 = old_sum + old_pix;
|
||||
col_pix_buf[x-1] = temp1;
|
||||
col_sum_buf[x-1] = temp1;
|
||||
}
|
||||
|
||||
for (y++; y < h; y++) {
|
||||
src=buf+y*stride;
|
||||
dst=buf+(y-1)*stride;
|
||||
|
||||
x = 1;
|
||||
old_pix = src[x-1];
|
||||
old_sum = old_pix;
|
||||
for ( ; x < w; x++) {
|
||||
temp1 = src[x];
|
||||
temp2 = old_pix + temp1;
|
||||
old_pix = temp1;
|
||||
temp1 = old_sum + temp2;
|
||||
old_sum = temp2;
|
||||
|
||||
temp2 = col_pix_buf[x-1] + temp1;
|
||||
col_pix_buf[x-1] = temp1;
|
||||
dst[x-1] = (col_sum_buf[x-1] + temp2) >> 4;
|
||||
col_sum_buf[x-1] = temp2;
|
||||
}
|
||||
temp1 = old_sum + old_pix;
|
||||
temp2 = col_pix_buf[x-1] + temp1;
|
||||
col_pix_buf[x-1] = temp1;
|
||||
dst[x-1] = (col_sum_buf[x-1] + temp2) >> 4;
|
||||
col_sum_buf[x-1] = temp2;
|
||||
}
|
||||
|
||||
{
|
||||
dst=buf+(y-1)*stride;
|
||||
for (x = 0; x < w; x++)
|
||||
dst[x] = (col_sum_buf[x] + col_pix_buf[x]) >> 4;
|
||||
}
|
||||
}
|
||||
|
||||
void be_blur_pre(uint8_t *buf, intptr_t w, intptr_t h, intptr_t stride)
|
||||
{
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
// This is equivalent to (value * 64 + 127) / 255 for all
|
||||
// values from 0 to 256 inclusive. Assist vectorizing
|
||||
// compilers by noting that all temporaries fit in 8 bits.
|
||||
buf[y * stride + x] =
|
||||
(uint8_t) ((buf[y * stride + x] >> 1) + 1) >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void be_blur_post(uint8_t *buf, intptr_t w, intptr_t h, intptr_t stride)
|
||||
{
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
// This is equivalent to (value * 255 + 32) / 64 for all values
|
||||
// from 0 to 96 inclusive, and we only care about 0 to 64.
|
||||
uint8_t value = buf[y * stride + x];
|
||||
buf[y * stride + x] = (value << 2) - (value > 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* To find these values, simulate blur on the border between two
|
||||
* half-planes, one zero-filled (background) and the other filled
|
||||
* with the maximum supported value (foreground). Keep incrementing
|
||||
* the \be argument. The necessary padding is the distance by which
|
||||
* the blurred foreground image extends beyond the original border
|
||||
* and into the background. Initially it increases along with \be,
|
||||
* but very soon it grinds to a halt. At some point, the blurred
|
||||
* image actually reaches a stationary point and stays unchanged
|
||||
* forever after, simply _shifting_ by one pixel for each \be
|
||||
* step--moving in the direction of the non-zero half-plane and
|
||||
* thus decreasing the necessary padding (although the large
|
||||
* padding is still needed for intermediate results). In practice,
|
||||
* images are finite rather than infinite like half-planes, but
|
||||
* this can only decrease the required padding. Half-planes filled
|
||||
* with extreme values are the theoretical limit of the worst case.
|
||||
* Make sure to use the right pixel value range in the simulation!
|
||||
*/
|
||||
int be_padding(int be)
|
||||
{
|
||||
if (be <= 3)
|
||||
return be;
|
||||
if (be <= 7)
|
||||
return 4;
|
||||
if (be <= 123)
|
||||
return 5;
|
||||
return FFMAX(128 - be, 0);
|
||||
}
|
||||
|
||||
bool outline_to_bitmap2(ASS_Renderer *render_priv, ASS_Outline *outline,
|
||||
ASS_Outline *border1, ASS_Outline *border2,
|
||||
Bitmap **bm_g, Bitmap **bm_o)
|
||||
{
|
||||
assert(bm_g && bm_o);
|
||||
*bm_g = *bm_o = NULL;
|
||||
|
||||
if (outline && !outline->n_points)
|
||||
outline = NULL;
|
||||
if (border1 && !border1->n_points)
|
||||
border1 = NULL;
|
||||
if (border2 && !border2->n_points)
|
||||
border2 = NULL;
|
||||
|
||||
if (outline) {
|
||||
*bm_g = outline_to_bitmap(render_priv, outline, NULL, 1);
|
||||
if (!*bm_g)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (border1 || border2) {
|
||||
*bm_o = outline_to_bitmap(render_priv, border1, border2, 1);
|
||||
if (!*bm_o) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Add two bitmaps together at a given position
|
||||
* Uses additive blending, clipped to [0,255]. Pure C implementation.
|
||||
*/
|
||||
void ass_add_bitmaps_c(uint8_t *dst, intptr_t dst_stride,
|
||||
uint8_t *src, intptr_t src_stride,
|
||||
intptr_t height, intptr_t width)
|
||||
{
|
||||
unsigned out;
|
||||
uint8_t* end = dst + dst_stride * height;
|
||||
while (dst < end) {
|
||||
for (unsigned j = 0; j < width; ++j) {
|
||||
out = dst[j] + src[j];
|
||||
dst[j] = FFMIN(out, 255);
|
||||
}
|
||||
dst += dst_stride;
|
||||
src += src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void ass_sub_bitmaps_c(uint8_t *dst, intptr_t dst_stride,
|
||||
uint8_t *src, intptr_t src_stride,
|
||||
intptr_t height, intptr_t width)
|
||||
{
|
||||
short out;
|
||||
uint8_t* end = dst + dst_stride * height;
|
||||
while (dst < end) {
|
||||
for (unsigned j = 0; j < width; ++j) {
|
||||
out = dst[j] - src[j];
|
||||
dst[j] = FFMAX(out, 0);
|
||||
}
|
||||
dst += dst_stride;
|
||||
src += src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void ass_mul_bitmaps_c(uint8_t *dst, intptr_t dst_stride,
|
||||
uint8_t *src1, intptr_t src1_stride,
|
||||
uint8_t *src2, intptr_t src2_stride,
|
||||
intptr_t w, intptr_t h)
|
||||
{
|
||||
uint8_t* end = src1 + src1_stride * h;
|
||||
while (src1 < end) {
|
||||
for (unsigned x = 0; x < w; ++x) {
|
||||
dst[x] = (src1[x] * src2[x] + 255) >> 8;
|
||||
}
|
||||
dst += dst_stride;
|
||||
src1 += src1_stride;
|
||||
src2 += src2_stride;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBASS_BITMAP_H
|
||||
#define LIBASS_BITMAP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_GLYPH_H
|
||||
|
||||
#include "ass.h"
|
||||
#include "ass_outline.h"
|
||||
|
||||
|
||||
struct segment;
|
||||
typedef void (*FillSolidTileFunc)(uint8_t *buf, ptrdiff_t stride, int set);
|
||||
typedef void (*FillHalfplaneTileFunc)(uint8_t *buf, ptrdiff_t stride,
|
||||
int32_t a, int32_t b, int64_t c, int32_t scale);
|
||||
typedef void (*FillGenericTileFunc)(uint8_t *buf, ptrdiff_t stride,
|
||||
const struct segment *line, size_t n_lines,
|
||||
int winding);
|
||||
|
||||
typedef void (*BitmapBlendFunc)(uint8_t *dst, intptr_t dst_stride,
|
||||
uint8_t *src, intptr_t src_stride,
|
||||
intptr_t height, intptr_t width);
|
||||
typedef void (*BitmapMulFunc)(uint8_t *dst, intptr_t dst_stride,
|
||||
uint8_t *src1, intptr_t src1_stride,
|
||||
uint8_t *src2, intptr_t src2_stride,
|
||||
intptr_t width, intptr_t height);
|
||||
|
||||
typedef void (*BeBlurFunc)(uint8_t *buf, intptr_t w, intptr_t h,
|
||||
intptr_t stride, uint16_t *tmp);
|
||||
|
||||
// intermediate bitmaps represented as sets of verical stripes of int16_t[alignment / 2]
|
||||
typedef void (*Convert8to16Func)(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride,
|
||||
uintptr_t width, uintptr_t height);
|
||||
typedef void (*Convert16to8Func)(uint8_t *dst, ptrdiff_t dst_stride, const int16_t *src,
|
||||
uintptr_t width, uintptr_t height);
|
||||
typedef void (*FilterFunc)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height);
|
||||
typedef void (*ParamFilterFunc)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height,
|
||||
const int16_t *param);
|
||||
|
||||
#define C_ALIGN_ORDER 5
|
||||
|
||||
typedef struct {
|
||||
int align_order; // log2(alignment)
|
||||
|
||||
// rasterizer functions
|
||||
int tile_order; // log2(tile_size)
|
||||
FillSolidTileFunc fill_solid;
|
||||
FillHalfplaneTileFunc fill_halfplane;
|
||||
FillGenericTileFunc fill_generic;
|
||||
|
||||
// blend functions
|
||||
BitmapBlendFunc add_bitmaps, sub_bitmaps;
|
||||
BitmapMulFunc mul_bitmaps;
|
||||
|
||||
// be blur function
|
||||
BeBlurFunc be_blur;
|
||||
|
||||
// gaussian blur functions
|
||||
Convert8to16Func stripe_unpack;
|
||||
Convert16to8Func stripe_pack;
|
||||
FilterFunc shrink_horz, shrink_vert;
|
||||
FilterFunc expand_horz, expand_vert;
|
||||
FilterFunc pre_blur_horz[3], pre_blur_vert[3];
|
||||
ParamFilterFunc main_blur_horz[3], main_blur_vert[3];
|
||||
} BitmapEngine;
|
||||
|
||||
extern const BitmapEngine ass_bitmap_engine_c;
|
||||
extern const BitmapEngine ass_bitmap_engine_sse2;
|
||||
extern const BitmapEngine ass_bitmap_engine_avx2;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int left, top;
|
||||
int w, h; // width, height
|
||||
int stride;
|
||||
unsigned char *buffer; // h * stride buffer
|
||||
} Bitmap;
|
||||
|
||||
Bitmap *alloc_bitmap(const BitmapEngine *engine, int w, int h, bool zero);
|
||||
bool realloc_bitmap(const BitmapEngine *engine, Bitmap *bm, int w, int h);
|
||||
Bitmap *copy_bitmap(const BitmapEngine *engine, const Bitmap *src);
|
||||
void ass_free_bitmap(Bitmap *bm);
|
||||
|
||||
Bitmap *outline_to_bitmap(ASS_Renderer *render_priv,
|
||||
ASS_Outline *outline1, ASS_Outline *outline2,
|
||||
int bord);
|
||||
|
||||
void ass_synth_blur(const BitmapEngine *engine, int opaque_box, int be,
|
||||
double blur_radius, Bitmap *bm_g, Bitmap *bm_o);
|
||||
|
||||
/**
|
||||
* \brief perform glyph rendering
|
||||
* \param outline original glyph
|
||||
* \param border1 inside "border" outline, produced by stroker
|
||||
* \param border2 outside "border" outline, produced by stroker
|
||||
* \param bm_g out: pointer to the bitmap of original glyph is returned here
|
||||
* \param bm_o out: pointer to the bitmap of border glyph is returned here
|
||||
*/
|
||||
bool outline_to_bitmap2(ASS_Renderer *render_priv, ASS_Outline *outline,
|
||||
ASS_Outline *border1, ASS_Outline *border2,
|
||||
Bitmap **bm_g, Bitmap **bm_o);
|
||||
|
||||
int be_padding(int be);
|
||||
void be_blur_pre(uint8_t *buf, intptr_t w,
|
||||
intptr_t h, intptr_t stride);
|
||||
void be_blur_post(uint8_t *buf, intptr_t w,
|
||||
intptr_t h, intptr_t stride);
|
||||
bool ass_gaussian_blur(const BitmapEngine *engine, Bitmap *bm, double r2);
|
||||
void shift_bitmap(Bitmap *bm, int shift_x, int shift_y);
|
||||
void fix_outline(Bitmap *bm_g, Bitmap *bm_o);
|
||||
|
||||
#endif /* LIBASS_BITMAP_H */
|
|
@ -0,0 +1,912 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Vabishchevich Nikolay <vabnick@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ass_compat.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "ass_utils.h"
|
||||
#include "ass_bitmap.h"
|
||||
|
||||
|
||||
/*
|
||||
* Cascade Blur Algorithm
|
||||
*
|
||||
* The main idea is simple: to approximate gaussian blur with large radius
|
||||
* you can downscale, then apply filter with small pattern, then upscale back.
|
||||
*
|
||||
* To achieve desired precision down/upscaling should be done with sufficiently smooth kernel.
|
||||
* Experiment shows that downscaling of factor 2 with kernel [1, 5, 10, 10, 5, 1] and
|
||||
* corresponding upscaling are enough for 8-bit precision.
|
||||
*
|
||||
* For central filter here is used generic 9-tap filter with one of 3 different patterns
|
||||
* combined with one of optional prefilters with fixed kernels. Kernel coefficients
|
||||
* of the main filter are obtained from solution of least squares problem
|
||||
* for Fourier transform of resulting kernel.
|
||||
*/
|
||||
|
||||
|
||||
#define STRIPE_WIDTH (1 << (C_ALIGN_ORDER - 1))
|
||||
#define STRIPE_MASK (STRIPE_WIDTH - 1)
|
||||
static int16_t zero_line[STRIPE_WIDTH];
|
||||
static int16_t dither_line[2 * STRIPE_WIDTH] = {
|
||||
#if STRIPE_WIDTH > 8
|
||||
8, 40, 8, 40, 8, 40, 8, 40, 8, 40, 8, 40, 8, 40, 8, 40,
|
||||
56, 24, 56, 24, 56, 24, 56, 24, 56, 24, 56, 24, 56, 24, 56, 24,
|
||||
#else
|
||||
8, 40, 8, 40, 8, 40, 8, 40,
|
||||
56, 24, 56, 24, 56, 24, 56, 24,
|
||||
#endif
|
||||
};
|
||||
|
||||
inline static const int16_t *get_line(const int16_t *ptr, uintptr_t offs, uintptr_t size)
|
||||
{
|
||||
return offs < size ? ptr + offs : zero_line;
|
||||
}
|
||||
|
||||
inline static void copy_line(int16_t *buf, const int16_t *ptr, uintptr_t offs, uintptr_t size)
|
||||
{
|
||||
ptr = get_line(ptr, offs, size);
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
buf[k] = ptr[k];
|
||||
}
|
||||
|
||||
/*
|
||||
* Unpack/Pack Functions
|
||||
*
|
||||
* Convert between regular 8-bit bitmap and internal format.
|
||||
* Internal image is stored as set of vertical stripes of size [STRIPE_WIDTH x height].
|
||||
* Each pixel is represented as 16-bit integer in range of [0-0x4000].
|
||||
*/
|
||||
|
||||
void ass_stripe_unpack_c(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride,
|
||||
uintptr_t width, uintptr_t height)
|
||||
{
|
||||
for (uintptr_t y = 0; y < height; ++y) {
|
||||
int16_t *ptr = dst;
|
||||
for (uintptr_t x = 0; x < width; x += STRIPE_WIDTH) {
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
ptr[k] = (uint16_t) (((src[x + k] << 7) | (src[x + k] >> 1)) + 1) >> 1;
|
||||
//ptr[k] = (0x4000 * src[x + k] + 127) / 255;
|
||||
ptr += STRIPE_WIDTH * height;
|
||||
}
|
||||
dst += STRIPE_WIDTH;
|
||||
src += src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void ass_stripe_pack_c(uint8_t *dst, ptrdiff_t dst_stride, const int16_t *src,
|
||||
uintptr_t width, uintptr_t height)
|
||||
{
|
||||
for (uintptr_t x = 0; x < width; x += STRIPE_WIDTH) {
|
||||
uint8_t *ptr = dst;
|
||||
for (uintptr_t y = 0; y < height; ++y) {
|
||||
const int16_t *dither = dither_line + (y & 1) * STRIPE_WIDTH;
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
ptr[k] = (uint16_t) (src[k] - (src[k] >> 8) + dither[k]) >> 6;
|
||||
//ptr[k] = (255 * src[k] + 0x1FFF) / 0x4000;
|
||||
ptr += dst_stride;
|
||||
src += STRIPE_WIDTH;
|
||||
}
|
||||
dst += STRIPE_WIDTH;
|
||||
}
|
||||
uintptr_t left = dst_stride - ((width + STRIPE_MASK) & ~STRIPE_MASK);
|
||||
for (uintptr_t y = 0; y < height; ++y) {
|
||||
for (uintptr_t x = 0; x < left; ++x)
|
||||
dst[x] = 0;
|
||||
dst += dst_stride;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Contract Filters
|
||||
*
|
||||
* Contract image by factor 2 with kernel [1, 5, 10, 10, 5, 1].
|
||||
*/
|
||||
|
||||
static inline int16_t shrink_func(int16_t p1p, int16_t p1n,
|
||||
int16_t z0p, int16_t z0n,
|
||||
int16_t n1p, int16_t n1n)
|
||||
{
|
||||
/*
|
||||
return (1 * p1p + 5 * p1n + 10 * z0p + 10 * z0n + 5 * n1p + 1 * n1n + 16) >> 5;
|
||||
*/
|
||||
int32_t r = (p1p + p1n + n1p + n1n) >> 1;
|
||||
r = (r + z0p + z0n) >> 1;
|
||||
r = (r + p1n + n1p) >> 1;
|
||||
return (r + z0p + z0n + 2) >> 2;
|
||||
}
|
||||
|
||||
void ass_shrink_horz_c(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height)
|
||||
{
|
||||
uintptr_t dst_width = (src_width + 5) >> 1;
|
||||
uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height;
|
||||
uintptr_t step = STRIPE_WIDTH * src_height;
|
||||
|
||||
uintptr_t offs = 0;
|
||||
int16_t buf[3 * STRIPE_WIDTH];
|
||||
int16_t *ptr = buf + STRIPE_WIDTH;
|
||||
for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) {
|
||||
for (uintptr_t y = 0; y < src_height; ++y) {
|
||||
copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size);
|
||||
copy_line(ptr + 0 * STRIPE_WIDTH, src, offs + 0 * step, size);
|
||||
copy_line(ptr + 1 * STRIPE_WIDTH, src, offs + 1 * step, size);
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
dst[k] = shrink_func(ptr[2 * k - 4], ptr[2 * k - 3],
|
||||
ptr[2 * k - 2], ptr[2 * k - 1],
|
||||
ptr[2 * k + 0], ptr[2 * k + 1]);
|
||||
dst += STRIPE_WIDTH;
|
||||
offs += STRIPE_WIDTH;
|
||||
}
|
||||
offs += step;
|
||||
}
|
||||
}
|
||||
|
||||
void ass_shrink_vert_c(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height)
|
||||
{
|
||||
uintptr_t dst_height = (src_height + 5) >> 1;
|
||||
uintptr_t step = STRIPE_WIDTH * src_height;
|
||||
|
||||
for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) {
|
||||
uintptr_t offs = 0;
|
||||
for (uintptr_t y = 0; y < dst_height; ++y) {
|
||||
const int16_t *p1p = get_line(src, offs - 4 * STRIPE_WIDTH, step);
|
||||
const int16_t *p1n = get_line(src, offs - 3 * STRIPE_WIDTH, step);
|
||||
const int16_t *z0p = get_line(src, offs - 2 * STRIPE_WIDTH, step);
|
||||
const int16_t *z0n = get_line(src, offs - 1 * STRIPE_WIDTH, step);
|
||||
const int16_t *n1p = get_line(src, offs - 0 * STRIPE_WIDTH, step);
|
||||
const int16_t *n1n = get_line(src, offs + 1 * STRIPE_WIDTH, step);
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
dst[k] = shrink_func(p1p[k], p1n[k], z0p[k], z0n[k], n1p[k], n1n[k]);
|
||||
dst += STRIPE_WIDTH;
|
||||
offs += 2 * STRIPE_WIDTH;
|
||||
}
|
||||
src += step;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand Filters
|
||||
*
|
||||
* Expand image by factor 2 with kernel [5, 10, 1], [1, 10, 5].
|
||||
*/
|
||||
|
||||
static inline void expand_func(int16_t *rp, int16_t *rn,
|
||||
int16_t p1, int16_t z0, int16_t n1)
|
||||
{
|
||||
/*
|
||||
*rp = (5 * p1 + 10 * z0 + 1 * n1 + 8) >> 4;
|
||||
*rn = (1 * p1 + 10 * z0 + 5 * n1 + 8) >> 4;
|
||||
*/
|
||||
uint16_t r = (uint16_t) (((uint16_t) (p1 + n1) >> 1) + z0) >> 1;
|
||||
*rp = (uint16_t) (((uint16_t) (r + p1) >> 1) + z0 + 1) >> 1;
|
||||
*rn = (uint16_t) (((uint16_t) (r + n1) >> 1) + z0 + 1) >> 1;
|
||||
}
|
||||
|
||||
void ass_expand_horz_c(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height)
|
||||
{
|
||||
uintptr_t dst_width = 2 * src_width + 4;
|
||||
uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height;
|
||||
uintptr_t step = STRIPE_WIDTH * src_height;
|
||||
|
||||
uintptr_t offs = 0;
|
||||
int16_t buf[2 * STRIPE_WIDTH];
|
||||
int16_t *ptr = buf + STRIPE_WIDTH;
|
||||
for (uintptr_t x = STRIPE_WIDTH; x < dst_width; x += 2 * STRIPE_WIDTH) {
|
||||
for (uintptr_t y = 0; y < src_height; ++y) {
|
||||
copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size);
|
||||
copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size);
|
||||
for (int k = 0; k < STRIPE_WIDTH / 2; ++k)
|
||||
expand_func(&dst[2 * k], &dst[2 * k + 1],
|
||||
ptr[k - 2], ptr[k - 1], ptr[k]);
|
||||
int16_t *next = dst + step - STRIPE_WIDTH;
|
||||
for (int k = STRIPE_WIDTH / 2; k < STRIPE_WIDTH; ++k)
|
||||
expand_func(&next[2 * k], &next[2 * k + 1],
|
||||
ptr[k - 2], ptr[k - 1], ptr[k]);
|
||||
dst += STRIPE_WIDTH;
|
||||
offs += STRIPE_WIDTH;
|
||||
}
|
||||
dst += step;
|
||||
}
|
||||
if ((dst_width - 1) & STRIPE_WIDTH)
|
||||
return;
|
||||
|
||||
for (uintptr_t y = 0; y < src_height; ++y) {
|
||||
copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size);
|
||||
copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size);
|
||||
for (int k = 0; k < STRIPE_WIDTH / 2; ++k)
|
||||
expand_func(&dst[2 * k], &dst[2 * k + 1],
|
||||
ptr[k - 2], ptr[k - 1], ptr[k]);
|
||||
dst += STRIPE_WIDTH;
|
||||
offs += STRIPE_WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
void ass_expand_vert_c(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height)
|
||||
{
|
||||
uintptr_t dst_height = 2 * src_height + 4;
|
||||
uintptr_t step = STRIPE_WIDTH * src_height;
|
||||
|
||||
for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) {
|
||||
uintptr_t offs = 0;
|
||||
for (uintptr_t y = 0; y < dst_height; y += 2) {
|
||||
const int16_t *p1 = get_line(src, offs - 2 * STRIPE_WIDTH, step);
|
||||
const int16_t *z0 = get_line(src, offs - 1 * STRIPE_WIDTH, step);
|
||||
const int16_t *n1 = get_line(src, offs - 0 * STRIPE_WIDTH, step);
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
expand_func(&dst[k], &dst[k + STRIPE_WIDTH],
|
||||
p1[k], z0[k], n1[k]);
|
||||
dst += 2 * STRIPE_WIDTH;
|
||||
offs += STRIPE_WIDTH;
|
||||
}
|
||||
src += step;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* First Supplementary Filters
|
||||
*
|
||||
* Perform 1D convolution with kernel [1, 2, 1].
|
||||
*/
|
||||
|
||||
static inline int16_t pre_blur1_func(int16_t p1, int16_t z0, int16_t n1)
|
||||
{
|
||||
/*
|
||||
return (1 * p1 + 2 * z0 + 1 * n1 + 2) >> 2;
|
||||
*/
|
||||
return (uint16_t) (((uint16_t) (p1 + n1) >> 1) + z0 + 1) >> 1;
|
||||
}
|
||||
|
||||
void ass_pre_blur1_horz_c(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height)
|
||||
{
|
||||
uintptr_t dst_width = src_width + 2;
|
||||
uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height;
|
||||
uintptr_t step = STRIPE_WIDTH * src_height;
|
||||
|
||||
uintptr_t offs = 0;
|
||||
int16_t buf[2 * STRIPE_WIDTH];
|
||||
int16_t *ptr = buf + STRIPE_WIDTH;
|
||||
for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) {
|
||||
for (uintptr_t y = 0; y < src_height; ++y) {
|
||||
copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size);
|
||||
copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size);
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
dst[k] = pre_blur1_func(ptr[k - 2], ptr[k - 1], ptr[k]);
|
||||
dst += STRIPE_WIDTH;
|
||||
offs += STRIPE_WIDTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ass_pre_blur1_vert_c(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height)
|
||||
{
|
||||
uintptr_t dst_height = src_height + 2;
|
||||
uintptr_t step = STRIPE_WIDTH * src_height;
|
||||
|
||||
for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) {
|
||||
uintptr_t offs = 0;
|
||||
for (uintptr_t y = 0; y < dst_height; ++y) {
|
||||
const int16_t *p1 = get_line(src, offs - 2 * STRIPE_WIDTH, step);
|
||||
const int16_t *z0 = get_line(src, offs - 1 * STRIPE_WIDTH, step);
|
||||
const int16_t *n1 = get_line(src, offs - 0 * STRIPE_WIDTH, step);
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
dst[k] = pre_blur1_func(p1[k], z0[k], n1[k]);
|
||||
dst += STRIPE_WIDTH;
|
||||
offs += STRIPE_WIDTH;
|
||||
}
|
||||
src += step;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Second Supplementary Filters
|
||||
*
|
||||
* Perform 1D convolution with kernel [1, 4, 6, 4, 1].
|
||||
*/
|
||||
|
||||
static inline int16_t pre_blur2_func(int16_t p2, int16_t p1, int16_t z0,
|
||||
int16_t n1, int16_t n2)
|
||||
{
|
||||
/*
|
||||
return (1 * p2 + 4 * p1 + 6 * z0 + 4 * n1 + 1 * n2 + 8) >> 4;
|
||||
*/
|
||||
uint16_t r1 = ((uint16_t) (((uint16_t) (p2 + n2) >> 1) + z0) >> 1) + z0;
|
||||
uint16_t r2 = p1 + n1;
|
||||
uint16_t r = ((uint16_t) (r1 + r2) >> 1) | (0x8000 & r1 & r2);
|
||||
return (uint16_t) (r + 1) >> 1;
|
||||
}
|
||||
|
||||
void ass_pre_blur2_horz_c(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height)
|
||||
{
|
||||
uintptr_t dst_width = src_width + 4;
|
||||
uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height;
|
||||
uintptr_t step = STRIPE_WIDTH * src_height;
|
||||
|
||||
uintptr_t offs = 0;
|
||||
int16_t buf[2 * STRIPE_WIDTH];
|
||||
int16_t *ptr = buf + STRIPE_WIDTH;
|
||||
for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) {
|
||||
for (uintptr_t y = 0; y < src_height; ++y) {
|
||||
copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size);
|
||||
copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size);
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
dst[k] = pre_blur2_func(ptr[k - 4], ptr[k - 3], ptr[k - 2], ptr[k - 1], ptr[k]);
|
||||
dst += STRIPE_WIDTH;
|
||||
offs += STRIPE_WIDTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ass_pre_blur2_vert_c(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height)
|
||||
{
|
||||
uintptr_t dst_height = src_height + 4;
|
||||
uintptr_t step = STRIPE_WIDTH * src_height;
|
||||
|
||||
for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) {
|
||||
uintptr_t offs = 0;
|
||||
for (uintptr_t y = 0; y < dst_height; ++y) {
|
||||
const int16_t *p2 = get_line(src, offs - 4 * STRIPE_WIDTH, step);
|
||||
const int16_t *p1 = get_line(src, offs - 3 * STRIPE_WIDTH, step);
|
||||
const int16_t *z0 = get_line(src, offs - 2 * STRIPE_WIDTH, step);
|
||||
const int16_t *n1 = get_line(src, offs - 1 * STRIPE_WIDTH, step);
|
||||
const int16_t *n2 = get_line(src, offs - 0 * STRIPE_WIDTH, step);
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
dst[k] = pre_blur2_func(p2[k], p1[k], z0[k], n1[k], n2[k]);
|
||||
dst += STRIPE_WIDTH;
|
||||
offs += STRIPE_WIDTH;
|
||||
}
|
||||
src += step;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Third Supplementary Filters
|
||||
*
|
||||
* Perform 1D convolution with kernel [1, 6, 15, 20, 15, 6, 1].
|
||||
*/
|
||||
|
||||
static inline int16_t pre_blur3_func(int16_t p3, int16_t p2, int16_t p1, int16_t z0,
|
||||
int16_t n1, int16_t n2, int16_t n3)
|
||||
{
|
||||
/*
|
||||
return (1 * p3 + 6 * p2 + 15 * p1 + 20 * z0 + 15 * n1 + 6 * n2 + 1 * n3 + 32) >> 6;
|
||||
*/
|
||||
return (20 * (uint16_t) z0 +
|
||||
15 * (uint16_t) (p1 + n1) +
|
||||
6 * (uint16_t) (p2 + n2) +
|
||||
1 * (uint16_t) (p3 + n3) + 32) >> 6;
|
||||
}
|
||||
|
||||
void ass_pre_blur3_horz_c(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height)
|
||||
{
|
||||
uintptr_t dst_width = src_width + 6;
|
||||
uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height;
|
||||
uintptr_t step = STRIPE_WIDTH * src_height;
|
||||
|
||||
uintptr_t offs = 0;
|
||||
int16_t buf[2 * STRIPE_WIDTH];
|
||||
int16_t *ptr = buf + STRIPE_WIDTH;
|
||||
for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) {
|
||||
for (uintptr_t y = 0; y < src_height; ++y) {
|
||||
copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size);
|
||||
copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size);
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
dst[k] = pre_blur3_func(ptr[k - 6], ptr[k - 5], ptr[k - 4], ptr[k - 3],
|
||||
ptr[k - 2], ptr[k - 1], ptr[k]);
|
||||
dst += STRIPE_WIDTH;
|
||||
offs += STRIPE_WIDTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ass_pre_blur3_vert_c(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height)
|
||||
{
|
||||
uintptr_t dst_height = src_height + 6;
|
||||
uintptr_t step = STRIPE_WIDTH * src_height;
|
||||
|
||||
for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) {
|
||||
uintptr_t offs = 0;
|
||||
for (uintptr_t y = 0; y < dst_height; ++y) {
|
||||
const int16_t *p3 = get_line(src, offs - 6 * STRIPE_WIDTH, step);
|
||||
const int16_t *p2 = get_line(src, offs - 5 * STRIPE_WIDTH, step);
|
||||
const int16_t *p1 = get_line(src, offs - 4 * STRIPE_WIDTH, step);
|
||||
const int16_t *z0 = get_line(src, offs - 3 * STRIPE_WIDTH, step);
|
||||
const int16_t *n1 = get_line(src, offs - 2 * STRIPE_WIDTH, step);
|
||||
const int16_t *n2 = get_line(src, offs - 1 * STRIPE_WIDTH, step);
|
||||
const int16_t *n3 = get_line(src, offs - 0 * STRIPE_WIDTH, step);
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
dst[k] = pre_blur3_func(p3[k], p2[k], p1[k], z0[k], n1[k], n2[k], n3[k]);
|
||||
dst += STRIPE_WIDTH;
|
||||
offs += STRIPE_WIDTH;
|
||||
}
|
||||
src += step;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Main 9-tap Parametric Filters
|
||||
*
|
||||
* Perform 1D convolution with kernel
|
||||
* [c3, c2, c1, c0, d, c0, c1, c2, c3] or
|
||||
* [c3, 0, c2, c1, c0, d, c0, c1, c2, 0, c3] or
|
||||
* [c3, 0, c2, 0, c1, c0, d, c0, c1, 0, c2, 0, c3] accordingly.
|
||||
*
|
||||
* cN = param[N], d = 1 - 2 * (c0 + c1 + c2 + c3).
|
||||
*/
|
||||
|
||||
static inline int16_t blur_func(int16_t p4, int16_t p3, int16_t p2, int16_t p1, int16_t z0,
|
||||
int16_t n1, int16_t n2, int16_t n3, int16_t n4, const int16_t c[])
|
||||
{
|
||||
p1 -= z0;
|
||||
p2 -= z0;
|
||||
p3 -= z0;
|
||||
p4 -= z0;
|
||||
n1 -= z0;
|
||||
n2 -= z0;
|
||||
n3 -= z0;
|
||||
n4 -= z0;
|
||||
return (((p1 + n1) * c[0] +
|
||||
(p2 + n2) * c[1] +
|
||||
(p3 + n3) * c[2] +
|
||||
(p4 + n4) * c[3] +
|
||||
0x8000) >> 16) + z0;
|
||||
}
|
||||
|
||||
void ass_blur1234_horz_c(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height,
|
||||
const int16_t *param)
|
||||
{
|
||||
uintptr_t dst_width = src_width + 8;
|
||||
uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height;
|
||||
uintptr_t step = STRIPE_WIDTH * src_height;
|
||||
|
||||
uintptr_t offs = 0;
|
||||
int16_t buf[2 * STRIPE_WIDTH];
|
||||
int16_t *ptr = buf + STRIPE_WIDTH;
|
||||
for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) {
|
||||
for (uintptr_t y = 0; y < src_height; ++y) {
|
||||
copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size);
|
||||
copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size);
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
dst[k] = blur_func(ptr[k - 8], ptr[k - 7], ptr[k - 6], ptr[k - 5], ptr[k - 4],
|
||||
ptr[k - 3], ptr[k - 2], ptr[k - 1], ptr[k - 0], param);
|
||||
dst += STRIPE_WIDTH;
|
||||
offs += STRIPE_WIDTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ass_blur1234_vert_c(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height,
|
||||
const int16_t *param)
|
||||
{
|
||||
uintptr_t dst_height = src_height + 8;
|
||||
uintptr_t step = STRIPE_WIDTH * src_height;
|
||||
|
||||
for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) {
|
||||
uintptr_t offs = 0;
|
||||
for (uintptr_t y = 0; y < dst_height; ++y) {
|
||||
const int16_t *p4 = get_line(src, offs - 8 * STRIPE_WIDTH, step);
|
||||
const int16_t *p3 = get_line(src, offs - 7 * STRIPE_WIDTH, step);
|
||||
const int16_t *p2 = get_line(src, offs - 6 * STRIPE_WIDTH, step);
|
||||
const int16_t *p1 = get_line(src, offs - 5 * STRIPE_WIDTH, step);
|
||||
const int16_t *z0 = get_line(src, offs - 4 * STRIPE_WIDTH, step);
|
||||
const int16_t *n1 = get_line(src, offs - 3 * STRIPE_WIDTH, step);
|
||||
const int16_t *n2 = get_line(src, offs - 2 * STRIPE_WIDTH, step);
|
||||
const int16_t *n3 = get_line(src, offs - 1 * STRIPE_WIDTH, step);
|
||||
const int16_t *n4 = get_line(src, offs - 0 * STRIPE_WIDTH, step);
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
dst[k] = blur_func(p4[k], p3[k], p2[k], p1[k], z0[k],
|
||||
n1[k], n2[k], n3[k], n4[k], param);
|
||||
dst += STRIPE_WIDTH;
|
||||
offs += STRIPE_WIDTH;
|
||||
}
|
||||
src += step;
|
||||
}
|
||||
}
|
||||
|
||||
void ass_blur1235_horz_c(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height,
|
||||
const int16_t *param)
|
||||
{
|
||||
uintptr_t dst_width = src_width + 10;
|
||||
uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height;
|
||||
uintptr_t step = STRIPE_WIDTH * src_height;
|
||||
|
||||
uintptr_t offs = 0;
|
||||
#if STRIPE_WIDTH < 10
|
||||
int16_t buf[3 * STRIPE_WIDTH];
|
||||
int16_t *ptr = buf + 2 * STRIPE_WIDTH;
|
||||
#else
|
||||
int16_t buf[2 * STRIPE_WIDTH];
|
||||
int16_t *ptr = buf + STRIPE_WIDTH;
|
||||
#endif
|
||||
for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) {
|
||||
for (uintptr_t y = 0; y < src_height; ++y) {
|
||||
#if STRIPE_WIDTH < 10
|
||||
copy_line(ptr - 2 * STRIPE_WIDTH, src, offs - 2 * step, size);
|
||||
#endif
|
||||
copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size);
|
||||
copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size);
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
dst[k] = blur_func(ptr[k - 10], ptr[k - 8], ptr[k - 7], ptr[k - 6], ptr[k - 5],
|
||||
ptr[k - 4], ptr[k - 3], ptr[k - 2], ptr[k - 0], param);
|
||||
dst += STRIPE_WIDTH;
|
||||
offs += STRIPE_WIDTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ass_blur1235_vert_c(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height,
|
||||
const int16_t *param)
|
||||
{
|
||||
uintptr_t dst_height = src_height + 10;
|
||||
uintptr_t step = STRIPE_WIDTH * src_height;
|
||||
|
||||
for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) {
|
||||
uintptr_t offs = 0;
|
||||
for (uintptr_t y = 0; y < dst_height; ++y) {
|
||||
const int16_t *p4 = get_line(src, offs - 10 * STRIPE_WIDTH, step);
|
||||
const int16_t *p3 = get_line(src, offs - 8 * STRIPE_WIDTH, step);
|
||||
const int16_t *p2 = get_line(src, offs - 7 * STRIPE_WIDTH, step);
|
||||
const int16_t *p1 = get_line(src, offs - 6 * STRIPE_WIDTH, step);
|
||||
const int16_t *z0 = get_line(src, offs - 5 * STRIPE_WIDTH, step);
|
||||
const int16_t *n1 = get_line(src, offs - 4 * STRIPE_WIDTH, step);
|
||||
const int16_t *n2 = get_line(src, offs - 3 * STRIPE_WIDTH, step);
|
||||
const int16_t *n3 = get_line(src, offs - 2 * STRIPE_WIDTH, step);
|
||||
const int16_t *n4 = get_line(src, offs - 0 * STRIPE_WIDTH, step);
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
dst[k] = blur_func(p4[k], p3[k], p2[k], p1[k], z0[k],
|
||||
n1[k], n2[k], n3[k], n4[k], param);
|
||||
dst += STRIPE_WIDTH;
|
||||
offs += STRIPE_WIDTH;
|
||||
}
|
||||
src += step;
|
||||
}
|
||||
}
|
||||
|
||||
void ass_blur1246_horz_c(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height,
|
||||
const int16_t *param)
|
||||
{
|
||||
uintptr_t dst_width = src_width + 12;
|
||||
uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height;
|
||||
uintptr_t step = STRIPE_WIDTH * src_height;
|
||||
|
||||
uintptr_t offs = 0;
|
||||
#if STRIPE_WIDTH < 12
|
||||
int16_t buf[3 * STRIPE_WIDTH];
|
||||
int16_t *ptr = buf + 2 * STRIPE_WIDTH;
|
||||
#else
|
||||
int16_t buf[2 * STRIPE_WIDTH];
|
||||
int16_t *ptr = buf + STRIPE_WIDTH;
|
||||
#endif
|
||||
for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) {
|
||||
for (uintptr_t y = 0; y < src_height; ++y) {
|
||||
#if STRIPE_WIDTH < 12
|
||||
copy_line(ptr - 2 * STRIPE_WIDTH, src, offs - 2 * step, size);
|
||||
#endif
|
||||
copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size);
|
||||
copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size);
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
dst[k] = blur_func(ptr[k - 12], ptr[k - 10], ptr[k - 8], ptr[k - 7], ptr[k - 6],
|
||||
ptr[k - 5], ptr[k - 4], ptr[k - 2], ptr[k - 0], param);
|
||||
dst += STRIPE_WIDTH;
|
||||
offs += STRIPE_WIDTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ass_blur1246_vert_c(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height,
|
||||
const int16_t *param)
|
||||
{
|
||||
uintptr_t dst_height = src_height + 12;
|
||||
uintptr_t step = STRIPE_WIDTH * src_height;
|
||||
|
||||
for (uintptr_t x = 0; x < src_width; x += STRIPE_WIDTH) {
|
||||
uintptr_t offs = 0;
|
||||
for (uintptr_t y = 0; y < dst_height; ++y) {
|
||||
const int16_t *p4 = get_line(src, offs - 12 * STRIPE_WIDTH, step);
|
||||
const int16_t *p3 = get_line(src, offs - 10 * STRIPE_WIDTH, step);
|
||||
const int16_t *p2 = get_line(src, offs - 8 * STRIPE_WIDTH, step);
|
||||
const int16_t *p1 = get_line(src, offs - 7 * STRIPE_WIDTH, step);
|
||||
const int16_t *z0 = get_line(src, offs - 6 * STRIPE_WIDTH, step);
|
||||
const int16_t *n1 = get_line(src, offs - 5 * STRIPE_WIDTH, step);
|
||||
const int16_t *n2 = get_line(src, offs - 4 * STRIPE_WIDTH, step);
|
||||
const int16_t *n3 = get_line(src, offs - 2 * STRIPE_WIDTH, step);
|
||||
const int16_t *n4 = get_line(src, offs - 0 * STRIPE_WIDTH, step);
|
||||
for (int k = 0; k < STRIPE_WIDTH; ++k)
|
||||
dst[k] = blur_func(p4[k], p3[k], p2[k], p1[k], z0[k],
|
||||
n1[k], n2[k], n3[k], n4[k], param);
|
||||
dst += STRIPE_WIDTH;
|
||||
offs += STRIPE_WIDTH;
|
||||
}
|
||||
src += step;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void calc_gauss(double *res, int n, double r2)
|
||||
{
|
||||
double alpha = 0.5 / r2;
|
||||
double mul = exp(-alpha), mul2 = mul * mul;
|
||||
double cur = sqrt(alpha / M_PI);
|
||||
|
||||
res[0] = cur;
|
||||
cur *= mul;
|
||||
res[1] = cur;
|
||||
for (int i = 2; i <= n; ++i) {
|
||||
mul *= mul2;
|
||||
cur *= mul;
|
||||
res[i] = cur;
|
||||
}
|
||||
}
|
||||
|
||||
static void coeff_blur121(double *coeff, int n)
|
||||
{
|
||||
double prev = coeff[1];
|
||||
for (int i = 0; i <= n; ++i) {
|
||||
double res = (prev + 2 * coeff[i] + coeff[i + 1]) / 4;
|
||||
prev = coeff[i];
|
||||
coeff[i] = res;
|
||||
}
|
||||
}
|
||||
|
||||
static void coeff_filter(double *coeff, int n, const double kernel[4])
|
||||
{
|
||||
double prev1 = coeff[1], prev2 = coeff[2], prev3 = coeff[3];
|
||||
for (int i = 0; i <= n; ++i) {
|
||||
double res = coeff[i + 0] * kernel[0] +
|
||||
(prev1 + coeff[i + 1]) * kernel[1] +
|
||||
(prev2 + coeff[i + 2]) * kernel[2] +
|
||||
(prev3 + coeff[i + 3]) * kernel[3];
|
||||
prev3 = prev2;
|
||||
prev2 = prev1;
|
||||
prev1 = coeff[i];
|
||||
coeff[i] = res;
|
||||
}
|
||||
}
|
||||
|
||||
static void calc_matrix(double mat[4][4], const double *mat_freq, const int *index)
|
||||
{
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
mat[i][i] = mat_freq[2 * index[i]] + 3 * mat_freq[0] - 4 * mat_freq[index[i]];
|
||||
for (int j = i + 1; j < 4; ++j)
|
||||
mat[i][j] = mat[j][i] =
|
||||
mat_freq[index[i] + index[j]] + mat_freq[index[j] - index[i]] +
|
||||
2 * (mat_freq[0] - mat_freq[index[i]] - mat_freq[index[j]]);
|
||||
}
|
||||
|
||||
// invert transpose
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
int ip = k, jp = k; // pivot
|
||||
double z = 1 / mat[ip][jp];
|
||||
mat[ip][jp] = 1;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (i == ip)
|
||||
continue;
|
||||
|
||||
double mul = mat[i][jp] * z;
|
||||
mat[i][jp] = 0;
|
||||
for (int j = 0; j < 4; ++j)
|
||||
mat[i][j] -= mat[ip][j] * mul;
|
||||
}
|
||||
for (int j = 0; j < 4; ++j)
|
||||
mat[ip][j] *= z;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Solve least squares problem for kernel of the main filter
|
||||
* \param mu out: output coefficients
|
||||
* \param index in: filter tap positions
|
||||
* \param prefilter in: supplementary filter type
|
||||
* \param r2 in: desired standard deviation squared
|
||||
* \param mul in: scale multiplier
|
||||
*/
|
||||
static void calc_coeff(double mu[4], const int index[4], int prefilter, double r2, double mul)
|
||||
{
|
||||
double mul2 = mul * mul, mul3 = mul2 * mul;
|
||||
double kernel[] = {
|
||||
(5204 + 2520 * mul + 1092 * mul2 + 3280 * mul3) / 12096,
|
||||
(2943 - 210 * mul - 273 * mul2 - 2460 * mul3) / 12096,
|
||||
( 486 - 924 * mul - 546 * mul2 + 984 * mul3) / 12096,
|
||||
( 17 - 126 * mul + 273 * mul2 - 164 * mul3) / 12096,
|
||||
};
|
||||
|
||||
double mat_freq[14];
|
||||
memcpy(mat_freq, kernel, sizeof(kernel));
|
||||
memset(mat_freq + 4, 0, sizeof(mat_freq) - sizeof(kernel));
|
||||
int n = 6;
|
||||
coeff_filter(mat_freq, n, kernel);
|
||||
for (int k = 0; k < 2 * prefilter; ++k)
|
||||
coeff_blur121(mat_freq, ++n);
|
||||
|
||||
double vec_freq[13];
|
||||
n = index[3] + prefilter + 3;
|
||||
calc_gauss(vec_freq, n, r2);
|
||||
memset(vec_freq + n + 1, 0, sizeof(vec_freq) - (n + 1) * sizeof(vec_freq[0]));
|
||||
n -= 3;
|
||||
coeff_filter(vec_freq, n, kernel);
|
||||
for (int k = 0; k < prefilter; ++k)
|
||||
coeff_blur121(vec_freq, --n);
|
||||
|
||||
double mat[4][4];
|
||||
calc_matrix(mat, mat_freq, index);
|
||||
|
||||
double vec[4];
|
||||
for (int i = 0; i < 4; ++i)
|
||||
vec[i] = mat_freq[0] - mat_freq[index[i]] - vec_freq[0] + vec_freq[index[i]];
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
double res = 0;
|
||||
for (int j = 0; j < 4; ++j)
|
||||
res += mat[i][j] * vec[j];
|
||||
mu[i] = FFMAX(0, res);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int level, prefilter, filter;
|
||||
int16_t coeff[4];
|
||||
} BlurMethod;
|
||||
|
||||
static void find_best_method(BlurMethod *blur, double r2)
|
||||
{
|
||||
static const int index[][4] = {
|
||||
{ 1, 2, 3, 4 },
|
||||
{ 1, 2, 3, 5 },
|
||||
{ 1, 2, 4, 6 },
|
||||
};
|
||||
|
||||
double mu[5];
|
||||
if (r2 < 1.9) {
|
||||
blur->level = blur->prefilter = blur->filter = 0;
|
||||
|
||||
if (r2 < 0.5) {
|
||||
mu[2] = 0.085 * r2 * r2 * r2;
|
||||
mu[1] = 0.5 * r2 - 4 * mu[2];
|
||||
mu[3] = mu[4] = 0;
|
||||
} else {
|
||||
calc_gauss(mu, 4, r2);
|
||||
}
|
||||
} else {
|
||||
double mul = 1;
|
||||
if (r2 < 6.693) {
|
||||
blur->level = 0;
|
||||
|
||||
if (r2 < 2.8)
|
||||
blur->prefilter = 1;
|
||||
else if (r2 < 4.4)
|
||||
blur->prefilter = 2;
|
||||
else
|
||||
blur->prefilter = 3;
|
||||
|
||||
blur->filter = blur->prefilter - 1;
|
||||
} else {
|
||||
frexp((r2 + 0.7) / 26.5, &blur->level);
|
||||
blur->level = (blur->level + 3) >> 1;
|
||||
mul = pow(0.25, blur->level);
|
||||
r2 *= mul;
|
||||
|
||||
if (r2 < 3.15 - 1.5 * mul)
|
||||
blur->prefilter = 0;
|
||||
else if (r2 < 5.3 - 5.2 * mul)
|
||||
blur->prefilter = 1;
|
||||
else
|
||||
blur->prefilter = 2;
|
||||
|
||||
blur->filter = blur->prefilter;
|
||||
}
|
||||
calc_coeff(mu + 1, index[blur->filter], blur->prefilter, r2, mul);
|
||||
}
|
||||
|
||||
for (int i = 1; i <= 4; ++i)
|
||||
blur->coeff[i - 1] = (int) (0x10000 * mu[i] + 0.5);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Perform approximate gaussian blur
|
||||
* \param r2 in: desired standard deviation squared
|
||||
*/
|
||||
bool ass_gaussian_blur(const BitmapEngine *engine, Bitmap *bm, double r2)
|
||||
{
|
||||
BlurMethod blur;
|
||||
find_best_method(&blur, r2);
|
||||
|
||||
int w = bm->w, h = bm->h;
|
||||
int offset = ((2 * (blur.prefilter + blur.filter) + 17) << blur.level) - 5;
|
||||
int end_w = ((w + offset) & ~((1 << blur.level) - 1)) - 4;
|
||||
int end_h = ((h + offset) & ~((1 << blur.level) - 1)) - 4;
|
||||
|
||||
const int stripe_width = 1 << (engine->align_order - 1);
|
||||
int size = end_h * ((end_w + stripe_width - 1) & ~(stripe_width - 1));
|
||||
int16_t *tmp = ass_aligned_alloc(2 * stripe_width, 4 * size, false);
|
||||
if (!tmp)
|
||||
return false;
|
||||
|
||||
engine->stripe_unpack(tmp, bm->buffer, bm->stride, w, h);
|
||||
int16_t *buf[2] = {tmp, tmp + size};
|
||||
int index = 0;
|
||||
|
||||
for (int i = 0; i < blur.level; ++i) {
|
||||
engine->shrink_vert(buf[index ^ 1], buf[index], w, h);
|
||||
h = (h + 5) >> 1;
|
||||
index ^= 1;
|
||||
}
|
||||
for (int i = 0; i < blur.level; ++i) {
|
||||
engine->shrink_horz(buf[index ^ 1], buf[index], w, h);
|
||||
w = (w + 5) >> 1;
|
||||
index ^= 1;
|
||||
}
|
||||
if (blur.prefilter) {
|
||||
engine->pre_blur_horz[blur.prefilter - 1](buf[index ^ 1], buf[index], w, h);
|
||||
w += 2 * blur.prefilter;
|
||||
index ^= 1;
|
||||
}
|
||||
engine->main_blur_horz[blur.filter](buf[index ^ 1], buf[index], w, h, blur.coeff);
|
||||
w += 2 * blur.filter + 8;
|
||||
index ^= 1;
|
||||
for (int i = 0; i < blur.level; ++i) {
|
||||
engine->expand_horz(buf[index ^ 1], buf[index], w, h);
|
||||
w = 2 * w + 4;
|
||||
index ^= 1;
|
||||
}
|
||||
if (blur.prefilter) {
|
||||
engine->pre_blur_vert[blur.prefilter - 1](buf[index ^ 1], buf[index], w, h);
|
||||
h += 2 * blur.prefilter;
|
||||
index ^= 1;
|
||||
}
|
||||
engine->main_blur_vert[blur.filter](buf[index ^ 1], buf[index], w, h, blur.coeff);
|
||||
h += 2 * blur.filter + 8;
|
||||
index ^= 1;
|
||||
for (int i = 0; i < blur.level; ++i) {
|
||||
engine->expand_vert(buf[index ^ 1], buf[index], w, h);
|
||||
h = 2 * h + 4;
|
||||
index ^= 1;
|
||||
}
|
||||
assert(w == end_w && h == end_h);
|
||||
|
||||
if (!realloc_bitmap(engine, bm, w, h)) {
|
||||
ass_aligned_free(tmp);
|
||||
return false;
|
||||
}
|
||||
offset = ((blur.prefilter + blur.filter + 8) << blur.level) - 4;
|
||||
bm->left -= offset;
|
||||
bm->top -= offset;
|
||||
|
||||
engine->stripe_pack(bm->buffer, bm->stride, buf[index], w, h);
|
||||
ass_aligned_free(tmp);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,580 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
||||
* Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ass_compat.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_OUTLINE_H
|
||||
#include <assert.h>
|
||||
|
||||
#include "ass_utils.h"
|
||||
#include "ass_font.h"
|
||||
#include "ass_outline.h"
|
||||
#include "ass_cache.h"
|
||||
|
||||
// type-specific functions
|
||||
// create hash/compare functions for bitmap, outline and composite cache
|
||||
#define CREATE_HASH_FUNCTIONS
|
||||
#include "ass_cache_template.h"
|
||||
#define CREATE_COMPARISON_FUNCTIONS
|
||||
#include "ass_cache_template.h"
|
||||
|
||||
// font cache
|
||||
static unsigned font_hash(void *buf, size_t len)
|
||||
{
|
||||
ASS_FontDesc *desc = buf;
|
||||
unsigned hval;
|
||||
hval = fnv_32a_str(desc->family, FNV1_32A_INIT);
|
||||
hval = fnv_32a_buf(&desc->bold, sizeof(desc->bold), hval);
|
||||
hval = fnv_32a_buf(&desc->italic, sizeof(desc->italic), hval);
|
||||
hval = fnv_32a_buf(&desc->vertical, sizeof(desc->vertical), hval);
|
||||
return hval;
|
||||
}
|
||||
|
||||
static unsigned font_compare(void *key1, void *key2, size_t key_size)
|
||||
{
|
||||
ASS_FontDesc *a = key1;
|
||||
ASS_FontDesc *b = key2;
|
||||
if (strcmp(a->family, b->family) != 0)
|
||||
return 0;
|
||||
if (a->bold != b->bold)
|
||||
return 0;
|
||||
if (a->italic != b->italic)
|
||||
return 0;
|
||||
if (a->vertical != b->vertical)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool font_key_move(void *dst, void *src, size_t key_size)
|
||||
{
|
||||
ASS_FontDesc *k = src;
|
||||
if (dst)
|
||||
memcpy(dst, src, key_size);
|
||||
else
|
||||
free(k->family);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void font_destruct(void *key, void *value)
|
||||
{
|
||||
ass_font_clear(value);
|
||||
}
|
||||
|
||||
const CacheDesc font_cache_desc = {
|
||||
.hash_func = font_hash,
|
||||
.compare_func = font_compare,
|
||||
.key_move_func = font_key_move,
|
||||
.destruct_func = font_destruct,
|
||||
.key_size = sizeof(ASS_FontDesc),
|
||||
.value_size = sizeof(ASS_Font)
|
||||
};
|
||||
|
||||
|
||||
// bitmap cache
|
||||
static unsigned bitmap_hash(void *key, size_t key_size)
|
||||
{
|
||||
BitmapHashKey *k = key;
|
||||
switch (k->type) {
|
||||
case BITMAP_OUTLINE: return outline_bitmap_hash(&k->u, key_size);
|
||||
case BITMAP_CLIP: return clip_bitmap_hash(&k->u, key_size);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned bitmap_compare(void *a, void *b, size_t key_size)
|
||||
{
|
||||
BitmapHashKey *ak = a;
|
||||
BitmapHashKey *bk = b;
|
||||
if (ak->type != bk->type) return 0;
|
||||
switch (ak->type) {
|
||||
case BITMAP_OUTLINE: return outline_bitmap_compare(&ak->u, &bk->u, key_size);
|
||||
case BITMAP_CLIP: return clip_bitmap_compare(&ak->u, &bk->u, key_size);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool bitmap_key_move(void *dst, void *src, size_t key_size)
|
||||
{
|
||||
BitmapHashKey *d = dst, *s = src;
|
||||
if (!dst) {
|
||||
if (s->type == BITMAP_OUTLINE)
|
||||
ass_cache_dec_ref(s->u.outline.outline);
|
||||
return true;
|
||||
}
|
||||
memcpy(dst, src, key_size);
|
||||
if (s->type != BITMAP_CLIP)
|
||||
return true;
|
||||
d->u.clip.text = strdup(s->u.clip.text);
|
||||
return d->u.clip.text;
|
||||
}
|
||||
|
||||
static void bitmap_destruct(void *key, void *value)
|
||||
{
|
||||
BitmapHashValue *v = value;
|
||||
BitmapHashKey *k = key;
|
||||
if (v->bm)
|
||||
ass_free_bitmap(v->bm);
|
||||
if (v->bm_o)
|
||||
ass_free_bitmap(v->bm_o);
|
||||
switch (k->type) {
|
||||
case BITMAP_OUTLINE: ass_cache_dec_ref(k->u.outline.outline); break;
|
||||
case BITMAP_CLIP: free(k->u.clip.text); break;
|
||||
}
|
||||
}
|
||||
|
||||
const CacheDesc bitmap_cache_desc = {
|
||||
.hash_func = bitmap_hash,
|
||||
.compare_func = bitmap_compare,
|
||||
.key_move_func = bitmap_key_move,
|
||||
.destruct_func = bitmap_destruct,
|
||||
.key_size = sizeof(BitmapHashKey),
|
||||
.value_size = sizeof(BitmapHashValue)
|
||||
};
|
||||
|
||||
|
||||
// composite cache
|
||||
static unsigned composite_hash(void *key, size_t key_size)
|
||||
{
|
||||
CompositeHashKey *k = key;
|
||||
unsigned hval = filter_hash(&k->filter, key_size);
|
||||
for (size_t i = 0; i < k->bitmap_count; i++) {
|
||||
hval = fnv_32a_buf(&k->bitmaps[i].image, sizeof(k->bitmaps[i].image), hval);
|
||||
hval = fnv_32a_buf(&k->bitmaps[i].x, sizeof(k->bitmaps[i].x), hval);
|
||||
hval = fnv_32a_buf(&k->bitmaps[i].y, sizeof(k->bitmaps[i].y), hval);
|
||||
}
|
||||
return hval;
|
||||
}
|
||||
|
||||
static unsigned composite_compare(void *a, void *b, size_t key_size)
|
||||
{
|
||||
CompositeHashKey *ak = a;
|
||||
CompositeHashKey *bk = b;
|
||||
if (ak->bitmap_count != bk->bitmap_count)
|
||||
return 0;
|
||||
for (size_t i = 0; i < ak->bitmap_count; i++) {
|
||||
if (ak->bitmaps[i].image != bk->bitmaps[i].image ||
|
||||
ak->bitmaps[i].x != bk->bitmaps[i].x ||
|
||||
ak->bitmaps[i].y != bk->bitmaps[i].y)
|
||||
return 0;
|
||||
}
|
||||
return filter_compare(&ak->filter, &bk->filter, key_size);
|
||||
}
|
||||
|
||||
static bool composite_key_move(void *dst, void *src, size_t key_size)
|
||||
{
|
||||
if (dst) {
|
||||
memcpy(dst, src, key_size);
|
||||
return true;
|
||||
}
|
||||
CompositeHashKey *k = src;
|
||||
for (size_t i = 0; i < k->bitmap_count; i++)
|
||||
ass_cache_dec_ref(k->bitmaps[i].image);
|
||||
free(k->bitmaps);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void composite_destruct(void *key, void *value)
|
||||
{
|
||||
CompositeHashValue *v = value;
|
||||
CompositeHashKey *k = key;
|
||||
if (v->bm)
|
||||
ass_free_bitmap(v->bm);
|
||||
if (v->bm_o)
|
||||
ass_free_bitmap(v->bm_o);
|
||||
if (v->bm_s)
|
||||
ass_free_bitmap(v->bm_s);
|
||||
for (size_t i = 0; i < k->bitmap_count; i++)
|
||||
ass_cache_dec_ref(k->bitmaps[i].image);
|
||||
free(k->bitmaps);
|
||||
}
|
||||
|
||||
const CacheDesc composite_cache_desc = {
|
||||
.hash_func = composite_hash,
|
||||
.compare_func = composite_compare,
|
||||
.key_move_func = composite_key_move,
|
||||
.destruct_func = composite_destruct,
|
||||
.key_size = sizeof(CompositeHashKey),
|
||||
.value_size = sizeof(CompositeHashValue)
|
||||
};
|
||||
|
||||
|
||||
// outline cache
|
||||
static unsigned outline_hash(void *key, size_t key_size)
|
||||
{
|
||||
OutlineHashKey *k = key;
|
||||
switch (k->type) {
|
||||
case OUTLINE_GLYPH: return glyph_hash(&k->u, key_size);
|
||||
case OUTLINE_DRAWING: return drawing_hash(&k->u, key_size);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned outline_compare(void *a, void *b, size_t key_size)
|
||||
{
|
||||
OutlineHashKey *ak = a;
|
||||
OutlineHashKey *bk = b;
|
||||
if (ak->type != bk->type) return 0;
|
||||
switch (ak->type) {
|
||||
case OUTLINE_GLYPH: return glyph_compare(&ak->u, &bk->u, key_size);
|
||||
case OUTLINE_DRAWING: return drawing_compare(&ak->u, &bk->u, key_size);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool outline_key_move(void *dst, void *src, size_t key_size)
|
||||
{
|
||||
OutlineHashKey *d = dst, *s = src;
|
||||
if (!dst) {
|
||||
if (s->type == OUTLINE_GLYPH)
|
||||
ass_cache_dec_ref(s->u.glyph.font);
|
||||
return true;
|
||||
}
|
||||
memcpy(dst, src, key_size);
|
||||
if (s->type != OUTLINE_DRAWING)
|
||||
return true;
|
||||
d->u.drawing.text = strdup(s->u.drawing.text);
|
||||
return d->u.drawing.text;
|
||||
}
|
||||
|
||||
static void outline_destruct(void *key, void *value)
|
||||
{
|
||||
OutlineHashValue *v = value;
|
||||
OutlineHashKey *k = key;
|
||||
outline_free(&v->outline);
|
||||
outline_free(&v->border[0]);
|
||||
outline_free(&v->border[1]);
|
||||
switch (k->type) {
|
||||
case OUTLINE_GLYPH: ass_cache_dec_ref(k->u.glyph.font); break;
|
||||
case OUTLINE_DRAWING: free(k->u.drawing.text); break;
|
||||
}
|
||||
}
|
||||
|
||||
const CacheDesc outline_cache_desc = {
|
||||
.hash_func = outline_hash,
|
||||
.compare_func = outline_compare,
|
||||
.key_move_func = outline_key_move,
|
||||
.destruct_func = outline_destruct,
|
||||
.key_size = sizeof(OutlineHashKey),
|
||||
.value_size = sizeof(OutlineHashValue)
|
||||
};
|
||||
|
||||
|
||||
// glyph metric cache
|
||||
static bool glyph_metrics_key_move(void *dst, void *src, size_t key_size)
|
||||
{
|
||||
if (!dst)
|
||||
return true;
|
||||
memcpy(dst, src, key_size);
|
||||
GlyphMetricsHashKey *k = src;
|
||||
ass_cache_inc_ref(k->font);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void glyph_metrics_destruct(void *key, void *value)
|
||||
{
|
||||
GlyphMetricsHashKey *k = key;
|
||||
ass_cache_dec_ref(k->font);
|
||||
}
|
||||
|
||||
const CacheDesc glyph_metrics_cache_desc = {
|
||||
.hash_func = glyph_metrics_hash,
|
||||
.compare_func = glyph_metrics_compare,
|
||||
.key_move_func = glyph_metrics_key_move,
|
||||
.destruct_func = glyph_metrics_destruct,
|
||||
.key_size = sizeof(GlyphMetricsHashKey),
|
||||
.value_size = sizeof(GlyphMetricsHashValue)
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Cache data
|
||||
typedef struct cache_item {
|
||||
Cache *cache;
|
||||
const CacheDesc *desc;
|
||||
struct cache_item *next, **prev;
|
||||
struct cache_item *queue_next, **queue_prev;
|
||||
size_t size, ref_count;
|
||||
} CacheItem;
|
||||
|
||||
struct cache {
|
||||
unsigned buckets;
|
||||
CacheItem **map;
|
||||
CacheItem *queue_first, **queue_last;
|
||||
|
||||
const CacheDesc *desc;
|
||||
|
||||
size_t cache_size;
|
||||
unsigned hits;
|
||||
unsigned misses;
|
||||
unsigned items;
|
||||
};
|
||||
|
||||
#define CACHE_ALIGN 8
|
||||
#define CACHE_ITEM_SIZE ((sizeof(CacheItem) + (CACHE_ALIGN - 1)) & ~(CACHE_ALIGN - 1))
|
||||
|
||||
static inline size_t align_cache(size_t size)
|
||||
{
|
||||
return (size + (CACHE_ALIGN - 1)) & ~(CACHE_ALIGN - 1);
|
||||
}
|
||||
|
||||
static inline CacheItem *value_to_item(void *value)
|
||||
{
|
||||
return (CacheItem *) ((char *) value - CACHE_ITEM_SIZE);
|
||||
}
|
||||
|
||||
|
||||
// Create a cache with type-specific hash/compare/destruct/size functions
|
||||
Cache *ass_cache_create(const CacheDesc *desc)
|
||||
{
|
||||
Cache *cache = calloc(1, sizeof(*cache));
|
||||
if (!cache)
|
||||
return NULL;
|
||||
cache->buckets = 0xFFFF;
|
||||
cache->queue_last = &cache->queue_first;
|
||||
cache->desc = desc;
|
||||
cache->map = calloc(cache->buckets, sizeof(CacheItem *));
|
||||
if (!cache->map) {
|
||||
free(cache);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
bool ass_cache_get(Cache *cache, void *key, void *value_ptr)
|
||||
{
|
||||
char **value = (char **) value_ptr;
|
||||
const CacheDesc *desc = cache->desc;
|
||||
size_t key_offs = CACHE_ITEM_SIZE + align_cache(desc->value_size);
|
||||
unsigned bucket = desc->hash_func(key, desc->key_size) % cache->buckets;
|
||||
CacheItem *item = cache->map[bucket];
|
||||
while (item) {
|
||||
if (desc->compare_func(key, (char *) item + key_offs, desc->key_size)) {
|
||||
assert(item->size);
|
||||
if (!item->queue_prev || item->queue_next) {
|
||||
if (item->queue_prev) {
|
||||
item->queue_next->queue_prev = item->queue_prev;
|
||||
*item->queue_prev = item->queue_next;
|
||||
} else
|
||||
item->ref_count++;
|
||||
*cache->queue_last = item;
|
||||
item->queue_prev = cache->queue_last;
|
||||
cache->queue_last = &item->queue_next;
|
||||
item->queue_next = NULL;
|
||||
}
|
||||
cache->hits++;
|
||||
desc->key_move_func(NULL, key, desc->key_size);
|
||||
*value = (char *) item + CACHE_ITEM_SIZE;
|
||||
item->ref_count++;
|
||||
return true;
|
||||
}
|
||||
item = item->next;
|
||||
}
|
||||
cache->misses++;
|
||||
|
||||
item = malloc(key_offs + desc->key_size);
|
||||
if (!item) {
|
||||
desc->key_move_func(NULL, key, desc->key_size);
|
||||
*value = NULL;
|
||||
return false;
|
||||
}
|
||||
item->size = 0;
|
||||
item->cache = cache;
|
||||
item->desc = desc;
|
||||
if (!desc->key_move_func((char *) item + key_offs, key, desc->key_size)) {
|
||||
free(item);
|
||||
*value = NULL;
|
||||
return false;
|
||||
}
|
||||
*value = (char *) item + CACHE_ITEM_SIZE;
|
||||
|
||||
CacheItem **bucketptr = &cache->map[bucket];
|
||||
if (*bucketptr)
|
||||
(*bucketptr)->prev = &item->next;
|
||||
item->prev = bucketptr;
|
||||
item->next = *bucketptr;
|
||||
*bucketptr = item;
|
||||
|
||||
item->queue_prev = NULL;
|
||||
item->queue_next = NULL;
|
||||
item->ref_count = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
void *ass_cache_key(void *value)
|
||||
{
|
||||
CacheItem *item = value_to_item(value);
|
||||
return (char *) value + align_cache(item->desc->value_size);
|
||||
}
|
||||
|
||||
void ass_cache_commit(void *value, size_t item_size)
|
||||
{
|
||||
CacheItem *item = value_to_item(value);
|
||||
assert(!item->size && item_size);
|
||||
item->size = item_size;
|
||||
Cache *cache = item->cache;
|
||||
cache->cache_size += item_size;
|
||||
cache->items++;
|
||||
|
||||
*cache->queue_last = item;
|
||||
item->queue_prev = cache->queue_last;
|
||||
cache->queue_last = &item->queue_next;
|
||||
item->ref_count++;
|
||||
}
|
||||
|
||||
static inline void destroy_item(const CacheDesc *desc, CacheItem *item)
|
||||
{
|
||||
assert(item->desc == desc);
|
||||
char *value = (char *) item + CACHE_ITEM_SIZE;
|
||||
desc->destruct_func(value + align_cache(desc->value_size), value);
|
||||
free(item);
|
||||
}
|
||||
|
||||
void ass_cache_inc_ref(void *value)
|
||||
{
|
||||
if (!value)
|
||||
return;
|
||||
CacheItem *item = value_to_item(value);
|
||||
assert(item->size && item->ref_count);
|
||||
item->ref_count++;
|
||||
}
|
||||
|
||||
void ass_cache_dec_ref(void *value)
|
||||
{
|
||||
if (!value)
|
||||
return;
|
||||
CacheItem *item = value_to_item(value);
|
||||
assert(item->size && item->ref_count);
|
||||
if (--item->ref_count)
|
||||
return;
|
||||
|
||||
Cache *cache = item->cache;
|
||||
if (cache) {
|
||||
if (item->next)
|
||||
item->next->prev = item->prev;
|
||||
*item->prev = item->next;
|
||||
|
||||
cache->items--;
|
||||
cache->cache_size -= item->size;
|
||||
}
|
||||
destroy_item(item->desc, item);
|
||||
}
|
||||
|
||||
void ass_cache_cut(Cache *cache, size_t max_size)
|
||||
{
|
||||
if (cache->cache_size <= max_size)
|
||||
return;
|
||||
|
||||
do {
|
||||
CacheItem *item = cache->queue_first;
|
||||
if (!item)
|
||||
break;
|
||||
assert(item->size);
|
||||
|
||||
cache->queue_first = item->queue_next;
|
||||
if (--item->ref_count) {
|
||||
item->queue_prev = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item->next)
|
||||
item->next->prev = item->prev;
|
||||
*item->prev = item->next;
|
||||
|
||||
cache->items--;
|
||||
cache->cache_size -= item->size;
|
||||
destroy_item(cache->desc, item);
|
||||
} while (cache->cache_size > max_size);
|
||||
if (cache->queue_first)
|
||||
cache->queue_first->queue_prev = &cache->queue_first;
|
||||
else
|
||||
cache->queue_last = &cache->queue_first;
|
||||
}
|
||||
|
||||
void ass_cache_stats(Cache *cache, size_t *size, unsigned *hits,
|
||||
unsigned *misses, unsigned *count)
|
||||
{
|
||||
if (size)
|
||||
*size = cache->cache_size;
|
||||
if (hits)
|
||||
*hits = cache->hits;
|
||||
if (misses)
|
||||
*misses = cache->misses;
|
||||
if (count)
|
||||
*count = cache->items;
|
||||
}
|
||||
|
||||
void ass_cache_empty(Cache *cache)
|
||||
{
|
||||
for (int i = 0; i < cache->buckets; i++) {
|
||||
CacheItem *item = cache->map[i];
|
||||
while (item) {
|
||||
assert(item->size);
|
||||
CacheItem *next = item->next;
|
||||
if (item->queue_prev)
|
||||
item->ref_count--;
|
||||
if (item->ref_count)
|
||||
item->cache = NULL;
|
||||
else
|
||||
destroy_item(cache->desc, item);
|
||||
item = next;
|
||||
}
|
||||
cache->map[i] = NULL;
|
||||
}
|
||||
|
||||
cache->queue_first = NULL;
|
||||
cache->queue_last = &cache->queue_first;
|
||||
cache->items = cache->hits = cache->misses = cache->cache_size = 0;
|
||||
}
|
||||
|
||||
void ass_cache_done(Cache *cache)
|
||||
{
|
||||
ass_cache_empty(cache);
|
||||
free(cache->map);
|
||||
free(cache);
|
||||
}
|
||||
|
||||
// Type-specific creation function
|
||||
Cache *ass_font_cache_create(void)
|
||||
{
|
||||
return ass_cache_create(&font_cache_desc);
|
||||
}
|
||||
|
||||
Cache *ass_outline_cache_create(void)
|
||||
{
|
||||
return ass_cache_create(&outline_cache_desc);
|
||||
}
|
||||
|
||||
Cache *ass_glyph_metrics_cache_create(void)
|
||||
{
|
||||
return ass_cache_create(&glyph_metrics_cache_desc);
|
||||
}
|
||||
|
||||
Cache *ass_bitmap_cache_create(void)
|
||||
{
|
||||
return ass_cache_create(&bitmap_cache_desc);
|
||||
}
|
||||
|
||||
Cache *ass_composite_cache_create(void)
|
||||
{
|
||||
return ass_cache_create(&composite_cache_desc);
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
||||
* Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBASS_CACHE_H
|
||||
#define LIBASS_CACHE_H
|
||||
|
||||
#include "ass.h"
|
||||
#include "ass_font.h"
|
||||
#include "ass_outline.h"
|
||||
#include "ass_bitmap.h"
|
||||
|
||||
typedef struct cache Cache;
|
||||
|
||||
// cache values
|
||||
|
||||
typedef struct {
|
||||
bool valid;
|
||||
Bitmap *bm; // the actual bitmaps
|
||||
Bitmap *bm_o;
|
||||
} BitmapHashValue;
|
||||
|
||||
typedef struct {
|
||||
Bitmap *bm;
|
||||
Bitmap *bm_o;
|
||||
Bitmap *bm_s;
|
||||
} CompositeHashValue;
|
||||
|
||||
typedef struct {
|
||||
bool valid;
|
||||
ASS_Outline outline;
|
||||
ASS_Outline border[2];
|
||||
ASS_Rect bbox_scaled; // bbox after scaling, but before rotation
|
||||
ASS_Vector advance; // 26.6, advance distance to the next outline in line
|
||||
int asc, desc; // ascender/descender
|
||||
} OutlineHashValue;
|
||||
|
||||
typedef struct {
|
||||
FT_Glyph_Metrics metrics;
|
||||
} GlyphMetricsHashValue;
|
||||
|
||||
// Create definitions for bitmap, outline and composite hash keys
|
||||
#define CREATE_STRUCT_DEFINITIONS
|
||||
#include "ass_cache_template.h"
|
||||
|
||||
// Type-specific function pointers
|
||||
typedef unsigned(*HashFunction)(void *key, size_t key_size);
|
||||
typedef unsigned(*HashCompare)(void *a, void *b, size_t key_size);
|
||||
typedef bool(*CacheKeyMove)(void *dst, void *src, size_t key_size);
|
||||
typedef void(*CacheItemDestructor)(void *key, void *value);
|
||||
|
||||
// cache hash keys
|
||||
|
||||
typedef struct outline_hash_key {
|
||||
enum {
|
||||
OUTLINE_GLYPH,
|
||||
OUTLINE_DRAWING,
|
||||
} type;
|
||||
union {
|
||||
GlyphHashKey glyph;
|
||||
DrawingHashKey drawing;
|
||||
} u;
|
||||
} OutlineHashKey;
|
||||
|
||||
typedef struct bitmap_hash_key {
|
||||
enum {
|
||||
BITMAP_OUTLINE,
|
||||
BITMAP_CLIP,
|
||||
} type;
|
||||
union {
|
||||
OutlineBitmapHashKey outline;
|
||||
ClipMaskHashKey clip;
|
||||
} u;
|
||||
} BitmapHashKey;
|
||||
|
||||
typedef struct {
|
||||
BitmapHashValue *image;
|
||||
int x, y;
|
||||
} BitmapRef;
|
||||
|
||||
enum {
|
||||
FILTER_BORDER_STYLE_3 = 1,
|
||||
FILTER_NONZERO_BORDER = 2,
|
||||
FILTER_NONZERO_SHADOW = 4,
|
||||
FILTER_DRAW_SHADOW = 8, // VSFilter compatibility
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
FilterDesc filter;
|
||||
size_t bitmap_count;
|
||||
BitmapRef *bitmaps;
|
||||
} CompositeHashKey;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HashFunction hash_func;
|
||||
HashCompare compare_func;
|
||||
CacheKeyMove key_move_func;
|
||||
CacheItemDestructor destruct_func;
|
||||
size_t key_size;
|
||||
size_t value_size;
|
||||
} CacheDesc;
|
||||
|
||||
Cache *ass_cache_create(const CacheDesc *desc);
|
||||
bool ass_cache_get(Cache *cache, void *key, void *value_ptr);
|
||||
void *ass_cache_key(void *value);
|
||||
void ass_cache_commit(void *value, size_t item_size);
|
||||
void ass_cache_inc_ref(void *value);
|
||||
void ass_cache_dec_ref(void *value);
|
||||
void ass_cache_cut(Cache *cache, size_t max_size);
|
||||
void ass_cache_stats(Cache *cache, size_t *size, unsigned *hits,
|
||||
unsigned *misses, unsigned *count);
|
||||
void ass_cache_empty(Cache *cache);
|
||||
void ass_cache_done(Cache *cache);
|
||||
Cache *ass_font_cache_create(void);
|
||||
Cache *ass_outline_cache_create(void);
|
||||
Cache *ass_glyph_metrics_cache_create(void);
|
||||
Cache *ass_bitmap_cache_create(void);
|
||||
Cache *ass_composite_cache_create(void);
|
||||
|
||||
#endif /* LIBASS_CACHE_H */
|
|
@ -0,0 +1,134 @@
|
|||
#ifdef CREATE_STRUCT_DEFINITIONS
|
||||
#undef CREATE_STRUCT_DEFINITIONS
|
||||
#define START(funcname, structname) \
|
||||
typedef struct structname {
|
||||
#define GENERIC(type, member) \
|
||||
type member;
|
||||
#define STRING(member) \
|
||||
char *member;
|
||||
#define VECTOR(member) \
|
||||
ASS_Vector member;
|
||||
#define BITMAPHASHKEY(member) \
|
||||
BitmapHashKey member;
|
||||
#define END(typedefnamename) \
|
||||
} typedefnamename;
|
||||
|
||||
#elif defined(CREATE_COMPARISON_FUNCTIONS)
|
||||
#undef CREATE_COMPARISON_FUNCTIONS
|
||||
#define START(funcname, structname) \
|
||||
static unsigned funcname##_compare(void *key1, void *key2, size_t key_size) \
|
||||
{ \
|
||||
struct structname *a = key1; \
|
||||
struct structname *b = key2; \
|
||||
return // conditions follow
|
||||
#define GENERIC(type, member) \
|
||||
a->member == b->member &&
|
||||
#define STRING(member) \
|
||||
strcmp(a->member, b->member) == 0 &&
|
||||
#define VECTOR(member) \
|
||||
a->member.x == b->member.x && a->member.y == b->member.y &&
|
||||
#define BITMAPHASHKEY(member) \
|
||||
bitmap_compare(&a->member, &b->member, sizeof(a->member)) &&
|
||||
#define END(typedefname) \
|
||||
1; \
|
||||
}
|
||||
|
||||
#elif defined(CREATE_HASH_FUNCTIONS)
|
||||
#undef CREATE_HASH_FUNCTIONS
|
||||
#define START(funcname, structname) \
|
||||
static unsigned funcname##_hash(void *buf, size_t len) \
|
||||
{ \
|
||||
struct structname *p = buf; \
|
||||
unsigned hval = FNV1_32A_INIT;
|
||||
#define GENERIC(type, member) \
|
||||
hval = fnv_32a_buf(&p->member, sizeof(p->member), hval);
|
||||
#define STRING(member) \
|
||||
hval = fnv_32a_str(p->member, hval);
|
||||
#define VECTOR(member) GENERIC(, member.x); GENERIC(, member.y);
|
||||
#define BITMAPHASHKEY(member) { \
|
||||
unsigned temp = bitmap_hash(&p->member, sizeof(p->member)); \
|
||||
hval = fnv_32a_buf(&temp, sizeof(temp), hval); \
|
||||
}
|
||||
#define END(typedefname) \
|
||||
return hval; \
|
||||
}
|
||||
|
||||
#else
|
||||
#error missing defines
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// describes an outline bitmap
|
||||
START(outline_bitmap, outline_bitmap_hash_key)
|
||||
GENERIC(OutlineHashValue *, outline)
|
||||
GENERIC(int, frx) // signed 10.22
|
||||
GENERIC(int, fry) // signed 10.22
|
||||
GENERIC(int, frz) // signed 10.22
|
||||
GENERIC(int, fax) // signed 16.16
|
||||
GENERIC(int, fay) // signed 16.16
|
||||
// shift vector that was added to glyph before applying rotation
|
||||
// = 0, if frx = fry = frx = 0
|
||||
// = (glyph base point) - (rotation origin), otherwise
|
||||
GENERIC(int, shift_x)
|
||||
GENERIC(int, shift_y)
|
||||
VECTOR(advance) // subpixel shift vector
|
||||
END(OutlineBitmapHashKey)
|
||||
|
||||
// describe a clip mask bitmap
|
||||
START(clip_bitmap, clip_bitmap_hash_key)
|
||||
STRING(text)
|
||||
END(ClipMaskHashKey)
|
||||
|
||||
// describes an outline glyph
|
||||
START(glyph, glyph_hash_key)
|
||||
GENERIC(ASS_Font *, font)
|
||||
GENERIC(double, size) // font size
|
||||
GENERIC(int, face_index)
|
||||
GENERIC(int, glyph_index)
|
||||
GENERIC(int, bold)
|
||||
GENERIC(int, italic)
|
||||
GENERIC(unsigned, scale_x) // 16.16
|
||||
GENERIC(unsigned, scale_y) // 16.16
|
||||
VECTOR(outline) // border width, 26.6
|
||||
GENERIC(unsigned, flags) // glyph decoration flags
|
||||
GENERIC(unsigned, border_style)
|
||||
GENERIC(int, hspacing) // 16.16
|
||||
END(GlyphHashKey)
|
||||
|
||||
START(glyph_metrics, glyph_metrics_hash_key)
|
||||
GENERIC(ASS_Font *, font)
|
||||
GENERIC(double, size)
|
||||
GENERIC(int, face_index)
|
||||
GENERIC(int, glyph_index)
|
||||
GENERIC(unsigned, scale_x)
|
||||
GENERIC(unsigned, scale_y)
|
||||
END(GlyphMetricsHashKey)
|
||||
|
||||
// describes an outline drawing
|
||||
START(drawing, drawing_hash_key)
|
||||
GENERIC(unsigned, scale_x)
|
||||
GENERIC(unsigned, scale_y)
|
||||
GENERIC(int, pbo)
|
||||
VECTOR(outline)
|
||||
GENERIC(unsigned, border_style)
|
||||
GENERIC(int, hspacing)
|
||||
GENERIC(int, scale)
|
||||
GENERIC(unsigned, hash)
|
||||
STRING(text)
|
||||
END(DrawingHashKey)
|
||||
|
||||
// describes post-combining effects
|
||||
START(filter, filter_desc)
|
||||
GENERIC(int, flags)
|
||||
GENERIC(int, be)
|
||||
GENERIC(double, blur)
|
||||
VECTOR(shadow)
|
||||
END(FilterDesc)
|
||||
|
||||
#undef START
|
||||
#undef GENERIC
|
||||
#undef STRING
|
||||
#undef VECTOR
|
||||
#undef BITMAPHASHKEY
|
||||
#undef END
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Oleg Oshmyan <chortos@inbox.lv>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBASS_COMPAT_H
|
||||
#define LIBASS_COMPAT_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#define _USE_MATH_DEFINES
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
#endif /* LIBASS_COMPAT_H */
|
|
@ -0,0 +1,324 @@
|
|||
/*
|
||||
* Copyright (C) 2013 Stefano Pigozzi <stefano.pigozzi@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ass_compat.h"
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <TargetConditionals.h>
|
||||
#if TARGET_OS_IPHONE
|
||||
#include <CoreText/CoreText.h>
|
||||
#else
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#endif
|
||||
|
||||
#include "ass_coretext.h"
|
||||
|
||||
#define SAFE_CFRelease(x) do { if (x) CFRelease(x); } while(0)
|
||||
|
||||
static const ASS_FontMapping font_substitutions[] = {
|
||||
{"sans-serif", "Helvetica"},
|
||||
{"serif", "Times"},
|
||||
{"monospace", "Courier"}
|
||||
};
|
||||
|
||||
static char *cfstr2buf(CFStringRef string)
|
||||
{
|
||||
if (!string)
|
||||
return NULL;
|
||||
const int encoding = kCFStringEncodingUTF8;
|
||||
const char *buf_ptr = CFStringGetCStringPtr(string, encoding);
|
||||
if (buf_ptr) {
|
||||
return strdup(buf_ptr);
|
||||
} else {
|
||||
size_t len = CFStringGetLength(string);
|
||||
CFIndex buf_len = CFStringGetMaximumSizeForEncoding(len, encoding);
|
||||
char *buf = malloc(buf_len);
|
||||
CFStringGetCString(string, buf, buf_len, encoding);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
static void destroy_font(void *priv)
|
||||
{
|
||||
CTFontDescriptorRef fontd = priv;
|
||||
SAFE_CFRelease(fontd);
|
||||
}
|
||||
|
||||
static bool check_postscript(void *priv)
|
||||
{
|
||||
CTFontDescriptorRef fontd = priv;
|
||||
CFNumberRef cfformat =
|
||||
CTFontDescriptorCopyAttribute(fontd, kCTFontFormatAttribute);
|
||||
int format;
|
||||
|
||||
if (!CFNumberGetValue(cfformat, kCFNumberIntType, &format))
|
||||
return false;
|
||||
|
||||
SAFE_CFRelease(cfformat);
|
||||
|
||||
return format == kCTFontFormatOpenTypePostScript ||
|
||||
format == kCTFontFormatPostScript;
|
||||
}
|
||||
|
||||
static bool check_glyph(void *priv, uint32_t code)
|
||||
{
|
||||
if (code == 0)
|
||||
return true;
|
||||
|
||||
CTFontDescriptorRef fontd = priv;
|
||||
CFCharacterSetRef set =
|
||||
CTFontDescriptorCopyAttribute(fontd, kCTFontCharacterSetAttribute);
|
||||
|
||||
if (!set)
|
||||
return true;
|
||||
|
||||
bool result = CFCharacterSetIsLongCharacterMember(set, code);
|
||||
SAFE_CFRelease(set);
|
||||
return result;
|
||||
}
|
||||
|
||||
static char *get_font_file(CTFontDescriptorRef fontd)
|
||||
{
|
||||
CFURLRef url = CTFontDescriptorCopyAttribute(fontd, kCTFontURLAttribute);
|
||||
CFStringRef path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
|
||||
char *buffer = cfstr2buf(path);
|
||||
SAFE_CFRelease(path);
|
||||
SAFE_CFRelease(url);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void get_name(CTFontDescriptorRef fontd, CFStringRef attr,
|
||||
char **array, int *idx)
|
||||
{
|
||||
|
||||
CFStringRef name = CTFontDescriptorCopyAttribute(fontd, attr);
|
||||
if (name) {
|
||||
array[*idx] = cfstr2buf(name);
|
||||
SAFE_CFRelease(name);
|
||||
*idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void get_trait(CFDictionaryRef traits, CFStringRef attribute,
|
||||
float *trait)
|
||||
{
|
||||
CFNumberRef cftrait = CFDictionaryGetValue(traits, attribute);
|
||||
if (!CFNumberGetValue(cftrait, kCFNumberFloatType, trait))
|
||||
*trait = 0.0;
|
||||
}
|
||||
|
||||
static void get_font_traits(CTFontDescriptorRef fontd,
|
||||
ASS_FontProviderMetaData *meta)
|
||||
{
|
||||
float weight, slant, width;
|
||||
|
||||
CFDictionaryRef traits =
|
||||
CTFontDescriptorCopyAttribute(fontd, kCTFontTraitsAttribute);
|
||||
|
||||
get_trait(traits, kCTFontWeightTrait, &weight);
|
||||
get_trait(traits, kCTFontSlantTrait, &slant);
|
||||
get_trait(traits, kCTFontWidthTrait, &width);
|
||||
|
||||
SAFE_CFRelease(traits);
|
||||
|
||||
// Printed all of my system fonts (see if'deffed code below). Here is how
|
||||
// CoreText 'normalized' weights maps to CSS/libass:
|
||||
|
||||
// opentype: 0 100 200 300 400 500 600 700 800 900
|
||||
// css: LIGHT REG MED SBOLD BOLD BLACK EXTRABL
|
||||
// libass: LIGHT MEDIUM BOLD
|
||||
// coretext: -0.4 0.0 0.23 0.3 0.4 0.62
|
||||
|
||||
if (weight >= 0.62)
|
||||
meta->weight = 800;
|
||||
else if (weight >= 0.4)
|
||||
meta->weight = 700;
|
||||
else if (weight >= 0.3)
|
||||
meta->weight = 600;
|
||||
else if (weight >= 0.23)
|
||||
meta->weight = 500;
|
||||
else if (weight >= -0.4)
|
||||
meta->weight = 400;
|
||||
else
|
||||
meta->weight = 200;
|
||||
|
||||
if (slant > 0.03)
|
||||
meta->slant = FONT_SLANT_ITALIC;
|
||||
else
|
||||
meta->slant = FONT_SLANT_NONE;
|
||||
|
||||
if (width <= -0.2)
|
||||
meta->width = FONT_WIDTH_CONDENSED;
|
||||
else if (width >= 0.2)
|
||||
meta->width = FONT_WIDTH_EXPANDED;
|
||||
else
|
||||
meta->width = FONT_WIDTH_NORMAL;
|
||||
|
||||
#if 0
|
||||
char *name[1];
|
||||
int idx = 0;
|
||||
get_name(fontd, kCTFontDisplayNameAttribute, name, &idx);
|
||||
char *file = get_font_file(fontd);
|
||||
printf(
|
||||
"Font traits for: %-40s [%-50s] "
|
||||
"<slant: %f, %03d>, <weight: (%f, %03d)>, <width: %f, %03d>\n",
|
||||
name[0], file,
|
||||
slant, meta->slant, weight, meta->weight, width, meta->width);
|
||||
free(name[0]);
|
||||
free(file);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void process_descriptors(ASS_FontProvider *provider, CFArrayRef fontsd)
|
||||
{
|
||||
ASS_FontProviderMetaData meta;
|
||||
char *families[1];
|
||||
char *identifiers[1];
|
||||
char *fullnames[1];
|
||||
|
||||
if (!fontsd)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < CFArrayGetCount(fontsd); i++) {
|
||||
CTFontDescriptorRef fontd = CFArrayGetValueAtIndex(fontsd, i);
|
||||
int index = -1;
|
||||
|
||||
char *path = get_font_file(fontd);
|
||||
if (strcmp("", path) == 0) {
|
||||
// skip the font if the URL field in the font descriptor is empty
|
||||
free(path);
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(&meta, 0, sizeof(meta));
|
||||
get_font_traits(fontd, &meta);
|
||||
|
||||
get_name(fontd, kCTFontFamilyNameAttribute, families, &meta.n_family);
|
||||
meta.families = families;
|
||||
|
||||
get_name(fontd, kCTFontDisplayNameAttribute, fullnames, &meta.n_fullname);
|
||||
meta.fullnames = fullnames;
|
||||
|
||||
int zero = 0;
|
||||
get_name(fontd, kCTFontNameAttribute, identifiers, &zero);
|
||||
meta.postscript_name = identifiers[0];
|
||||
|
||||
CFRetain(fontd);
|
||||
ass_font_provider_add_font(provider, &meta, path, index, (void*)fontd);
|
||||
|
||||
for (int j = 0; j < meta.n_family; j++)
|
||||
free(meta.families[j]);
|
||||
|
||||
for (int j = 0; j < meta.n_fullname; j++)
|
||||
free(meta.fullnames[j]);
|
||||
|
||||
free(meta.postscript_name);
|
||||
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
|
||||
static void match_fonts(ASS_Library *lib, ASS_FontProvider *provider,
|
||||
char *name)
|
||||
{
|
||||
enum { attributes_n = 3 };
|
||||
CTFontDescriptorRef ctdescrs[attributes_n];
|
||||
CFMutableDictionaryRef cfattrs[attributes_n];
|
||||
CFStringRef attributes[attributes_n] = {
|
||||
kCTFontFamilyNameAttribute,
|
||||
kCTFontDisplayNameAttribute,
|
||||
kCTFontNameAttribute,
|
||||
};
|
||||
|
||||
CFStringRef cfname =
|
||||
CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8);
|
||||
|
||||
for (int i = 0; i < attributes_n; i++) {
|
||||
cfattrs[i] = CFDictionaryCreateMutable(NULL, 0, 0, 0);
|
||||
CFDictionaryAddValue(cfattrs[i], attributes[i], cfname);
|
||||
ctdescrs[i] = CTFontDescriptorCreateWithAttributes(cfattrs[i]);
|
||||
}
|
||||
|
||||
CFArrayRef descriptors =
|
||||
CFArrayCreate(NULL, (const void **)&ctdescrs, attributes_n, NULL);
|
||||
|
||||
CTFontCollectionRef ctcoll =
|
||||
CTFontCollectionCreateWithFontDescriptors(descriptors, 0);
|
||||
|
||||
CFArrayRef fontsd =
|
||||
CTFontCollectionCreateMatchingFontDescriptors(ctcoll);
|
||||
|
||||
process_descriptors(provider, fontsd);
|
||||
|
||||
SAFE_CFRelease(fontsd);
|
||||
SAFE_CFRelease(ctcoll);
|
||||
|
||||
for (int i = 0; i < attributes_n; i++) {
|
||||
SAFE_CFRelease(cfattrs[i]);
|
||||
SAFE_CFRelease(ctdescrs[i]);
|
||||
}
|
||||
|
||||
SAFE_CFRelease(descriptors);
|
||||
SAFE_CFRelease(cfname);
|
||||
}
|
||||
|
||||
static char *get_fallback(void *priv, const char *family, uint32_t codepoint)
|
||||
{
|
||||
CFStringRef name = CFStringCreateWithBytes(
|
||||
0, (UInt8 *)family, strlen(family), kCFStringEncodingUTF8, false);
|
||||
CTFontRef font = CTFontCreateWithName(name, 0, NULL);
|
||||
uint32_t codepointle = OSSwapHostToLittleInt32(codepoint);
|
||||
CFStringRef r = CFStringCreateWithBytes(
|
||||
0, (UInt8*)&codepointle, sizeof(codepointle),
|
||||
kCFStringEncodingUTF32LE, false);
|
||||
CTFontRef fb = CTFontCreateForString(font, r, CFRangeMake(0, 1));
|
||||
CFStringRef cffamily = CTFontCopyFamilyName(fb);
|
||||
char *res_family = cfstr2buf(cffamily);
|
||||
|
||||
SAFE_CFRelease(name);
|
||||
SAFE_CFRelease(font);
|
||||
SAFE_CFRelease(r);
|
||||
SAFE_CFRelease(fb);
|
||||
SAFE_CFRelease(cffamily);
|
||||
|
||||
return res_family;
|
||||
}
|
||||
|
||||
static void get_substitutions(void *priv, const char *name,
|
||||
ASS_FontProviderMetaData *meta)
|
||||
{
|
||||
const int n = sizeof(font_substitutions) / sizeof(font_substitutions[0]);
|
||||
ass_map_font(font_substitutions, n, name, meta);
|
||||
}
|
||||
|
||||
static ASS_FontProviderFuncs coretext_callbacks = {
|
||||
.check_postscript = check_postscript,
|
||||
.check_glyph = check_glyph,
|
||||
.destroy_font = destroy_font,
|
||||
.match_fonts = match_fonts,
|
||||
.get_substitutions = get_substitutions,
|
||||
.get_fallback = get_fallback,
|
||||
};
|
||||
|
||||
ASS_FontProvider *
|
||||
ass_coretext_add_provider(ASS_Library *lib, ASS_FontSelector *selector,
|
||||
const char *config)
|
||||
{
|
||||
return ass_font_provider_new(selector, &coretext_callbacks, NULL);
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (C) 2013 Stefano Pigozzi <stefano.pigozzi@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ass_types.h"
|
||||
#include "ass_fontselect.h"
|
||||
|
||||
#ifndef ASS_CORETEXT_H
|
||||
#define ASS_CORETEXT_H
|
||||
|
||||
#ifdef CONFIG_CORETEXT
|
||||
|
||||
ASS_FontProvider *
|
||||
ass_coretext_add_provider(ASS_Library *lib, ASS_FontSelector *selector,
|
||||
const char *config);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,800 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Stephan Vedder <stephan.vedder@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#define COBJMACROS
|
||||
|
||||
#include "config.h"
|
||||
#include "ass_compat.h"
|
||||
|
||||
#include <initguid.h>
|
||||
#include <ole2.h>
|
||||
#include <shobjidl.h>
|
||||
|
||||
#include "dwrite_c.h"
|
||||
|
||||
#include "ass_directwrite.h"
|
||||
#include "ass_utils.h"
|
||||
|
||||
#define NAME_MAX_LENGTH 256
|
||||
#define FALLBACK_DEFAULT_FONT L"Arial"
|
||||
|
||||
static const ASS_FontMapping font_substitutions[] = {
|
||||
{"sans-serif", "Arial"},
|
||||
{"serif", "Times New Roman"},
|
||||
{"monospace", "Courier New"}
|
||||
};
|
||||
|
||||
/*
|
||||
* The private data stored for every font, detected by this backend.
|
||||
*/
|
||||
typedef struct {
|
||||
IDWriteFont *font;
|
||||
IDWriteFontFace *face;
|
||||
IDWriteFontFileStream *stream;
|
||||
} FontPrivate;
|
||||
|
||||
typedef struct {
|
||||
HMODULE directwrite_lib;
|
||||
IDWriteFactory *factory;
|
||||
} ProviderPrivate;
|
||||
|
||||
/**
|
||||
* Custom text renderer class for logging the fonts used. It does not
|
||||
* actually render anything or do anything apart from that.
|
||||
*/
|
||||
|
||||
typedef struct FallbackLogTextRenderer {
|
||||
IDWriteTextRenderer iface;
|
||||
IDWriteTextRendererVtbl vtbl;
|
||||
IDWriteFactory *dw_factory;
|
||||
LONG ref_count;
|
||||
} FallbackLogTextRenderer;
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_IsPixelSnappingDisabled(
|
||||
IDWriteTextRenderer *This,
|
||||
void* clientDrawingContext,
|
||||
BOOL* isDisabled
|
||||
)
|
||||
{
|
||||
*isDisabled = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_GetCurrentTransform(
|
||||
IDWriteTextRenderer *This,
|
||||
void* clientDrawingContext,
|
||||
DWRITE_MATRIX* transform
|
||||
)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_GetPixelsPerDip(
|
||||
IDWriteTextRenderer *This,
|
||||
void* clientDrawingContext,
|
||||
FLOAT* pixelsPerDip
|
||||
)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_DrawGlyphRun(
|
||||
IDWriteTextRenderer *This,
|
||||
void* clientDrawingContext,
|
||||
FLOAT baselineOriginX,
|
||||
FLOAT baselineOriginY,
|
||||
DWRITE_MEASURING_MODE measuringMode,
|
||||
DWRITE_GLYPH_RUN const* glyphRun,
|
||||
DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
|
||||
IUnknown* clientDrawingEffect
|
||||
)
|
||||
{
|
||||
FallbackLogTextRenderer *this = (FallbackLogTextRenderer *)This;
|
||||
HRESULT hr;
|
||||
IDWriteFontCollection *font_coll = NULL;
|
||||
IDWriteFont **font = (IDWriteFont **)clientDrawingContext;
|
||||
|
||||
hr = IDWriteFactory_GetSystemFontCollection(this->dw_factory, &font_coll, FALSE);
|
||||
if (FAILED(hr))
|
||||
return E_FAIL;
|
||||
|
||||
hr = IDWriteFontCollection_GetFontFromFontFace(font_coll, glyphRun->fontFace,
|
||||
font);
|
||||
if (FAILED(hr))
|
||||
return E_FAIL;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_DrawUnderline(
|
||||
IDWriteTextRenderer *This,
|
||||
void* clientDrawingContext,
|
||||
FLOAT baselineOriginX,
|
||||
FLOAT baselineOriginY,
|
||||
DWRITE_UNDERLINE const* underline,
|
||||
IUnknown* clientDrawingEffect
|
||||
)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_DrawStrikethrough(
|
||||
IDWriteTextRenderer *This,
|
||||
void* clientDrawingContext,
|
||||
FLOAT baselineOriginX,
|
||||
FLOAT baselineOriginY,
|
||||
DWRITE_STRIKETHROUGH const* strikethrough,
|
||||
IUnknown* clientDrawingEffect
|
||||
)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_DrawInlineObject(
|
||||
IDWriteTextRenderer *This,
|
||||
void *clientDrawingContext,
|
||||
FLOAT originX,
|
||||
FLOAT originY,
|
||||
IDWriteInlineObject *inlineObject,
|
||||
BOOL isSideways,
|
||||
BOOL isRightToLeft,
|
||||
IUnknown *clientDrawingEffect
|
||||
)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// IUnknown methods
|
||||
|
||||
static ULONG STDMETHODCALLTYPE FallbackLogTextRenderer_AddRef(
|
||||
IDWriteTextRenderer *This
|
||||
)
|
||||
{
|
||||
FallbackLogTextRenderer *this = (FallbackLogTextRenderer *)This;
|
||||
return InterlockedIncrement(&this->ref_count);
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE FallbackLogTextRenderer_Release(
|
||||
IDWriteTextRenderer *This
|
||||
)
|
||||
{
|
||||
FallbackLogTextRenderer *this = (FallbackLogTextRenderer *)This;
|
||||
unsigned long new_count = InterlockedDecrement(&this->ref_count);
|
||||
if (new_count == 0) {
|
||||
free(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return new_count;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE FallbackLogTextRenderer_QueryInterface(
|
||||
IDWriteTextRenderer *This,
|
||||
REFIID riid,
|
||||
void **ppvObject
|
||||
)
|
||||
{
|
||||
if (IsEqualGUID(riid, &IID_IDWriteTextRenderer)
|
||||
|| IsEqualGUID(riid, &IID_IDWritePixelSnapping)
|
||||
|| IsEqualGUID(riid, &IID_IUnknown)) {
|
||||
*ppvObject = This;
|
||||
} else {
|
||||
*ppvObject = NULL;
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
This->lpVtbl->AddRef(This);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void init_FallbackLogTextRenderer(FallbackLogTextRenderer *r,
|
||||
IDWriteFactory *factory)
|
||||
{
|
||||
*r = (FallbackLogTextRenderer){
|
||||
.iface = {
|
||||
.lpVtbl = &r->vtbl,
|
||||
},
|
||||
.vtbl = {
|
||||
FallbackLogTextRenderer_QueryInterface,
|
||||
FallbackLogTextRenderer_AddRef,
|
||||
FallbackLogTextRenderer_Release,
|
||||
FallbackLogTextRenderer_IsPixelSnappingDisabled,
|
||||
FallbackLogTextRenderer_GetCurrentTransform,
|
||||
FallbackLogTextRenderer_GetPixelsPerDip,
|
||||
FallbackLogTextRenderer_DrawGlyphRun,
|
||||
FallbackLogTextRenderer_DrawUnderline,
|
||||
FallbackLogTextRenderer_DrawStrikethrough,
|
||||
FallbackLogTextRenderer_DrawInlineObject,
|
||||
},
|
||||
.dw_factory = factory,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called whenever a font is accessed for the
|
||||
* first time. It will create a FontFace for metadata access and
|
||||
* memory reading, which will be stored within the private data.
|
||||
*/
|
||||
static bool init_font_private_face(FontPrivate *priv)
|
||||
{
|
||||
HRESULT hr;
|
||||
IDWriteFontFace *face;
|
||||
|
||||
if (priv->face != NULL)
|
||||
return true;
|
||||
|
||||
hr = IDWriteFont_CreateFontFace(priv->font, &face);
|
||||
if (FAILED(hr) || !face)
|
||||
return false;
|
||||
|
||||
priv->face = face;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called whenever a font is used for the first
|
||||
* time. It will create a FontStream for memory reading, which
|
||||
* will be stored within the private data.
|
||||
*/
|
||||
static bool init_font_private_stream(FontPrivate *priv)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
IDWriteFontFile *file = NULL;
|
||||
IDWriteFontFileStream *stream = NULL;
|
||||
IDWriteFontFileLoader *loader = NULL;
|
||||
UINT32 n_files = 1;
|
||||
const void *refKey = NULL;
|
||||
UINT32 keySize = 0;
|
||||
|
||||
if (priv->stream != NULL)
|
||||
return true;
|
||||
|
||||
if (!init_font_private_face(priv))
|
||||
return false;
|
||||
|
||||
/* DirectWrite only supports one file per face */
|
||||
hr = IDWriteFontFace_GetFiles(priv->face, &n_files, &file);
|
||||
if (FAILED(hr) || !file)
|
||||
return false;
|
||||
|
||||
hr = IDWriteFontFile_GetReferenceKey(file, &refKey, &keySize);
|
||||
if (FAILED(hr)) {
|
||||
IDWriteFontFile_Release(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = IDWriteFontFile_GetLoader(file, &loader);
|
||||
if (FAILED(hr) || !loader) {
|
||||
IDWriteFontFile_Release(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, refKey, keySize, &stream);
|
||||
if (FAILED(hr) || !stream) {
|
||||
IDWriteFontFile_Release(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
priv->stream = stream;
|
||||
IDWriteFontFile_Release(file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a specified part of a fontfile into memory.
|
||||
* If the font wasn't used before first creates a
|
||||
* FontStream and save it into the private data for later usage.
|
||||
* If the parameter "buf" is NULL libass wants to know the
|
||||
* size of the Fontfile
|
||||
*/
|
||||
static size_t get_data(void *data, unsigned char *buf, size_t offset,
|
||||
size_t length)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
FontPrivate *priv = (FontPrivate *) data;
|
||||
const void *fileBuf = NULL;
|
||||
void *fragContext = NULL;
|
||||
|
||||
if (!init_font_private_stream(priv))
|
||||
return 0;
|
||||
|
||||
if (buf == NULL) {
|
||||
UINT64 fileSize;
|
||||
hr = IDWriteFontFileStream_GetFileSize(priv->stream, &fileSize);
|
||||
if (FAILED(hr))
|
||||
return 0;
|
||||
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
hr = IDWriteFontFileStream_ReadFileFragment(priv->stream, &fileBuf, offset,
|
||||
length, &fragContext);
|
||||
|
||||
if (FAILED(hr) || !fileBuf)
|
||||
return 0;
|
||||
|
||||
memcpy(buf, fileBuf, length);
|
||||
|
||||
IDWriteFontFileStream_ReleaseFileFragment(priv->stream, fragContext);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the font contains PostScript outlines.
|
||||
*/
|
||||
static bool check_postscript(void *data)
|
||||
{
|
||||
FontPrivate *priv = (FontPrivate *) data;
|
||||
|
||||
if (!init_font_private_face(priv))
|
||||
return false;
|
||||
|
||||
DWRITE_FONT_FACE_TYPE type = IDWriteFontFace_GetType(priv->face);
|
||||
return type == DWRITE_FONT_FACE_TYPE_CFF ||
|
||||
type == DWRITE_FONT_FACE_TYPE_RAW_CFF ||
|
||||
type == DWRITE_FONT_FACE_TYPE_TYPE1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lazily return index of font. It requires the FontFace to be present, which is expensive to initialize.
|
||||
*/
|
||||
static unsigned get_font_index(void *data)
|
||||
{
|
||||
FontPrivate *priv = (FontPrivate *)data;
|
||||
|
||||
if (!init_font_private_face(priv))
|
||||
return 0;
|
||||
|
||||
return IDWriteFontFace_GetIndex(priv->face);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the passed font has a specific unicode character.
|
||||
*/
|
||||
static bool check_glyph(void *data, uint32_t code)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
FontPrivate *priv = (FontPrivate *) data;
|
||||
BOOL exists = FALSE;
|
||||
|
||||
if (code == 0)
|
||||
return true;
|
||||
|
||||
hr = IDWriteFont_HasCharacter(priv->font, code, &exists);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
/*
|
||||
* This will release the directwrite backend
|
||||
*/
|
||||
static void destroy_provider(void *priv)
|
||||
{
|
||||
ProviderPrivate *provider_priv = (ProviderPrivate *)priv;
|
||||
provider_priv->factory->lpVtbl->Release(provider_priv->factory);
|
||||
FreeLibrary(provider_priv->directwrite_lib);
|
||||
free(provider_priv);
|
||||
}
|
||||
|
||||
/*
|
||||
* This will destroy a specific font and it's
|
||||
* Fontstream (in case it does exist)
|
||||
*/
|
||||
|
||||
static void destroy_font(void *data)
|
||||
{
|
||||
FontPrivate *priv = (FontPrivate *) data;
|
||||
|
||||
IDWriteFont_Release(priv->font);
|
||||
if (priv->face != NULL)
|
||||
IDWriteFontFace_Release(priv->face);
|
||||
if (priv->stream != NULL)
|
||||
IDWriteFontFileStream_Release(priv->stream);
|
||||
|
||||
free(priv);
|
||||
}
|
||||
|
||||
static int encode_utf16(wchar_t *chars, uint32_t codepoint)
|
||||
{
|
||||
if (codepoint < 0x10000) {
|
||||
chars[0] = codepoint;
|
||||
return 1;
|
||||
} else {
|
||||
chars[0] = (codepoint >> 10) + 0xD7C0;
|
||||
chars[1] = (codepoint & 0x3FF) + 0xDC00;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static char *get_fallback(void *priv, const char *base, uint32_t codepoint)
|
||||
{
|
||||
HRESULT hr;
|
||||
ProviderPrivate *provider_priv = (ProviderPrivate *)priv;
|
||||
IDWriteFactory *dw_factory = provider_priv->factory;
|
||||
IDWriteTextFormat *text_format = NULL;
|
||||
IDWriteTextLayout *text_layout = NULL;
|
||||
FallbackLogTextRenderer renderer;
|
||||
|
||||
init_FallbackLogTextRenderer(&renderer, dw_factory);
|
||||
|
||||
hr = IDWriteFactory_CreateTextFormat(dw_factory, FALLBACK_DEFAULT_FONT, NULL,
|
||||
DWRITE_FONT_WEIGHT_MEDIUM, DWRITE_FONT_STYLE_NORMAL,
|
||||
DWRITE_FONT_STRETCH_NORMAL, 1.0f, L"", &text_format);
|
||||
if (FAILED(hr)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Encode codepoint as UTF-16
|
||||
wchar_t char_string[2];
|
||||
int char_len = encode_utf16(char_string, codepoint);
|
||||
|
||||
// Create a text_layout, a high-level text rendering facility, using
|
||||
// the given codepoint and dummy format.
|
||||
hr = IDWriteFactory_CreateTextLayout(dw_factory, char_string, char_len, text_format,
|
||||
0.0f, 0.0f, &text_layout);
|
||||
if (FAILED(hr)) {
|
||||
IDWriteTextFormat_Release(text_format);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Draw the layout with a dummy renderer, which logs the
|
||||
// font used and stores it.
|
||||
IDWriteFont *font = NULL;
|
||||
hr = IDWriteTextLayout_Draw(text_layout, &font, &renderer.iface, 0.0f, 0.0f);
|
||||
if (FAILED(hr) || font == NULL) {
|
||||
IDWriteTextLayout_Release(text_layout);
|
||||
IDWriteTextFormat_Release(text_format);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// We're done with these now
|
||||
IDWriteTextLayout_Release(text_layout);
|
||||
IDWriteTextFormat_Release(text_format);
|
||||
|
||||
// Now, just extract the first family name
|
||||
BOOL exists = FALSE;
|
||||
IDWriteLocalizedStrings *familyNames = NULL;
|
||||
hr = IDWriteFont_GetInformationalStrings(font,
|
||||
DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES,
|
||||
&familyNames, &exists);
|
||||
if (FAILED(hr) || !exists) {
|
||||
IDWriteFont_Release(font);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wchar_t temp_name[NAME_MAX_LENGTH];
|
||||
hr = IDWriteLocalizedStrings_GetString(familyNames, 0, temp_name, NAME_MAX_LENGTH);
|
||||
if (FAILED(hr)) {
|
||||
IDWriteLocalizedStrings_Release(familyNames);
|
||||
IDWriteFont_Release(font);
|
||||
return NULL;
|
||||
}
|
||||
temp_name[NAME_MAX_LENGTH-1] = 0;
|
||||
|
||||
// DirectWrite may not have found a valid fallback, so check that
|
||||
// the selected font actually has the requested glyph.
|
||||
if (codepoint > 0) {
|
||||
hr = IDWriteFont_HasCharacter(font, codepoint, &exists);
|
||||
if (FAILED(hr) || !exists) {
|
||||
IDWriteLocalizedStrings_Release(familyNames);
|
||||
IDWriteFont_Release(font);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, NULL, 0,NULL, NULL);
|
||||
char *family = (char *) malloc(size_needed);
|
||||
WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, family, size_needed, NULL, NULL);
|
||||
|
||||
IDWriteLocalizedStrings_Release(familyNames);
|
||||
IDWriteFont_Release(font);
|
||||
return family;
|
||||
}
|
||||
|
||||
static int map_width(enum DWRITE_FONT_STRETCH stretch)
|
||||
{
|
||||
switch (stretch) {
|
||||
case DWRITE_FONT_STRETCH_ULTRA_CONDENSED: return 50;
|
||||
case DWRITE_FONT_STRETCH_EXTRA_CONDENSED: return 63;
|
||||
case DWRITE_FONT_STRETCH_CONDENSED: return FONT_WIDTH_CONDENSED;
|
||||
case DWRITE_FONT_STRETCH_SEMI_CONDENSED: return 88;
|
||||
case DWRITE_FONT_STRETCH_MEDIUM: return FONT_WIDTH_NORMAL;
|
||||
case DWRITE_FONT_STRETCH_SEMI_EXPANDED: return 113;
|
||||
case DWRITE_FONT_STRETCH_EXPANDED: return FONT_WIDTH_EXPANDED;
|
||||
case DWRITE_FONT_STRETCH_EXTRA_EXPANDED: return 150;
|
||||
case DWRITE_FONT_STRETCH_ULTRA_EXPANDED: return 200;
|
||||
default:
|
||||
return FONT_WIDTH_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
static void add_font(IDWriteFont *font, IDWriteFontFamily *fontFamily,
|
||||
ASS_FontProvider *provider)
|
||||
{
|
||||
HRESULT hr;
|
||||
BOOL exists;
|
||||
wchar_t temp_name[NAME_MAX_LENGTH];
|
||||
int size_needed;
|
||||
ASS_FontProviderMetaData meta = {0};
|
||||
|
||||
meta.weight = IDWriteFont_GetWeight(font);
|
||||
meta.width = map_width(IDWriteFont_GetStretch(font));
|
||||
|
||||
DWRITE_FONT_STYLE style = IDWriteFont_GetStyle(font);
|
||||
meta.slant = (style == DWRITE_FONT_STYLE_NORMAL) ? FONT_SLANT_NONE :
|
||||
(style == DWRITE_FONT_STYLE_OBLIQUE)? FONT_SLANT_OBLIQUE :
|
||||
(style == DWRITE_FONT_STYLE_ITALIC) ? FONT_SLANT_ITALIC : FONT_SLANT_NONE;
|
||||
|
||||
IDWriteLocalizedStrings *psNames;
|
||||
hr = IDWriteFont_GetInformationalStrings(font,
|
||||
DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, &psNames, &exists);
|
||||
if (FAILED(hr))
|
||||
goto cleanup;
|
||||
|
||||
if (exists) {
|
||||
hr = IDWriteLocalizedStrings_GetString(psNames, 0, temp_name, NAME_MAX_LENGTH);
|
||||
if (FAILED(hr)) {
|
||||
IDWriteLocalizedStrings_Release(psNames);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
temp_name[NAME_MAX_LENGTH-1] = 0;
|
||||
size_needed = WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, NULL, 0, NULL, NULL);
|
||||
char *mbName = (char *) malloc(size_needed);
|
||||
if (!mbName) {
|
||||
IDWriteLocalizedStrings_Release(psNames);
|
||||
goto cleanup;
|
||||
}
|
||||
WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, mbName, size_needed, NULL, NULL);
|
||||
meta.postscript_name = mbName;
|
||||
|
||||
IDWriteLocalizedStrings_Release(psNames);
|
||||
}
|
||||
|
||||
IDWriteLocalizedStrings *fontNames;
|
||||
hr = IDWriteFont_GetInformationalStrings(font,
|
||||
DWRITE_INFORMATIONAL_STRING_FULL_NAME, &fontNames, &exists);
|
||||
if (FAILED(hr))
|
||||
goto cleanup;
|
||||
|
||||
if (exists) {
|
||||
meta.n_fullname = IDWriteLocalizedStrings_GetCount(fontNames);
|
||||
meta.fullnames = (char **) calloc(meta.n_fullname, sizeof(char *));
|
||||
if (!meta.fullnames) {
|
||||
IDWriteLocalizedStrings_Release(fontNames);
|
||||
goto cleanup;
|
||||
}
|
||||
for (int k = 0; k < meta.n_fullname; k++) {
|
||||
hr = IDWriteLocalizedStrings_GetString(fontNames, k,
|
||||
temp_name,
|
||||
NAME_MAX_LENGTH);
|
||||
if (FAILED(hr)) {
|
||||
IDWriteLocalizedStrings_Release(fontNames);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
temp_name[NAME_MAX_LENGTH-1] = 0;
|
||||
size_needed = WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, NULL, 0, NULL, NULL);
|
||||
char *mbName = (char *) malloc(size_needed);
|
||||
if (!mbName) {
|
||||
IDWriteLocalizedStrings_Release(fontNames);
|
||||
goto cleanup;
|
||||
}
|
||||
WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, mbName, size_needed, NULL, NULL);
|
||||
meta.fullnames[k] = mbName;
|
||||
}
|
||||
IDWriteLocalizedStrings_Release(fontNames);
|
||||
}
|
||||
|
||||
IDWriteLocalizedStrings *familyNames;
|
||||
hr = IDWriteFont_GetInformationalStrings(font,
|
||||
DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &familyNames, &exists);
|
||||
if (FAILED(hr) || !exists)
|
||||
hr = IDWriteFontFamily_GetFamilyNames(fontFamily, &familyNames);
|
||||
if (FAILED(hr))
|
||||
goto cleanup;
|
||||
|
||||
meta.n_family = IDWriteLocalizedStrings_GetCount(familyNames);
|
||||
meta.families = (char **) calloc(meta.n_family, sizeof(char *));
|
||||
if (!meta.families) {
|
||||
IDWriteLocalizedStrings_Release(familyNames);
|
||||
goto cleanup;
|
||||
}
|
||||
for (int k = 0; k < meta.n_family; k++) {
|
||||
hr = IDWriteLocalizedStrings_GetString(familyNames, k,
|
||||
temp_name,
|
||||
NAME_MAX_LENGTH);
|
||||
if (FAILED(hr)) {
|
||||
IDWriteLocalizedStrings_Release(familyNames);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
temp_name[NAME_MAX_LENGTH-1] = 0;
|
||||
size_needed = WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, NULL, 0, NULL, NULL);
|
||||
char *mbName = (char *) malloc(size_needed);
|
||||
if (!mbName) {
|
||||
IDWriteLocalizedStrings_Release(familyNames);
|
||||
goto cleanup;
|
||||
}
|
||||
WideCharToMultiByte(CP_UTF8, 0, temp_name, -1, mbName, size_needed, NULL, NULL);
|
||||
meta.families[k] = mbName;
|
||||
}
|
||||
IDWriteLocalizedStrings_Release(familyNames);
|
||||
|
||||
FontPrivate *font_priv = (FontPrivate *) calloc(1, sizeof(*font_priv));
|
||||
if (!font_priv)
|
||||
goto cleanup;
|
||||
font_priv->font = font;
|
||||
font = NULL;
|
||||
|
||||
ass_font_provider_add_font(provider, &meta, NULL, 0, font_priv);
|
||||
|
||||
cleanup:
|
||||
if (meta.families) {
|
||||
for (int k = 0; k < meta.n_family; k++)
|
||||
free(meta.families[k]);
|
||||
free(meta.families);
|
||||
}
|
||||
|
||||
if (meta.fullnames) {
|
||||
for (int k = 0; k < meta.n_fullname; k++)
|
||||
free(meta.fullnames[k]);
|
||||
free(meta.fullnames);
|
||||
}
|
||||
|
||||
free(meta.postscript_name);
|
||||
|
||||
if (font)
|
||||
IDWriteFont_Release(font);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan every system font on the current machine and add it
|
||||
* to the libass lookup. Stores the FontPrivate as private data
|
||||
* for later memory reading
|
||||
*/
|
||||
static void scan_fonts(IDWriteFactory *factory,
|
||||
ASS_FontProvider *provider)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
IDWriteFontCollection *fontCollection = NULL;
|
||||
IDWriteFont *font = NULL;
|
||||
hr = IDWriteFactory_GetSystemFontCollection(factory, &fontCollection, FALSE);
|
||||
|
||||
if (FAILED(hr) || !fontCollection)
|
||||
return;
|
||||
|
||||
UINT32 familyCount = IDWriteFontCollection_GetFontFamilyCount(fontCollection);
|
||||
|
||||
for (UINT32 i = 0; i < familyCount; ++i) {
|
||||
IDWriteFontFamily *fontFamily = NULL;
|
||||
|
||||
hr = IDWriteFontCollection_GetFontFamily(fontCollection, i, &fontFamily);
|
||||
if (FAILED(hr))
|
||||
continue;
|
||||
|
||||
UINT32 fontCount = IDWriteFontFamily_GetFontCount(fontFamily);
|
||||
for (UINT32 j = 0; j < fontCount; ++j) {
|
||||
hr = IDWriteFontFamily_GetFont(fontFamily, j, &font);
|
||||
if (FAILED(hr))
|
||||
continue;
|
||||
|
||||
// Simulations for bold or oblique are sometimes synthesized by
|
||||
// DirectWrite. We are only interested in physical fonts.
|
||||
if (IDWriteFont_GetSimulations(font) != 0) {
|
||||
IDWriteFont_Release(font);
|
||||
continue;
|
||||
}
|
||||
|
||||
add_font(font, fontFamily, provider);
|
||||
}
|
||||
|
||||
IDWriteFontFamily_Release(fontFamily);
|
||||
}
|
||||
|
||||
IDWriteFontCollection_Release(fontCollection);
|
||||
}
|
||||
|
||||
static void get_substitutions(void *priv, const char *name,
|
||||
ASS_FontProviderMetaData *meta)
|
||||
{
|
||||
const int n = sizeof(font_substitutions) / sizeof(font_substitutions[0]);
|
||||
ass_map_font(font_substitutions, n, name, meta);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by libass when the provider should perform the
|
||||
* specified task
|
||||
*/
|
||||
static ASS_FontProviderFuncs directwrite_callbacks = {
|
||||
.get_data = get_data,
|
||||
.check_postscript = check_postscript,
|
||||
.check_glyph = check_glyph,
|
||||
.destroy_font = destroy_font,
|
||||
.destroy_provider = destroy_provider,
|
||||
.get_substitutions = get_substitutions,
|
||||
.get_fallback = get_fallback,
|
||||
.get_font_index = get_font_index,
|
||||
};
|
||||
|
||||
typedef HRESULT (WINAPI *DWriteCreateFactoryFn)(
|
||||
DWRITE_FACTORY_TYPE factoryType,
|
||||
REFIID iid,
|
||||
IUnknown **factory
|
||||
);
|
||||
|
||||
/*
|
||||
* Register the directwrite provider. Upon registering
|
||||
* scans all system fonts. The private data for this
|
||||
* provider is IDWriteFactory
|
||||
* On failure returns NULL
|
||||
*/
|
||||
ASS_FontProvider *ass_directwrite_add_provider(ASS_Library *lib,
|
||||
ASS_FontSelector *selector,
|
||||
const char *config)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
IDWriteFactory *dwFactory = NULL;
|
||||
ASS_FontProvider *provider = NULL;
|
||||
DWriteCreateFactoryFn DWriteCreateFactoryPtr = NULL;
|
||||
ProviderPrivate *priv = NULL;
|
||||
|
||||
HMODULE directwrite_lib = LoadLibraryW(L"Dwrite.dll");
|
||||
if (!directwrite_lib)
|
||||
goto cleanup;
|
||||
|
||||
DWriteCreateFactoryPtr = (DWriteCreateFactoryFn)GetProcAddress(directwrite_lib,
|
||||
"DWriteCreateFactory");
|
||||
if (!DWriteCreateFactoryPtr)
|
||||
goto cleanup;
|
||||
|
||||
hr = DWriteCreateFactoryPtr(DWRITE_FACTORY_TYPE_SHARED,
|
||||
&IID_IDWriteFactory,
|
||||
(IUnknown **) (&dwFactory));
|
||||
if (FAILED(hr) || !dwFactory) {
|
||||
ass_msg(lib, MSGL_WARN, "Failed to initialize directwrite.");
|
||||
dwFactory = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
priv = (ProviderPrivate *)calloc(sizeof(*priv), 1);
|
||||
if (!priv)
|
||||
goto cleanup;
|
||||
|
||||
priv->directwrite_lib = directwrite_lib;
|
||||
priv->factory = dwFactory;
|
||||
provider = ass_font_provider_new(selector, &directwrite_callbacks, priv);
|
||||
if (!provider)
|
||||
goto cleanup;
|
||||
|
||||
scan_fonts(dwFactory, provider);
|
||||
return provider;
|
||||
|
||||
cleanup:
|
||||
|
||||
free(priv);
|
||||
if (dwFactory)
|
||||
dwFactory->lpVtbl->Release(dwFactory);
|
||||
if (directwrite_lib)
|
||||
FreeLibrary(directwrite_lib);
|
||||
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Stephan Vedder <stephan.vedder@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ass_types.h"
|
||||
#include "ass_fontselect.h"
|
||||
|
||||
#ifndef ASS_DIRECTWRITE_H
|
||||
#define ASS_DIRECTWRITE_H
|
||||
|
||||
ASS_FontProvider *
|
||||
ass_directwrite_add_provider(ASS_Library *lib, ASS_FontSelector *selector,
|
||||
const char *config);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,365 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ass_compat.h"
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_OUTLINE_H
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "ass_utils.h"
|
||||
#include "ass_drawing.h"
|
||||
#include "ass_font.h"
|
||||
|
||||
#define GLYPH_INITIAL_POINTS 100
|
||||
#define GLYPH_INITIAL_SEGMENTS 100
|
||||
|
||||
/*
|
||||
* \brief Prepare drawing for parsing. This just sets a few parameters.
|
||||
*/
|
||||
static void drawing_prepare(ASS_Drawing *drawing)
|
||||
{
|
||||
// Scaling parameters
|
||||
drawing->point_scale_x = drawing->scale_x / (1 << (drawing->scale - 1));
|
||||
drawing->point_scale_y = drawing->scale_y / (1 << (drawing->scale - 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Finish a drawing. This only sets the horizontal advance according
|
||||
* to the outline's bbox at the moment.
|
||||
*/
|
||||
static void drawing_finish(ASS_Drawing *drawing, bool raw_mode)
|
||||
{
|
||||
ASS_Rect bbox = drawing->cbox;
|
||||
ASS_Outline *ol = &drawing->outline;
|
||||
|
||||
if (drawing->library)
|
||||
ass_msg(drawing->library, MSGL_V,
|
||||
"Parsed drawing with %d points and %d segments",
|
||||
ol->n_points, ol->n_segments);
|
||||
|
||||
if (raw_mode)
|
||||
return;
|
||||
|
||||
drawing->advance.x = bbox.x_max - bbox.x_min;
|
||||
|
||||
double pbo = drawing->pbo / (1 << (drawing->scale - 1));
|
||||
drawing->desc = double_to_d6(pbo * drawing->scale_y);
|
||||
drawing->asc = bbox.y_max - bbox.y_min - drawing->desc;
|
||||
|
||||
// Place it onto the baseline
|
||||
for (size_t i = 0; i < ol->n_points; i++)
|
||||
ol->points[i].y -= drawing->asc;
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Check whether a number of items on the list is available
|
||||
*/
|
||||
static int token_check_values(ASS_DrawingToken *token, int i, int type)
|
||||
{
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (!token || token->type != type) return 0;
|
||||
token = token->next;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Tokenize a drawing string into a list of ASS_DrawingToken
|
||||
* This also expands points for closing b-splines
|
||||
*/
|
||||
static ASS_DrawingToken *drawing_tokenize(char *str)
|
||||
{
|
||||
char *p = str;
|
||||
int type = -1, is_set = 0;
|
||||
double val;
|
||||
ASS_Vector point = {0, 0};
|
||||
|
||||
ASS_DrawingToken *root = NULL, *tail = NULL, *spline_start = NULL;
|
||||
|
||||
while (p && *p) {
|
||||
int got_coord = 0;
|
||||
if (*p == 'c' && spline_start) {
|
||||
// Close b-splines: add the first three points of the b-spline
|
||||
// back to the end
|
||||
if (token_check_values(spline_start->next, 2, TOKEN_B_SPLINE)) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
tail->next = calloc(1, sizeof(ASS_DrawingToken));
|
||||
tail->next->prev = tail;
|
||||
tail = tail->next;
|
||||
tail->type = TOKEN_B_SPLINE;
|
||||
tail->point = spline_start->point;
|
||||
spline_start = spline_start->next;
|
||||
}
|
||||
spline_start = NULL;
|
||||
}
|
||||
} else if (!is_set && mystrtod(&p, &val)) {
|
||||
point.x = double_to_d6(val);
|
||||
is_set = 1;
|
||||
got_coord = 1;
|
||||
p--;
|
||||
} else if (is_set == 1 && mystrtod(&p, &val)) {
|
||||
point.y = double_to_d6(val);
|
||||
is_set = 2;
|
||||
got_coord = 1;
|
||||
p--;
|
||||
} else if (*p == 'm')
|
||||
type = TOKEN_MOVE;
|
||||
else if (*p == 'n')
|
||||
type = TOKEN_MOVE_NC;
|
||||
else if (*p == 'l')
|
||||
type = TOKEN_LINE;
|
||||
else if (*p == 'b')
|
||||
type = TOKEN_CUBIC_BEZIER;
|
||||
else if (*p == 'q')
|
||||
type = TOKEN_CONIC_BEZIER;
|
||||
else if (*p == 's')
|
||||
type = TOKEN_B_SPLINE;
|
||||
// We're simply ignoring TOKEN_EXTEND_B_SPLINE here.
|
||||
// This is not harmful at all, since it can be ommitted with
|
||||
// similar result (the spline is extended anyway).
|
||||
|
||||
// Ignore the odd extra value, it makes no sense.
|
||||
if (!got_coord)
|
||||
is_set = 0;
|
||||
|
||||
if (type != -1 && is_set == 2) {
|
||||
if (root) {
|
||||
tail->next = calloc(1, sizeof(ASS_DrawingToken));
|
||||
tail->next->prev = tail;
|
||||
tail = tail->next;
|
||||
} else
|
||||
root = tail = calloc(1, sizeof(ASS_DrawingToken));
|
||||
tail->type = type;
|
||||
tail->point = point;
|
||||
is_set = 0;
|
||||
if (type == TOKEN_B_SPLINE && !spline_start)
|
||||
spline_start = tail->prev;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Free a list of tokens
|
||||
*/
|
||||
static void drawing_free_tokens(ASS_DrawingToken *token)
|
||||
{
|
||||
while (token) {
|
||||
ASS_DrawingToken *at = token;
|
||||
token = token->next;
|
||||
free(at);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Translate and scale a point coordinate according to baseline
|
||||
* offset and scale.
|
||||
*/
|
||||
static inline void translate_point(ASS_Drawing *drawing, ASS_Vector *point)
|
||||
{
|
||||
point->x = lrint(drawing->point_scale_x * point->x);
|
||||
point->y = lrint(drawing->point_scale_y * point->y);
|
||||
|
||||
rectangle_update(&drawing->cbox, point->x, point->y, point->x, point->y);
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Add curve to drawing
|
||||
*/
|
||||
static bool drawing_add_curve(ASS_Drawing *drawing, ASS_DrawingToken *token,
|
||||
bool spline, int started)
|
||||
{
|
||||
ASS_Vector p[4];
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
p[i] = token->point;
|
||||
translate_point(drawing, &p[i]);
|
||||
token = token->next;
|
||||
}
|
||||
|
||||
if (spline) {
|
||||
int x01 = (p[1].x - p[0].x) / 3;
|
||||
int y01 = (p[1].y - p[0].y) / 3;
|
||||
int x12 = (p[2].x - p[1].x) / 3;
|
||||
int y12 = (p[2].y - p[1].y) / 3;
|
||||
int x23 = (p[3].x - p[2].x) / 3;
|
||||
int y23 = (p[3].y - p[2].y) / 3;
|
||||
|
||||
p[0].x = p[1].x + ((x12 - x01) >> 1);
|
||||
p[0].y = p[1].y + ((y12 - y01) >> 1);
|
||||
p[3].x = p[2].x + ((x23 - x12) >> 1);
|
||||
p[3].y = p[2].y + ((y23 - y12) >> 1);
|
||||
p[1].x += x12;
|
||||
p[1].y += y12;
|
||||
p[2].x -= x12;
|
||||
p[2].y -= y12;
|
||||
}
|
||||
|
||||
return (started ||
|
||||
outline_add_point(&drawing->outline, p[0], 0)) &&
|
||||
outline_add_point(&drawing->outline, p[1], 0) &&
|
||||
outline_add_point(&drawing->outline, p[2], 0) &&
|
||||
outline_add_point(&drawing->outline, p[3], OUTLINE_CUBIC_SPLINE);
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Create and initialize a new drawing and return it
|
||||
*/
|
||||
ASS_Drawing *ass_drawing_new(ASS_Library *lib)
|
||||
{
|
||||
ASS_Drawing *drawing = calloc(1, sizeof(*drawing));
|
||||
if (!drawing)
|
||||
return NULL;
|
||||
rectangle_reset(&drawing->cbox);
|
||||
drawing->library = lib;
|
||||
drawing->scale_x = 1.;
|
||||
drawing->scale_y = 1.;
|
||||
|
||||
if (!outline_alloc(&drawing->outline, GLYPH_INITIAL_POINTS, GLYPH_INITIAL_SEGMENTS)) {
|
||||
free(drawing);
|
||||
return NULL;
|
||||
}
|
||||
return drawing;
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Free a drawing
|
||||
*/
|
||||
void ass_drawing_free(ASS_Drawing *drawing)
|
||||
{
|
||||
if (drawing) {
|
||||
free(drawing->text);
|
||||
outline_free(&drawing->outline);
|
||||
}
|
||||
free(drawing);
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Copy an ASCII string to the drawing text buffer
|
||||
*/
|
||||
void ass_drawing_set_text(ASS_Drawing *drawing, char *str, size_t len)
|
||||
{
|
||||
free(drawing->text);
|
||||
drawing->text = strndup(str, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Create a hashcode for the drawing
|
||||
* XXX: To avoid collisions a better hash algorithm might be useful.
|
||||
*/
|
||||
void ass_drawing_hash(ASS_Drawing *drawing)
|
||||
{
|
||||
if (!drawing->text)
|
||||
return;
|
||||
drawing->hash = fnv_32a_str(drawing->text, FNV1_32A_INIT);
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Convert token list to outline. Calls the line and curve evaluators.
|
||||
*/
|
||||
ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, bool raw_mode)
|
||||
{
|
||||
bool started = false;
|
||||
ASS_DrawingToken *token;
|
||||
ASS_Vector pen = {0, 0};
|
||||
|
||||
drawing->tokens = drawing_tokenize(drawing->text);
|
||||
drawing_prepare(drawing);
|
||||
|
||||
token = drawing->tokens;
|
||||
while (token) {
|
||||
// Draw something according to current command
|
||||
switch (token->type) {
|
||||
case TOKEN_MOVE_NC:
|
||||
pen = token->point;
|
||||
translate_point(drawing, &pen);
|
||||
token = token->next;
|
||||
break;
|
||||
case TOKEN_MOVE:
|
||||
pen = token->point;
|
||||
translate_point(drawing, &pen);
|
||||
if (started) {
|
||||
if (!outline_add_segment(&drawing->outline, OUTLINE_LINE_SEGMENT))
|
||||
goto error;
|
||||
if (!outline_close_contour(&drawing->outline))
|
||||
goto error;
|
||||
started = false;
|
||||
}
|
||||
token = token->next;
|
||||
break;
|
||||
case TOKEN_LINE: {
|
||||
ASS_Vector to = token->point;
|
||||
translate_point(drawing, &to);
|
||||
if (!started && !outline_add_point(&drawing->outline, pen, 0))
|
||||
goto error;
|
||||
if (!outline_add_point(&drawing->outline, to, OUTLINE_LINE_SEGMENT))
|
||||
goto error;
|
||||
started = true;
|
||||
token = token->next;
|
||||
break;
|
||||
}
|
||||
case TOKEN_CUBIC_BEZIER:
|
||||
if (token_check_values(token, 3, TOKEN_CUBIC_BEZIER) &&
|
||||
token->prev) {
|
||||
if (!drawing_add_curve(drawing, token->prev, false, started))
|
||||
goto error;
|
||||
token = token->next;
|
||||
token = token->next;
|
||||
token = token->next;
|
||||
started = true;
|
||||
} else
|
||||
token = token->next;
|
||||
break;
|
||||
case TOKEN_B_SPLINE:
|
||||
if (token_check_values(token, 3, TOKEN_B_SPLINE) &&
|
||||
token->prev) {
|
||||
if (!drawing_add_curve(drawing, token->prev, true, started))
|
||||
goto error;
|
||||
token = token->next;
|
||||
started = true;
|
||||
} else
|
||||
token = token->next;
|
||||
break;
|
||||
default:
|
||||
token = token->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Close the last contour
|
||||
if (started) {
|
||||
if (!outline_add_segment(&drawing->outline, OUTLINE_LINE_SEGMENT))
|
||||
goto error;
|
||||
if (!outline_close_contour(&drawing->outline))
|
||||
goto error;
|
||||
}
|
||||
|
||||
drawing_finish(drawing, raw_mode);
|
||||
drawing_free_tokens(drawing->tokens);
|
||||
return &drawing->outline;
|
||||
|
||||
error:
|
||||
drawing_free_tokens(drawing->tokens);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBASS_DRAWING_H
|
||||
#define LIBASS_DRAWING_H
|
||||
|
||||
#include "ass.h"
|
||||
#include "ass_outline.h"
|
||||
#include "ass_bitmap.h"
|
||||
|
||||
typedef enum {
|
||||
TOKEN_MOVE,
|
||||
TOKEN_MOVE_NC,
|
||||
TOKEN_LINE,
|
||||
TOKEN_CUBIC_BEZIER,
|
||||
TOKEN_CONIC_BEZIER,
|
||||
TOKEN_B_SPLINE,
|
||||
TOKEN_EXTEND_SPLINE,
|
||||
TOKEN_CLOSE
|
||||
} ASS_TokenType;
|
||||
|
||||
typedef struct ass_drawing_token {
|
||||
ASS_TokenType type;
|
||||
ASS_Vector point;
|
||||
struct ass_drawing_token *next;
|
||||
struct ass_drawing_token *prev;
|
||||
} ASS_DrawingToken;
|
||||
|
||||
typedef struct {
|
||||
char *text; // drawing string
|
||||
int scale; // scale (1-64) for subpixel accuracy
|
||||
double pbo; // drawing will be shifted in y direction by this amount
|
||||
double scale_x; // FontScaleX
|
||||
double scale_y; // FontScaleY
|
||||
int asc; // ascender
|
||||
int desc; // descender
|
||||
ASS_Outline outline; // target outline
|
||||
ASS_Vector advance; // advance (from cbox)
|
||||
int hash; // hash value (for caching)
|
||||
|
||||
// private
|
||||
ASS_Library *library;
|
||||
ASS_DrawingToken *tokens; // tokenized drawing
|
||||
double point_scale_x;
|
||||
double point_scale_y;
|
||||
ASS_Rect cbox; // bounding box, or let's say... VSFilter's idea of it
|
||||
} ASS_Drawing;
|
||||
|
||||
ASS_Drawing *ass_drawing_new(ASS_Library *lib);
|
||||
void ass_drawing_free(ASS_Drawing *drawing);
|
||||
void ass_drawing_set_text(ASS_Drawing *drawing, char *str, size_t n);
|
||||
void ass_drawing_hash(ASS_Drawing *drawing);
|
||||
ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, bool raw_mode);
|
||||
|
||||
#endif /* LIBASS_DRAWING_H */
|
|
@ -0,0 +1,624 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ass_compat.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_SYNTHESIS_H
|
||||
#include FT_GLYPH_H
|
||||
#include FT_TRUETYPE_TABLES_H
|
||||
#include FT_OUTLINE_H
|
||||
#include <limits.h>
|
||||
|
||||
#include "ass.h"
|
||||
#include "ass_library.h"
|
||||
#include "ass_font.h"
|
||||
#include "ass_fontselect.h"
|
||||
#include "ass_utils.h"
|
||||
#include "ass_shaper.h"
|
||||
|
||||
/**
|
||||
* Select a good charmap, prefer Microsoft Unicode charmaps.
|
||||
* Otherwise, let FreeType decide.
|
||||
*/
|
||||
void charmap_magic(ASS_Library *library, FT_Face face)
|
||||
{
|
||||
int i;
|
||||
int ms_cmap = -1;
|
||||
|
||||
// Search for a Microsoft Unicode cmap
|
||||
for (i = 0; i < face->num_charmaps; ++i) {
|
||||
FT_CharMap cmap = face->charmaps[i];
|
||||
unsigned pid = cmap->platform_id;
|
||||
unsigned eid = cmap->encoding_id;
|
||||
if (pid == 3 /*microsoft */
|
||||
&& (eid == 1 /*unicode bmp */
|
||||
|| eid == 10 /*full unicode */ )) {
|
||||
FT_Set_Charmap(face, cmap);
|
||||
return;
|
||||
} else if (pid == 3 && ms_cmap < 0)
|
||||
ms_cmap = i;
|
||||
}
|
||||
|
||||
// Try the first Microsoft cmap if no Microsoft Unicode cmap was found
|
||||
if (ms_cmap >= 0) {
|
||||
FT_CharMap cmap = face->charmaps[ms_cmap];
|
||||
FT_Set_Charmap(face, cmap);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!face->charmap) {
|
||||
if (face->num_charmaps == 0) {
|
||||
ass_msg(library, MSGL_WARN, "Font face with no charmaps");
|
||||
return;
|
||||
}
|
||||
ass_msg(library, MSGL_WARN,
|
||||
"No charmap autodetected, trying the first one");
|
||||
FT_Set_Charmap(face, face->charmaps[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust char index if the charmap is weird
|
||||
* (currently just MS Symbol)
|
||||
*/
|
||||
|
||||
uint32_t ass_font_index_magic(FT_Face face, uint32_t symbol)
|
||||
{
|
||||
if (!face->charmap)
|
||||
return symbol;
|
||||
|
||||
switch(face->charmap->encoding){
|
||||
case FT_ENCODING_MS_SYMBOL:
|
||||
return 0xF000 | symbol;
|
||||
default:
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
|
||||
static void buggy_font_workaround(FT_Face face)
|
||||
{
|
||||
// Some fonts have zero Ascender/Descender fields in 'hhea' table.
|
||||
// In this case, get the information from 'os2' table or, as
|
||||
// a last resort, from face.bbox.
|
||||
if (face->ascender + face->descender == 0 || face->height == 0) {
|
||||
TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
|
||||
if (os2) {
|
||||
face->ascender = os2->sTypoAscender;
|
||||
face->descender = os2->sTypoDescender;
|
||||
face->height = face->ascender - face->descender;
|
||||
} else {
|
||||
face->ascender = face->bbox.yMax;
|
||||
face->descender = face->bbox.yMin;
|
||||
face->height = face->ascender - face->descender;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
read_stream_font(FT_Stream stream, unsigned long offset, unsigned char *buffer,
|
||||
unsigned long count)
|
||||
{
|
||||
ASS_FontStream *font = (ASS_FontStream *)stream->descriptor.pointer;
|
||||
|
||||
font->func(font->priv, buffer, offset, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
close_stream_font(FT_Stream stream)
|
||||
{
|
||||
free(stream->descriptor.pointer);
|
||||
free(stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Select a face with the given charcode and add it to ASS_Font
|
||||
* \return index of the new face in font->faces, -1 if failed
|
||||
*/
|
||||
static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch)
|
||||
{
|
||||
char *path;
|
||||
char *postscript_name = NULL;
|
||||
int i, index, uid, error;
|
||||
ASS_FontStream stream = { NULL, NULL };
|
||||
FT_Face face;
|
||||
|
||||
if (font->n_faces == ASS_FONT_MAX_FACES)
|
||||
return -1;
|
||||
|
||||
path = ass_font_select(fontsel, font->library, font , &index,
|
||||
&postscript_name, &uid, &stream, ch);
|
||||
|
||||
if (!path)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < font->n_faces; i++) {
|
||||
if (font->faces_uid[i] == uid) {
|
||||
ass_msg(font->library, MSGL_INFO,
|
||||
"Got a font face that already is available! Skipping.");
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
if (stream.func) {
|
||||
FT_Open_Args args;
|
||||
FT_Stream ftstream = calloc(1, sizeof(FT_StreamRec));
|
||||
ASS_FontStream *fs = calloc(1, sizeof(ASS_FontStream));
|
||||
|
||||
*fs = stream;
|
||||
ftstream->size = stream.func(stream.priv, NULL, 0, 0);
|
||||
ftstream->read = read_stream_font;
|
||||
ftstream->close = close_stream_font;
|
||||
ftstream->descriptor.pointer = (void *)fs;
|
||||
|
||||
memset(&args, 0, sizeof(FT_Open_Args));
|
||||
args.flags = FT_OPEN_STREAM;
|
||||
args.stream = ftstream;
|
||||
|
||||
error = FT_Open_Face(font->ftlibrary, &args, index, &face);
|
||||
|
||||
if (error) {
|
||||
ass_msg(font->library, MSGL_WARN,
|
||||
"Error opening memory font: '%s'", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
error = FT_New_Face(font->ftlibrary, path, index, &face);
|
||||
if (error) {
|
||||
ass_msg(font->library, MSGL_WARN,
|
||||
"Error opening font: '%s', %d", path, index);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (postscript_name && index < 0 && face->num_faces > 0) {
|
||||
// The font provider gave us a post_script name and is not sure
|
||||
// about the face index.. so use the postscript name to find the
|
||||
// correct face_index in the collection!
|
||||
for (int i = 0; i < face->num_faces; i++) {
|
||||
FT_Done_Face(face);
|
||||
error = FT_New_Face(font->ftlibrary, path, i, &face);
|
||||
if (error) {
|
||||
ass_msg(font->library, MSGL_WARN,
|
||||
"Error opening font: '%s', %d", path, i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *face_psname = FT_Get_Postscript_Name(face);
|
||||
if (face_psname != NULL &&
|
||||
strcmp(face_psname, postscript_name) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
charmap_magic(font->library, face);
|
||||
buggy_font_workaround(face);
|
||||
|
||||
font->faces[font->n_faces] = face;
|
||||
font->faces_uid[font->n_faces++] = uid;
|
||||
ass_face_set_size(face, font->size);
|
||||
return font->n_faces - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Create a new ASS_Font according to "desc" argument
|
||||
*/
|
||||
ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library,
|
||||
FT_Library ftlibrary, ASS_FontSelector *fontsel,
|
||||
ASS_FontDesc *desc)
|
||||
{
|
||||
ASS_Font *font;
|
||||
if (ass_cache_get(font_cache, desc, &font)) {
|
||||
if (font->desc.family)
|
||||
return font;
|
||||
ass_cache_dec_ref(font);
|
||||
return NULL;
|
||||
}
|
||||
if (!font)
|
||||
return NULL;
|
||||
|
||||
font->library = library;
|
||||
font->ftlibrary = ftlibrary;
|
||||
font->shaper_priv = NULL;
|
||||
font->n_faces = 0;
|
||||
ASS_FontDesc *new_desc = ass_cache_key(font);
|
||||
font->desc.family = new_desc->family;
|
||||
font->desc.bold = desc->bold;
|
||||
font->desc.italic = desc->italic;
|
||||
font->desc.vertical = desc->vertical;
|
||||
|
||||
font->scale_x = font->scale_y = 1.;
|
||||
font->v.x = font->v.y = 0;
|
||||
font->size = 0.;
|
||||
|
||||
int error = add_face(fontsel, font, 0);
|
||||
if (error == -1) {
|
||||
font->desc.family = NULL;
|
||||
ass_cache_commit(font, 1);
|
||||
ass_cache_dec_ref(font);
|
||||
return NULL;
|
||||
}
|
||||
ass_cache_commit(font, 1);
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set font transformation matrix and shift vector
|
||||
**/
|
||||
void ass_font_set_transform(ASS_Font *font, double scale_x,
|
||||
double scale_y, FT_Vector *v)
|
||||
{
|
||||
font->scale_x = scale_x;
|
||||
font->scale_y = scale_y;
|
||||
if (v) {
|
||||
font->v.x = v->x;
|
||||
font->v.y = v->y;
|
||||
}
|
||||
}
|
||||
|
||||
void ass_face_set_size(FT_Face face, double size)
|
||||
{
|
||||
TT_HoriHeader *hori = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
|
||||
TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
|
||||
double mscale = 1.;
|
||||
FT_Size_RequestRec rq;
|
||||
FT_Size_Metrics *m = &face->size->metrics;
|
||||
// VSFilter uses metrics from TrueType OS/2 table
|
||||
// The idea was borrowed from asa (http://asa.diac24.net)
|
||||
if (os2) {
|
||||
int ft_height = 0;
|
||||
if (hori)
|
||||
ft_height = hori->Ascender - hori->Descender;
|
||||
if (!ft_height)
|
||||
ft_height = os2->sTypoAscender - os2->sTypoDescender;
|
||||
/* sometimes used for signed values despite unsigned in spec */
|
||||
int os2_height = (short)os2->usWinAscent + (short)os2->usWinDescent;
|
||||
if (ft_height && os2_height)
|
||||
mscale = (double) ft_height / os2_height;
|
||||
}
|
||||
memset(&rq, 0, sizeof(rq));
|
||||
rq.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
|
||||
rq.width = 0;
|
||||
rq.height = double_to_d6(size * mscale);
|
||||
rq.horiResolution = rq.vertResolution = 0;
|
||||
FT_Request_Size(face, &rq);
|
||||
m->ascender /= mscale;
|
||||
m->descender /= mscale;
|
||||
m->height /= mscale;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set font size
|
||||
**/
|
||||
void ass_font_set_size(ASS_Font *font, double size)
|
||||
{
|
||||
int i;
|
||||
if (font->size != size) {
|
||||
font->size = size;
|
||||
for (i = 0; i < font->n_faces; ++i)
|
||||
ass_face_set_size(font->faces[i], size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get maximal font ascender and descender.
|
||||
* \param ch character code
|
||||
* The values are extracted from the font face that provides glyphs for the given character
|
||||
**/
|
||||
void ass_font_get_asc_desc(ASS_Font *font, uint32_t ch, int *asc,
|
||||
int *desc)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < font->n_faces; ++i) {
|
||||
FT_Face face = font->faces[i];
|
||||
TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
|
||||
if (FT_Get_Char_Index(face, ass_font_index_magic(face, ch))) {
|
||||
int y_scale = face->size->metrics.y_scale;
|
||||
if (os2) {
|
||||
*asc = FT_MulFix((short)os2->usWinAscent, y_scale);
|
||||
*desc = FT_MulFix((short)os2->usWinDescent, y_scale);
|
||||
} else {
|
||||
*asc = FT_MulFix(face->ascender, y_scale);
|
||||
*desc = FT_MulFix(-face->descender, y_scale);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
*asc = *desc = 0;
|
||||
}
|
||||
|
||||
static void add_line(FT_Outline *ol, int bear, int advance, int dir, int pos, int size) {
|
||||
FT_Vector points[4] = {
|
||||
{.x = bear, .y = pos + size},
|
||||
{.x = advance, .y = pos + size},
|
||||
{.x = advance, .y = pos - size},
|
||||
{.x = bear, .y = pos - size},
|
||||
};
|
||||
|
||||
if (dir == FT_ORIENTATION_TRUETYPE) {
|
||||
int i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
ol->points[ol->n_points] = points[i];
|
||||
ol->tags[ol->n_points++] = 1;
|
||||
}
|
||||
} else {
|
||||
int i;
|
||||
for (i = 3; i >= 0; i--) {
|
||||
ol->points[ol->n_points] = points[i];
|
||||
ol->tags[ol->n_points++] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ol->contours[ol->n_contours++] = ol->n_points - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Strike a glyph with a horizontal line; it's possible to underline it
|
||||
* and/or strike through it. For the line's position and size, truetype
|
||||
* tables are consulted. Obviously this relies on the data in the tables
|
||||
* being accurate.
|
||||
*
|
||||
*/
|
||||
static int ass_strike_outline_glyph(FT_Face face, ASS_Font *font,
|
||||
FT_Glyph glyph, int under, int through)
|
||||
{
|
||||
TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
|
||||
TT_Postscript *ps = FT_Get_Sfnt_Table(face, ft_sfnt_post);
|
||||
FT_Outline *ol = &((FT_OutlineGlyph) glyph)->outline;
|
||||
int advance, y_scale, i, dir;
|
||||
|
||||
if (!under && !through)
|
||||
return 0;
|
||||
|
||||
// Grow outline
|
||||
i = (under ? 4 : 0) + (through ? 4 : 0);
|
||||
if (ol->n_points > SHRT_MAX - i)
|
||||
return 0;
|
||||
if (!ASS_REALLOC_ARRAY(ol->points, ol->n_points + i))
|
||||
return 0;
|
||||
if (!ASS_REALLOC_ARRAY(ol->tags, ol->n_points + i))
|
||||
return 0;
|
||||
i = !!under + !!through;
|
||||
if (ol->n_contours > SHRT_MAX - i)
|
||||
return 0;
|
||||
if (!ASS_REALLOC_ARRAY(ol->contours, ol->n_contours + i))
|
||||
return 0;
|
||||
|
||||
advance = d16_to_d6(glyph->advance.x);
|
||||
y_scale = face->size->metrics.y_scale;
|
||||
|
||||
// Reverse drawing direction for non-truetype fonts
|
||||
dir = FT_Outline_Get_Orientation(ol);
|
||||
|
||||
// Add points to the outline
|
||||
if (under && ps) {
|
||||
int pos = FT_MulFix(ps->underlinePosition, y_scale);
|
||||
int size = FT_MulFix(ps->underlineThickness, y_scale / 2);
|
||||
|
||||
if (pos > 0 || size <= 0)
|
||||
return 1;
|
||||
|
||||
add_line(ol, 0, advance, dir, pos, size);
|
||||
}
|
||||
|
||||
if (through && os2) {
|
||||
int pos = FT_MulFix(os2->yStrikeoutPosition, y_scale);
|
||||
int size = FT_MulFix(os2->yStrikeoutSize, y_scale / 2);
|
||||
|
||||
if (pos < 0 || size <= 0)
|
||||
return 1;
|
||||
|
||||
add_line(ol, 0, advance, dir, pos, size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Slightly embold a glyph without touching its metrics
|
||||
*/
|
||||
static void ass_glyph_embolden(FT_GlyphSlot slot)
|
||||
{
|
||||
int str;
|
||||
|
||||
if (slot->format != FT_GLYPH_FORMAT_OUTLINE)
|
||||
return;
|
||||
|
||||
str = FT_MulFix(slot->face->units_per_EM,
|
||||
slot->face->size->metrics.y_scale) / 64;
|
||||
|
||||
FT_Outline_Embolden(&slot->outline, str);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get glyph and face index
|
||||
* Finds a face that has the requested codepoint and returns both face
|
||||
* and glyph index.
|
||||
*/
|
||||
int ass_font_get_index(ASS_FontSelector *fontsel, ASS_Font *font,
|
||||
uint32_t symbol, int *face_index, int *glyph_index)
|
||||
{
|
||||
int index = 0;
|
||||
int i;
|
||||
FT_Face face = 0;
|
||||
|
||||
*glyph_index = 0;
|
||||
|
||||
if (symbol < 0x20) {
|
||||
*face_index = 0;
|
||||
return 0;
|
||||
}
|
||||
// Handle NBSP like a regular space when rendering the glyph
|
||||
if (symbol == 0xa0)
|
||||
symbol = ' ';
|
||||
if (font->n_faces == 0) {
|
||||
*face_index = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// try with the requested face
|
||||
if (*face_index < font->n_faces) {
|
||||
face = font->faces[*face_index];
|
||||
index = FT_Get_Char_Index(face, ass_font_index_magic(face, symbol));
|
||||
}
|
||||
|
||||
// not found in requested face, try all others
|
||||
for (i = 0; i < font->n_faces && index == 0; ++i) {
|
||||
face = font->faces[i];
|
||||
index = FT_Get_Char_Index(face, ass_font_index_magic(face, symbol));
|
||||
if (index)
|
||||
*face_index = i;
|
||||
}
|
||||
|
||||
if (index == 0) {
|
||||
int face_idx;
|
||||
ass_msg(font->library, MSGL_INFO,
|
||||
"Glyph 0x%X not found, selecting one more "
|
||||
"font for (%s, %d, %d)", symbol, font->desc.family,
|
||||
font->desc.bold, font->desc.italic);
|
||||
face_idx = *face_index = add_face(fontsel, font, symbol);
|
||||
if (face_idx >= 0) {
|
||||
face = font->faces[face_idx];
|
||||
index = FT_Get_Char_Index(face, ass_font_index_magic(face, symbol));
|
||||
if (index == 0 && face->num_charmaps > 0) {
|
||||
int i;
|
||||
ass_msg(font->library, MSGL_WARN,
|
||||
"Glyph 0x%X not found, broken font? Trying all charmaps", symbol);
|
||||
for (i = 0; i < face->num_charmaps; i++) {
|
||||
FT_Set_Charmap(face, face->charmaps[i]);
|
||||
if ((index = FT_Get_Char_Index(face, ass_font_index_magic(face, symbol))) != 0) break;
|
||||
}
|
||||
}
|
||||
if (index == 0) {
|
||||
ass_msg(font->library, MSGL_ERR,
|
||||
"Glyph 0x%X not found in font for (%s, %d, %d)",
|
||||
symbol, font->desc.family, font->desc.bold,
|
||||
font->desc.italic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: make sure we have a valid face_index. this is a HACK.
|
||||
*face_index = FFMAX(*face_index, 0);
|
||||
*glyph_index = index;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get a glyph
|
||||
* \param ch character code
|
||||
**/
|
||||
FT_Glyph ass_font_get_glyph(ASS_Font *font, uint32_t ch, int face_index,
|
||||
int index, ASS_Hinting hinting, int deco)
|
||||
{
|
||||
int error;
|
||||
FT_Glyph glyph;
|
||||
FT_Face face = font->faces[face_index];
|
||||
int flags = 0;
|
||||
int vertical = font->desc.vertical;
|
||||
|
||||
flags = FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
|
||||
| FT_LOAD_IGNORE_TRANSFORM;
|
||||
switch (hinting) {
|
||||
case ASS_HINTING_NONE:
|
||||
flags |= FT_LOAD_NO_HINTING;
|
||||
break;
|
||||
case ASS_HINTING_LIGHT:
|
||||
flags |= FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
|
||||
break;
|
||||
case ASS_HINTING_NORMAL:
|
||||
flags |= FT_LOAD_FORCE_AUTOHINT;
|
||||
break;
|
||||
case ASS_HINTING_NATIVE:
|
||||
break;
|
||||
}
|
||||
|
||||
error = FT_Load_Glyph(face, index, flags);
|
||||
if (error) {
|
||||
ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d",
|
||||
index);
|
||||
return 0;
|
||||
}
|
||||
if (!(face->style_flags & FT_STYLE_FLAG_ITALIC) &&
|
||||
(font->desc.italic > 55)) {
|
||||
FT_GlyphSlot_Oblique(face->glyph);
|
||||
}
|
||||
|
||||
if (!(face->style_flags & FT_STYLE_FLAG_BOLD) &&
|
||||
(font->desc.bold > 400)) {
|
||||
ass_glyph_embolden(face->glyph);
|
||||
}
|
||||
error = FT_Get_Glyph(face->glyph, &glyph);
|
||||
if (error) {
|
||||
ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d",
|
||||
index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Rotate glyph, if needed
|
||||
if (vertical && ch >= VERTICAL_LOWER_BOUND) {
|
||||
FT_Matrix m = { 0, double_to_d16(-1.0), double_to_d16(1.0), 0 };
|
||||
TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
|
||||
int desc = 0;
|
||||
|
||||
if (os2)
|
||||
desc = FT_MulFix(os2->sTypoDescender, face->size->metrics.y_scale);
|
||||
|
||||
FT_Outline_Translate(&((FT_OutlineGlyph) glyph)->outline, 0, -desc);
|
||||
FT_Outline_Transform(&((FT_OutlineGlyph) glyph)->outline, &m);
|
||||
FT_Outline_Translate(&((FT_OutlineGlyph) glyph)->outline,
|
||||
face->glyph->metrics.vertAdvance, desc);
|
||||
glyph->advance.x = face->glyph->linearVertAdvance;
|
||||
}
|
||||
|
||||
ass_strike_outline_glyph(face, font, glyph, deco & DECO_UNDERLINE,
|
||||
deco & DECO_STRIKETHROUGH);
|
||||
|
||||
// Apply scaling and shift
|
||||
FT_Matrix scale = { double_to_d16(font->scale_x), 0, 0,
|
||||
double_to_d16(font->scale_y) };
|
||||
FT_Outline *outl = &((FT_OutlineGlyph) glyph)->outline;
|
||||
FT_Outline_Transform(outl, &scale);
|
||||
FT_Outline_Translate(outl, font->v.x, font->v.y);
|
||||
glyph->advance.x *= font->scale_x;
|
||||
|
||||
return glyph;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Deallocate ASS_Font internals
|
||||
**/
|
||||
void ass_font_clear(ASS_Font *font)
|
||||
{
|
||||
int i;
|
||||
if (font->shaper_priv)
|
||||
ass_shaper_font_data_free(font->shaper_priv);
|
||||
for (i = 0; i < font->n_faces; ++i) {
|
||||
if (font->faces[i])
|
||||
FT_Done_Face(font->faces[i]);
|
||||
}
|
||||
free(font->desc.family);
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBASS_FONT_H
|
||||
#define LIBASS_FONT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_GLYPH_H
|
||||
#include FT_OUTLINE_H
|
||||
|
||||
typedef struct ass_font ASS_Font;
|
||||
typedef struct ass_font_desc ASS_FontDesc;
|
||||
|
||||
#include "ass.h"
|
||||
#include "ass_types.h"
|
||||
#include "ass_fontselect.h"
|
||||
#include "ass_cache.h"
|
||||
|
||||
#define VERTICAL_LOWER_BOUND 0x02f1
|
||||
|
||||
#define ASS_FONT_MAX_FACES 10
|
||||
#define DECO_UNDERLINE 1
|
||||
#define DECO_STRIKETHROUGH 2
|
||||
|
||||
struct ass_font_desc {
|
||||
char *family;
|
||||
unsigned bold;
|
||||
unsigned italic;
|
||||
int vertical; // @font vertical layout
|
||||
};
|
||||
|
||||
struct ass_font {
|
||||
ASS_FontDesc desc;
|
||||
ASS_Library *library;
|
||||
FT_Library ftlibrary;
|
||||
int faces_uid[ASS_FONT_MAX_FACES];
|
||||
FT_Face faces[ASS_FONT_MAX_FACES];
|
||||
ASS_ShaperFontData *shaper_priv;
|
||||
int n_faces;
|
||||
double scale_x, scale_y; // current transform
|
||||
FT_Vector v; // current shift
|
||||
double size;
|
||||
};
|
||||
|
||||
void charmap_magic(ASS_Library *library, FT_Face face);
|
||||
ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library,
|
||||
FT_Library ftlibrary, ASS_FontSelector *fontsel,
|
||||
ASS_FontDesc *desc);
|
||||
void ass_font_set_transform(ASS_Font *font, double scale_x,
|
||||
double scale_y, FT_Vector *v);
|
||||
void ass_face_set_size(FT_Face face, double size);
|
||||
void ass_font_set_size(ASS_Font *font, double size);
|
||||
void ass_font_get_asc_desc(ASS_Font *font, uint32_t ch, int *asc,
|
||||
int *desc);
|
||||
int ass_font_get_index(ASS_FontSelector *fontsel, ASS_Font *font,
|
||||
uint32_t symbol, int *face_index, int *glyph_index);
|
||||
uint32_t ass_font_index_magic(FT_Face face, uint32_t symbol);
|
||||
FT_Glyph ass_font_get_glyph(ASS_Font *font,
|
||||
uint32_t ch, int face_index, int index,
|
||||
ASS_Hinting hinting, int deco);
|
||||
void ass_font_clear(ASS_Font *font);
|
||||
|
||||
#endif /* LIBASS_FONT_H */
|
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ass_compat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <fontconfig/fontconfig.h>
|
||||
#include <fontconfig/fcfreetype.h>
|
||||
|
||||
#include "ass_fontconfig.h"
|
||||
#include "ass_fontselect.h"
|
||||
#include "ass_utils.h"
|
||||
|
||||
#define MAX_NAME 100
|
||||
|
||||
typedef struct fc_private {
|
||||
FcConfig *config;
|
||||
FcFontSet *fallbacks;
|
||||
FcCharSet *fallback_chars;
|
||||
} ProviderPrivate;
|
||||
|
||||
static bool check_postscript(void *priv)
|
||||
{
|
||||
FcPattern *pat = (FcPattern *)priv;
|
||||
char *format;
|
||||
|
||||
FcResult result =
|
||||
FcPatternGetString(pat, FC_FONTFORMAT, 0, (FcChar8 **)&format);
|
||||
if (result != FcResultMatch)
|
||||
return false;
|
||||
|
||||
return !strcmp(format, "Type 1") || !strcmp(format, "Type 42") ||
|
||||
!strcmp(format, "CID Type 1") || !strcmp(format, "CFF");
|
||||
}
|
||||
|
||||
static bool check_glyph(void *priv, uint32_t code)
|
||||
{
|
||||
FcPattern *pat = (FcPattern *)priv;
|
||||
FcCharSet *charset;
|
||||
|
||||
if (!pat)
|
||||
return true;
|
||||
|
||||
if (code == 0)
|
||||
return true;
|
||||
|
||||
FcResult result = FcPatternGetCharSet(pat, FC_CHARSET, 0, &charset);
|
||||
if (result != FcResultMatch)
|
||||
return false;
|
||||
if (FcCharSetHasChar(charset, code) == FcTrue)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void destroy(void *priv)
|
||||
{
|
||||
ProviderPrivate *fc = (ProviderPrivate *)priv;
|
||||
|
||||
if (fc->fallback_chars)
|
||||
FcCharSetDestroy(fc->fallback_chars);
|
||||
if (fc->fallbacks)
|
||||
FcFontSetDestroy(fc->fallbacks);
|
||||
FcConfigDestroy(fc->config);
|
||||
free(fc);
|
||||
}
|
||||
|
||||
static void scan_fonts(FcConfig *config, ASS_FontProvider *provider)
|
||||
{
|
||||
int i;
|
||||
FcFontSet *fonts;
|
||||
ASS_FontProviderMetaData meta;
|
||||
|
||||
// get list of fonts
|
||||
fonts = FcConfigGetFonts(config, FcSetSystem);
|
||||
|
||||
// fill font_info list
|
||||
for (i = 0; i < fonts->nfont; i++) {
|
||||
FcPattern *pat = fonts->fonts[i];
|
||||
FcBool outline;
|
||||
int index, weight;
|
||||
char *path;
|
||||
char *fullnames[MAX_NAME];
|
||||
char *families[MAX_NAME];
|
||||
|
||||
// skip non-outline fonts
|
||||
FcResult result = FcPatternGetBool(pat, FC_OUTLINE, 0, &outline);
|
||||
if (result != FcResultMatch || outline != FcTrue)
|
||||
continue;
|
||||
|
||||
// simple types
|
||||
result = FcPatternGetInteger(pat, FC_SLANT, 0, &meta.slant);
|
||||
result |= FcPatternGetInteger(pat, FC_WIDTH, 0, &meta.width);
|
||||
result |= FcPatternGetInteger(pat, FC_WEIGHT, 0, &weight);
|
||||
result |= FcPatternGetInteger(pat, FC_INDEX, 0, &index);
|
||||
if (result != FcResultMatch)
|
||||
continue;
|
||||
|
||||
// fontconfig uses its own weight scale, apparently derived
|
||||
// from typographical weight. we're using truetype weights, so
|
||||
// convert appropriately
|
||||
if (weight <= FC_WEIGHT_LIGHT)
|
||||
meta.weight = FONT_WEIGHT_LIGHT;
|
||||
else if (weight <= FC_WEIGHT_MEDIUM)
|
||||
meta.weight = FONT_WEIGHT_MEDIUM;
|
||||
else
|
||||
meta.weight = FONT_WEIGHT_BOLD;
|
||||
|
||||
// path
|
||||
result = FcPatternGetString(pat, FC_FILE, 0, (FcChar8 **)&path);
|
||||
if (result != FcResultMatch)
|
||||
continue;
|
||||
|
||||
// read family names
|
||||
meta.n_family = 0;
|
||||
while (FcPatternGetString(pat, FC_FAMILY, meta.n_family,
|
||||
(FcChar8 **)&families[meta.n_family]) == FcResultMatch
|
||||
&& meta.n_family < MAX_NAME)
|
||||
meta.n_family++;
|
||||
meta.families = families;
|
||||
|
||||
// read fullnames
|
||||
meta.n_fullname = 0;
|
||||
while (FcPatternGetString(pat, FC_FULLNAME, meta.n_fullname,
|
||||
(FcChar8 **)&fullnames[meta.n_fullname]) == FcResultMatch
|
||||
&& meta.n_fullname < MAX_NAME)
|
||||
meta.n_fullname++;
|
||||
meta.fullnames = fullnames;
|
||||
|
||||
// read PostScript name
|
||||
result = FcPatternGetString(pat, FC_POSTSCRIPT_NAME, 0,
|
||||
(FcChar8 **)&meta.postscript_name);
|
||||
if (result != FcResultMatch)
|
||||
meta.postscript_name = NULL;
|
||||
|
||||
ass_font_provider_add_font(provider, &meta, path, index, (void *)pat);
|
||||
}
|
||||
}
|
||||
|
||||
static void cache_fallbacks(ProviderPrivate *fc)
|
||||
{
|
||||
FcResult result;
|
||||
|
||||
if (fc->fallbacks)
|
||||
return;
|
||||
|
||||
// Create a suitable pattern
|
||||
FcPattern *pat = FcPatternCreate();
|
||||
FcPatternAddString(pat, FC_FAMILY, (FcChar8 *)"sans-serif");
|
||||
FcPatternAddBool(pat, FC_OUTLINE, FcTrue);
|
||||
FcConfigSubstitute (fc->config, pat, FcMatchPattern);
|
||||
FcDefaultSubstitute (pat);
|
||||
|
||||
// FC_LANG is automatically set according to locale, but this results
|
||||
// in strange sorting sometimes, so remove the attribute completely.
|
||||
FcPatternDel(pat, FC_LANG);
|
||||
|
||||
// Sort installed fonts and eliminate duplicates; this can be very
|
||||
// expensive.
|
||||
fc->fallbacks = FcFontSort(fc->config, pat, FcTrue, &fc->fallback_chars,
|
||||
&result);
|
||||
|
||||
// If this fails, just add an empty set
|
||||
if (result != FcResultMatch)
|
||||
fc->fallbacks = FcFontSetCreate();
|
||||
|
||||
FcPatternDestroy(pat);
|
||||
}
|
||||
|
||||
static char *get_fallback(void *priv, const char *family, uint32_t codepoint)
|
||||
{
|
||||
ProviderPrivate *fc = (ProviderPrivate *)priv;
|
||||
FcResult result;
|
||||
|
||||
cache_fallbacks(fc);
|
||||
|
||||
if (!fc->fallbacks || fc->fallbacks->nfont == 0)
|
||||
return NULL;
|
||||
|
||||
if (codepoint == 0) {
|
||||
char *family = NULL;
|
||||
result = FcPatternGetString(fc->fallbacks->fonts[0], FC_FAMILY, 0,
|
||||
(FcChar8 **)&family);
|
||||
if (result == FcResultMatch) {
|
||||
return strdup(family);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// fallback_chars is the union of all available charsets, so
|
||||
// if we can't find the glyph in there, the system does not
|
||||
// have any font to render this glyph.
|
||||
if (FcCharSetHasChar(fc->fallback_chars, codepoint) == FcFalse)
|
||||
return NULL;
|
||||
|
||||
for (int j = 0; j < fc->fallbacks->nfont; j++) {
|
||||
FcPattern *pattern = fc->fallbacks->fonts[j];
|
||||
|
||||
FcCharSet *charset;
|
||||
result = FcPatternGetCharSet(pattern, FC_CHARSET, 0, &charset);
|
||||
|
||||
if (result == FcResultMatch && FcCharSetHasChar(charset,
|
||||
codepoint)) {
|
||||
char *family = NULL;
|
||||
result = FcPatternGetString(pattern, FC_FAMILY, 0,
|
||||
(FcChar8 **)&family);
|
||||
if (result == FcResultMatch) {
|
||||
return strdup(family);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we shouldn't get here
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void get_substitutions(void *priv, const char *name,
|
||||
ASS_FontProviderMetaData *meta)
|
||||
{
|
||||
ProviderPrivate *fc = (ProviderPrivate *)priv;
|
||||
|
||||
FcPattern *pat = FcPatternCreate();
|
||||
if (!pat)
|
||||
return;
|
||||
|
||||
FcPatternAddString(pat, FC_FAMILY, (FcChar8 *)name);
|
||||
FcPatternAddString(pat, FC_FAMILY, (FcChar8 *)"__libass_delimiter");
|
||||
FcPatternAddBool(pat, FC_OUTLINE, FcTrue);
|
||||
if (!FcConfigSubstitute(fc->config, pat, FcMatchPattern))
|
||||
goto cleanup;
|
||||
|
||||
// read and strdup fullnames
|
||||
meta->n_fullname = 0;
|
||||
meta->fullnames = calloc(MAX_NAME, sizeof(char *));
|
||||
if (!meta->fullnames)
|
||||
goto cleanup;
|
||||
|
||||
char *alias = NULL;
|
||||
while (FcPatternGetString(pat, FC_FAMILY, meta->n_fullname,
|
||||
(FcChar8 **)&alias) == FcResultMatch
|
||||
&& meta->n_fullname < MAX_NAME
|
||||
&& strcmp(alias, "__libass_delimiter") != 0) {
|
||||
alias = strdup(alias);
|
||||
if (!alias)
|
||||
goto cleanup;
|
||||
meta->fullnames[meta->n_fullname] = alias;
|
||||
meta->n_fullname++;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
FcPatternDestroy(pat);
|
||||
}
|
||||
|
||||
static ASS_FontProviderFuncs fontconfig_callbacks = {
|
||||
.check_postscript = check_postscript,
|
||||
.check_glyph = check_glyph,
|
||||
.destroy_provider = destroy,
|
||||
.get_substitutions = get_substitutions,
|
||||
.get_fallback = get_fallback,
|
||||
};
|
||||
|
||||
ASS_FontProvider *
|
||||
ass_fontconfig_add_provider(ASS_Library *lib, ASS_FontSelector *selector,
|
||||
const char *config)
|
||||
{
|
||||
int rc;
|
||||
ProviderPrivate *fc = NULL;
|
||||
ASS_FontProvider *provider = NULL;
|
||||
|
||||
fc = calloc(1, sizeof(ProviderPrivate));
|
||||
if (fc == NULL)
|
||||
return NULL;
|
||||
|
||||
// build and load fontconfig configuration
|
||||
fc->config = FcConfigCreate();
|
||||
rc = FcConfigParseAndLoad(fc->config, (unsigned char *) config, FcTrue);
|
||||
if (!rc) {
|
||||
ass_msg(lib, MSGL_WARN, "No usable fontconfig configuration "
|
||||
"file found, using fallback.");
|
||||
FcConfigDestroy(fc->config);
|
||||
fc->config = FcInitLoadConfig();
|
||||
}
|
||||
if (fc->config)
|
||||
rc = FcConfigBuildFonts(fc->config);
|
||||
|
||||
if (!rc || !fc->config) {
|
||||
ass_msg(lib, MSGL_FATAL,
|
||||
"No valid fontconfig configuration found!");
|
||||
FcConfigDestroy(fc->config);
|
||||
free(fc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// create font provider
|
||||
provider = ass_font_provider_new(selector, &fontconfig_callbacks, fc);
|
||||
|
||||
// build database from system fonts
|
||||
scan_fonts(fc->config, provider);
|
||||
|
||||
return provider;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ass_types.h"
|
||||
#include "ass_fontselect.h"
|
||||
|
||||
#ifndef ASS_FONTCONFIG_H
|
||||
#define ASS_FONTCONFIG_H
|
||||
|
||||
#ifdef CONFIG_FONTCONFIG
|
||||
|
||||
ASS_FontProvider *
|
||||
ass_fontconfig_add_provider(ASS_Library *lib, ASS_FontSelector *selector,
|
||||
const char *config);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBASS_FONTSELECT_H
|
||||
#define LIBASS_FONTSELECT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
typedef struct ass_shaper_font_data ASS_ShaperFontData;
|
||||
typedef struct font_selector ASS_FontSelector;
|
||||
typedef struct font_info ASS_FontInfo;
|
||||
|
||||
#include "ass_types.h"
|
||||
#include "ass.h"
|
||||
#include "ass_font.h"
|
||||
|
||||
typedef struct font_provider ASS_FontProvider;
|
||||
|
||||
/* Font Provider */
|
||||
typedef struct ass_font_provider_meta_data ASS_FontProviderMetaData;
|
||||
|
||||
/**
|
||||
* Get font data. This is a stream interface which can be used as an
|
||||
* alternative to providing a font path (which may not be available).
|
||||
*
|
||||
* This is called by fontselect if a given font was added without a
|
||||
* font path (i.e. the path was set to NULL).
|
||||
*
|
||||
* \param font_priv font private data
|
||||
* \param output buffer; set to NULL to query stream size
|
||||
* \param offset stream offset
|
||||
* \param len bytes to read into output buffer from stream
|
||||
* \return actual number of bytes read, or stream size if data == NULL
|
||||
*/
|
||||
typedef size_t (*GetDataFunc)(void *font_priv, unsigned char *data,
|
||||
size_t offset, size_t len);
|
||||
|
||||
/**
|
||||
* Check whether the font contains PostScript outlines.
|
||||
*
|
||||
* \param font_priv font private data
|
||||
* \return true if the font contains PostScript outlines
|
||||
*/
|
||||
typedef bool (*CheckPostscriptFunc)(void *font_priv);
|
||||
|
||||
/**
|
||||
* Check if a glyph is supported by a font.
|
||||
*
|
||||
* \param font_priv font private data
|
||||
* \param codepont Unicode codepoint (UTF-32)
|
||||
* \return true if codepoint is supported by the font
|
||||
*/
|
||||
typedef bool (*CheckGlyphFunc)(void *font_priv, uint32_t codepoint);
|
||||
|
||||
/**
|
||||
* Get index of a font in context of a font collection.
|
||||
* This function is optional and may be needed to initialize the font index
|
||||
* lazily.
|
||||
*
|
||||
* \param font_priv font private data
|
||||
* \return font index inside the collection, or 0 in case of a single font
|
||||
*/
|
||||
typedef unsigned (*GetFontIndex)(void *font_priv);
|
||||
|
||||
/**
|
||||
* Destroy a font's private data.
|
||||
*
|
||||
* \param font_priv font private data
|
||||
*/
|
||||
typedef void (*DestroyFontFunc)(void *font_priv);
|
||||
|
||||
/**
|
||||
* Destroy a font provider's private data.
|
||||
*
|
||||
* \param priv font provider private data
|
||||
*/
|
||||
typedef void (*DestroyProviderFunc)(void *priv);
|
||||
|
||||
/**
|
||||
* Add fonts for a given font name; this should add all fonts matching the
|
||||
* given name to the fontselect database.
|
||||
*
|
||||
* This is called by fontselect whenever a new logical font is created. The
|
||||
* font provider set as default is used.
|
||||
*
|
||||
* \param lib ASS_Library instance
|
||||
* \param provider font provider instance
|
||||
* \param name font name (as specified in script)
|
||||
*/
|
||||
typedef void (*MatchFontsFunc)(ASS_Library *lib,
|
||||
ASS_FontProvider *provider,
|
||||
char *name);
|
||||
|
||||
/**
|
||||
* Substitute font name by another. This implements generic font family
|
||||
* substitutions (e.g. sans-serif, serif, monospace) as well as font aliases.
|
||||
*
|
||||
* The generic families should map to sensible platform-specific font families.
|
||||
* Aliases are sometimes used to map from common fonts that don't exist on
|
||||
* a particular platform to similar alternatives. For example, a Linux
|
||||
* system with fontconfig may map "Arial" to "Liberation Sans" and Windows
|
||||
* maps "Helvetica" to "Arial".
|
||||
*
|
||||
* This is called by fontselect when a new logical font is created. The font
|
||||
* provider set as default is used.
|
||||
*
|
||||
* \param priv font provider private data
|
||||
* \param name input string for substitution, as specified in the script
|
||||
* \param meta metadata (fullnames and n_fullname) to be filled in
|
||||
*/
|
||||
typedef void (*SubstituteFontFunc)(void *priv, const char *name,
|
||||
ASS_FontProviderMetaData *meta);
|
||||
|
||||
/**
|
||||
* Get an appropriate fallback font for a given codepoint.
|
||||
*
|
||||
* This is called by fontselect whenever a glyph is not found in the
|
||||
* physical font list of a logical font. fontselect will try to add the
|
||||
* font family with match_fonts if it does not exist in the font list
|
||||
* add match_fonts is not NULL. Note that the returned font family should
|
||||
* contain the requested codepoint.
|
||||
*
|
||||
* Note that fontselect uses the font provider set as default to determine
|
||||
* fallbacks.
|
||||
*
|
||||
* \param priv font provider private data
|
||||
* \param family original font family name (try matching a similar font) (never NULL)
|
||||
* \param codepoint Unicode codepoint (UTF-32)
|
||||
* \return output font family, allocated with malloc(), must be freed
|
||||
* by caller.
|
||||
*/
|
||||
typedef char *(*GetFallbackFunc)(void *priv,
|
||||
const char *family,
|
||||
uint32_t codepoint);
|
||||
|
||||
typedef struct font_provider_funcs {
|
||||
GetDataFunc get_data; /* optional/mandatory */
|
||||
CheckPostscriptFunc check_postscript; /* mandatory */
|
||||
CheckGlyphFunc check_glyph; /* mandatory */
|
||||
DestroyFontFunc destroy_font; /* optional */
|
||||
DestroyProviderFunc destroy_provider; /* optional */
|
||||
MatchFontsFunc match_fonts; /* optional */
|
||||
SubstituteFontFunc get_substitutions; /* optional */
|
||||
GetFallbackFunc get_fallback; /* optional */
|
||||
GetFontIndex get_font_index; /* optional */
|
||||
} ASS_FontProviderFuncs;
|
||||
|
||||
/*
|
||||
* Basic font metadata. All strings must be encoded with UTF-8.
|
||||
* At minimum one family is required.
|
||||
*/
|
||||
struct ass_font_provider_meta_data {
|
||||
/**
|
||||
* List of localized font family names, e.g. "Arial".
|
||||
*/
|
||||
char **families;
|
||||
|
||||
/**
|
||||
* List of localized full names, e.g. "Arial Bold".
|
||||
* The English name should be listed first to speed up typical matching.
|
||||
*/
|
||||
char **fullnames;
|
||||
|
||||
/**
|
||||
* The PostScript name, e.g. "Arial-BoldMT".
|
||||
*/
|
||||
char *postscript_name;
|
||||
|
||||
int n_family; // Number of localized family names
|
||||
int n_fullname; // Number of localized full names
|
||||
|
||||
int slant; // Font slant value from FONT_SLANT_*
|
||||
int weight; // Font weight in TrueType scale, 100-900
|
||||
// See FONT_WEIGHT_*
|
||||
int width; // Font weight in percent, normally 100
|
||||
// See FONT_WIDTH_*
|
||||
};
|
||||
|
||||
typedef struct ass_font_stream ASS_FontStream;
|
||||
|
||||
struct ass_font_stream {
|
||||
// GetDataFunc
|
||||
size_t (*func)(void *font_priv, unsigned char *data,
|
||||
size_t offset, size_t len);
|
||||
void *priv;
|
||||
};
|
||||
|
||||
|
||||
typedef struct ass_font_mapping ASS_FontMapping;
|
||||
|
||||
struct ass_font_mapping {
|
||||
const char *from;
|
||||
const char *to;
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple font substitution helper. This can be used to implement basic
|
||||
* mappings from one name to another. This is useful for supporting
|
||||
* generic font families in font providers.
|
||||
*
|
||||
* \param map list of mappings
|
||||
* \param len length of list of mappings
|
||||
* \param name font name to map from
|
||||
* \param meta metadata struct, mapped fonts will be stored into this
|
||||
*/
|
||||
void ass_map_font(const ASS_FontMapping *map, int len, const char *name,
|
||||
ASS_FontProviderMetaData *meta);
|
||||
|
||||
ASS_FontSelector *
|
||||
ass_fontselect_init(ASS_Library *library,
|
||||
FT_Library ftlibrary, const char *family,
|
||||
const char *path, const char *config,
|
||||
ASS_DefaultFontProvider dfp);
|
||||
char *ass_font_select(ASS_FontSelector *priv, ASS_Library *library,
|
||||
ASS_Font *font, int *index, char **postscript_name,
|
||||
int *uid, ASS_FontStream *data, uint32_t code);
|
||||
void ass_fontselect_free(ASS_FontSelector *priv);
|
||||
|
||||
// Font provider functions
|
||||
ASS_FontProvider *ass_font_provider_new(ASS_FontSelector *selector,
|
||||
ASS_FontProviderFuncs *funcs, void *data);
|
||||
|
||||
/**
|
||||
* \brief Create an empty font provider. A font provider can be used to
|
||||
* provide additional fonts to libass.
|
||||
* \param priv parent renderer
|
||||
* \param funcs callback functions
|
||||
* \param private data for provider callbacks
|
||||
*
|
||||
*/
|
||||
ASS_FontProvider *
|
||||
ass_create_font_provider(ASS_Renderer *priv, ASS_FontProviderFuncs *funcs,
|
||||
void *data);
|
||||
|
||||
/**
|
||||
* \brief Add a font to a font provider.
|
||||
* \param provider the font provider
|
||||
* \param meta font metadata. See struct definition for more information.
|
||||
* \param path absolute path to font, or NULL for memory-based fonts
|
||||
* \param index index inside a font collection file
|
||||
* (-1 to look up by PostScript name)
|
||||
* \param data private data for font callbacks
|
||||
* \return success
|
||||
*
|
||||
*/
|
||||
bool
|
||||
ass_font_provider_add_font(ASS_FontProvider *provider,
|
||||
ASS_FontProviderMetaData *meta, const char *path,
|
||||
int index, void *data);
|
||||
|
||||
/**
|
||||
* \brief Free font provider and associated fonts.
|
||||
* \param provider the font provider
|
||||
*
|
||||
*/
|
||||
void ass_font_provider_free(ASS_FontProvider *provider);
|
||||
|
||||
#endif /* LIBASS_FONTSELECT_H */
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Vabishchevich Nikolay <vabnick@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
void DECORATE(fill_solid_tile16)(uint8_t *buf, ptrdiff_t stride, int set);
|
||||
void DECORATE(fill_solid_tile32)(uint8_t *buf, ptrdiff_t stride, int set);
|
||||
void DECORATE(fill_halfplane_tile16)(uint8_t *buf, ptrdiff_t stride,
|
||||
int32_t a, int32_t b, int64_t c, int32_t scale);
|
||||
void DECORATE(fill_halfplane_tile32)(uint8_t *buf, ptrdiff_t stride,
|
||||
int32_t a, int32_t b, int64_t c, int32_t scale);
|
||||
void DECORATE(fill_generic_tile16)(uint8_t *buf, ptrdiff_t stride,
|
||||
const struct segment *line, size_t n_lines,
|
||||
int winding);
|
||||
void DECORATE(fill_generic_tile32)(uint8_t *buf, ptrdiff_t stride,
|
||||
const struct segment *line, size_t n_lines,
|
||||
int winding);
|
||||
|
||||
void DECORATE(add_bitmaps)(uint8_t *dst, intptr_t dst_stride,
|
||||
uint8_t *src, intptr_t src_stride,
|
||||
intptr_t height, intptr_t width);
|
||||
void DECORATE(sub_bitmaps)(uint8_t *dst, intptr_t dst_stride,
|
||||
uint8_t *src, intptr_t src_stride,
|
||||
intptr_t height, intptr_t width);
|
||||
void DECORATE(mul_bitmaps)(uint8_t *dst, intptr_t dst_stride,
|
||||
uint8_t *src1, intptr_t src1_stride,
|
||||
uint8_t *src2, intptr_t src2_stride,
|
||||
intptr_t width, intptr_t height);
|
||||
|
||||
void DECORATE(be_blur)(uint8_t *buf, intptr_t w, intptr_t h,
|
||||
intptr_t stride, uint16_t *tmp);
|
||||
|
||||
void DECORATE(stripe_unpack)(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride,
|
||||
uintptr_t width, uintptr_t height);
|
||||
void DECORATE(stripe_pack)(uint8_t *dst, ptrdiff_t dst_stride, const int16_t *src,
|
||||
uintptr_t width, uintptr_t height);
|
||||
void DECORATE(shrink_horz)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height);
|
||||
void DECORATE(shrink_vert)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height);
|
||||
void DECORATE(expand_horz)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height);
|
||||
void DECORATE(expand_vert)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height);
|
||||
void DECORATE(pre_blur1_horz)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height);
|
||||
void DECORATE(pre_blur1_vert)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height);
|
||||
void DECORATE(pre_blur2_horz)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height);
|
||||
void DECORATE(pre_blur2_vert)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height);
|
||||
void DECORATE(pre_blur3_horz)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height);
|
||||
void DECORATE(pre_blur3_vert)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height);
|
||||
void DECORATE(blur1234_horz)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height,
|
||||
const int16_t *param);
|
||||
void DECORATE(blur1234_vert)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height,
|
||||
const int16_t *param);
|
||||
void DECORATE(blur1235_horz)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height,
|
||||
const int16_t *param);
|
||||
void DECORATE(blur1235_vert)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height,
|
||||
const int16_t *param);
|
||||
void DECORATE(blur1246_horz)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height,
|
||||
const int16_t *param);
|
||||
void DECORATE(blur1246_vert)(int16_t *dst, const int16_t *src,
|
||||
uintptr_t src_width, uintptr_t src_height,
|
||||
const int16_t *param);
|
||||
|
||||
|
||||
const BitmapEngine DECORATE(bitmap_engine) = {
|
||||
.align_order = ALIGN,
|
||||
|
||||
#if CONFIG_LARGE_TILES
|
||||
.tile_order = 5,
|
||||
.fill_solid = DECORATE(fill_solid_tile32),
|
||||
.fill_halfplane = DECORATE(fill_halfplane_tile32),
|
||||
.fill_generic = DECORATE(fill_generic_tile32),
|
||||
#else
|
||||
.tile_order = 4,
|
||||
.fill_solid = DECORATE(fill_solid_tile16),
|
||||
.fill_halfplane = DECORATE(fill_halfplane_tile16),
|
||||
.fill_generic = DECORATE(fill_generic_tile16),
|
||||
#endif
|
||||
|
||||
.add_bitmaps = DECORATE(add_bitmaps),
|
||||
#ifdef __x86_64__
|
||||
.sub_bitmaps = DECORATE(sub_bitmaps),
|
||||
.mul_bitmaps = DECORATE(mul_bitmaps),
|
||||
#else
|
||||
.sub_bitmaps = ass_sub_bitmaps_c,
|
||||
.mul_bitmaps = ass_mul_bitmaps_c,
|
||||
#endif
|
||||
|
||||
#ifdef __x86_64__
|
||||
.be_blur = DECORATE(be_blur),
|
||||
#else
|
||||
.be_blur = ass_be_blur_c,
|
||||
#endif
|
||||
|
||||
.stripe_unpack = DECORATE(stripe_unpack),
|
||||
.stripe_pack = DECORATE(stripe_pack),
|
||||
.shrink_horz = DECORATE(shrink_horz),
|
||||
.shrink_vert = DECORATE(shrink_vert),
|
||||
.expand_horz = DECORATE(expand_horz),
|
||||
.expand_vert = DECORATE(expand_vert),
|
||||
.pre_blur_horz = { DECORATE(pre_blur1_horz), DECORATE(pre_blur2_horz), DECORATE(pre_blur3_horz) },
|
||||
.pre_blur_vert = { DECORATE(pre_blur1_vert), DECORATE(pre_blur2_vert), DECORATE(pre_blur3_vert) },
|
||||
.main_blur_horz = { DECORATE(blur1234_horz), DECORATE(blur1235_horz), DECORATE(blur1246_horz) },
|
||||
.main_blur_vert = { DECORATE(blur1234_vert), DECORATE(blur1235_vert), DECORATE(blur1246_vert) },
|
||||
};
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ass_compat.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "ass.h"
|
||||
#include "ass_library.h"
|
||||
#include "ass_utils.h"
|
||||
#include "ass_string.h"
|
||||
|
||||
static void ass_msg_handler(int level, const char *fmt, va_list va, void *data)
|
||||
{
|
||||
if (level > MSGL_INFO)
|
||||
return;
|
||||
fprintf(stderr, "[ass] ");
|
||||
vfprintf(stderr, fmt, va);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
ASS_Library *ass_library_init(void)
|
||||
{
|
||||
ASS_Library* lib = calloc(1, sizeof(*lib));
|
||||
if (lib)
|
||||
lib->msg_callback = ass_msg_handler;
|
||||
return lib;
|
||||
}
|
||||
|
||||
void ass_library_done(ASS_Library *priv)
|
||||
{
|
||||
if (priv) {
|
||||
ass_set_fonts_dir(priv, NULL);
|
||||
ass_set_style_overrides(priv, NULL);
|
||||
ass_clear_fonts(priv);
|
||||
free(priv);
|
||||
}
|
||||
}
|
||||
|
||||
void ass_set_fonts_dir(ASS_Library *priv, const char *fonts_dir)
|
||||
{
|
||||
free(priv->fonts_dir);
|
||||
|
||||
priv->fonts_dir = fonts_dir ? strdup(fonts_dir) : 0;
|
||||
}
|
||||
|
||||
void ass_set_extract_fonts(ASS_Library *priv, int extract)
|
||||
{
|
||||
priv->extract_fonts = !!extract;
|
||||
}
|
||||
|
||||
void ass_set_style_overrides(ASS_Library *priv, char **list)
|
||||
{
|
||||
char **p;
|
||||
char **q;
|
||||
int cnt;
|
||||
|
||||
if (priv->style_overrides) {
|
||||
for (p = priv->style_overrides; *p; ++p)
|
||||
free(*p);
|
||||
}
|
||||
free(priv->style_overrides);
|
||||
priv->style_overrides = NULL;
|
||||
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
for (p = list, cnt = 0; *p; ++p, ++cnt) {
|
||||
}
|
||||
|
||||
priv->style_overrides = calloc(cnt + 1, sizeof(char *));
|
||||
if (!priv->style_overrides)
|
||||
return;
|
||||
for (p = list, q = priv->style_overrides; *p; ++p, ++q)
|
||||
*q = strdup(*p);
|
||||
}
|
||||
|
||||
static int grow_array(void **array, int nelem, size_t elsize)
|
||||
{
|
||||
if (!(nelem & 31)) {
|
||||
void *ptr = realloc(*array, (nelem + 32) * elsize);
|
||||
if (!ptr)
|
||||
return 0;
|
||||
*array = ptr;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ass_add_font(ASS_Library *priv, char *name, char *data, int size)
|
||||
{
|
||||
int idx = priv->num_fontdata;
|
||||
if (!name || !data || !size)
|
||||
return;
|
||||
if (!grow_array((void **) &priv->fontdata, priv->num_fontdata,
|
||||
sizeof(*priv->fontdata)))
|
||||
return;
|
||||
|
||||
priv->fontdata[idx].name = strdup(name);
|
||||
priv->fontdata[idx].data = malloc(size);
|
||||
|
||||
if (!priv->fontdata[idx].name || !priv->fontdata[idx].data)
|
||||
goto error;
|
||||
|
||||
memcpy(priv->fontdata[idx].data, data, size);
|
||||
|
||||
priv->fontdata[idx].size = size;
|
||||
|
||||
priv->num_fontdata++;
|
||||
return;
|
||||
|
||||
error:
|
||||
free(priv->fontdata[idx].name);
|
||||
free(priv->fontdata[idx].data);
|
||||
}
|
||||
|
||||
void ass_clear_fonts(ASS_Library *priv)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < priv->num_fontdata; ++i) {
|
||||
free(priv->fontdata[i].name);
|
||||
free(priv->fontdata[i].data);
|
||||
}
|
||||
free(priv->fontdata);
|
||||
priv->fontdata = NULL;
|
||||
priv->num_fontdata = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register a message callback function with libass. Without setting one,
|
||||
* a default handler is used which prints everything with MSGL_INFO or
|
||||
* higher to the standard output.
|
||||
*
|
||||
* \param msg_cb the callback function
|
||||
* \param data additional data that will be passed to the callback
|
||||
*/
|
||||
void ass_set_message_cb(ASS_Library *priv,
|
||||
void (*msg_cb)(int, const char *, va_list, void *),
|
||||
void *data)
|
||||
{
|
||||
if (msg_cb) {
|
||||
priv->msg_callback = msg_cb;
|
||||
priv->msg_callback_data = data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBASS_LIBRARY_H
|
||||
#define LIBASS_LIBRARY_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
char *data;
|
||||
int size;
|
||||
} ASS_Fontdata;
|
||||
|
||||
struct ass_library {
|
||||
char *fonts_dir;
|
||||
int extract_fonts;
|
||||
char **style_overrides;
|
||||
|
||||
ASS_Fontdata *fontdata;
|
||||
int num_fontdata;
|
||||
void (*msg_callback)(int, const char *, va_list, void *);
|
||||
void *msg_callback_data;
|
||||
};
|
||||
|
||||
char *read_file(struct ass_library *library, char *fname, size_t *bufsize);
|
||||
|
||||
#endif /* LIBASS_LIBRARY_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Vabishchevich Nikolay <vabnick@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBASS_OUTLINE_H
|
||||
#define LIBASS_OUTLINE_H
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_OUTLINE_H
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ass_utils.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
int32_t x, y;
|
||||
} ASS_Vector;
|
||||
|
||||
typedef struct {
|
||||
double x, y;
|
||||
} ASS_DVector;
|
||||
|
||||
typedef struct {
|
||||
int32_t x_min, y_min, x_max, y_max;
|
||||
} ASS_Rect;
|
||||
|
||||
typedef struct {
|
||||
double x_min, y_min, x_max, y_max;
|
||||
} ASS_DRect;
|
||||
|
||||
static inline void rectangle_reset(ASS_Rect *rect)
|
||||
{
|
||||
rect->x_min = rect->y_min = INT32_MAX;
|
||||
rect->x_max = rect->y_max = INT32_MIN;
|
||||
}
|
||||
|
||||
static inline void rectangle_update(ASS_Rect *rect,
|
||||
int32_t x_min, int32_t y_min, int32_t x_max, int32_t y_max)
|
||||
{
|
||||
rect->x_min = FFMIN(rect->x_min, x_min);
|
||||
rect->y_min = FFMIN(rect->y_min, y_min);
|
||||
rect->x_max = FFMAX(rect->x_max, x_max);
|
||||
rect->y_max = FFMAX(rect->y_max, y_max);
|
||||
}
|
||||
|
||||
/*
|
||||
* Outline represented with array of points and array of segments.
|
||||
* Segment here is spline of order 1 (line), 2 (quadratic) or 3 (cubic).
|
||||
* Each segment owns number of points equal to its order in point array
|
||||
* and uses first point owned by the next segment as last point.
|
||||
* Last segment in each contour instead of the next segment point uses
|
||||
* point owned by the first segment in that contour. Correspondingly
|
||||
* total number of points is equal to the sum of spline orders of all segments.
|
||||
*/
|
||||
|
||||
enum {
|
||||
OUTLINE_LINE_SEGMENT = 1, // line segment
|
||||
OUTLINE_QUADRATIC_SPLINE = 2, // quadratic spline
|
||||
OUTLINE_CUBIC_SPLINE = 3, // cubic spline
|
||||
OUTLINE_COUNT_MASK = 3, // spline order mask
|
||||
OUTLINE_CONTOUR_END = 4 // last segment in contour flag
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
size_t n_points, max_points;
|
||||
size_t n_segments, max_segments;
|
||||
ASS_Vector *points;
|
||||
char *segments;
|
||||
} ASS_Outline;
|
||||
|
||||
#define OUTLINE_MIN (-((int32_t) 1 << 28))
|
||||
#define OUTLINE_MAX (((int32_t) 1 << 28) - 1)
|
||||
|
||||
bool outline_alloc(ASS_Outline *outline, size_t n_points, size_t n_segments);
|
||||
bool outline_convert(ASS_Outline *outline, const FT_Outline *source);
|
||||
bool outline_copy(ASS_Outline *outline, const ASS_Outline *source);
|
||||
void outline_free(ASS_Outline *outline);
|
||||
|
||||
bool outline_add_point(ASS_Outline *outline, ASS_Vector pt, char segment);
|
||||
bool outline_add_segment(ASS_Outline *outline, char segment);
|
||||
bool outline_close_contour(ASS_Outline *outline);
|
||||
|
||||
void outline_translate(const ASS_Outline *outline, int32_t dx, int32_t dy);
|
||||
void outline_adjust(const ASS_Outline *outline, double scale_x, int32_t dx, int32_t dy);
|
||||
void outline_get_cbox(const ASS_Outline *outline, ASS_Rect *cbox);
|
||||
|
||||
bool outline_stroke(ASS_Outline *result, ASS_Outline *result1,
|
||||
const ASS_Outline *path, int xbord, int ybord, int eps);
|
||||
|
||||
|
||||
#endif /* LIBASS_OUTLINE_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBASS_PARSE_H
|
||||
#define LIBASS_PARSE_H
|
||||
|
||||
#define BLUR_MAX_RADIUS 100.0
|
||||
|
||||
#define _r(c) ((c) >> 24)
|
||||
#define _g(c) (((c) >> 16) & 0xFF)
|
||||
#define _b(c) (((c) >> 8) & 0xFF)
|
||||
#define _a(c) ((c) & 0xFF)
|
||||
|
||||
void update_font(ASS_Renderer *render_priv);
|
||||
double ensure_font_size(ASS_Renderer *priv, double size);
|
||||
void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event);
|
||||
void process_karaoke_effects(ASS_Renderer *render_priv);
|
||||
unsigned get_next_char(ASS_Renderer *render_priv, char **str);
|
||||
char *parse_tag(ASS_Renderer *render_priv, char *p, char *end, double pwr);
|
||||
int event_has_hard_overrides(char *str);
|
||||
extern void change_alpha(uint32_t *var, int32_t new, double pwr);
|
||||
extern uint32_t mult_alpha(uint32_t a, uint32_t b);
|
||||
|
||||
|
||||
#endif /* LIBASS_PARSE_H */
|
|
@ -0,0 +1,786 @@
|
|||
/*
|
||||
* Copyright (C) 2014 Vabishchevich Nikolay <vabnick@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ass_compat.h"
|
||||
|
||||
#include <assert.h>
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_BitScanReverse)
|
||||
#endif
|
||||
|
||||
#include "ass_utils.h"
|
||||
#include "ass_outline.h"
|
||||
#include "ass_rasterizer.h"
|
||||
|
||||
|
||||
|
||||
static inline int ilog2(uint32_t n)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
return __builtin_clz(n) ^ 31;
|
||||
#elif defined(_MSC_VER)
|
||||
int res;
|
||||
_BitScanReverse(&res, n);
|
||||
return res;
|
||||
#else
|
||||
int res = 0;
|
||||
for (int ord = 16; ord; ord /= 2)
|
||||
if (n >= ((uint32_t) 1 << ord)) {
|
||||
res += ord;
|
||||
n >>= ord;
|
||||
}
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool rasterizer_init(RasterizerData *rst, int tile_order, int outline_error)
|
||||
{
|
||||
rst->outline_error = outline_error;
|
||||
rst->linebuf[0] = rst->linebuf[1] = NULL;
|
||||
rst->size[0] = rst->capacity[0] = 0;
|
||||
rst->size[1] = rst->capacity[1] = 0;
|
||||
rst->n_first = 0;
|
||||
|
||||
rst->tile = ass_aligned_alloc(32, 1 << (2 * tile_order), false);
|
||||
return rst->tile;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Ensure sufficient buffer size (allocate if necessary)
|
||||
* \param index index (0 or 1) of the input segment buffer (rst->linebuf)
|
||||
* \param delta requested size increase
|
||||
* \return false on error
|
||||
*/
|
||||
static inline bool check_capacity(RasterizerData *rst, int index, size_t delta)
|
||||
{
|
||||
delta += rst->size[index];
|
||||
if (rst->capacity[index] >= delta)
|
||||
return true;
|
||||
|
||||
size_t capacity = FFMAX(2 * rst->capacity[index], 64);
|
||||
while (capacity < delta)
|
||||
capacity *= 2;
|
||||
void *ptr = realloc(rst->linebuf[index], sizeof(struct segment) * capacity);
|
||||
if (!ptr)
|
||||
return false;
|
||||
|
||||
rst->linebuf[index] = (struct segment *) ptr;
|
||||
rst->capacity[index] = capacity;
|
||||
return true;
|
||||
}
|
||||
|
||||
void rasterizer_done(RasterizerData *rst)
|
||||
{
|
||||
free(rst->linebuf[0]);
|
||||
free(rst->linebuf[1]);
|
||||
|
||||
ass_aligned_free(rst->tile);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Tiled Rasterization Algorithm
|
||||
*
|
||||
* 1) Convert splines into polylines using recursive subdivision.
|
||||
*
|
||||
* 2) Determine which segments of resulting polylines fall into each tile.
|
||||
* That's done through recursive splitting of segment array with horizontal or vertical lines.
|
||||
* Each individual segment can lie fully left(top) or right(bottom) from the splitting line or cross it.
|
||||
* In the latter case copies of such segment go to both output arrays. Also winding count
|
||||
* of the top-left corner of the second result rectangle gets calculated simultaneously with splitting.
|
||||
* Winding count of the first result rectangle is the same as of the source rectangle.
|
||||
*
|
||||
* 3) When the splitting is done to the tile level, there are 3 possible outcome:
|
||||
* - Tile doesn't have segments at all--fill it with solid color in accordance with winding count.
|
||||
* - Tile have only 1 segment--use simple half-plane filling algorithm.
|
||||
* - Generic case with 2 or more segments.
|
||||
* In the latter case each segment gets rasterized as right trapezoid into buffer
|
||||
* with additive or subtractive blending.
|
||||
*/
|
||||
|
||||
|
||||
// Helper struct for spline split decision
|
||||
typedef struct {
|
||||
ASS_Vector r;
|
||||
int64_t r2, er;
|
||||
} OutlineSegment;
|
||||
|
||||
static inline void segment_init(OutlineSegment *seg,
|
||||
ASS_Vector beg, ASS_Vector end,
|
||||
int32_t outline_error)
|
||||
{
|
||||
int32_t x = end.x - beg.x;
|
||||
int32_t y = end.y - beg.y;
|
||||
int32_t abs_x = x < 0 ? -x : x;
|
||||
int32_t abs_y = y < 0 ? -y : y;
|
||||
|
||||
seg->r.x = x;
|
||||
seg->r.y = y;
|
||||
seg->r2 = x * (int64_t) x + y * (int64_t) y;
|
||||
seg->er = outline_error * (int64_t) FFMAX(abs_x, abs_y);
|
||||
}
|
||||
|
||||
static inline bool segment_subdivide(const OutlineSegment *seg,
|
||||
ASS_Vector beg, ASS_Vector pt)
|
||||
{
|
||||
int32_t x = pt.x - beg.x;
|
||||
int32_t y = pt.y - beg.y;
|
||||
int64_t pdr = seg->r.x * (int64_t) x + seg->r.y * (int64_t) y;
|
||||
int64_t pcr = seg->r.x * (int64_t) y - seg->r.y * (int64_t) x;
|
||||
return pdr < -seg->er || pdr > seg->r2 + seg->er ||
|
||||
(pcr < 0 ? -pcr : pcr) > seg->er;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Add new segment to polyline
|
||||
*/
|
||||
static bool add_line(RasterizerData *rst, ASS_Vector pt0, ASS_Vector pt1)
|
||||
{
|
||||
int32_t x = pt1.x - pt0.x;
|
||||
int32_t y = pt1.y - pt0.y;
|
||||
if (!x && !y)
|
||||
return true;
|
||||
|
||||
if (!check_capacity(rst, 0, 1))
|
||||
return false;
|
||||
struct segment *line = rst->linebuf[0] + rst->size[0];
|
||||
rst->size[0]++;
|
||||
|
||||
line->flags = SEGFLAG_EXACT_LEFT | SEGFLAG_EXACT_RIGHT |
|
||||
SEGFLAG_EXACT_TOP | SEGFLAG_EXACT_BOTTOM;
|
||||
if (x < 0)
|
||||
line->flags ^= SEGFLAG_UL_DR;
|
||||
if (y >= 0)
|
||||
line->flags ^= SEGFLAG_DN | SEGFLAG_UL_DR;
|
||||
|
||||
line->x_min = FFMIN(pt0.x, pt1.x);
|
||||
line->x_max = FFMAX(pt0.x, pt1.x);
|
||||
line->y_min = FFMIN(pt0.y, pt1.y);
|
||||
line->y_max = FFMAX(pt0.y, pt1.y);
|
||||
|
||||
line->a = y;
|
||||
line->b = -x;
|
||||
line->c = y * (int64_t) pt0.x - x * (int64_t) pt0.y;
|
||||
|
||||
// halfplane normalization
|
||||
int32_t abs_x = x < 0 ? -x : x;
|
||||
int32_t abs_y = y < 0 ? -y : y;
|
||||
uint32_t max_ab = (abs_x > abs_y ? abs_x : abs_y);
|
||||
int shift = 30 - ilog2(max_ab);
|
||||
max_ab <<= shift + 1;
|
||||
line->a *= 1 << shift;
|
||||
line->b *= 1 << shift;
|
||||
line->c *= 1 << shift;
|
||||
line->scale = (uint64_t) 0x53333333 * (uint32_t) (max_ab * (uint64_t) max_ab >> 32) >> 32;
|
||||
line->scale += 0x8810624D - (0xBBC6A7EF * (uint64_t) max_ab >> 32);
|
||||
//line->scale = ((uint64_t) 1 << 61) / max_ab;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Add quadratic spline to polyline
|
||||
* Performs recursive subdivision if necessary.
|
||||
*/
|
||||
static bool add_quadratic(RasterizerData *rst, const ASS_Vector *pt)
|
||||
{
|
||||
OutlineSegment seg;
|
||||
segment_init(&seg, pt[0], pt[2], rst->outline_error);
|
||||
if (!segment_subdivide(&seg, pt[0], pt[1]))
|
||||
return add_line(rst, pt[0], pt[2]);
|
||||
|
||||
ASS_Vector next[5];
|
||||
next[1].x = pt[0].x + pt[1].x;
|
||||
next[1].y = pt[0].y + pt[1].y;
|
||||
next[3].x = pt[1].x + pt[2].x;
|
||||
next[3].y = pt[1].y + pt[2].y;
|
||||
next[2].x = (next[1].x + next[3].x + 2) >> 2;
|
||||
next[2].y = (next[1].y + next[3].y + 2) >> 2;
|
||||
next[1].x >>= 1;
|
||||
next[1].y >>= 1;
|
||||
next[3].x >>= 1;
|
||||
next[3].y >>= 1;
|
||||
next[0] = pt[0];
|
||||
next[4] = pt[2];
|
||||
return add_quadratic(rst, next) && add_quadratic(rst, next + 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Add cubic spline to polyline
|
||||
* Performs recursive subdivision if necessary.
|
||||
*/
|
||||
static bool add_cubic(RasterizerData *rst, const ASS_Vector *pt)
|
||||
{
|
||||
OutlineSegment seg;
|
||||
segment_init(&seg, pt[0], pt[3], rst->outline_error);
|
||||
if (!segment_subdivide(&seg, pt[0], pt[1]) && !segment_subdivide(&seg, pt[0], pt[2]))
|
||||
return add_line(rst, pt[0], pt[3]);
|
||||
|
||||
ASS_Vector next[7], center;
|
||||
next[1].x = pt[0].x + pt[1].x;
|
||||
next[1].y = pt[0].y + pt[1].y;
|
||||
center.x = pt[1].x + pt[2].x + 2;
|
||||
center.y = pt[1].y + pt[2].y + 2;
|
||||
next[5].x = pt[2].x + pt[3].x;
|
||||
next[5].y = pt[2].y + pt[3].y;
|
||||
next[2].x = next[1].x + center.x;
|
||||
next[2].y = next[1].y + center.y;
|
||||
next[4].x = center.x + next[5].x;
|
||||
next[4].y = center.y + next[5].y;
|
||||
next[3].x = (next[2].x + next[4].x - 1) >> 3;
|
||||
next[3].y = (next[2].y + next[4].y - 1) >> 3;
|
||||
next[2].x >>= 2;
|
||||
next[2].y >>= 2;
|
||||
next[4].x >>= 2;
|
||||
next[4].y >>= 2;
|
||||
next[1].x >>= 1;
|
||||
next[1].y >>= 1;
|
||||
next[5].x >>= 1;
|
||||
next[5].y >>= 1;
|
||||
next[0] = pt[0];
|
||||
next[6] = pt[3];
|
||||
return add_cubic(rst, next) && add_cubic(rst, next + 3);
|
||||
}
|
||||
|
||||
|
||||
bool rasterizer_set_outline(RasterizerData *rst,
|
||||
const ASS_Outline *path, bool extra)
|
||||
{
|
||||
if (!extra) {
|
||||
rectangle_reset(&rst->bbox);
|
||||
rst->n_first = 0;
|
||||
}
|
||||
rst->size[0] = rst->n_first;
|
||||
|
||||
for (size_t i = 0; i < path->n_points; i++) {
|
||||
if (path->points[i].x < OUTLINE_MIN || path->points[i].x > OUTLINE_MAX)
|
||||
return false;
|
||||
if (path->points[i].y < OUTLINE_MIN || path->points[i].y > OUTLINE_MAX)
|
||||
return false;
|
||||
}
|
||||
|
||||
ASS_Vector *start = path->points, *cur = start;
|
||||
for (size_t i = 0; i < path->n_segments; i++) {
|
||||
int n = path->segments[i] & OUTLINE_COUNT_MASK;
|
||||
cur += n;
|
||||
|
||||
ASS_Vector *end = cur, p[4];
|
||||
if (path->segments[i] & OUTLINE_CONTOUR_END) {
|
||||
end = start;
|
||||
start = cur;
|
||||
}
|
||||
|
||||
switch (n) {
|
||||
case OUTLINE_LINE_SEGMENT:
|
||||
if (!add_line(rst, cur[-1], *end))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case OUTLINE_QUADRATIC_SPLINE:
|
||||
p[0] = cur[-2];
|
||||
p[1] = cur[-1];
|
||||
p[2] = *end;
|
||||
if (!add_quadratic(rst, p))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case OUTLINE_CUBIC_SPLINE:
|
||||
p[0] = cur[-3];
|
||||
p[1] = cur[-2];
|
||||
p[2] = cur[-1];
|
||||
p[3] = *end;
|
||||
if (!add_cubic(rst, p))
|
||||
return false;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
assert(start == cur && cur == path->points + path->n_points);
|
||||
|
||||
for (size_t k = rst->n_first; k < rst->size[0]; k++) {
|
||||
struct segment *line = &rst->linebuf[0][k];
|
||||
rectangle_update(&rst->bbox,
|
||||
line->x_min, line->y_min,
|
||||
line->x_max, line->y_max);
|
||||
}
|
||||
if (!extra)
|
||||
rst->n_first = rst->size[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void segment_move_x(struct segment *line, int32_t x)
|
||||
{
|
||||
line->x_min -= x;
|
||||
line->x_max -= x;
|
||||
line->x_min = FFMAX(line->x_min, 0);
|
||||
line->c -= line->a * (int64_t) x;
|
||||
|
||||
static const int test = SEGFLAG_EXACT_LEFT | SEGFLAG_UL_DR;
|
||||
if (!line->x_min && (line->flags & test) == test)
|
||||
line->flags &= ~SEGFLAG_EXACT_TOP;
|
||||
}
|
||||
|
||||
static void segment_move_y(struct segment *line, int32_t y)
|
||||
{
|
||||
line->y_min -= y;
|
||||
line->y_max -= y;
|
||||
line->y_min = FFMAX(line->y_min, 0);
|
||||
line->c -= line->b * (int64_t) y;
|
||||
|
||||
static const int test = SEGFLAG_EXACT_TOP | SEGFLAG_UL_DR;
|
||||
if (!line->y_min && (line->flags & test) == test)
|
||||
line->flags &= ~SEGFLAG_EXACT_LEFT;
|
||||
}
|
||||
|
||||
static void segment_split_horz(struct segment *line, struct segment *next, int32_t x)
|
||||
{
|
||||
assert(x > line->x_min && x < line->x_max);
|
||||
|
||||
*next = *line;
|
||||
next->c -= line->a * (int64_t) x;
|
||||
next->x_min = 0;
|
||||
next->x_max -= x;
|
||||
line->x_max = x;
|
||||
|
||||
line->flags &= ~SEGFLAG_EXACT_TOP;
|
||||
next->flags &= ~SEGFLAG_EXACT_BOTTOM;
|
||||
if (line->flags & SEGFLAG_UL_DR) {
|
||||
int32_t tmp = line->flags;
|
||||
line->flags = next->flags;
|
||||
next->flags = tmp;
|
||||
}
|
||||
line->flags |= SEGFLAG_EXACT_RIGHT;
|
||||
next->flags |= SEGFLAG_EXACT_LEFT;
|
||||
}
|
||||
|
||||
static void segment_split_vert(struct segment *line, struct segment *next, int32_t y)
|
||||
{
|
||||
assert(y > line->y_min && y < line->y_max);
|
||||
|
||||
*next = *line;
|
||||
next->c -= line->b * (int64_t) y;
|
||||
next->y_min = 0;
|
||||
next->y_max -= y;
|
||||
line->y_max = y;
|
||||
|
||||
line->flags &= ~SEGFLAG_EXACT_LEFT;
|
||||
next->flags &= ~SEGFLAG_EXACT_RIGHT;
|
||||
if (line->flags & SEGFLAG_UL_DR) {
|
||||
int32_t tmp = line->flags;
|
||||
line->flags = next->flags;
|
||||
next->flags = tmp;
|
||||
}
|
||||
line->flags |= SEGFLAG_EXACT_BOTTOM;
|
||||
next->flags |= SEGFLAG_EXACT_TOP;
|
||||
}
|
||||
|
||||
static inline int segment_check_left(const struct segment *line, int32_t x)
|
||||
{
|
||||
if (line->flags & SEGFLAG_EXACT_LEFT)
|
||||
return line->x_min >= x;
|
||||
int64_t cc = line->c - line->a * (int64_t) x -
|
||||
line->b * (int64_t) (line->flags & SEGFLAG_UL_DR ? line->y_min : line->y_max);
|
||||
if (line->a < 0)
|
||||
cc = -cc;
|
||||
return cc >= 0;
|
||||
}
|
||||
|
||||
static inline int segment_check_right(const struct segment *line, int32_t x)
|
||||
{
|
||||
if (line->flags & SEGFLAG_EXACT_RIGHT)
|
||||
return line->x_max <= x;
|
||||
int64_t cc = line->c - line->a * (int64_t) x -
|
||||
line->b * (int64_t) (line->flags & SEGFLAG_UL_DR ? line->y_max : line->y_min);
|
||||
if (line->a > 0)
|
||||
cc = -cc;
|
||||
return cc >= 0;
|
||||
}
|
||||
|
||||
static inline int segment_check_top(const struct segment *line, int32_t y)
|
||||
{
|
||||
if (line->flags & SEGFLAG_EXACT_TOP)
|
||||
return line->y_min >= y;
|
||||
int64_t cc = line->c - line->b * (int64_t) y -
|
||||
line->a * (int64_t) (line->flags & SEGFLAG_UL_DR ? line->x_min : line->x_max);
|
||||
if (line->b < 0)
|
||||
cc = -cc;
|
||||
return cc >= 0;
|
||||
}
|
||||
|
||||
static inline int segment_check_bottom(const struct segment *line, int32_t y)
|
||||
{
|
||||
if (line->flags & SEGFLAG_EXACT_BOTTOM)
|
||||
return line->y_max <= y;
|
||||
int64_t cc = line->c - line->b * (int64_t) y -
|
||||
line->a * (int64_t) (line->flags & SEGFLAG_UL_DR ? line->x_max : line->x_min);
|
||||
if (line->b > 0)
|
||||
cc = -cc;
|
||||
return cc >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Split list of segments horizontally
|
||||
* \param src in: input array, can coincide with *dst0 or *dst1
|
||||
* \param n_src in: numbers of input segments for both groups
|
||||
* \param dst0, dst1 out: output arrays of at least n_src[0] + n_src[1] size
|
||||
* \param n_dst0, n_dst1 out: numbers of output segments for both groups
|
||||
* \param winding out: resulting winding of bottom-split point
|
||||
* \param x in: split coordinate
|
||||
*/
|
||||
static void polyline_split_horz(const struct segment *src, const size_t n_src[2],
|
||||
struct segment *dst0, size_t n_dst0[2],
|
||||
struct segment *dst1, size_t n_dst1[2],
|
||||
int winding[2], int32_t x)
|
||||
{
|
||||
const struct segment *cmp = src + n_src[0];
|
||||
const struct segment *end = cmp + n_src[1];
|
||||
n_dst0[0] = n_dst0[1] = 0;
|
||||
n_dst1[0] = n_dst1[1] = 0;
|
||||
for (; src != end; src++) {
|
||||
int group = src < cmp ? 0 : 1;
|
||||
|
||||
int delta = 0;
|
||||
if (!src->y_min && (src->flags & SEGFLAG_EXACT_TOP))
|
||||
delta = src->a < 0 ? 1 : -1;
|
||||
if (segment_check_right(src, x)) {
|
||||
winding[group] += delta;
|
||||
if (src->x_min >= x)
|
||||
continue;
|
||||
*dst0 = *src;
|
||||
dst0->x_max = FFMIN(dst0->x_max, x);
|
||||
n_dst0[group]++;
|
||||
dst0++;
|
||||
continue;
|
||||
}
|
||||
if (segment_check_left(src, x)) {
|
||||
*dst1 = *src;
|
||||
segment_move_x(dst1, x);
|
||||
n_dst1[group]++;
|
||||
dst1++;
|
||||
continue;
|
||||
}
|
||||
if (src->flags & SEGFLAG_UL_DR)
|
||||
winding[group] += delta;
|
||||
*dst0 = *src;
|
||||
segment_split_horz(dst0, dst1, x);
|
||||
n_dst0[group]++;
|
||||
dst0++;
|
||||
n_dst1[group]++;
|
||||
dst1++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Split list of segments vertically
|
||||
*/
|
||||
static void polyline_split_vert(const struct segment *src, const size_t n_src[2],
|
||||
struct segment *dst0, size_t n_dst0[2],
|
||||
struct segment *dst1, size_t n_dst1[2],
|
||||
int winding[2], int32_t y)
|
||||
{
|
||||
const struct segment *cmp = src + n_src[0];
|
||||
const struct segment *end = cmp + n_src[1];
|
||||
n_dst0[0] = n_dst0[1] = 0;
|
||||
n_dst1[0] = n_dst1[1] = 0;
|
||||
for (; src != end; src++) {
|
||||
int group = src < cmp ? 0 : 1;
|
||||
|
||||
int delta = 0;
|
||||
if (!src->x_min && (src->flags & SEGFLAG_EXACT_LEFT))
|
||||
delta = src->b < 0 ? 1 : -1;
|
||||
if (segment_check_bottom(src, y)) {
|
||||
winding[group] += delta;
|
||||
if (src->y_min >= y)
|
||||
continue;
|
||||
*dst0 = *src;
|
||||
dst0->y_max = dst0->y_max < y ? dst0->y_max : y;
|
||||
n_dst0[group]++;
|
||||
dst0++;
|
||||
continue;
|
||||
}
|
||||
if (segment_check_top(src, y)) {
|
||||
*dst1 = *src;
|
||||
segment_move_y(dst1, y);
|
||||
n_dst1[group]++;
|
||||
dst1++;
|
||||
continue;
|
||||
}
|
||||
if (src->flags & SEGFLAG_UL_DR)
|
||||
winding[group] += delta;
|
||||
*dst0 = *src;
|
||||
segment_split_vert(dst0, dst1, y);
|
||||
n_dst0[group]++;
|
||||
dst0++;
|
||||
n_dst1[group]++;
|
||||
dst1++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline void rasterizer_fill_solid(const BitmapEngine *engine,
|
||||
uint8_t *buf, int width, int height, ptrdiff_t stride,
|
||||
int set)
|
||||
{
|
||||
assert(!(width & ((1 << engine->tile_order) - 1)));
|
||||
assert(!(height & ((1 << engine->tile_order) - 1)));
|
||||
|
||||
ptrdiff_t step = 1 << engine->tile_order;
|
||||
ptrdiff_t tile_stride = stride * (1 << engine->tile_order);
|
||||
width >>= engine->tile_order;
|
||||
height >>= engine->tile_order;
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++)
|
||||
engine->fill_solid(buf + x * step, stride, set);
|
||||
buf += tile_stride;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void rasterizer_fill_halfplane(const BitmapEngine *engine,
|
||||
uint8_t *buf, int width, int height, ptrdiff_t stride,
|
||||
int32_t a, int32_t b, int64_t c, int32_t scale)
|
||||
{
|
||||
assert(!(width & ((1 << engine->tile_order) - 1)));
|
||||
assert(!(height & ((1 << engine->tile_order) - 1)));
|
||||
if (width == 1 << engine->tile_order && height == 1 << engine->tile_order) {
|
||||
engine->fill_halfplane(buf, stride, a, b, c, scale);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t abs_a = a < 0 ? -a : a;
|
||||
uint32_t abs_b = b < 0 ? -b : b;
|
||||
int64_t size = (int64_t) (abs_a + abs_b) << (engine->tile_order + 5);
|
||||
int64_t offs = ((int64_t) a + b) * (1 << (engine->tile_order + 5));
|
||||
|
||||
ptrdiff_t step = 1 << engine->tile_order;
|
||||
ptrdiff_t tile_stride = stride * (1 << engine->tile_order);
|
||||
width >>= engine->tile_order;
|
||||
height >>= engine->tile_order;
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int64_t cc = c - (a * (int64_t) x + b * (int64_t) y) * (1 << (engine->tile_order + 6));
|
||||
int64_t offs_c = offs - cc;
|
||||
int64_t abs_c = offs_c < 0 ? -offs_c : offs_c;
|
||||
if (abs_c < size)
|
||||
engine->fill_halfplane(buf + x * step, stride, a, b, cc, scale);
|
||||
else
|
||||
engine->fill_solid(buf + x * step, stride,
|
||||
((uint32_t) (offs_c >> 32) ^ scale) & 0x80000000);
|
||||
}
|
||||
buf += tile_stride;
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
FLAG_SOLID = 1,
|
||||
FLAG_COMPLEX = 2,
|
||||
FLAG_REVERSE = 4,
|
||||
FLAG_GENERIC = 8,
|
||||
};
|
||||
|
||||
static inline int get_fill_flags(struct segment *line, size_t n_lines, int winding)
|
||||
{
|
||||
if (!n_lines)
|
||||
return winding ? FLAG_SOLID : 0;
|
||||
if (n_lines > 1)
|
||||
return FLAG_COMPLEX | FLAG_GENERIC;
|
||||
|
||||
static const int test = SEGFLAG_UL_DR | SEGFLAG_EXACT_LEFT;
|
||||
if (((line->flags & test) != test) == !(line->flags & SEGFLAG_DN))
|
||||
winding++;
|
||||
|
||||
switch (winding) {
|
||||
case 0:
|
||||
return FLAG_COMPLEX | FLAG_REVERSE;
|
||||
case 1:
|
||||
return FLAG_COMPLEX;
|
||||
default:
|
||||
return FLAG_SOLID;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Main quad-tree filling function
|
||||
* \param index index (0 or 1) of the input segment buffer (rst->linebuf)
|
||||
* \param offs current offset from the beginning of the buffer
|
||||
* \param winding bottom-left winding value
|
||||
* \return false on error
|
||||
* Rasterizes (possibly recursive) one quad-tree level.
|
||||
* Truncates used input buffer.
|
||||
*/
|
||||
static bool rasterizer_fill_level(const BitmapEngine *engine, RasterizerData *rst,
|
||||
uint8_t *buf, int width, int height, ptrdiff_t stride,
|
||||
int index, const size_t n_lines[2], const int winding[2])
|
||||
{
|
||||
assert(width > 0 && height > 0);
|
||||
assert((unsigned) index < 2u && n_lines[0] + n_lines[1] <= rst->size[index]);
|
||||
assert(!(width & ((1 << engine->tile_order) - 1)));
|
||||
assert(!(height & ((1 << engine->tile_order) - 1)));
|
||||
|
||||
size_t offs = rst->size[index] - n_lines[0] - n_lines[1];
|
||||
struct segment *line = rst->linebuf[index] + offs, *line1 = line + n_lines[0];
|
||||
int flags0 = get_fill_flags(line, n_lines[0], winding[0]);
|
||||
int flags1 = get_fill_flags(line1, n_lines[1], winding[1]);
|
||||
int flags = (flags0 | flags1) ^ FLAG_COMPLEX;
|
||||
if (flags & (FLAG_SOLID | FLAG_COMPLEX)) {
|
||||
rasterizer_fill_solid(engine, buf, width, height, stride, flags & FLAG_SOLID);
|
||||
rst->size[index] = offs;
|
||||
return true;
|
||||
}
|
||||
if (!(flags & FLAG_GENERIC) && ((flags0 ^ flags1) & FLAG_COMPLEX)) {
|
||||
if (flags1 & FLAG_COMPLEX)
|
||||
line = line1;
|
||||
rasterizer_fill_halfplane(engine, buf, width, height, stride,
|
||||
line->a, line->b, line->c,
|
||||
flags & FLAG_REVERSE ? -line->scale : line->scale);
|
||||
rst->size[index] = offs;
|
||||
return true;
|
||||
}
|
||||
if (width == 1 << engine->tile_order && height == 1 << engine->tile_order) {
|
||||
if (!(flags1 & FLAG_COMPLEX)) {
|
||||
engine->fill_generic(buf, stride, line, n_lines[0], winding[0]);
|
||||
rst->size[index] = offs;
|
||||
return true;
|
||||
}
|
||||
if (!(flags0 & FLAG_COMPLEX)) {
|
||||
engine->fill_generic(buf, stride, line1, n_lines[1], winding[1]);
|
||||
rst->size[index] = offs;
|
||||
return true;
|
||||
}
|
||||
if (flags0 & FLAG_GENERIC)
|
||||
engine->fill_generic(buf, stride, line, n_lines[0], winding[0]);
|
||||
else
|
||||
engine->fill_halfplane(buf, stride, line->a, line->b, line->c,
|
||||
flags0 & FLAG_REVERSE ? -line->scale : line->scale);
|
||||
if (flags1 & FLAG_GENERIC)
|
||||
engine->fill_generic(rst->tile, width, line1, n_lines[1], winding[1]);
|
||||
else
|
||||
engine->fill_halfplane(rst->tile, width, line1->a, line1->b, line1->c,
|
||||
flags1 & FLAG_REVERSE ? -line1->scale : line1->scale);
|
||||
// XXX: better to use max instead of add
|
||||
engine->add_bitmaps(buf, stride, rst->tile, width, height, width);
|
||||
rst->size[index] = offs;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t offs1 = rst->size[index ^ 1];
|
||||
if (!check_capacity(rst, index ^ 1, n_lines[0] + n_lines[1]))
|
||||
return false;
|
||||
struct segment *dst0 = line;
|
||||
struct segment *dst1 = rst->linebuf[index ^ 1] + offs1;
|
||||
|
||||
uint8_t *buf1 = buf;
|
||||
int width1 = width;
|
||||
int height1 = height;
|
||||
size_t n_next0[2], n_next1[2];
|
||||
int winding1[2] = { winding[0], winding[1] };
|
||||
if (width > height) {
|
||||
width = 1 << ilog2(width - 1);
|
||||
width1 -= width;
|
||||
buf1 += width;
|
||||
polyline_split_horz(line, n_lines,
|
||||
dst0, n_next0, dst1, n_next1,
|
||||
winding1, (int32_t) width << 6);
|
||||
} else {
|
||||
height = 1 << ilog2(height - 1);
|
||||
height1 -= height;
|
||||
buf1 += height * stride;
|
||||
polyline_split_vert(line, n_lines,
|
||||
dst0, n_next0, dst1, n_next1,
|
||||
winding1, (int32_t) height << 6);
|
||||
}
|
||||
rst->size[index ^ 0] = offs + n_next0[0] + n_next0[1];
|
||||
rst->size[index ^ 1] = offs1 + n_next1[0] + n_next1[1];
|
||||
|
||||
if (!rasterizer_fill_level(engine, rst, buf, width, height, stride, index ^ 0, n_next0, winding))
|
||||
return false;
|
||||
assert(rst->size[index ^ 0] == offs);
|
||||
if (!rasterizer_fill_level(engine, rst, buf1, width1, height1, stride, index ^ 1, n_next1, winding1))
|
||||
return false;
|
||||
assert(rst->size[index ^ 1] == offs1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rasterizer_fill(const BitmapEngine *engine, RasterizerData *rst,
|
||||
uint8_t *buf, int x0, int y0,
|
||||
int width, int height, ptrdiff_t stride)
|
||||
{
|
||||
assert(width > 0 && height > 0);
|
||||
assert(!(width & ((1 << engine->tile_order) - 1)));
|
||||
assert(!(height & ((1 << engine->tile_order) - 1)));
|
||||
x0 *= 1 << 6; y0 *= 1 << 6;
|
||||
|
||||
struct segment *line = rst->linebuf[0];
|
||||
struct segment *end = line + rst->size[0];
|
||||
for (; line != end; line++) {
|
||||
line->x_min -= x0;
|
||||
line->x_max -= x0;
|
||||
line->y_min -= y0;
|
||||
line->y_max -= y0;
|
||||
line->c -= line->a * (int64_t) x0 + line->b * (int64_t) y0;
|
||||
}
|
||||
rst->bbox.x_min -= x0;
|
||||
rst->bbox.x_max -= x0;
|
||||
rst->bbox.y_min -= y0;
|
||||
rst->bbox.y_max -= y0;
|
||||
|
||||
if (!check_capacity(rst, 1, rst->size[0]))
|
||||
return false;
|
||||
|
||||
size_t n_unused[2];
|
||||
size_t n_lines[2] = { rst->n_first, rst->size[0] - rst->n_first };
|
||||
int winding[2] = { 0, 0 };
|
||||
|
||||
int32_t size_x = (int32_t) width << 6;
|
||||
int32_t size_y = (int32_t) height << 6;
|
||||
if (rst->bbox.x_max >= size_x) {
|
||||
polyline_split_horz(rst->linebuf[0], n_lines,
|
||||
rst->linebuf[0], n_lines,
|
||||
rst->linebuf[1], n_unused,
|
||||
winding, size_x);
|
||||
winding[0] = winding[1] = 0;
|
||||
}
|
||||
if (rst->bbox.y_max >= size_y) {
|
||||
polyline_split_vert(rst->linebuf[0], n_lines,
|
||||
rst->linebuf[0], n_lines,
|
||||
rst->linebuf[1], n_unused,
|
||||
winding, size_y);
|
||||
winding[0] = winding[1] = 0;
|
||||
}
|
||||
if (rst->bbox.x_min <= 0) {
|
||||
polyline_split_horz(rst->linebuf[0], n_lines,
|
||||
rst->linebuf[1], n_unused,
|
||||
rst->linebuf[0], n_lines,
|
||||
winding, 0);
|
||||
}
|
||||
if (rst->bbox.y_min <= 0) {
|
||||
polyline_split_vert(rst->linebuf[0], n_lines,
|
||||
rst->linebuf[1], n_unused,
|
||||
rst->linebuf[0], n_lines,
|
||||
winding, 0);
|
||||
}
|
||||
rst->size[0] = n_lines[0] + n_lines[1];
|
||||
rst->size[1] = 0;
|
||||
return rasterizer_fill_level(engine, rst,
|
||||
buf, width, height, stride,
|
||||
0, n_lines, winding);
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (C) 2014 Vabishchevich Nikolay <vabnick@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBASS_RASTERIZER_H
|
||||
#define LIBASS_RASTERIZER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "ass_bitmap.h"
|
||||
|
||||
|
||||
enum {
|
||||
SEGFLAG_DN = 1,
|
||||
SEGFLAG_UL_DR = 2,
|
||||
SEGFLAG_EXACT_LEFT = 4,
|
||||
SEGFLAG_EXACT_RIGHT = 8,
|
||||
SEGFLAG_EXACT_TOP = 16,
|
||||
SEGFLAG_EXACT_BOTTOM = 32,
|
||||
};
|
||||
|
||||
// Polyline segment struct
|
||||
struct segment {
|
||||
int64_t c;
|
||||
int32_t a, b, scale, flags;
|
||||
int32_t x_min, x_max, y_min, y_max;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int outline_error; // acceptable error (in 1/64 pixel units)
|
||||
|
||||
// usable after rasterizer_set_outline
|
||||
ASS_Rect bbox;
|
||||
|
||||
// internal buffers
|
||||
struct segment *linebuf[2];
|
||||
size_t size[2], capacity[2];
|
||||
size_t n_first;
|
||||
|
||||
uint8_t *tile;
|
||||
} RasterizerData;
|
||||
|
||||
bool rasterizer_init(RasterizerData *rst, int tile_order, int outline_error);
|
||||
void rasterizer_done(RasterizerData *rst);
|
||||
|
||||
/**
|
||||
* \brief Convert outline to polyline and calculate exact bounds
|
||||
* \param path in: source outline
|
||||
* \param extra in: true if path is second border outline
|
||||
* \return false on error
|
||||
*/
|
||||
bool rasterizer_set_outline(RasterizerData *rst,
|
||||
const ASS_Outline *path, bool extra);
|
||||
|
||||
/**
|
||||
* \brief Polyline rasterization function
|
||||
* \param x0, y0, width, height in: source window (full pixel units)
|
||||
* \param buf out: aligned output buffer (size = stride * height)
|
||||
* \param stride output buffer stride (aligned)
|
||||
* \return false on error
|
||||
* Deletes preprocessed polyline after work.
|
||||
*/
|
||||
bool rasterizer_fill(const BitmapEngine *engine, RasterizerData *rst,
|
||||
uint8_t *buf, int x0, int y0,
|
||||
int width, int height, ptrdiff_t stride);
|
||||
|
||||
|
||||
#endif /* LIBASS_RASTERIZER_H */
|
|
@ -0,0 +1,377 @@
|
|||
/*
|
||||
* Copyright (C) 2014 Vabishchevich Nikolay <vabnick@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ass_compat.h"
|
||||
|
||||
#include "ass_utils.h"
|
||||
#include "ass_rasterizer.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
|
||||
void ass_fill_solid_tile16_c(uint8_t *buf, ptrdiff_t stride, int set)
|
||||
{
|
||||
uint8_t value = set ? 255 : 0;
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int x = 0; x < 16; x++)
|
||||
buf[x] = value;
|
||||
buf += stride;
|
||||
}
|
||||
}
|
||||
|
||||
void ass_fill_solid_tile32_c(uint8_t *buf, ptrdiff_t stride, int set)
|
||||
{
|
||||
uint8_t value = set ? 255 : 0;
|
||||
for (int y = 0; y < 32; y++) {
|
||||
for (int x = 0; x < 32; x++)
|
||||
buf[x] = value;
|
||||
buf += stride;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Halfplane Filling Functions
|
||||
*
|
||||
* Fill pixels with antialiasing corresponding to equation
|
||||
* A * x + B * y < C, where
|
||||
* x, y - offset of pixel center from bottom-left,
|
||||
* A = a * scale, B = b * scale, C = c * scale / 64.
|
||||
*
|
||||
* Normalization of coefficients prior call:
|
||||
* max(abs(a), abs(b)) * scale = 1 << 61
|
||||
*
|
||||
* Used Algorithm
|
||||
* Let
|
||||
* max_ab = max(abs(A), abs(B)),
|
||||
* min_ab = min(abs(A), abs(B)),
|
||||
* CC = C - A * x - B * y, then
|
||||
* result = (clamp((CC - min_ab / 4) / max_ab) +
|
||||
* clamp((CC + min_ab / 4) / max_ab) +
|
||||
* 1) / 2,
|
||||
* where clamp(Z) = max(-0.5, min(0.5, Z)).
|
||||
*/
|
||||
|
||||
void ass_fill_halfplane_tile16_c(uint8_t *buf, ptrdiff_t stride,
|
||||
int32_t a, int32_t b, int64_t c, int32_t scale)
|
||||
{
|
||||
int16_t aa = (a * (int64_t) scale + ((int64_t) 1 << 49)) >> 50;
|
||||
int16_t bb = (b * (int64_t) scale + ((int64_t) 1 << 49)) >> 50;
|
||||
int16_t cc = ((int32_t) (c >> 11) * (int64_t) scale + ((int64_t) 1 << 44)) >> 45;
|
||||
cc += (1 << 9) - ((aa + bb) >> 1);
|
||||
|
||||
int16_t abs_a = aa < 0 ? -aa : aa;
|
||||
int16_t abs_b = bb < 0 ? -bb : bb;
|
||||
int16_t delta = (FFMIN(abs_a, abs_b) + 2) >> 2;
|
||||
|
||||
int16_t va1[16], va2[16];
|
||||
for (int x = 0; x < 16; x++) {
|
||||
va1[x] = aa * x - delta;
|
||||
va2[x] = aa * x + delta;
|
||||
}
|
||||
|
||||
static const int16_t full = (1 << 10) - 1;
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
int16_t c1 = cc - va1[x];
|
||||
int16_t c2 = cc - va2[x];
|
||||
c1 = FFMINMAX(c1, 0, full);
|
||||
c2 = FFMINMAX(c2, 0, full);
|
||||
buf[x] = (c1 + c2) >> 3;
|
||||
}
|
||||
buf += stride;
|
||||
cc -= bb;
|
||||
}
|
||||
}
|
||||
|
||||
void ass_fill_halfplane_tile32_c(uint8_t *buf, ptrdiff_t stride,
|
||||
int32_t a, int32_t b, int64_t c, int32_t scale)
|
||||
{
|
||||
int16_t aa = (a * (int64_t) scale + ((int64_t) 1 << 50)) >> 51;
|
||||
int16_t bb = (b * (int64_t) scale + ((int64_t) 1 << 50)) >> 51;
|
||||
int16_t cc = ((int32_t) (c >> 12) * (int64_t) scale + ((int64_t) 1 << 44)) >> 45;
|
||||
cc += (1 << 8) - ((aa + bb) >> 1);
|
||||
|
||||
int16_t abs_a = aa < 0 ? -aa : aa;
|
||||
int16_t abs_b = bb < 0 ? -bb : bb;
|
||||
int16_t delta = (FFMIN(abs_a, abs_b) + 2) >> 2;
|
||||
|
||||
int16_t va1[32], va2[32];
|
||||
for (int x = 0; x < 32; x++) {
|
||||
va1[x] = aa * x - delta;
|
||||
va2[x] = aa * x + delta;
|
||||
}
|
||||
|
||||
static const int16_t full = (1 << 9) - 1;
|
||||
for (int y = 0; y < 32; y++) {
|
||||
for (int x = 0; x < 32; x++) {
|
||||
int16_t c1 = cc - va1[x];
|
||||
int16_t c2 = cc - va2[x];
|
||||
c1 = FFMINMAX(c1, 0, full);
|
||||
c2 = FFMINMAX(c2, 0, full);
|
||||
buf[x] = (c1 + c2) >> 2;
|
||||
}
|
||||
buf += stride;
|
||||
cc -= bb;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Generic Filling Functions
|
||||
*
|
||||
* Used Algorithm
|
||||
* Construct trapeziod from each polyline segment and its projection into left side of tile.
|
||||
* Render that trapeziod into internal buffer with additive blending and correct sign.
|
||||
* Store clamped absolute value from internal buffer into result buffer.
|
||||
*/
|
||||
|
||||
// Render top/bottom line of the trapeziod with antialiasing
|
||||
static inline void update_border_line16(int16_t res[16],
|
||||
int16_t abs_a, const int16_t va[16],
|
||||
int16_t b, int16_t abs_b,
|
||||
int16_t c, int up, int dn)
|
||||
{
|
||||
int16_t size = dn - up;
|
||||
int16_t w = (1 << 10) + (size << 4) - abs_a;
|
||||
w = FFMIN(w, 1 << 10) << 3;
|
||||
|
||||
int16_t dc_b = abs_b * (int32_t) size >> 6;
|
||||
int16_t dc = (FFMIN(abs_a, dc_b) + 2) >> 2;
|
||||
|
||||
int16_t base = (int32_t) b * (int16_t) (up + dn) >> 7;
|
||||
int16_t offs1 = size - ((base + dc) * (int32_t) w >> 16);
|
||||
int16_t offs2 = size - ((base - dc) * (int32_t) w >> 16);
|
||||
|
||||
size <<= 1;
|
||||
for (int x = 0; x < 16; x++) {
|
||||
int16_t cw = (c - va[x]) * (int32_t) w >> 16;
|
||||
int16_t c1 = cw + offs1;
|
||||
int16_t c2 = cw + offs2;
|
||||
c1 = FFMINMAX(c1, 0, size);
|
||||
c2 = FFMINMAX(c2, 0, size);
|
||||
res[x] += c1 + c2;
|
||||
}
|
||||
}
|
||||
|
||||
void ass_fill_generic_tile16_c(uint8_t *buf, ptrdiff_t stride,
|
||||
const struct segment *line, size_t n_lines,
|
||||
int winding)
|
||||
{
|
||||
int16_t res[16][16], delta[18];
|
||||
for (int y = 0; y < 16; y++)
|
||||
for (int x = 0; x < 16; x++)
|
||||
res[y][x] = 0;
|
||||
for (int y = 0; y < 18; y++)
|
||||
delta[y] = 0;
|
||||
|
||||
static const int16_t full = 1 << 10;
|
||||
const struct segment *end = line + n_lines;
|
||||
for (; line != end; ++line) {
|
||||
assert(line->y_min >= 0 && line->y_min < 1 << 10);
|
||||
assert(line->y_max > 0 && line->y_max <= 1 << 10);
|
||||
assert(line->y_min <= line->y_max);
|
||||
|
||||
int16_t up_delta = line->flags & SEGFLAG_DN ? 4 : 0;
|
||||
int16_t dn_delta = up_delta;
|
||||
if (!line->x_min && (line->flags & SEGFLAG_EXACT_LEFT)) dn_delta ^= 4;
|
||||
if (line->flags & SEGFLAG_UL_DR) {
|
||||
int16_t tmp = up_delta;
|
||||
up_delta = dn_delta;
|
||||
dn_delta = tmp;
|
||||
}
|
||||
|
||||
int up = line->y_min >> 6, dn = line->y_max >> 6;
|
||||
int16_t up_pos = line->y_min & 63;
|
||||
int16_t up_delta1 = up_delta * up_pos;
|
||||
int16_t dn_pos = line->y_max & 63;
|
||||
int16_t dn_delta1 = dn_delta * dn_pos;
|
||||
delta[up + 1] -= up_delta1;
|
||||
delta[up] -= (up_delta << 6) - up_delta1;
|
||||
delta[dn + 1] += dn_delta1;
|
||||
delta[dn] += (dn_delta << 6) - dn_delta1;
|
||||
if (line->y_min == line->y_max)
|
||||
continue;
|
||||
|
||||
int16_t a = (line->a * (int64_t) line->scale + ((int64_t) 1 << 49)) >> 50;
|
||||
int16_t b = (line->b * (int64_t) line->scale + ((int64_t) 1 << 49)) >> 50;
|
||||
int16_t c = ((int32_t) (line->c >> 11) * (int64_t) line->scale + ((int64_t) 1 << 44)) >> 45;
|
||||
c -= (a >> 1) + b * up;
|
||||
|
||||
int16_t va[16];
|
||||
for (int x = 0; x < 16; x++)
|
||||
va[x] = a * x;
|
||||
int16_t abs_a = a < 0 ? -a : a;
|
||||
int16_t abs_b = b < 0 ? -b : b;
|
||||
int16_t dc = (FFMIN(abs_a, abs_b) + 2) >> 2;
|
||||
int16_t base = (1 << 9) - (b >> 1);
|
||||
int16_t dc1 = base + dc;
|
||||
int16_t dc2 = base - dc;
|
||||
|
||||
if (up_pos) {
|
||||
if (dn == up) {
|
||||
update_border_line16(res[up], abs_a, va, b, abs_b, c, up_pos, dn_pos);
|
||||
continue;
|
||||
}
|
||||
update_border_line16(res[up], abs_a, va, b, abs_b, c, up_pos, 64);
|
||||
up++;
|
||||
c -= b;
|
||||
}
|
||||
for (int y = up; y < dn; y++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
int16_t c1 = c - va[x] + dc1;
|
||||
int16_t c2 = c - va[x] + dc2;
|
||||
c1 = FFMINMAX(c1, 0, full);
|
||||
c2 = FFMINMAX(c2, 0, full);
|
||||
res[y][x] += (c1 + c2) >> 3;
|
||||
}
|
||||
c -= b;
|
||||
}
|
||||
if (dn_pos)
|
||||
update_border_line16(res[dn], abs_a, va, b, abs_b, c, 0, dn_pos);
|
||||
}
|
||||
|
||||
int16_t cur = 256 * winding;
|
||||
for (int y = 0; y < 16; y++) {
|
||||
cur += delta[y];
|
||||
for (int x = 0; x < 16; x++) {
|
||||
int16_t val = res[y][x] + cur, neg_val = -val;
|
||||
val = (val > neg_val ? val : neg_val);
|
||||
buf[x] = FFMIN(val, 255);
|
||||
}
|
||||
buf += stride;
|
||||
}
|
||||
}
|
||||
|
||||
// Render top/bottom line of the trapeziod with antialiasing
|
||||
static inline void update_border_line32(int16_t res[32],
|
||||
int16_t abs_a, const int16_t va[32],
|
||||
int16_t b, int16_t abs_b,
|
||||
int16_t c, int up, int dn)
|
||||
{
|
||||
int16_t size = dn - up;
|
||||
int16_t w = (1 << 9) + (size << 3) - abs_a;
|
||||
w = FFMIN(w, 1 << 9) << 5;
|
||||
|
||||
int16_t dc_b = abs_b * (int32_t) size >> 6;
|
||||
int16_t dc = (FFMIN(abs_a, dc_b) + 2) >> 2;
|
||||
|
||||
int16_t base = (int32_t) b * (int16_t) (up + dn) >> 7;
|
||||
int16_t offs1 = size - ((base + dc) * (int32_t) w >> 16);
|
||||
int16_t offs2 = size - ((base - dc) * (int32_t) w >> 16);
|
||||
|
||||
size <<= 1;
|
||||
for (int x = 0; x < 32; x++) {
|
||||
int16_t cw = (c - va[x]) * (int32_t) w >> 16;
|
||||
int16_t c1 = cw + offs1;
|
||||
int16_t c2 = cw + offs2;
|
||||
c1 = FFMINMAX(c1, 0, size);
|
||||
c2 = FFMINMAX(c2, 0, size);
|
||||
res[x] += c1 + c2;
|
||||
}
|
||||
}
|
||||
|
||||
void ass_fill_generic_tile32_c(uint8_t *buf, ptrdiff_t stride,
|
||||
const struct segment *line, size_t n_lines,
|
||||
int winding)
|
||||
{
|
||||
int16_t res[32][32], delta[34];
|
||||
for (int y = 0; y < 32; y++)
|
||||
for (int x = 0; x < 32; x++)
|
||||
res[y][x] = 0;
|
||||
for (int y = 0; y < 34; y++)
|
||||
delta[y] = 0;
|
||||
|
||||
static const int16_t full = 1 << 9;
|
||||
const struct segment *end = line + n_lines;
|
||||
for (; line != end; ++line) {
|
||||
assert(line->y_min >= 0 && line->y_min < 1 << 11);
|
||||
assert(line->y_max > 0 && line->y_max <= 1 << 11);
|
||||
assert(line->y_min <= line->y_max);
|
||||
|
||||
int16_t up_delta = line->flags & SEGFLAG_DN ? 4 : 0;
|
||||
int16_t dn_delta = up_delta;
|
||||
if (!line->x_min && (line->flags & SEGFLAG_EXACT_LEFT)) dn_delta ^= 4;
|
||||
if (line->flags & SEGFLAG_UL_DR) {
|
||||
int16_t tmp = up_delta;
|
||||
up_delta = dn_delta;
|
||||
dn_delta = tmp;
|
||||
}
|
||||
|
||||
int up = line->y_min >> 6, dn = line->y_max >> 6;
|
||||
int16_t up_pos = line->y_min & 63;
|
||||
int16_t up_delta1 = up_delta * up_pos;
|
||||
int16_t dn_pos = line->y_max & 63;
|
||||
int16_t dn_delta1 = dn_delta * dn_pos;
|
||||
delta[up + 1] -= up_delta1;
|
||||
delta[up] -= (up_delta << 6) - up_delta1;
|
||||
delta[dn + 1] += dn_delta1;
|
||||
delta[dn] += (dn_delta << 6) - dn_delta1;
|
||||
if (line->y_min == line->y_max)
|
||||
continue;
|
||||
|
||||
int16_t a = (line->a * (int64_t) line->scale + ((int64_t) 1 << 50)) >> 51;
|
||||
int16_t b = (line->b * (int64_t) line->scale + ((int64_t) 1 << 50)) >> 51;
|
||||
int16_t c = ((int32_t) (line->c >> 12) * (int64_t) line->scale + ((int64_t) 1 << 44)) >> 45;
|
||||
c -= (a >> 1) + b * up;
|
||||
|
||||
int16_t va[32];
|
||||
for (int x = 0; x < 32; x++)
|
||||
va[x] = a * x;
|
||||
int16_t abs_a = a < 0 ? -a : a;
|
||||
int16_t abs_b = b < 0 ? -b : b;
|
||||
int16_t dc = (FFMIN(abs_a, abs_b) + 2) >> 2;
|
||||
int16_t base = (1 << 8) - (b >> 1);
|
||||
int16_t dc1 = base + dc;
|
||||
int16_t dc2 = base - dc;
|
||||
|
||||
if (up_pos) {
|
||||
if (dn == up) {
|
||||
update_border_line32(res[up], abs_a, va, b, abs_b, c, up_pos, dn_pos);
|
||||
continue;
|
||||
}
|
||||
update_border_line32(res[up], abs_a, va, b, abs_b, c, up_pos, 64);
|
||||
up++;
|
||||
c -= b;
|
||||
}
|
||||
for (int y = up; y < dn; y++) {
|
||||
for (int x = 0; x < 32; x++) {
|
||||
int16_t c1 = c - va[x] + dc1;
|
||||
int16_t c2 = c - va[x] + dc2;
|
||||
c1 = FFMINMAX(c1, 0, full);
|
||||
c2 = FFMINMAX(c2, 0, full);
|
||||
res[y][x] += (c1 + c2) >> 2;
|
||||
}
|
||||
c -= b;
|
||||
}
|
||||
if (dn_pos)
|
||||
update_border_line32(res[dn], abs_a, va, b, abs_b, c, 0, dn_pos);
|
||||
}
|
||||
|
||||
int16_t cur = 256 * winding;
|
||||
for (int y = 0; y < 32; y++) {
|
||||
cur += delta[y];
|
||||
for (int x = 0; x < 32; x++) {
|
||||
int16_t val = res[y][x] + cur, neg_val = -val;
|
||||
val = (val > neg_val ? val : neg_val);
|
||||
buf[x] = FFMIN(val, 255);
|
||||
}
|
||||
buf += stride;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,339 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
||||
* Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBASS_RENDER_H
|
||||
#define LIBASS_RENDER_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_GLYPH_H
|
||||
#include FT_SYNTHESIS_H
|
||||
#ifdef CONFIG_HARFBUZZ
|
||||
#include <hb.h>
|
||||
#endif
|
||||
|
||||
#include "ass.h"
|
||||
#include "ass_font.h"
|
||||
#include "ass_bitmap.h"
|
||||
#include "ass_cache.h"
|
||||
#include "ass_utils.h"
|
||||
#include "ass_fontselect.h"
|
||||
#include "ass_library.h"
|
||||
#include "ass_drawing.h"
|
||||
#include "ass_bitmap.h"
|
||||
#include "ass_rasterizer.h"
|
||||
|
||||
#define GLYPH_CACHE_MAX 10000
|
||||
#define MEGABYTE (1024 * 1024)
|
||||
#define BITMAP_CACHE_MAX_SIZE (128 * MEGABYTE)
|
||||
#define COMPOSITE_CACHE_RATIO 2
|
||||
#define COMPOSITE_CACHE_MAX_SIZE (BITMAP_CACHE_MAX_SIZE / COMPOSITE_CACHE_RATIO)
|
||||
|
||||
#define PARSED_FADE (1<<0)
|
||||
#define PARSED_A (1<<1)
|
||||
|
||||
typedef struct {
|
||||
ASS_Image result;
|
||||
CompositeHashValue *source;
|
||||
size_t ref_count;
|
||||
} ASS_ImagePriv;
|
||||
|
||||
typedef struct {
|
||||
int frame_width;
|
||||
int frame_height;
|
||||
int storage_width; // video width before any rescaling
|
||||
int storage_height; // video height before any rescaling
|
||||
double font_size_coeff; // font size multiplier
|
||||
double line_spacing; // additional line spacing (in frame pixels)
|
||||
double line_position; // vertical position for subtitles, 0-100 (0 = no change)
|
||||
int top_margin; // height of top margin. Everything except toptitles is shifted down by top_margin.
|
||||
int bottom_margin; // height of bottom margin. (frame_height - top_margin - bottom_margin) is original video height.
|
||||
int left_margin;
|
||||
int right_margin;
|
||||
int use_margins; // 0 - place all subtitles inside original frame
|
||||
// 1 - use margins for placing toptitles and subtitles
|
||||
double par; // user defined pixel aspect ratio (0 = unset)
|
||||
ASS_Hinting hinting;
|
||||
ASS_ShapingLevel shaper;
|
||||
int selective_style_overrides; // ASS_OVERRIDE_* flags
|
||||
|
||||
char *default_font;
|
||||
char *default_family;
|
||||
} ASS_Settings;
|
||||
|
||||
// a rendered event
|
||||
typedef struct {
|
||||
ASS_Image *imgs;
|
||||
int top, height, left, width;
|
||||
int detect_collisions;
|
||||
int shift_direction;
|
||||
ASS_Event *event;
|
||||
} EventImages;
|
||||
|
||||
typedef enum {
|
||||
EF_NONE = 0,
|
||||
EF_KARAOKE,
|
||||
EF_KARAOKE_KF,
|
||||
EF_KARAOKE_KO
|
||||
} Effect;
|
||||
|
||||
// describes a combined bitmap
|
||||
typedef struct {
|
||||
FilterDesc filter;
|
||||
uint32_t c[4]; // colors
|
||||
Effect effect_type;
|
||||
int effect_timing; // time duration of current karaoke word
|
||||
// after process_karaoke_effects: distance in pixels from the glyph origin.
|
||||
// part of the glyph to the left of it is displayed in a different color.
|
||||
|
||||
int first_pos_x;
|
||||
|
||||
size_t bitmap_count, max_bitmap_count;
|
||||
BitmapRef *bitmaps;
|
||||
|
||||
int x, y;
|
||||
ASS_Rect rect, rect_o;
|
||||
size_t n_bm, n_bm_o;
|
||||
|
||||
Bitmap *bm, *bm_o, *bm_s; // glyphs, outline, shadow bitmaps
|
||||
CompositeHashValue *image;
|
||||
} CombinedBitmapInfo;
|
||||
|
||||
// describes a glyph
|
||||
// GlyphInfo and TextInfo are used for text centering and word-wrapping operations
|
||||
typedef struct glyph_info {
|
||||
unsigned symbol;
|
||||
unsigned skip; // skip glyph when layouting text
|
||||
ASS_Font *font;
|
||||
int face_index;
|
||||
int glyph_index;
|
||||
#ifdef CONFIG_HARFBUZZ
|
||||
hb_script_t script;
|
||||
#else
|
||||
int script;
|
||||
#endif
|
||||
double font_size;
|
||||
ASS_Drawing *drawing;
|
||||
ASS_Outline *outline;
|
||||
ASS_Outline *border[2];
|
||||
ASS_Rect bbox;
|
||||
ASS_Vector pos;
|
||||
ASS_Vector offset;
|
||||
char linebreak; // the first (leading) glyph of some line ?
|
||||
uint32_t c[4]; // colors
|
||||
ASS_Vector advance; // 26.6
|
||||
ASS_Vector cluster_advance;
|
||||
char effect; // the first (leading) glyph of some effect ?
|
||||
Effect effect_type;
|
||||
int effect_timing; // time duration of current karaoke word
|
||||
// after process_karaoke_effects: distance in pixels from the glyph origin.
|
||||
// part of the glyph to the left of it is displayed in a different color.
|
||||
int effect_skip_timing; // delay after the end of last karaoke word
|
||||
int asc, desc; // font max ascender and descender
|
||||
int be; // blur edges
|
||||
double blur; // gaussian blur
|
||||
double shadow_x;
|
||||
double shadow_y;
|
||||
double frx, fry, frz; // rotation
|
||||
double fax, fay; // text shearing
|
||||
double scale_x, scale_y;
|
||||
double orig_scale_x, orig_scale_y; // scale_x,y before fix_glyph_scaling
|
||||
int border_style;
|
||||
double border_x, border_y;
|
||||
double hspacing;
|
||||
unsigned italic;
|
||||
unsigned bold;
|
||||
int flags;
|
||||
|
||||
int shape_run_id;
|
||||
|
||||
BitmapHashKey hash_key;
|
||||
BitmapHashValue *image;
|
||||
|
||||
// next glyph in this cluster
|
||||
struct glyph_info *next;
|
||||
} GlyphInfo;
|
||||
|
||||
typedef struct {
|
||||
double asc, desc;
|
||||
int offset, len;
|
||||
} LineInfo;
|
||||
|
||||
typedef struct {
|
||||
GlyphInfo *glyphs;
|
||||
int length;
|
||||
LineInfo *lines;
|
||||
int n_lines;
|
||||
CombinedBitmapInfo *combined_bitmaps;
|
||||
unsigned n_bitmaps;
|
||||
double height;
|
||||
int max_glyphs;
|
||||
int max_lines;
|
||||
unsigned max_bitmaps;
|
||||
} TextInfo;
|
||||
|
||||
// Renderer state.
|
||||
// Values like current font face, color, screen position, clipping and so on are stored here.
|
||||
typedef struct {
|
||||
ASS_Event *event;
|
||||
ASS_Style *style;
|
||||
int parsed_tags;
|
||||
|
||||
ASS_Font *font;
|
||||
double font_size;
|
||||
int flags; // decoration flags (underline/strike-through)
|
||||
|
||||
int alignment; // alignment overrides go here; if zero, style value will be used
|
||||
int justify; // justify instructions
|
||||
double frx, fry, frz;
|
||||
double fax, fay; // text shearing
|
||||
enum {
|
||||
EVENT_NORMAL, // "normal" top-, sub- or mid- title
|
||||
EVENT_POSITIONED, // happens after pos(,), margins are ignored
|
||||
EVENT_HSCROLL, // "Banner" transition effect, text_width is unlimited
|
||||
EVENT_VSCROLL // "Scroll up", "Scroll down" transition effects
|
||||
} evt_type;
|
||||
double pos_x, pos_y; // position
|
||||
double org_x, org_y; // origin
|
||||
char have_origin; // origin is explicitly defined; if 0, get_base_point() is used
|
||||
double scale_x, scale_y;
|
||||
double hspacing; // distance between letters, in pixels
|
||||
int border_style;
|
||||
double border_x; // outline width
|
||||
double border_y;
|
||||
uint32_t c[4]; // colors(Primary, Secondary, so on) in RGBA
|
||||
int clip_x0, clip_y0, clip_x1, clip_y1;
|
||||
char clip_mode; // 1 = iclip
|
||||
char detect_collisions;
|
||||
int fade; // alpha from \fad
|
||||
char be; // blur edges
|
||||
double blur; // gaussian blur
|
||||
double shadow_x;
|
||||
double shadow_y;
|
||||
int drawing_scale; // currently reading: regular text if 0, drawing otherwise
|
||||
double pbo; // drawing baseline offset
|
||||
ASS_Drawing *clip_drawing; // clip vector
|
||||
int clip_drawing_mode; // 0 = regular clip, 1 = inverse clip
|
||||
|
||||
Effect effect_type;
|
||||
int effect_timing;
|
||||
int effect_skip_timing;
|
||||
|
||||
enum {
|
||||
SCROLL_LR, // left-to-right
|
||||
SCROLL_RL,
|
||||
SCROLL_TB, // top-to-bottom
|
||||
SCROLL_BT
|
||||
} scroll_direction; // for EVENT_HSCROLL, EVENT_VSCROLL
|
||||
int scroll_shift;
|
||||
|
||||
// face properties
|
||||
char *family;
|
||||
unsigned bold;
|
||||
unsigned italic;
|
||||
int treat_family_as_pattern;
|
||||
int wrap_style;
|
||||
int font_encoding;
|
||||
|
||||
// combination of ASS_OVERRIDE_BIT_* flags that apply right now
|
||||
unsigned overrides;
|
||||
// whether to apply font_scale
|
||||
int apply_font_scale;
|
||||
// whether this is assumed to be explicitly positioned
|
||||
int explicit;
|
||||
|
||||
// used to store RenderContext.style when doing selective style overrides
|
||||
ASS_Style override_style_temp_storage;
|
||||
} RenderContext;
|
||||
|
||||
typedef struct {
|
||||
Cache *font_cache;
|
||||
Cache *outline_cache;
|
||||
Cache *bitmap_cache;
|
||||
Cache *composite_cache;
|
||||
size_t glyph_max;
|
||||
size_t bitmap_max_size;
|
||||
size_t composite_max_size;
|
||||
} CacheStore;
|
||||
|
||||
#include "ass_shaper.h"
|
||||
|
||||
struct ass_renderer {
|
||||
ASS_Library *library;
|
||||
FT_Library ftlibrary;
|
||||
ASS_FontSelector *fontselect;
|
||||
ASS_Settings settings;
|
||||
int render_id;
|
||||
ASS_Shaper *shaper;
|
||||
|
||||
ASS_Image *images_root; // rendering result is stored here
|
||||
ASS_Image *prev_images_root;
|
||||
|
||||
EventImages *eimg; // temporary buffer for sorting rendered events
|
||||
int eimg_size; // allocated buffer size
|
||||
|
||||
// frame-global data
|
||||
int width, height; // screen dimensions
|
||||
int orig_height; // frame height ( = screen height - margins )
|
||||
int orig_width; // frame width ( = screen width - margins )
|
||||
int orig_height_nocrop; // frame height ( = screen height - margins + cropheight)
|
||||
int orig_width_nocrop; // frame width ( = screen width - margins + cropwidth)
|
||||
ASS_Track *track;
|
||||
long long time; // frame's timestamp, ms
|
||||
double font_scale;
|
||||
double font_scale_x; // x scale applied to all glyphs to preserve text aspect ratio
|
||||
double border_scale;
|
||||
double blur_scale;
|
||||
|
||||
RenderContext state;
|
||||
TextInfo text_info;
|
||||
CacheStore cache;
|
||||
|
||||
const BitmapEngine *engine;
|
||||
RasterizerData rasterizer;
|
||||
|
||||
ASS_Style user_override_style;
|
||||
};
|
||||
|
||||
typedef struct render_priv {
|
||||
int top, height, left, width;
|
||||
int render_id;
|
||||
} RenderPriv;
|
||||
|
||||
typedef struct {
|
||||
int x0;
|
||||
int y0;
|
||||
int x1;
|
||||
int y1;
|
||||
} Rect;
|
||||
|
||||
typedef struct {
|
||||
int a, b; // top and height
|
||||
int ha, hb; // left and width
|
||||
} Segment;
|
||||
|
||||
void reset_render_context(ASS_Renderer *render_priv, ASS_Style *style);
|
||||
void ass_frame_ref(ASS_Image *img);
|
||||
void ass_frame_unref(ASS_Image *img);
|
||||
|
||||
// XXX: this is actually in ass.c, includes should be fixed later on
|
||||
void ass_lazy_track_init(ASS_Library *lib, ASS_Track *track);
|
||||
|
||||
#endif /* LIBASS_RENDER_H */
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
||||
* Copyright (C) 2010 Grigori Goronzy <greg@geekmind.org>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ass_compat.h"
|
||||
|
||||
#include "ass_render.h"
|
||||
|
||||
static void ass_reconfigure(ASS_Renderer *priv)
|
||||
{
|
||||
ASS_Settings *settings = &priv->settings;
|
||||
|
||||
priv->render_id++;
|
||||
ass_cache_empty(priv->cache.composite_cache);
|
||||
ass_cache_empty(priv->cache.bitmap_cache);
|
||||
ass_cache_empty(priv->cache.outline_cache);
|
||||
|
||||
priv->width = settings->frame_width;
|
||||
priv->height = settings->frame_height;
|
||||
priv->orig_width = settings->frame_width - settings->left_margin -
|
||||
settings->right_margin;
|
||||
priv->orig_height = settings->frame_height - settings->top_margin -
|
||||
settings->bottom_margin;
|
||||
priv->orig_width_nocrop =
|
||||
settings->frame_width - FFMAX(settings->left_margin, 0) -
|
||||
FFMAX(settings->right_margin, 0);
|
||||
priv->orig_height_nocrop =
|
||||
settings->frame_height - FFMAX(settings->top_margin, 0) -
|
||||
FFMAX(settings->bottom_margin, 0);
|
||||
}
|
||||
|
||||
void ass_set_frame_size(ASS_Renderer *priv, int w, int h)
|
||||
{
|
||||
if (priv->settings.frame_width != w || priv->settings.frame_height != h) {
|
||||
priv->settings.frame_width = w;
|
||||
priv->settings.frame_height = h;
|
||||
ass_reconfigure(priv);
|
||||
}
|
||||
}
|
||||
|
||||
void ass_set_storage_size(ASS_Renderer *priv, int w, int h)
|
||||
{
|
||||
if (priv->settings.storage_width != w ||
|
||||
priv->settings.storage_height != h) {
|
||||
priv->settings.storage_width = w;
|
||||
priv->settings.storage_height = h;
|
||||
ass_reconfigure(priv);
|
||||
}
|
||||
}
|
||||
|
||||
void ass_set_shaper(ASS_Renderer *priv, ASS_ShapingLevel level)
|
||||
{
|
||||
#ifdef CONFIG_HARFBUZZ
|
||||
// select the complex shaper for illegal values
|
||||
if (level == ASS_SHAPING_SIMPLE || level == ASS_SHAPING_COMPLEX)
|
||||
priv->settings.shaper = level;
|
||||
else
|
||||
priv->settings.shaper = ASS_SHAPING_COMPLEX;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ass_set_margins(ASS_Renderer *priv, int t, int b, int l, int r)
|
||||
{
|
||||
if (priv->settings.left_margin != l || priv->settings.right_margin != r ||
|
||||
priv->settings.top_margin != t || priv->settings.bottom_margin != b) {
|
||||
priv->settings.left_margin = l;
|
||||
priv->settings.right_margin = r;
|
||||
priv->settings.top_margin = t;
|
||||
priv->settings.bottom_margin = b;
|
||||
ass_reconfigure(priv);
|
||||
}
|
||||
}
|
||||
|
||||
void ass_set_use_margins(ASS_Renderer *priv, int use)
|
||||
{
|
||||
priv->settings.use_margins = use;
|
||||
}
|
||||
|
||||
void ass_set_aspect_ratio(ASS_Renderer *priv, double dar, double sar)
|
||||
{
|
||||
ass_set_pixel_aspect(priv, dar / sar);
|
||||
}
|
||||
|
||||
void ass_set_pixel_aspect(ASS_Renderer *priv, double par)
|
||||
{
|
||||
if (priv->settings.par != par) {
|
||||
priv->settings.par = par;
|
||||
ass_reconfigure(priv);
|
||||
}
|
||||
}
|
||||
|
||||
void ass_set_font_scale(ASS_Renderer *priv, double font_scale)
|
||||
{
|
||||
if (priv->settings.font_size_coeff != font_scale) {
|
||||
priv->settings.font_size_coeff = font_scale;
|
||||
ass_reconfigure(priv);
|
||||
}
|
||||
}
|
||||
|
||||
void ass_set_hinting(ASS_Renderer *priv, ASS_Hinting ht)
|
||||
{
|
||||
if (priv->settings.hinting != ht) {
|
||||
priv->settings.hinting = ht;
|
||||
ass_reconfigure(priv);
|
||||
}
|
||||
}
|
||||
|
||||
void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing)
|
||||
{
|
||||
priv->settings.line_spacing = line_spacing;
|
||||
}
|
||||
|
||||
void ass_set_line_position(ASS_Renderer *priv, double line_position)
|
||||
{
|
||||
if (priv->settings.line_position != line_position) {
|
||||
priv->settings.line_position = line_position;
|
||||
ass_reconfigure(priv);
|
||||
}
|
||||
}
|
||||
|
||||
void ass_set_fonts(ASS_Renderer *priv, const char *default_font,
|
||||
const char *default_family, int dfp,
|
||||
const char *config, int update)
|
||||
{
|
||||
free(priv->settings.default_font);
|
||||
free(priv->settings.default_family);
|
||||
priv->settings.default_font = default_font ? strdup(default_font) : 0;
|
||||
priv->settings.default_family =
|
||||
default_family ? strdup(default_family) : 0;
|
||||
|
||||
ass_reconfigure(priv);
|
||||
|
||||
ass_cache_empty(priv->cache.font_cache);
|
||||
if (priv->shaper)
|
||||
ass_shaper_empty_cache(priv->shaper);
|
||||
|
||||
if (priv->fontselect)
|
||||
ass_fontselect_free(priv->fontselect);
|
||||
priv->fontselect = ass_fontselect_init(priv->library, priv->ftlibrary,
|
||||
default_family, default_font, config, dfp);
|
||||
}
|
||||
|
||||
void ass_set_selective_style_override_enabled(ASS_Renderer *priv, int bits)
|
||||
{
|
||||
if (priv->settings.selective_style_overrides != bits) {
|
||||
priv->settings.selective_style_overrides = bits;
|
||||
ass_reconfigure(priv);
|
||||
}
|
||||
}
|
||||
|
||||
void ass_set_selective_style_override(ASS_Renderer *priv, ASS_Style *style)
|
||||
{
|
||||
ASS_Style *user_style = &priv->user_override_style;
|
||||
free(user_style->FontName);
|
||||
*user_style = *style;
|
||||
user_style->FontName = strdup(user_style->FontName);
|
||||
}
|
||||
|
||||
int ass_fonts_update(ASS_Renderer *render_priv)
|
||||
{
|
||||
// This is just a stub now!
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ass_set_cache_limits(ASS_Renderer *render_priv, int glyph_max,
|
||||
int bitmap_max)
|
||||
{
|
||||
render_priv->cache.glyph_max = glyph_max ? glyph_max : GLYPH_CACHE_MAX;
|
||||
|
||||
size_t bitmap_cache, composite_cache;
|
||||
if (bitmap_max) {
|
||||
bitmap_cache = MEGABYTE * (size_t) bitmap_max;
|
||||
composite_cache = bitmap_cache / (COMPOSITE_CACHE_RATIO + 1);
|
||||
bitmap_cache -= composite_cache;
|
||||
} else {
|
||||
bitmap_cache = BITMAP_CACHE_MAX_SIZE;
|
||||
composite_cache = COMPOSITE_CACHE_MAX_SIZE;
|
||||
}
|
||||
render_priv->cache.bitmap_max_size = bitmap_cache;
|
||||
render_priv->cache.composite_max_size = composite_cache;
|
||||
}
|
||||
|
||||
ASS_FontProvider *
|
||||
ass_create_font_provider(ASS_Renderer *priv, ASS_FontProviderFuncs *funcs,
|
||||
void *data)
|
||||
{
|
||||
return ass_font_provider_new(priv->fontselect, funcs, data);
|
||||
}
|
|
@ -0,0 +1,996 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ass_compat.h"
|
||||
|
||||
#include "ass_shaper.h"
|
||||
#include "ass_render.h"
|
||||
#include "ass_font.h"
|
||||
#include "ass_parse.h"
|
||||
#include "ass_cache.h"
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef CONFIG_HARFBUZZ
|
||||
#include <hb-ft.h>
|
||||
enum {
|
||||
VERT = 0,
|
||||
VKNA,
|
||||
KERN,
|
||||
LIGA,
|
||||
CLIG
|
||||
};
|
||||
#define NUM_FEATURES 5
|
||||
#endif
|
||||
|
||||
struct ass_shaper {
|
||||
ASS_ShapingLevel shaping_level;
|
||||
|
||||
// FriBidi log2vis
|
||||
int n_glyphs;
|
||||
FriBidiChar *event_text;
|
||||
FriBidiCharType *ctypes;
|
||||
FriBidiLevel *emblevels;
|
||||
FriBidiStrIndex *cmap;
|
||||
FriBidiParType base_direction;
|
||||
|
||||
#ifdef CONFIG_HARFBUZZ
|
||||
// OpenType features
|
||||
int n_features;
|
||||
hb_feature_t *features;
|
||||
hb_language_t language;
|
||||
|
||||
// Glyph metrics cache, to speed up shaping
|
||||
Cache *metrics_cache;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_HARFBUZZ
|
||||
struct ass_shaper_metrics_data {
|
||||
Cache *metrics_cache;
|
||||
GlyphMetricsHashKey hash_key;
|
||||
int vertical;
|
||||
};
|
||||
|
||||
struct ass_shaper_font_data {
|
||||
hb_font_t *fonts[ASS_FONT_MAX_FACES];
|
||||
hb_font_funcs_t *font_funcs[ASS_FONT_MAX_FACES];
|
||||
struct ass_shaper_metrics_data *metrics_data[ASS_FONT_MAX_FACES];
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Print version information
|
||||
*/
|
||||
void ass_shaper_info(ASS_Library *lib)
|
||||
{
|
||||
ass_msg(lib, MSGL_INFO, "Shaper: FriBidi "
|
||||
FRIBIDI_VERSION " (SIMPLE)"
|
||||
#ifdef CONFIG_HARFBUZZ
|
||||
" HarfBuzz-ng %s (COMPLEX)", hb_version_string()
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief grow arrays, if needed
|
||||
* \param new_size requested size
|
||||
*/
|
||||
static bool check_allocations(ASS_Shaper *shaper, size_t new_size)
|
||||
{
|
||||
if (new_size > shaper->n_glyphs) {
|
||||
if (!ASS_REALLOC_ARRAY(shaper->event_text, new_size) ||
|
||||
!ASS_REALLOC_ARRAY(shaper->ctypes, new_size) ||
|
||||
!ASS_REALLOC_ARRAY(shaper->emblevels, new_size) ||
|
||||
!ASS_REALLOC_ARRAY(shaper->cmap, new_size))
|
||||
return false;
|
||||
shaper->n_glyphs = new_size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Free shaper and related data
|
||||
*/
|
||||
void ass_shaper_free(ASS_Shaper *shaper)
|
||||
{
|
||||
#ifdef CONFIG_HARFBUZZ
|
||||
ass_cache_done(shaper->metrics_cache);
|
||||
free(shaper->features);
|
||||
#endif
|
||||
free(shaper->event_text);
|
||||
free(shaper->ctypes);
|
||||
free(shaper->emblevels);
|
||||
free(shaper->cmap);
|
||||
free(shaper);
|
||||
}
|
||||
|
||||
void ass_shaper_empty_cache(ASS_Shaper *shaper)
|
||||
{
|
||||
#ifdef CONFIG_HARFBUZZ
|
||||
ass_cache_empty(shaper->metrics_cache);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ass_shaper_font_data_free(ASS_ShaperFontData *priv)
|
||||
{
|
||||
#ifdef CONFIG_HARFBUZZ
|
||||
int i;
|
||||
for (i = 0; i < ASS_FONT_MAX_FACES; i++)
|
||||
if (priv->fonts[i]) {
|
||||
free(priv->metrics_data[i]);
|
||||
hb_font_destroy(priv->fonts[i]);
|
||||
hb_font_funcs_destroy(priv->font_funcs[i]);
|
||||
}
|
||||
free(priv);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HARFBUZZ
|
||||
/**
|
||||
* \brief set up the HarfBuzz OpenType feature list with some
|
||||
* standard features.
|
||||
*/
|
||||
static bool init_features(ASS_Shaper *shaper)
|
||||
{
|
||||
shaper->features = calloc(sizeof(hb_feature_t), NUM_FEATURES);
|
||||
if (!shaper->features)
|
||||
return false;
|
||||
|
||||
shaper->n_features = NUM_FEATURES;
|
||||
shaper->features[VERT].tag = HB_TAG('v', 'e', 'r', 't');
|
||||
shaper->features[VERT].end = UINT_MAX;
|
||||
shaper->features[VKNA].tag = HB_TAG('v', 'k', 'n', 'a');
|
||||
shaper->features[VKNA].end = UINT_MAX;
|
||||
shaper->features[KERN].tag = HB_TAG('k', 'e', 'r', 'n');
|
||||
shaper->features[KERN].end = UINT_MAX;
|
||||
shaper->features[LIGA].tag = HB_TAG('l', 'i', 'g', 'a');
|
||||
shaper->features[LIGA].end = UINT_MAX;
|
||||
shaper->features[CLIG].tag = HB_TAG('c', 'l', 'i', 'g');
|
||||
shaper->features[CLIG].end = UINT_MAX;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set features depending on properties of the run
|
||||
*/
|
||||
static void set_run_features(ASS_Shaper *shaper, GlyphInfo *info)
|
||||
{
|
||||
// enable vertical substitutions for @font runs
|
||||
if (info->font->desc.vertical)
|
||||
shaper->features[VERT].value = shaper->features[VKNA].value = 1;
|
||||
else
|
||||
shaper->features[VERT].value = shaper->features[VKNA].value = 0;
|
||||
|
||||
// disable ligatures if horizontal spacing is non-standard
|
||||
if (info->hspacing)
|
||||
shaper->features[LIGA].value = shaper->features[CLIG].value = 0;
|
||||
else
|
||||
shaper->features[LIGA].value = shaper->features[CLIG].value = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Update HarfBuzz's idea of font metrics
|
||||
* \param hb_font HarfBuzz font
|
||||
* \param face associated FreeType font face
|
||||
*/
|
||||
static void update_hb_size(hb_font_t *hb_font, FT_Face face)
|
||||
{
|
||||
hb_font_set_scale (hb_font,
|
||||
((uint64_t) face->size->metrics.x_scale * (uint64_t) face->units_per_EM) >> 16,
|
||||
((uint64_t) face->size->metrics.y_scale * (uint64_t) face->units_per_EM) >> 16);
|
||||
hb_font_set_ppem (hb_font, face->size->metrics.x_ppem,
|
||||
face->size->metrics.y_ppem);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Cached glyph metrics getters follow
|
||||
*
|
||||
* These functions replace HarfBuzz' standard FreeType font functions
|
||||
* and provide cached access to essential glyph metrics. This usually
|
||||
* speeds up shaping a lot. It also allows us to use custom load flags.
|
||||
*
|
||||
*/
|
||||
|
||||
GlyphMetricsHashValue *
|
||||
get_cached_metrics(struct ass_shaper_metrics_data *metrics, FT_Face face,
|
||||
hb_codepoint_t unicode, hb_codepoint_t glyph)
|
||||
{
|
||||
GlyphMetricsHashValue *val;
|
||||
metrics->hash_key.glyph_index = glyph;
|
||||
if (ass_cache_get(metrics->metrics_cache, &metrics->hash_key, &val)) {
|
||||
if (val->metrics.width >= 0)
|
||||
return val;
|
||||
ass_cache_dec_ref(val);
|
||||
return NULL;
|
||||
}
|
||||
if (!val)
|
||||
return NULL;
|
||||
|
||||
int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
|
||||
| FT_LOAD_IGNORE_TRANSFORM;
|
||||
|
||||
if (FT_Load_Glyph(face, glyph, load_flags)) {
|
||||
val->metrics.width = -1;
|
||||
ass_cache_commit(val, 1);
|
||||
ass_cache_dec_ref(val);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(&val->metrics, &face->glyph->metrics, sizeof(FT_Glyph_Metrics));
|
||||
|
||||
// if @font rendering is enabled and the glyph should be rotated,
|
||||
// make cached_h_advance pick up the right advance later
|
||||
if (metrics->vertical && unicode >= VERTICAL_LOWER_BOUND)
|
||||
val->metrics.horiAdvance = val->metrics.vertAdvance;
|
||||
|
||||
ass_cache_commit(val, 1);
|
||||
return val;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
get_glyph(hb_font_t *font, void *font_data, hb_codepoint_t unicode,
|
||||
hb_codepoint_t variation, hb_codepoint_t *glyph, void *user_data)
|
||||
{
|
||||
FT_Face face = font_data;
|
||||
struct ass_shaper_metrics_data *metrics_priv = user_data;
|
||||
|
||||
if (variation)
|
||||
*glyph = FT_Face_GetCharVariantIndex(face, ass_font_index_magic(face, unicode), variation);
|
||||
else
|
||||
*glyph = FT_Get_Char_Index(face, ass_font_index_magic(face, unicode));
|
||||
if (!*glyph)
|
||||
return false;
|
||||
|
||||
// rotate glyph advances for @fonts while we still know the Unicode codepoints
|
||||
GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, unicode, *glyph);
|
||||
ass_cache_dec_ref(metrics);
|
||||
return true;
|
||||
}
|
||||
|
||||
static hb_position_t
|
||||
cached_h_advance(hb_font_t *font, void *font_data, hb_codepoint_t glyph,
|
||||
void *user_data)
|
||||
{
|
||||
FT_Face face = font_data;
|
||||
struct ass_shaper_metrics_data *metrics_priv = user_data;
|
||||
GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, 0, glyph);
|
||||
if (!metrics)
|
||||
return 0;
|
||||
|
||||
hb_position_t advance = metrics->metrics.horiAdvance;
|
||||
ass_cache_dec_ref(metrics);
|
||||
return advance;
|
||||
}
|
||||
|
||||
static hb_position_t
|
||||
cached_v_advance(hb_font_t *font, void *font_data, hb_codepoint_t glyph,
|
||||
void *user_data)
|
||||
{
|
||||
FT_Face face = font_data;
|
||||
struct ass_shaper_metrics_data *metrics_priv = user_data;
|
||||
GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, 0, glyph);
|
||||
if (!metrics)
|
||||
return 0;
|
||||
|
||||
hb_position_t advance = metrics->metrics.vertAdvance;
|
||||
ass_cache_dec_ref(metrics);
|
||||
return advance;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
cached_h_origin(hb_font_t *font, void *font_data, hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y, void *user_data)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
cached_v_origin(hb_font_t *font, void *font_data, hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y, void *user_data)
|
||||
{
|
||||
FT_Face face = font_data;
|
||||
struct ass_shaper_metrics_data *metrics_priv = user_data;
|
||||
GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, 0, glyph);
|
||||
if (!metrics)
|
||||
return false;
|
||||
|
||||
*x = metrics->metrics.horiBearingX - metrics->metrics.vertBearingX;
|
||||
*y = metrics->metrics.horiBearingY - (-metrics->metrics.vertBearingY);
|
||||
ass_cache_dec_ref(metrics);
|
||||
return true;
|
||||
}
|
||||
|
||||
static hb_position_t
|
||||
get_h_kerning(hb_font_t *font, void *font_data, hb_codepoint_t first,
|
||||
hb_codepoint_t second, void *user_data)
|
||||
{
|
||||
FT_Face face = font_data;
|
||||
FT_Vector kern;
|
||||
|
||||
if (FT_Get_Kerning(face, first, second, FT_KERNING_DEFAULT, &kern))
|
||||
return 0;
|
||||
|
||||
return kern.x;
|
||||
}
|
||||
|
||||
static hb_position_t
|
||||
get_v_kerning(hb_font_t *font, void *font_data, hb_codepoint_t first,
|
||||
hb_codepoint_t second, void *user_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
cached_extents(hb_font_t *font, void *font_data, hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents, void *user_data)
|
||||
{
|
||||
FT_Face face = font_data;
|
||||
struct ass_shaper_metrics_data *metrics_priv = user_data;
|
||||
GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, 0, glyph);
|
||||
if (!metrics)
|
||||
return false;
|
||||
|
||||
extents->x_bearing = metrics->metrics.horiBearingX;
|
||||
extents->y_bearing = metrics->metrics.horiBearingY;
|
||||
extents->width = metrics->metrics.width;
|
||||
extents->height = -metrics->metrics.height;
|
||||
ass_cache_dec_ref(metrics);
|
||||
return true;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
get_contour_point(hb_font_t *font, void *font_data, hb_codepoint_t glyph,
|
||||
unsigned int point_index, hb_position_t *x,
|
||||
hb_position_t *y, void *user_data)
|
||||
{
|
||||
FT_Face face = font_data;
|
||||
int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
|
||||
| FT_LOAD_IGNORE_TRANSFORM;
|
||||
|
||||
if (FT_Load_Glyph(face, glyph, load_flags))
|
||||
return false;
|
||||
|
||||
if (point_index >= (unsigned)face->glyph->outline.n_points)
|
||||
return false;
|
||||
|
||||
*x = face->glyph->outline.points[point_index].x;
|
||||
*y = face->glyph->outline.points[point_index].y;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieve HarfBuzz font from cache.
|
||||
* Create it from FreeType font, if needed.
|
||||
* \param info glyph cluster
|
||||
* \return HarfBuzz font
|
||||
*/
|
||||
static hb_font_t *get_hb_font(ASS_Shaper *shaper, GlyphInfo *info)
|
||||
{
|
||||
ASS_Font *font = info->font;
|
||||
hb_font_t **hb_fonts;
|
||||
|
||||
if (!font->shaper_priv)
|
||||
font->shaper_priv = calloc(sizeof(ASS_ShaperFontData), 1);
|
||||
|
||||
|
||||
hb_fonts = font->shaper_priv->fonts;
|
||||
if (!hb_fonts[info->face_index]) {
|
||||
hb_fonts[info->face_index] =
|
||||
hb_ft_font_create(font->faces[info->face_index], NULL);
|
||||
|
||||
// set up cached metrics access
|
||||
font->shaper_priv->metrics_data[info->face_index] =
|
||||
calloc(sizeof(struct ass_shaper_metrics_data), 1);
|
||||
struct ass_shaper_metrics_data *metrics =
|
||||
font->shaper_priv->metrics_data[info->face_index];
|
||||
metrics->metrics_cache = shaper->metrics_cache;
|
||||
metrics->vertical = info->font->desc.vertical;
|
||||
|
||||
hb_font_funcs_t *funcs = hb_font_funcs_create();
|
||||
font->shaper_priv->font_funcs[info->face_index] = funcs;
|
||||
hb_font_funcs_set_glyph_func(funcs, get_glyph,
|
||||
metrics, NULL);
|
||||
hb_font_funcs_set_glyph_h_advance_func(funcs, cached_h_advance,
|
||||
metrics, NULL);
|
||||
hb_font_funcs_set_glyph_v_advance_func(funcs, cached_v_advance,
|
||||
metrics, NULL);
|
||||
hb_font_funcs_set_glyph_h_origin_func(funcs, cached_h_origin,
|
||||
metrics, NULL);
|
||||
hb_font_funcs_set_glyph_v_origin_func(funcs, cached_v_origin,
|
||||
metrics, NULL);
|
||||
hb_font_funcs_set_glyph_h_kerning_func(funcs, get_h_kerning,
|
||||
metrics, NULL);
|
||||
hb_font_funcs_set_glyph_v_kerning_func(funcs, get_v_kerning,
|
||||
metrics, NULL);
|
||||
hb_font_funcs_set_glyph_extents_func(funcs, cached_extents,
|
||||
metrics, NULL);
|
||||
hb_font_funcs_set_glyph_contour_point_func(funcs, get_contour_point,
|
||||
metrics, NULL);
|
||||
hb_font_set_funcs(hb_fonts[info->face_index], funcs,
|
||||
font->faces[info->face_index], NULL);
|
||||
}
|
||||
|
||||
ass_face_set_size(font->faces[info->face_index], info->font_size);
|
||||
update_hb_size(hb_fonts[info->face_index], font->faces[info->face_index]);
|
||||
|
||||
// update hash key for cached metrics
|
||||
struct ass_shaper_metrics_data *metrics =
|
||||
font->shaper_priv->metrics_data[info->face_index];
|
||||
metrics->hash_key.font = info->font;
|
||||
metrics->hash_key.face_index = info->face_index;
|
||||
metrics->hash_key.size = info->font_size;
|
||||
metrics->hash_key.scale_x = double_to_d6(info->scale_x);
|
||||
metrics->hash_key.scale_y = double_to_d6(info->scale_y);
|
||||
|
||||
return hb_fonts[info->face_index];
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Map script to default language.
|
||||
*
|
||||
* This maps a script to a language, if a script has a representative
|
||||
* language it is typically used with. Otherwise, the invalid language
|
||||
* is returned.
|
||||
*
|
||||
* The mapping is similar to Pango's pango-language.c.
|
||||
*
|
||||
* \param script script tag
|
||||
* \return language tag
|
||||
*/
|
||||
static hb_language_t script_to_language(hb_script_t script)
|
||||
{
|
||||
switch (script) {
|
||||
// Unicode 1.1
|
||||
case HB_SCRIPT_ARABIC: return hb_language_from_string("ar", -1); break;
|
||||
case HB_SCRIPT_ARMENIAN: return hb_language_from_string("hy", -1); break;
|
||||
case HB_SCRIPT_BENGALI: return hb_language_from_string("bn", -1); break;
|
||||
case HB_SCRIPT_CANADIAN_ABORIGINAL: return hb_language_from_string("iu", -1); break;
|
||||
case HB_SCRIPT_CHEROKEE: return hb_language_from_string("chr", -1); break;
|
||||
case HB_SCRIPT_COPTIC: return hb_language_from_string("cop", -1); break;
|
||||
case HB_SCRIPT_CYRILLIC: return hb_language_from_string("ru", -1); break;
|
||||
case HB_SCRIPT_DEVANAGARI: return hb_language_from_string("hi", -1); break;
|
||||
case HB_SCRIPT_GEORGIAN: return hb_language_from_string("ka", -1); break;
|
||||
case HB_SCRIPT_GREEK: return hb_language_from_string("el", -1); break;
|
||||
case HB_SCRIPT_GUJARATI: return hb_language_from_string("gu", -1); break;
|
||||
case HB_SCRIPT_GURMUKHI: return hb_language_from_string("pa", -1); break;
|
||||
case HB_SCRIPT_HANGUL: return hb_language_from_string("ko", -1); break;
|
||||
case HB_SCRIPT_HEBREW: return hb_language_from_string("he", -1); break;
|
||||
case HB_SCRIPT_HIRAGANA: return hb_language_from_string("ja", -1); break;
|
||||
case HB_SCRIPT_KANNADA: return hb_language_from_string("kn", -1); break;
|
||||
case HB_SCRIPT_KATAKANA: return hb_language_from_string("ja", -1); break;
|
||||
case HB_SCRIPT_LAO: return hb_language_from_string("lo", -1); break;
|
||||
case HB_SCRIPT_LATIN: return hb_language_from_string("en", -1); break;
|
||||
case HB_SCRIPT_MALAYALAM: return hb_language_from_string("ml", -1); break;
|
||||
case HB_SCRIPT_MONGOLIAN: return hb_language_from_string("mn", -1); break;
|
||||
case HB_SCRIPT_ORIYA: return hb_language_from_string("or", -1); break;
|
||||
case HB_SCRIPT_SYRIAC: return hb_language_from_string("syr", -1); break;
|
||||
case HB_SCRIPT_TAMIL: return hb_language_from_string("ta", -1); break;
|
||||
case HB_SCRIPT_TELUGU: return hb_language_from_string("te", -1); break;
|
||||
case HB_SCRIPT_THAI: return hb_language_from_string("th", -1); break;
|
||||
|
||||
// Unicode 2.0
|
||||
case HB_SCRIPT_TIBETAN: return hb_language_from_string("bo", -1); break;
|
||||
|
||||
// Unicode 3.0
|
||||
case HB_SCRIPT_ETHIOPIC: return hb_language_from_string("am", -1); break;
|
||||
case HB_SCRIPT_KHMER: return hb_language_from_string("km", -1); break;
|
||||
case HB_SCRIPT_MYANMAR: return hb_language_from_string("my", -1); break;
|
||||
case HB_SCRIPT_SINHALA: return hb_language_from_string("si", -1); break;
|
||||
case HB_SCRIPT_THAANA: return hb_language_from_string("dv", -1); break;
|
||||
|
||||
// Unicode 3.2
|
||||
case HB_SCRIPT_BUHID: return hb_language_from_string("bku", -1); break;
|
||||
case HB_SCRIPT_HANUNOO: return hb_language_from_string("hnn", -1); break;
|
||||
case HB_SCRIPT_TAGALOG: return hb_language_from_string("tl", -1); break;
|
||||
case HB_SCRIPT_TAGBANWA: return hb_language_from_string("tbw", -1); break;
|
||||
|
||||
// Unicode 4.0
|
||||
case HB_SCRIPT_UGARITIC: return hb_language_from_string("uga", -1); break;
|
||||
|
||||
// Unicode 4.1
|
||||
case HB_SCRIPT_BUGINESE: return hb_language_from_string("bug", -1); break;
|
||||
case HB_SCRIPT_OLD_PERSIAN: return hb_language_from_string("peo", -1); break;
|
||||
case HB_SCRIPT_SYLOTI_NAGRI: return hb_language_from_string("syl", -1); break;
|
||||
|
||||
// Unicode 5.0
|
||||
case HB_SCRIPT_NKO: return hb_language_from_string("nko", -1); break;
|
||||
|
||||
// no representative language exists
|
||||
default: return HB_LANGUAGE_INVALID; break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Determine language to be used for shaping a run.
|
||||
*
|
||||
* \param shaper shaper instance
|
||||
* \param script script tag associated with run
|
||||
* \return language tag
|
||||
*/
|
||||
static hb_language_t
|
||||
hb_shaper_get_run_language(ASS_Shaper *shaper, hb_script_t script)
|
||||
{
|
||||
hb_language_t lang;
|
||||
|
||||
// override set, use it
|
||||
if (shaper->language != HB_LANGUAGE_INVALID)
|
||||
return shaper->language;
|
||||
|
||||
// get default language for given script
|
||||
lang = script_to_language(script);
|
||||
|
||||
// no dice, use system default
|
||||
if (lang == HB_LANGUAGE_INVALID)
|
||||
lang = hb_language_get_default();
|
||||
|
||||
return lang;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Feed a run of shaped characters into the GlyphInfo array.
|
||||
*
|
||||
* \param glyphs GlyphInfo array
|
||||
* \param buf buffer of shaped run
|
||||
* \param offset offset into GlyphInfo array
|
||||
*/
|
||||
static void
|
||||
shape_harfbuzz_process_run(GlyphInfo *glyphs, hb_buffer_t *buf, int offset)
|
||||
{
|
||||
int j;
|
||||
int num_glyphs = hb_buffer_get_length(buf);
|
||||
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, NULL);
|
||||
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(buf, NULL);
|
||||
|
||||
for (j = 0; j < num_glyphs; j++) {
|
||||
unsigned idx = glyph_info[j].cluster + offset;
|
||||
GlyphInfo *info = glyphs + idx;
|
||||
GlyphInfo *root = info;
|
||||
|
||||
// if we have more than one glyph per cluster, allocate a new one
|
||||
// and attach to the root glyph
|
||||
if (info->skip == 0) {
|
||||
while (info->next)
|
||||
info = info->next;
|
||||
info->next = malloc(sizeof(GlyphInfo));
|
||||
if (info->next) {
|
||||
memcpy(info->next, info, sizeof(GlyphInfo));
|
||||
ass_cache_inc_ref(info->font);
|
||||
info = info->next;
|
||||
info->next = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// set position and advance
|
||||
info->skip = 0;
|
||||
info->glyph_index = glyph_info[j].codepoint;
|
||||
info->offset.x = pos[j].x_offset * info->scale_x;
|
||||
info->offset.y = -pos[j].y_offset * info->scale_y;
|
||||
info->advance.x = pos[j].x_advance * info->scale_x;
|
||||
info->advance.y = -pos[j].y_advance * info->scale_y;
|
||||
|
||||
// accumulate advance in the root glyph
|
||||
root->cluster_advance.x += info->advance.x;
|
||||
root->cluster_advance.y += info->advance.y;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Shape event text with HarfBuzz. Full OpenType shaping.
|
||||
* \param glyphs glyph clusters
|
||||
* \param len number of clusters
|
||||
*/
|
||||
static void shape_harfbuzz(ASS_Shaper *shaper, GlyphInfo *glyphs, size_t len)
|
||||
{
|
||||
int i;
|
||||
hb_buffer_t *buf = hb_buffer_create();
|
||||
hb_segment_properties_t props = HB_SEGMENT_PROPERTIES_DEFAULT;
|
||||
|
||||
// Initialize: skip all glyphs, this is undone later as needed
|
||||
for (i = 0; i < len; i++)
|
||||
glyphs[i].skip = 1;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int offset = i;
|
||||
hb_font_t *font = get_hb_font(shaper, glyphs + offset);
|
||||
int level = glyphs[offset].shape_run_id;
|
||||
int direction = shaper->emblevels[offset] % 2;
|
||||
|
||||
// advance in text until end of run
|
||||
while (i < (len - 1) && level == glyphs[i+1].shape_run_id)
|
||||
i++;
|
||||
|
||||
hb_buffer_pre_allocate(buf, i - offset + 1);
|
||||
hb_buffer_add_utf32(buf, shaper->event_text + offset, i - offset + 1,
|
||||
0, i - offset + 1);
|
||||
|
||||
props.direction = direction ? HB_DIRECTION_RTL : HB_DIRECTION_LTR;
|
||||
props.script = glyphs[offset].script;
|
||||
props.language = hb_shaper_get_run_language(shaper, props.script);
|
||||
hb_buffer_set_segment_properties(buf, &props);
|
||||
|
||||
set_run_features(shaper, glyphs + offset);
|
||||
hb_shape(font, buf, shaper->features, shaper->n_features);
|
||||
|
||||
shape_harfbuzz_process_run(glyphs, buf, offset);
|
||||
hb_buffer_reset(buf);
|
||||
}
|
||||
|
||||
hb_buffer_destroy(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Determine script property of all characters. Characters of script
|
||||
* common and inherited get their script from their context.
|
||||
*
|
||||
*/
|
||||
void ass_shaper_determine_script(ASS_Shaper *shaper, GlyphInfo *glyphs,
|
||||
size_t len)
|
||||
{
|
||||
int i;
|
||||
int backwards_scan = 0;
|
||||
hb_unicode_funcs_t *ufuncs = hb_unicode_funcs_get_default();
|
||||
hb_script_t last_script = HB_SCRIPT_UNKNOWN;
|
||||
|
||||
// determine script (forward scan)
|
||||
for (i = 0; i < len; i++) {
|
||||
GlyphInfo *info = glyphs + i;
|
||||
info->script = hb_unicode_script(ufuncs, info->symbol);
|
||||
|
||||
// common/inherit codepoints inherit script from context
|
||||
if (info->script == HB_SCRIPT_COMMON ||
|
||||
info->script == HB_SCRIPT_INHERITED) {
|
||||
// unknown is not a valid context
|
||||
if (last_script != HB_SCRIPT_UNKNOWN)
|
||||
info->script = last_script;
|
||||
else
|
||||
// do a backwards scan to check if next codepoint
|
||||
// contains a valid script for context
|
||||
backwards_scan = 1;
|
||||
} else {
|
||||
last_script = info->script;
|
||||
}
|
||||
}
|
||||
|
||||
// determine script (backwards scan, if needed)
|
||||
last_script = HB_SCRIPT_UNKNOWN;
|
||||
for (i = len - 1; i >= 0 && backwards_scan; i--) {
|
||||
GlyphInfo *info = glyphs + i;
|
||||
|
||||
// common/inherit codepoints inherit script from context
|
||||
if (info->script == HB_SCRIPT_COMMON ||
|
||||
info->script == HB_SCRIPT_INHERITED) {
|
||||
// unknown script is not a valid context
|
||||
if (last_script != HB_SCRIPT_UNKNOWN)
|
||||
info->script = last_script;
|
||||
} else {
|
||||
last_script = info->script;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Shape event text with FriBidi. Does mirroring and simple
|
||||
* Arabic shaping.
|
||||
* \param len number of clusters
|
||||
*/
|
||||
static void shape_fribidi(ASS_Shaper *shaper, GlyphInfo *glyphs, size_t len)
|
||||
{
|
||||
int i;
|
||||
FriBidiJoiningType *joins = calloc(sizeof(*joins), len);
|
||||
|
||||
// shape on codepoint level
|
||||
fribidi_get_joining_types(shaper->event_text, len, joins);
|
||||
fribidi_join_arabic(shaper->ctypes, len, shaper->emblevels, joins);
|
||||
fribidi_shape(FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC,
|
||||
shaper->emblevels, len, joins, shaper->event_text);
|
||||
|
||||
// update indexes
|
||||
for (i = 0; i < len; i++) {
|
||||
GlyphInfo *info = glyphs + i;
|
||||
FT_Face face = info->font->faces[info->face_index];
|
||||
info->symbol = shaper->event_text[i];
|
||||
info->glyph_index = FT_Get_Char_Index(face, ass_font_index_magic(face, shaper->event_text[i]));
|
||||
}
|
||||
|
||||
free(joins);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Toggle kerning for HarfBuzz shaping.
|
||||
* \param shaper shaper instance
|
||||
* \param kern toggle kerning
|
||||
*/
|
||||
void ass_shaper_set_kerning(ASS_Shaper *shaper, int kern)
|
||||
{
|
||||
#ifdef CONFIG_HARFBUZZ
|
||||
shaper->features[KERN].value = !!kern;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Find shape runs according to the event's selected fonts
|
||||
*/
|
||||
void ass_shaper_find_runs(ASS_Shaper *shaper, ASS_Renderer *render_priv,
|
||||
GlyphInfo *glyphs, size_t len)
|
||||
{
|
||||
int i;
|
||||
int shape_run = 0;
|
||||
|
||||
#ifdef CONFIG_HARFBUZZ
|
||||
ass_shaper_determine_script(shaper, glyphs, len);
|
||||
#endif
|
||||
|
||||
// find appropriate fonts for the shape runs
|
||||
for (i = 0; i < len; i++) {
|
||||
GlyphInfo *last = glyphs + i - 1;
|
||||
GlyphInfo *info = glyphs + i;
|
||||
// skip drawings
|
||||
if (info->symbol == 0xfffc)
|
||||
continue;
|
||||
// set size and get glyph index
|
||||
ass_font_get_index(render_priv->fontselect, info->font,
|
||||
info->symbol, &info->face_index, &info->glyph_index);
|
||||
// shape runs break on: xbord, ybord, xshad, yshad,
|
||||
// all four colors, all four alphas, be, blur, fn, fs,
|
||||
// fscx, fscy, fsp, bold, italic, underline, strikeout,
|
||||
// frx, fry, frz, fax, fay, karaoke start, karaoke type,
|
||||
// and on every line break
|
||||
if (i > 0 && (last->font != info->font ||
|
||||
last->face_index != info->face_index ||
|
||||
last->script != info->script ||
|
||||
last->font_size != info->font_size ||
|
||||
last->c[0] != info->c[0] ||
|
||||
last->c[1] != info->c[1] ||
|
||||
last->c[2] != info->c[2] ||
|
||||
last->c[3] != info->c[3] ||
|
||||
last->be != info->be ||
|
||||
last->blur != info->blur ||
|
||||
last->shadow_x != info->shadow_x ||
|
||||
last->shadow_y != info->shadow_y ||
|
||||
last->frx != info->frx ||
|
||||
last->fry != info->fry ||
|
||||
last->frz != info->frz ||
|
||||
last->fax != info->fax ||
|
||||
last->fay != info->fay ||
|
||||
last->scale_x != info->scale_x ||
|
||||
last->scale_y != info->scale_y ||
|
||||
last->border_style != info->border_style ||
|
||||
last->border_x != info->border_x ||
|
||||
last->border_y != info->border_y ||
|
||||
last->hspacing != info->hspacing ||
|
||||
last->italic != info->italic ||
|
||||
last->bold != info->bold ||
|
||||
last->flags != info->flags))
|
||||
shape_run++;
|
||||
info->shape_run_id = shape_run;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set base direction (paragraph direction) of the text.
|
||||
* \param dir base direction
|
||||
*/
|
||||
void ass_shaper_set_base_direction(ASS_Shaper *shaper, FriBidiParType dir)
|
||||
{
|
||||
shaper->base_direction = dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set language hint. Some languages have specific character variants,
|
||||
* like Serbian Cyrillic.
|
||||
* \param lang ISO 639-1 two-letter language code
|
||||
*/
|
||||
void ass_shaper_set_language(ASS_Shaper *shaper, const char *code)
|
||||
{
|
||||
#ifdef CONFIG_HARFBUZZ
|
||||
hb_language_t lang;
|
||||
|
||||
if (code)
|
||||
lang = hb_language_from_string(code, -1);
|
||||
else
|
||||
lang = HB_LANGUAGE_INVALID;
|
||||
|
||||
shaper->language = lang;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Set shaping level. Essentially switches between FriBidi and HarfBuzz.
|
||||
*/
|
||||
void ass_shaper_set_level(ASS_Shaper *shaper, ASS_ShapingLevel level)
|
||||
{
|
||||
shaper->shaping_level = level;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Remove all zero-width invisible characters from the text.
|
||||
* \param text_info text
|
||||
*/
|
||||
static void ass_shaper_skip_characters(TextInfo *text_info)
|
||||
{
|
||||
int i;
|
||||
GlyphInfo *glyphs = text_info->glyphs;
|
||||
|
||||
for (i = 0; i < text_info->length; i++) {
|
||||
// Skip direction override control characters
|
||||
if ((glyphs[i].symbol <= 0x202e && glyphs[i].symbol >= 0x202a)
|
||||
|| (glyphs[i].symbol <= 0x200f && glyphs[i].symbol >= 0x200b)
|
||||
|| (glyphs[i].symbol <= 0x2063 && glyphs[i].symbol >= 0x2060)
|
||||
|| glyphs[i].symbol == 0xfeff
|
||||
|| glyphs[i].symbol == 0x00ad
|
||||
|| glyphs[i].symbol == 0x034f) {
|
||||
glyphs[i].symbol = 0;
|
||||
glyphs[i].skip++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Shape an event's text. Calculates directional runs and shapes them.
|
||||
* \param text_info event's text
|
||||
* \return success, when 0
|
||||
*/
|
||||
int ass_shaper_shape(ASS_Shaper *shaper, TextInfo *text_info)
|
||||
{
|
||||
int i, ret, last_break;
|
||||
FriBidiParType dir;
|
||||
GlyphInfo *glyphs = text_info->glyphs;
|
||||
|
||||
if (!check_allocations(shaper, text_info->length))
|
||||
return -1;
|
||||
|
||||
// Get bidi character types and embedding levels
|
||||
last_break = 0;
|
||||
for (i = 0; i < text_info->length; i++) {
|
||||
shaper->event_text[i] = glyphs[i].symbol;
|
||||
// embedding levels should be calculated paragraph by paragraph
|
||||
if (glyphs[i].symbol == '\n' || i == text_info->length - 1) {
|
||||
dir = shaper->base_direction;
|
||||
fribidi_get_bidi_types(shaper->event_text + last_break,
|
||||
i - last_break + 1, shaper->ctypes + last_break);
|
||||
ret = fribidi_get_par_embedding_levels(shaper->ctypes + last_break,
|
||||
i - last_break + 1, &dir, shaper->emblevels + last_break);
|
||||
if (ret == 0)
|
||||
return -1;
|
||||
last_break = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// add embedding levels to shape runs for final runs
|
||||
for (i = 0; i < text_info->length; i++) {
|
||||
glyphs[i].shape_run_id += shaper->emblevels[i];
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HARFBUZZ
|
||||
switch (shaper->shaping_level) {
|
||||
case ASS_SHAPING_SIMPLE:
|
||||
shape_fribidi(shaper, glyphs, text_info->length);
|
||||
ass_shaper_skip_characters(text_info);
|
||||
break;
|
||||
case ASS_SHAPING_COMPLEX:
|
||||
shape_harfbuzz(shaper, glyphs, text_info->length);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
shape_fribidi(shaper, glyphs, text_info->length);
|
||||
ass_shaper_skip_characters(text_info);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Create a new shaper instance and preallocate data structures
|
||||
* \param prealloc preallocation size
|
||||
*/
|
||||
ASS_Shaper *ass_shaper_new(size_t prealloc)
|
||||
{
|
||||
ASS_Shaper *shaper = calloc(sizeof(*shaper), 1);
|
||||
if (!shaper)
|
||||
return NULL;
|
||||
|
||||
shaper->base_direction = FRIBIDI_PAR_ON;
|
||||
if (!check_allocations(shaper, prealloc))
|
||||
goto error;
|
||||
|
||||
#ifdef CONFIG_HARFBUZZ
|
||||
if (!init_features(shaper))
|
||||
goto error;
|
||||
shaper->metrics_cache = ass_glyph_metrics_cache_create();
|
||||
if (!shaper->metrics_cache)
|
||||
goto error;
|
||||
#endif
|
||||
|
||||
return shaper;
|
||||
|
||||
error:
|
||||
ass_shaper_free(shaper);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief clean up additional data temporarily needed for shaping and
|
||||
* (e.g. additional glyphs allocated)
|
||||
*/
|
||||
void ass_shaper_cleanup(ASS_Shaper *shaper, TextInfo *text_info)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < text_info->length; i++) {
|
||||
GlyphInfo *info = text_info->glyphs + i;
|
||||
info = info->next;
|
||||
while (info) {
|
||||
GlyphInfo *next = info->next;
|
||||
free(info);
|
||||
info = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Calculate reorder map to render glyphs in visual order
|
||||
* \param shaper shaper instance
|
||||
* \param text_info text to be reordered
|
||||
* \return map of reordered characters, or NULL
|
||||
*/
|
||||
FriBidiStrIndex *ass_shaper_reorder(ASS_Shaper *shaper, TextInfo *text_info)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
// Initialize reorder map
|
||||
for (i = 0; i < text_info->length; i++)
|
||||
shaper->cmap[i] = i;
|
||||
|
||||
// Create reorder map line-by-line
|
||||
for (i = 0; i < text_info->n_lines; i++) {
|
||||
LineInfo *line = text_info->lines + i;
|
||||
FriBidiParType dir = FRIBIDI_PAR_ON;
|
||||
|
||||
ret = fribidi_reorder_line(0,
|
||||
shaper->ctypes + line->offset, line->len, 0, dir,
|
||||
shaper->emblevels + line->offset, NULL,
|
||||
shaper->cmap + line->offset);
|
||||
if (ret == 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return shaper->cmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Resolve a Windows font charset number to a suitable base
|
||||
* direction. Generally, use LTR for compatibility with VSFilter. The
|
||||
* special value -1, which is not a legal Windows font charset number,
|
||||
* can be used for autodetection.
|
||||
* \param enc Windows font encoding
|
||||
*/
|
||||
FriBidiParType resolve_base_direction(int enc)
|
||||
{
|
||||
switch (enc) {
|
||||
case -1:
|
||||
return FRIBIDI_PAR_ON;
|
||||
default:
|
||||
return FRIBIDI_PAR_LTR;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBASS_SHAPER_H
|
||||
#define LIBASS_SHAPER_H
|
||||
|
||||
typedef struct ass_shaper ASS_Shaper;
|
||||
|
||||
#include <fribidi.h>
|
||||
#include "ass_render.h"
|
||||
|
||||
void ass_shaper_info(ASS_Library *lib);
|
||||
ASS_Shaper *ass_shaper_new(size_t prealloc);
|
||||
void ass_shaper_free(ASS_Shaper *shaper);
|
||||
void ass_shaper_empty_cache(ASS_Shaper *shaper);
|
||||
void ass_shaper_set_kerning(ASS_Shaper *shaper, int kern);
|
||||
void ass_shaper_find_runs(ASS_Shaper *shaper, ASS_Renderer *render_priv,
|
||||
GlyphInfo *glyphs, size_t len);
|
||||
void ass_shaper_set_base_direction(ASS_Shaper *shaper, FriBidiParType dir);
|
||||
void ass_shaper_set_language(ASS_Shaper *shaper, const char *code);
|
||||
void ass_shaper_set_level(ASS_Shaper *shaper, ASS_ShapingLevel level);
|
||||
int ass_shaper_shape(ASS_Shaper *shaper, TextInfo *text_info);
|
||||
void ass_shaper_cleanup(ASS_Shaper *shaper, TextInfo *text_info);
|
||||
FriBidiStrIndex *ass_shaper_reorder(ASS_Shaper *shaper, TextInfo *text_info);
|
||||
FriBidiParType resolve_base_direction(int font_encoding);
|
||||
|
||||
void ass_shaper_font_data_free(ASS_ShaperFontData *priv);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Grigori Goronzy <greg@kinoho.net>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ass_compat.h"
|
||||
|
||||
#include "ass_string.h"
|
||||
|
||||
static const unsigned char lowertab[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
|
||||
0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
|
||||
0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
|
||||
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
|
||||
0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
|
||||
0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61,
|
||||
0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
|
||||
0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||||
0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62,
|
||||
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
|
||||
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
||||
0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
|
||||
0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
|
||||
0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
|
||||
0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
|
||||
0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
|
||||
0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
|
||||
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
|
||||
0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
|
||||
0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
|
||||
0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1,
|
||||
0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
|
||||
0xfd, 0xfe, 0xff
|
||||
};
|
||||
|
||||
int ass_strcasecmp(const char *s1, const char *s2)
|
||||
{
|
||||
unsigned char a, b;
|
||||
|
||||
do {
|
||||
a = lowertab[(unsigned char)*s1++];
|
||||
b = lowertab[(unsigned char)*s2++];
|
||||
} while (a && a == b);
|
||||
|
||||
return a - b;
|
||||
}
|
||||
|
||||
int ass_strncasecmp(const char *s1, const char *s2, size_t n)
|
||||
{
|
||||
unsigned char a, b;
|
||||
const char *last = s1 + n;
|
||||
|
||||
do {
|
||||
a = lowertab[(unsigned char)*s1++];
|
||||
b = lowertab[(unsigned char)*s2++];
|
||||
} while (s1 < last && a && a == b);
|
||||
|
||||
return a - b;
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Grigori Goronzy <greg@kinoho.net>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef ASS_STRING_H
|
||||
#define ASS_STRING_H
|
||||
|
||||
int ass_strcasecmp(const char *s1, const char *s2);
|
||||
int ass_strncasecmp(const char *s1, const char *s2, size_t n);
|
||||
|
||||
static inline int ass_isspace(int c)
|
||||
{
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\v' ||
|
||||
c == '\f' || c == '\r';
|
||||
}
|
||||
|
||||
static inline int ass_isdigit(int c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,337 @@
|
|||
/*
|
||||
* Copyright (c) 1988-1993 The Regents of the University of California.
|
||||
* Copyright (c) 1994 Sun Microsystems, Inc.
|
||||
* Copyright (c) 2016 Oleg Oshmyan <chortos@inbox.lv>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose and without
|
||||
* fee is hereby granted, provided that the above copyright
|
||||
* notice appear in all copies. The University of California
|
||||
* makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without
|
||||
* express or implied warranty.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ass_compat.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <float.h>
|
||||
#include <errno.h>
|
||||
#include "ass_string.h"
|
||||
|
||||
static
|
||||
const size_t maxExponent = 511; /* Largest possible base 10 exponent. Any
|
||||
* exponent larger than this will already
|
||||
* produce underflow or overflow, so there's
|
||||
* no need to worry about additional digits.
|
||||
*/
|
||||
|
||||
static
|
||||
const double powersOf10[] = { /* Table giving binary powers of 10. Entry */
|
||||
10., /* is 10^2^i. Used to convert decimal */
|
||||
100., /* exponents into floating-point numbers. */
|
||||
1.0e4,
|
||||
1.0e8,
|
||||
1.0e16,
|
||||
1.0e32,
|
||||
1.0e64,
|
||||
1.0e128,
|
||||
1.0e256
|
||||
};
|
||||
|
||||
static
|
||||
const double negPowOf10[] = { /* Table giving negative binary powers */
|
||||
0.1, /* of 10. Entry is 10^-2^i. */
|
||||
0.01, /* Used to convert decimal exponents */
|
||||
1.0e-4, /* into floating-point numbers. */
|
||||
1.0e-8,
|
||||
1.0e-16,
|
||||
1.0e-32,
|
||||
1.0e-64,
|
||||
1.0e-128,
|
||||
1.0e-256
|
||||
};
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* strtod --
|
||||
*
|
||||
* This procedure converts a floating-point number from an ASCII
|
||||
* decimal representation to internal double-precision format.
|
||||
*
|
||||
* Results:
|
||||
* The return value is the double-precision floating-point
|
||||
* representation of the characters in string. If endPtr isn't
|
||||
* NULL, then *endPtr is filled in with the address of the
|
||||
* next character after the last one that was part of the
|
||||
* floating-point number.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
double
|
||||
ass_strtod(
|
||||
const char *string, /* A decimal ASCII floating-point number,
|
||||
* optionally preceded by white space.
|
||||
* Must have form "-I.FE-X", where I is the
|
||||
* integer part of the mantissa, F is the
|
||||
* fractional part of the mantissa, and X
|
||||
* is the exponent. Either of the signs
|
||||
* may be "+", "-", or omitted. Either I
|
||||
* or F may be omitted, or both. The decimal
|
||||
* point isn't necessary unless F is present.
|
||||
* The "E" may actually be an "e". E and X
|
||||
* may both be omitted (but not just one).
|
||||
*/
|
||||
char **endPtr /* If non-NULL, store terminating character's
|
||||
* address here. */
|
||||
)
|
||||
{
|
||||
int sign, fracExpSign, expSign;
|
||||
double fraction, dblExp;
|
||||
const double *d;
|
||||
register const char *p;
|
||||
register int c;
|
||||
size_t exp = 0; /* Exponent read from "EX" field. */
|
||||
size_t fracExp; /* Exponent that derives from the fractional
|
||||
* part. Under normal circumstatnces, it is
|
||||
* the negative of the number of digits in F.
|
||||
* However, if I is very long, the last digits
|
||||
* of I get dropped (otherwise a long I with a
|
||||
* large negative exponent could cause an
|
||||
* unnecessary overflow on I alone). In this
|
||||
* case, fracExp is incremented one for each
|
||||
* dropped digit. */
|
||||
size_t mantSize; /* Number of digits in mantissa. */
|
||||
size_t decPt; /* Number of mantissa digits BEFORE decimal
|
||||
* point. */
|
||||
size_t leadZeros; /* Number of leading zeros in mantissa. */
|
||||
const char *pExp; /* Temporarily holds location of exponent
|
||||
* in string. */
|
||||
|
||||
/*
|
||||
* Strip off leading blanks and check for a sign.
|
||||
*/
|
||||
|
||||
p = string;
|
||||
while (ass_isspace(*p)) {
|
||||
p += 1;
|
||||
}
|
||||
if (*p == '-') {
|
||||
sign = 1;
|
||||
p += 1;
|
||||
} else {
|
||||
if (*p == '+') {
|
||||
p += 1;
|
||||
}
|
||||
sign = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count the number of digits in the mantissa (including the decimal
|
||||
* point), and also locate the decimal point.
|
||||
*/
|
||||
|
||||
decPt = -1;
|
||||
leadZeros = -1;
|
||||
for (mantSize = 0; ; mantSize += 1)
|
||||
{
|
||||
c = *p;
|
||||
if (!ass_isdigit(c)) {
|
||||
if ((c != '.') || (decPt != (size_t) -1)) {
|
||||
break;
|
||||
}
|
||||
decPt = mantSize;
|
||||
} else if ((c != '0') && (leadZeros == (size_t) -1)) {
|
||||
leadZeros = mantSize;
|
||||
}
|
||||
p += 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now suck up the digits in the mantissa. Use two integers to
|
||||
* collect 9 digits each (this is faster than using floating-point).
|
||||
* If the mantissa has more than 18 digits, ignore the extras, since
|
||||
* they can't affect the value anyway.
|
||||
*/
|
||||
|
||||
if (leadZeros == (size_t) -1) {
|
||||
leadZeros = mantSize;
|
||||
}
|
||||
pExp = p;
|
||||
p -= mantSize - leadZeros;
|
||||
if (decPt == (size_t) -1) {
|
||||
decPt = mantSize;
|
||||
} else {
|
||||
mantSize -= 1; /* One of the digits was the point. */
|
||||
if (decPt < leadZeros) {
|
||||
leadZeros -= 1;
|
||||
}
|
||||
}
|
||||
if (mantSize - leadZeros > 18) {
|
||||
mantSize = leadZeros + 18;
|
||||
}
|
||||
if (decPt < mantSize) {
|
||||
fracExpSign = 1;
|
||||
fracExp = mantSize - decPt;
|
||||
} else {
|
||||
fracExpSign = 0;
|
||||
fracExp = decPt - mantSize;
|
||||
}
|
||||
if (mantSize == 0) {
|
||||
fraction = 0.0;
|
||||
p = string;
|
||||
goto done;
|
||||
} else {
|
||||
int frac1, frac2, m;
|
||||
mantSize -= leadZeros;
|
||||
m = mantSize;
|
||||
frac1 = 0;
|
||||
for ( ; m > 9; m -= 1)
|
||||
{
|
||||
c = *p;
|
||||
p += 1;
|
||||
if (c == '.') {
|
||||
c = *p;
|
||||
p += 1;
|
||||
}
|
||||
frac1 = 10*frac1 + (c - '0');
|
||||
}
|
||||
frac2 = 0;
|
||||
for (; m > 0; m -= 1)
|
||||
{
|
||||
c = *p;
|
||||
p += 1;
|
||||
if (c == '.') {
|
||||
c = *p;
|
||||
p += 1;
|
||||
}
|
||||
frac2 = 10*frac2 + (c - '0');
|
||||
}
|
||||
fraction = (1.0e9 * frac1) + frac2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skim off the exponent.
|
||||
*/
|
||||
|
||||
p = pExp;
|
||||
if ((*p == 'E') || (*p == 'e')) {
|
||||
size_t expLimit; /* If exp > expLimit, appending another digit
|
||||
* to exp is guaranteed to make it too large.
|
||||
* If exp == expLimit, this may depend on
|
||||
* the exact digit, but in any case exp with
|
||||
* the digit appended and fracExp added will
|
||||
* still fit in size_t, even if it does
|
||||
* exceed maxExponent. */
|
||||
int expWraparound = 0;
|
||||
p += 1;
|
||||
if (*p == '-') {
|
||||
expSign = 1;
|
||||
p += 1;
|
||||
} else {
|
||||
if (*p == '+') {
|
||||
p += 1;
|
||||
}
|
||||
expSign = 0;
|
||||
}
|
||||
if (expSign == fracExpSign) {
|
||||
if (maxExponent < fracExp) {
|
||||
expLimit = 0;
|
||||
} else {
|
||||
expLimit = (maxExponent - fracExp) / 10;
|
||||
}
|
||||
} else {
|
||||
expLimit = fracExp / 10 + (fracExp % 10 + maxExponent) / 10;
|
||||
}
|
||||
while (ass_isdigit(*p)) {
|
||||
if ((exp > expLimit) || expWraparound) {
|
||||
do {
|
||||
p += 1;
|
||||
} while (ass_isdigit(*p));
|
||||
goto expOverflow;
|
||||
} else if (exp > ((size_t) -1 - (*p - '0')) / 10) {
|
||||
expWraparound = 1;
|
||||
}
|
||||
exp = exp * 10 + (*p - '0');
|
||||
p += 1;
|
||||
}
|
||||
if (expSign == fracExpSign) {
|
||||
exp = fracExp + exp;
|
||||
} else if ((fracExp <= exp) || expWraparound) {
|
||||
exp = exp - fracExp;
|
||||
} else {
|
||||
exp = fracExp - exp;
|
||||
expSign = fracExpSign;
|
||||
}
|
||||
} else {
|
||||
exp = fracExp;
|
||||
expSign = fracExpSign;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a floating-point number that represents the exponent.
|
||||
* Do this by processing the exponent one bit at a time to combine
|
||||
* many powers of 2 of 10. Then combine the exponent with the
|
||||
* fraction.
|
||||
*/
|
||||
|
||||
if (exp > maxExponent) {
|
||||
expOverflow:
|
||||
exp = maxExponent;
|
||||
if (fraction != 0.0) {
|
||||
errno = ERANGE;
|
||||
}
|
||||
}
|
||||
/* Prefer positive powers of 10 for increased precision, especially
|
||||
* for small powers that are represented exactly in floating-point. */
|
||||
if ((exp <= DBL_MAX_10_EXP) || !expSign) {
|
||||
d = powersOf10;
|
||||
} else {
|
||||
/* The floating-point format supports more negative exponents
|
||||
* than positive, or perhaps the result is a subnormal number. */
|
||||
if (exp > -DBL_MIN_10_EXP) {
|
||||
/* The result might be a valid subnormal number, but the
|
||||
* exponent underflows. Tweak fraction so that it is below
|
||||
* 1.0 first, so that if the exponent still underflows after
|
||||
* that, the result is sure to underflow as well. */
|
||||
exp -= mantSize;
|
||||
dblExp = 1.0;
|
||||
for (d = powersOf10; mantSize != 0; mantSize >>= 1, d += 1) {
|
||||
if (mantSize & 01) {
|
||||
dblExp *= *d;
|
||||
}
|
||||
}
|
||||
fraction /= dblExp;
|
||||
}
|
||||
d = negPowOf10;
|
||||
expSign = 0;
|
||||
}
|
||||
dblExp = 1.0;
|
||||
for (; exp != 0; exp >>= 1, d += 1) {
|
||||
if (exp & 01) {
|
||||
dblExp *= *d;
|
||||
}
|
||||
}
|
||||
if (expSign) {
|
||||
fraction /= dblExp;
|
||||
} else {
|
||||
fraction *= dblExp;
|
||||
}
|
||||
|
||||
done:
|
||||
if (endPtr != NULL) {
|
||||
*endPtr = (char *) p;
|
||||
}
|
||||
|
||||
if (sign) {
|
||||
return -fraction;
|
||||
}
|
||||
return fraction;
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
||||
* Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBASS_TYPES_H
|
||||
#define LIBASS_TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define VALIGN_SUB 0
|
||||
#define VALIGN_CENTER 8
|
||||
#define VALIGN_TOP 4
|
||||
#define HALIGN_LEFT 1
|
||||
#define HALIGN_CENTER 2
|
||||
#define HALIGN_RIGHT 3
|
||||
#define ASS_JUSTIFY_AUTO 0
|
||||
#define ASS_JUSTIFY_LEFT 1
|
||||
#define ASS_JUSTIFY_CENTER 2
|
||||
#define ASS_JUSTIFY_RIGHT 3
|
||||
|
||||
#define FONT_WEIGHT_LIGHT 300
|
||||
#define FONT_WEIGHT_MEDIUM 400
|
||||
#define FONT_WEIGHT_BOLD 700
|
||||
#define FONT_SLANT_NONE 0
|
||||
#define FONT_SLANT_ITALIC 100
|
||||
#define FONT_SLANT_OBLIQUE 110
|
||||
#define FONT_WIDTH_CONDENSED 75
|
||||
#define FONT_WIDTH_NORMAL 100
|
||||
#define FONT_WIDTH_EXPANDED 125
|
||||
|
||||
|
||||
/* Opaque objects internally used by libass. Contents are private. */
|
||||
typedef struct ass_renderer ASS_Renderer;
|
||||
typedef struct render_priv ASS_RenderPriv;
|
||||
typedef struct parser_priv ASS_ParserPriv;
|
||||
typedef struct ass_library ASS_Library;
|
||||
|
||||
/* ASS Style: line */
|
||||
typedef struct ass_style {
|
||||
char *Name;
|
||||
char *FontName;
|
||||
double FontSize;
|
||||
uint32_t PrimaryColour;
|
||||
uint32_t SecondaryColour;
|
||||
uint32_t OutlineColour;
|
||||
uint32_t BackColour;
|
||||
int Bold;
|
||||
int Italic;
|
||||
int Underline;
|
||||
int StrikeOut;
|
||||
double ScaleX;
|
||||
double ScaleY;
|
||||
double Spacing;
|
||||
double Angle;
|
||||
int BorderStyle;
|
||||
double Outline;
|
||||
double Shadow;
|
||||
int Alignment;
|
||||
int MarginL;
|
||||
int MarginR;
|
||||
int MarginV;
|
||||
int Encoding;
|
||||
int treat_fontname_as_pattern;
|
||||
double Blur;
|
||||
int Justify;
|
||||
} ASS_Style;
|
||||
|
||||
|
||||
/*
|
||||
* ASS_Event corresponds to a single Dialogue line;
|
||||
* text is stored as-is, style overrides will be parsed later.
|
||||
*/
|
||||
typedef struct ass_event {
|
||||
long long Start; // ms
|
||||
long long Duration; // ms
|
||||
|
||||
int ReadOrder;
|
||||
int Layer;
|
||||
int Style;
|
||||
char *Name;
|
||||
int MarginL;
|
||||
int MarginR;
|
||||
int MarginV;
|
||||
char *Effect;
|
||||
char *Text;
|
||||
|
||||
ASS_RenderPriv *render_priv;
|
||||
} ASS_Event;
|
||||
|
||||
/**
|
||||
* Support for (xy-)vsfilter mangled colors
|
||||
*
|
||||
* Generally, xy-vsfilter emulates the classic vsfilter behavior of
|
||||
* rendering directly into the (usually YCbCr) video. vsfilter is
|
||||
* hardcoded to use BT.601(TV) as target colorspace when converting
|
||||
* the subtitle RGB color to the video colorspace. This led to major
|
||||
* breakage when HDTV video was introduced: HDTV typically uses
|
||||
* BT.709(TV), but vsfilter still used BT.601(TV) for conversion.
|
||||
*
|
||||
* This means classic vsfilter will mangle colors as follows:
|
||||
*
|
||||
* screen_rgb = bt_709tv_to_rgb(rgb_to_bt601tv(ass_rgb))
|
||||
*
|
||||
* Or in general:
|
||||
*
|
||||
* screen_rgb = video_csp_to_rgb(rgb_to_bt601tv(ass_rgb))
|
||||
*
|
||||
* where video_csp is the colorspace of the video with which the
|
||||
* subtitle was muxed.
|
||||
*
|
||||
* xy-vsfilter did not fix this, but instead introduced explicit
|
||||
* rules how colors were mangled by adding a "YCbCr Matrix" header.
|
||||
* If this header specifies a real colorspace (like BT.601(TV) etc.),
|
||||
* xy-vsfilter behaves exactly like vsfilter, but using the specified
|
||||
* colorspace for conversion of ASS input RGB to screen RGB:
|
||||
*
|
||||
* screen_rgb = video_csp_to_rgb(rgb_to_ycbcr_header_csp(ass_rgb))
|
||||
*
|
||||
* Further, xy-vsfilter behaves like vsfilter with no changes if the header
|
||||
* is missing.
|
||||
*
|
||||
* The special value "None" means untouched RGB values. Keep in mind that
|
||||
* some version of xy-vsfilter are buggy and don't interpret this correctly.
|
||||
* It appears some people are advocating that this header value is
|
||||
* intended for situations where exact colors do not matter.
|
||||
*
|
||||
* Note that newer Aegisub versions (the main application to produce ASS
|
||||
* subtitle scripts) have an option that tries not to mangle the colors. It
|
||||
* is said that if the header is not set to BT.601(TV), the colors are
|
||||
* supposed not to be mangled, even if the "YCbCr Matrix" header is not
|
||||
* set to "None". In other words, the video colorspace as detected by
|
||||
* Aegisub is the same as identified in the file header.
|
||||
*
|
||||
* In general, misinterpreting this header or not using it will lead to
|
||||
* slightly different subtitle colors, which can matter if the subtitle
|
||||
* attempts to match solid colored areas in the video.
|
||||
*
|
||||
* Note that libass doesn't change colors based on this header. It
|
||||
* absolutely can't do that, because the video colorspace is required
|
||||
* in order to handle this as intended by xy-vsfilter.
|
||||
*/
|
||||
typedef enum ASS_YCbCrMatrix {
|
||||
YCBCR_DEFAULT = 0, // Header missing
|
||||
YCBCR_UNKNOWN, // Header could not be parsed correctly
|
||||
YCBCR_NONE, // "None" special value
|
||||
YCBCR_BT601_TV,
|
||||
YCBCR_BT601_PC,
|
||||
YCBCR_BT709_TV,
|
||||
YCBCR_BT709_PC,
|
||||
YCBCR_SMPTE240M_TV,
|
||||
YCBCR_SMPTE240M_PC,
|
||||
YCBCR_FCC_TV,
|
||||
YCBCR_FCC_PC
|
||||
} ASS_YCbCrMatrix;
|
||||
|
||||
/*
|
||||
* ass track represent either an external script or a matroska subtitle stream
|
||||
* (no real difference between them); it can be used in rendering after the
|
||||
* headers are parsed (i.e. events format line read).
|
||||
*/
|
||||
typedef struct ass_track {
|
||||
int n_styles; // amount used
|
||||
int max_styles; // amount allocated
|
||||
int n_events;
|
||||
int max_events;
|
||||
ASS_Style *styles; // array of styles, max_styles length, n_styles used
|
||||
ASS_Event *events; // the same as styles
|
||||
|
||||
char *style_format; // style format line (everything after "Format: ")
|
||||
char *event_format; // event format line
|
||||
|
||||
enum {
|
||||
TRACK_TYPE_UNKNOWN = 0,
|
||||
TRACK_TYPE_ASS,
|
||||
TRACK_TYPE_SSA
|
||||
} track_type;
|
||||
|
||||
// Script header fields
|
||||
int PlayResX;
|
||||
int PlayResY;
|
||||
double Timer;
|
||||
int WrapStyle;
|
||||
int ScaledBorderAndShadow;
|
||||
int Kerning;
|
||||
char *Language;
|
||||
ASS_YCbCrMatrix YCbCrMatrix;
|
||||
|
||||
int default_style; // index of default style
|
||||
char *name; // file name in case of external subs, 0 for streams
|
||||
|
||||
ASS_Library *library;
|
||||
ASS_ParserPriv *parser_priv;
|
||||
} ASS_Track;
|
||||
|
||||
#endif /* LIBASS_TYPES_H */
|
|
@ -0,0 +1,532 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ass_compat.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "ass_library.h"
|
||||
#include "ass.h"
|
||||
#include "ass_utils.h"
|
||||
#include "ass_string.h"
|
||||
|
||||
#if (defined(__i386__) || defined(__x86_64__)) && CONFIG_ASM
|
||||
|
||||
#include "x86/cpuid.h"
|
||||
|
||||
int has_sse2(void)
|
||||
{
|
||||
uint32_t eax = 1, ebx, ecx, edx;
|
||||
ass_get_cpuid(&eax, &ebx, &ecx, &edx);
|
||||
return (edx >> 26) & 0x1;
|
||||
}
|
||||
|
||||
int has_avx(void)
|
||||
{
|
||||
uint32_t eax = 1, ebx, ecx, edx;
|
||||
ass_get_cpuid(&eax, &ebx, &ecx, &edx);
|
||||
if(!(ecx & (1 << 27))) // not OSXSAVE
|
||||
return 0;
|
||||
uint32_t misc = ecx;
|
||||
ass_get_xgetbv(0, &eax, &edx);
|
||||
if((eax & 0x6) != 0x6)
|
||||
return 0;
|
||||
eax = 0;
|
||||
ass_get_cpuid(&eax, &ebx, &ecx, &edx);
|
||||
return (ecx & 0x6) == 0x6 ? (misc >> 28) & 0x1 : 0; // check high bits are relevant, then AVX support
|
||||
}
|
||||
|
||||
int has_avx2(void)
|
||||
{
|
||||
uint32_t eax = 7, ebx, ecx, edx;
|
||||
ass_get_cpuid(&eax, &ebx, &ecx, &edx);
|
||||
return (ebx >> 5) & has_avx();
|
||||
}
|
||||
|
||||
#endif // ASM
|
||||
|
||||
#ifndef HAVE_STRNDUP
|
||||
char *ass_strndup(const char *s, size_t n)
|
||||
{
|
||||
char *end = memchr(s, 0, n);
|
||||
size_t len = end ? end - s : n;
|
||||
char *new = len < SIZE_MAX ? malloc(len + 1) : NULL;
|
||||
if (new) {
|
||||
memcpy(new, s, len);
|
||||
new[len] = 0;
|
||||
}
|
||||
return new;
|
||||
}
|
||||
#endif
|
||||
|
||||
void *ass_aligned_alloc(size_t alignment, size_t size, bool zero)
|
||||
{
|
||||
assert(!(alignment & (alignment - 1))); // alignment must be power of 2
|
||||
if (size >= SIZE_MAX - alignment - sizeof(void *))
|
||||
return NULL;
|
||||
char *allocation = zero ? calloc(size + sizeof(void *) + alignment - 1, 1)
|
||||
: malloc(size + sizeof(void *) + alignment - 1);
|
||||
if (!allocation)
|
||||
return NULL;
|
||||
char *ptr = allocation + sizeof(void *);
|
||||
unsigned int misalign = (uintptr_t)ptr & (alignment - 1);
|
||||
if (misalign)
|
||||
ptr += alignment - misalign;
|
||||
*((void **)ptr - 1) = allocation;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void ass_aligned_free(void *ptr)
|
||||
{
|
||||
if (ptr)
|
||||
free(*((void **)ptr - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* This works similar to realloc(ptr, nmemb * size), but checks for overflow.
|
||||
*
|
||||
* Unlike some implementations of realloc, this never acts as a call to free().
|
||||
* If the total size is 0, it is bumped up to 1. This means a NULL return always
|
||||
* means allocation failure, and the unportable realloc(0, 0) case is avoided.
|
||||
*/
|
||||
void *ass_realloc_array(void *ptr, size_t nmemb, size_t size)
|
||||
{
|
||||
if (nmemb > (SIZE_MAX / size))
|
||||
return NULL;
|
||||
size *= nmemb;
|
||||
if (size < 1)
|
||||
size = 1;
|
||||
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like ass_realloc_array(), but:
|
||||
* 1. on failure, return the original ptr value, instead of NULL
|
||||
* 2. set errno to indicate failure (errno!=0) or success (errno==0)
|
||||
*/
|
||||
void *ass_try_realloc_array(void *ptr, size_t nmemb, size_t size)
|
||||
{
|
||||
void *new_ptr = ass_realloc_array(ptr, nmemb, size);
|
||||
if (new_ptr) {
|
||||
errno = 0;
|
||||
return new_ptr;
|
||||
} else {
|
||||
errno = ENOMEM;
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void skip_spaces(char **str)
|
||||
{
|
||||
char *p = *str;
|
||||
while ((*p == ' ') || (*p == '\t'))
|
||||
++p;
|
||||
*str = p;
|
||||
}
|
||||
|
||||
void rskip_spaces(char **str, char *limit)
|
||||
{
|
||||
char *p = *str;
|
||||
while ((p > limit) && ((p[-1] == ' ') || (p[-1] == '\t')))
|
||||
--p;
|
||||
*str = p;
|
||||
}
|
||||
|
||||
int mystrtoi(char **p, int *res)
|
||||
{
|
||||
char *start = *p;
|
||||
double temp_res = ass_strtod(*p, p);
|
||||
*res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5));
|
||||
return *p != start;
|
||||
}
|
||||
|
||||
int mystrtoll(char **p, long long *res)
|
||||
{
|
||||
char *start = *p;
|
||||
double temp_res = ass_strtod(*p, p);
|
||||
*res = (long long) (temp_res + (temp_res > 0 ? 0.5 : -0.5));
|
||||
return *p != start;
|
||||
}
|
||||
|
||||
int mystrtod(char **p, double *res)
|
||||
{
|
||||
char *start = *p;
|
||||
*res = ass_strtod(*p, p);
|
||||
return *p != start;
|
||||
}
|
||||
|
||||
int mystrtoi32(char **p, int base, int32_t *res)
|
||||
{
|
||||
char *start = *p;
|
||||
long long temp_res = strtoll(*p, p, base);
|
||||
*res = FFMINMAX(temp_res, INT32_MIN, INT32_MAX);
|
||||
return *p != start;
|
||||
}
|
||||
|
||||
static int read_digits(char **str, int base, uint32_t *res)
|
||||
{
|
||||
char *p = *str;
|
||||
char *start = p;
|
||||
uint32_t val = 0;
|
||||
|
||||
while (1) {
|
||||
int digit;
|
||||
if (*p >= '0' && *p < FFMIN(base, 10) + '0')
|
||||
digit = *p - '0';
|
||||
else if (*p >= 'a' && *p < base - 10 + 'a')
|
||||
digit = *p - 'a' + 10;
|
||||
else if (*p >= 'A' && *p < base - 10 + 'A')
|
||||
digit = *p - 'A' + 10;
|
||||
else
|
||||
break;
|
||||
val = val * base + digit;
|
||||
++p;
|
||||
}
|
||||
|
||||
*res = val;
|
||||
*str = p;
|
||||
return p != start;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Convert a string to an integer reduced modulo 2**32
|
||||
* Follows the rules for strtoul but reduces the number modulo 2**32
|
||||
* instead of saturating it to 2**32 - 1.
|
||||
*/
|
||||
static int mystrtou32_modulo(char **p, int base, uint32_t *res)
|
||||
{
|
||||
// This emulates scanf with %d or %x format as it works on
|
||||
// Windows, because that's what is used by VSFilter. In practice,
|
||||
// scanf works the same way on other platforms too, but
|
||||
// the standard leaves its behavior on overflow undefined.
|
||||
|
||||
// Unlike scanf and like strtoul, produce 0 for invalid inputs.
|
||||
|
||||
char *start = *p;
|
||||
int sign = 1;
|
||||
|
||||
skip_spaces(p);
|
||||
|
||||
if (**p == '+')
|
||||
++*p;
|
||||
else if (**p == '-')
|
||||
sign = -1, ++*p;
|
||||
|
||||
if (base == 16 && !ass_strncasecmp(*p, "0x", 2))
|
||||
*p += 2;
|
||||
|
||||
if (read_digits(p, base, res)) {
|
||||
*res *= sign;
|
||||
return 1;
|
||||
} else {
|
||||
*p = start;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t parse_alpha_tag(char *str)
|
||||
{
|
||||
int32_t alpha = 0;
|
||||
|
||||
while (*str == '&' || *str == 'H')
|
||||
++str;
|
||||
|
||||
mystrtoi32(&str, 16, &alpha);
|
||||
return alpha;
|
||||
}
|
||||
|
||||
uint32_t parse_color_tag(char *str)
|
||||
{
|
||||
int32_t color = 0;
|
||||
|
||||
while (*str == '&' || *str == 'H')
|
||||
++str;
|
||||
|
||||
mystrtoi32(&str, 16, &color);
|
||||
return ass_bswap32((uint32_t) color);
|
||||
}
|
||||
|
||||
uint32_t parse_color_header(char *str)
|
||||
{
|
||||
uint32_t color = 0;
|
||||
int base;
|
||||
|
||||
if (!ass_strncasecmp(str, "&h", 2) || !ass_strncasecmp(str, "0x", 2)) {
|
||||
str += 2;
|
||||
base = 16;
|
||||
} else
|
||||
base = 10;
|
||||
|
||||
mystrtou32_modulo(&str, base, &color);
|
||||
return ass_bswap32(color);
|
||||
}
|
||||
|
||||
// Return a boolean value for a string
|
||||
char parse_bool(char *str)
|
||||
{
|
||||
skip_spaces(&str);
|
||||
return !ass_strncasecmp(str, "yes", 3) || strtol(str, NULL, 10) > 0;
|
||||
}
|
||||
|
||||
int parse_ycbcr_matrix(char *str)
|
||||
{
|
||||
skip_spaces(&str);
|
||||
if (*str == '\0')
|
||||
return YCBCR_DEFAULT;
|
||||
|
||||
char *end = str + strlen(str);
|
||||
rskip_spaces(&end, str);
|
||||
|
||||
// Trim a local copy of the input that we know is safe to
|
||||
// modify. The buffer is larger than any valid string + NUL,
|
||||
// so we can simply chop off the rest of the input.
|
||||
char buffer[16];
|
||||
size_t n = FFMIN(end - str, sizeof buffer - 1);
|
||||
memcpy(buffer, str, n);
|
||||
buffer[n] = '\0';
|
||||
|
||||
if (!ass_strcasecmp(buffer, "none"))
|
||||
return YCBCR_NONE;
|
||||
if (!ass_strcasecmp(buffer, "tv.601"))
|
||||
return YCBCR_BT601_TV;
|
||||
if (!ass_strcasecmp(buffer, "pc.601"))
|
||||
return YCBCR_BT601_PC;
|
||||
if (!ass_strcasecmp(buffer, "tv.709"))
|
||||
return YCBCR_BT709_TV;
|
||||
if (!ass_strcasecmp(buffer, "pc.709"))
|
||||
return YCBCR_BT709_PC;
|
||||
if (!ass_strcasecmp(buffer, "tv.240m"))
|
||||
return YCBCR_SMPTE240M_TV;
|
||||
if (!ass_strcasecmp(buffer, "pc.240m"))
|
||||
return YCBCR_SMPTE240M_PC;
|
||||
if (!ass_strcasecmp(buffer, "tv.fcc"))
|
||||
return YCBCR_FCC_TV;
|
||||
if (!ass_strcasecmp(buffer, "pc.fcc"))
|
||||
return YCBCR_FCC_PC;
|
||||
return YCBCR_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief converts numpad-style align to align.
|
||||
*/
|
||||
int numpad2align(int val)
|
||||
{
|
||||
if (val < -INT_MAX)
|
||||
// Pick an alignment somewhat arbitrarily. VSFilter handles
|
||||
// INT32_MIN as a mix of 1, 2 and 3, so prefer one of those values.
|
||||
val = 2;
|
||||
else if (val < 0)
|
||||
val = -val;
|
||||
|
||||
int res = ((val - 1) % 3) + 1; // horizontal alignment
|
||||
if (val <= 3)
|
||||
res |= VALIGN_SUB;
|
||||
else if (val <= 6)
|
||||
res |= VALIGN_CENTER;
|
||||
else
|
||||
res |= VALIGN_TOP;
|
||||
return res;
|
||||
}
|
||||
|
||||
void ass_msg(ASS_Library *priv, int lvl, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
priv->msg_callback(lvl, fmt, va, priv->msg_callback_data);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
unsigned ass_utf8_get_char(char **str)
|
||||
{
|
||||
uint8_t *strp = (uint8_t *) * str;
|
||||
unsigned c = *strp++;
|
||||
unsigned mask = 0x80;
|
||||
int len = -1;
|
||||
while (c & mask) {
|
||||
mask >>= 1;
|
||||
len++;
|
||||
}
|
||||
if (len <= 0 || len > 4)
|
||||
goto no_utf8;
|
||||
c &= mask - 1;
|
||||
while ((*strp & 0xc0) == 0x80) {
|
||||
if (len-- <= 0)
|
||||
goto no_utf8;
|
||||
c = (c << 6) | (*strp++ & 0x3f);
|
||||
}
|
||||
if (len)
|
||||
goto no_utf8;
|
||||
*str = (char *) strp;
|
||||
return c;
|
||||
|
||||
no_utf8:
|
||||
strp = (uint8_t *) * str;
|
||||
c = *strp++;
|
||||
*str = (char *) strp;
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Original version from http://www.cprogramming.com/tutorial/utf8.c
|
||||
* \brief Converts a single UTF-32 code point to UTF-8
|
||||
* \param dest Buffer to write to. Writes a NULL terminator.
|
||||
* \param ch 32-bit character code to convert
|
||||
* \return number of bytes written
|
||||
* converts a single character and ASSUMES YOU HAVE ENOUGH SPACE
|
||||
*/
|
||||
unsigned ass_utf8_put_char(char *dest, uint32_t ch)
|
||||
{
|
||||
char *orig_dest = dest;
|
||||
|
||||
if (ch < 0x80) {
|
||||
*dest++ = (char)ch;
|
||||
} else if (ch < 0x800) {
|
||||
*dest++ = (ch >> 6) | 0xC0;
|
||||
*dest++ = (ch & 0x3F) | 0x80;
|
||||
} else if (ch < 0x10000) {
|
||||
*dest++ = (ch >> 12) | 0xE0;
|
||||
*dest++ = ((ch >> 6) & 0x3F) | 0x80;
|
||||
*dest++ = (ch & 0x3F) | 0x80;
|
||||
} else if (ch < 0x110000) {
|
||||
*dest++ = (ch >> 18) | 0xF0;
|
||||
*dest++ = ((ch >> 12) & 0x3F) | 0x80;
|
||||
*dest++ = ((ch >> 6) & 0x3F) | 0x80;
|
||||
*dest++ = (ch & 0x3F) | 0x80;
|
||||
}
|
||||
|
||||
*dest = '\0';
|
||||
return dest - orig_dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Parse UTF-16 and return the code point of the sequence starting at src.
|
||||
* \param src pointer to a pointer to the start of the UTF-16 data
|
||||
* (will be set to the start of the next code point)
|
||||
* \return the code point
|
||||
*/
|
||||
static uint32_t ass_read_utf16be(uint8_t **src, size_t bytes)
|
||||
{
|
||||
if (bytes < 2)
|
||||
goto too_short;
|
||||
|
||||
uint32_t cp = ((*src)[0] << 8) | (*src)[1];
|
||||
*src += 2;
|
||||
bytes -= 2;
|
||||
|
||||
if (cp >= 0xD800 && cp <= 0xDBFF) {
|
||||
if (bytes < 2)
|
||||
goto too_short;
|
||||
|
||||
uint32_t cp2 = ((*src)[0] << 8) | (*src)[1];
|
||||
|
||||
if (cp2 < 0xDC00 || cp2 > 0xDFFF)
|
||||
return 0xFFFD;
|
||||
|
||||
*src += 2;
|
||||
|
||||
cp = 0x10000 + ((cp - 0xD800) << 10) + (cp2 - 0xDC00);
|
||||
}
|
||||
|
||||
if (cp >= 0xDC00 && cp <= 0xDFFF)
|
||||
return 0xFFFD;
|
||||
|
||||
return cp;
|
||||
|
||||
too_short:
|
||||
*src += bytes;
|
||||
return 0xFFFD;
|
||||
}
|
||||
|
||||
void ass_utf16be_to_utf8(char *dst, size_t dst_size, uint8_t *src, size_t src_size)
|
||||
{
|
||||
uint8_t *end = src + src_size;
|
||||
|
||||
if (!dst_size)
|
||||
return;
|
||||
|
||||
while (src < end) {
|
||||
uint32_t cp = ass_read_utf16be(&src, end - src);
|
||||
if (dst_size < 5)
|
||||
break;
|
||||
unsigned s = ass_utf8_put_char(dst, cp);
|
||||
dst += s;
|
||||
dst_size -= s;
|
||||
}
|
||||
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief find style by name
|
||||
* \param track track
|
||||
* \param name style name
|
||||
* \return index in track->styles
|
||||
* Returns 0 if no styles found => expects at least 1 style.
|
||||
* Parsing code always adds "Default" style in the beginning.
|
||||
*/
|
||||
int lookup_style(ASS_Track *track, char *name)
|
||||
{
|
||||
int i;
|
||||
// '*' seem to mean literally nothing;
|
||||
// VSFilter removes them as soon as it can
|
||||
while (*name == '*')
|
||||
++name;
|
||||
// VSFilter then normalizes the case of "Default"
|
||||
// (only in contexts where this function is called)
|
||||
if (ass_strcasecmp(name, "Default") == 0)
|
||||
name = "Default";
|
||||
for (i = track->n_styles - 1; i >= 0; --i) {
|
||||
if (strcmp(track->styles[i].Name, name) == 0)
|
||||
return i;
|
||||
}
|
||||
i = track->default_style;
|
||||
ass_msg(track->library, MSGL_WARN,
|
||||
"[%p]: Warning: no style named '%s' found, using '%s'",
|
||||
track, name, track->styles[i].Name);
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief find style by name as in \r
|
||||
* \param track track
|
||||
* \param name style name
|
||||
* \param len style name length
|
||||
* \return style in track->styles
|
||||
* Returns NULL if no style has the given name.
|
||||
*/
|
||||
ASS_Style *lookup_style_strict(ASS_Track *track, char *name, size_t len)
|
||||
{
|
||||
int i;
|
||||
for (i = track->n_styles - 1; i >= 0; --i) {
|
||||
if (strncmp(track->styles[i].Name, name, len) == 0 &&
|
||||
track->styles[i].Name[len] == '\0')
|
||||
return track->styles + i;
|
||||
}
|
||||
ass_msg(track->library, MSGL_WARN,
|
||||
"[%p]: Warning: no style named '%.*s' found",
|
||||
track, (int) len, name);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBASS_UTILS_H
|
||||
#define LIBASS_UTILS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "ass.h"
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX ((size_t)-1)
|
||||
#endif
|
||||
|
||||
#define MSGL_FATAL 0
|
||||
#define MSGL_ERR 1
|
||||
#define MSGL_WARN 2
|
||||
#define MSGL_INFO 4
|
||||
#define MSGL_V 6
|
||||
#define MSGL_DBG2 7
|
||||
|
||||
#define FFMAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
|
||||
#define FFMINMAX(c,a,b) FFMIN(FFMAX(c, a), b)
|
||||
|
||||
#if (defined(__i386__) || defined(__x86_64__)) && CONFIG_ASM
|
||||
int has_sse2(void);
|
||||
int has_avx(void);
|
||||
int has_avx2(void);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRNDUP
|
||||
char *ass_strndup(const char *s, size_t n);
|
||||
#define strndup ass_strndup
|
||||
#endif
|
||||
|
||||
void *ass_aligned_alloc(size_t alignment, size_t size, bool zero);
|
||||
void ass_aligned_free(void *ptr);
|
||||
|
||||
void *ass_realloc_array(void *ptr, size_t nmemb, size_t size);
|
||||
void *ass_try_realloc_array(void *ptr, size_t nmemb, size_t size);
|
||||
|
||||
/**
|
||||
* Reallocate the array in ptr to at least count elements. For example, if
|
||||
* you do "int *ptr = NULL; ASS_REALLOC_ARRAY(ptr, 5)", you can access ptr[0]
|
||||
* through ptr[4] (inclusive).
|
||||
*
|
||||
* If memory allocation fails, ptr is left unchanged, and the macro returns 0:
|
||||
* "if (!ASS_REALLOC_ARRAY(ptr, 5)) goto error;"
|
||||
*
|
||||
* A count of 0 does not free the array (see ass_realloc_array for remarks).
|
||||
*/
|
||||
#define ASS_REALLOC_ARRAY(ptr, count) \
|
||||
(errno = 0, (ptr) = ass_try_realloc_array(ptr, count, sizeof(*ptr)), !errno)
|
||||
|
||||
void skip_spaces(char **str);
|
||||
void rskip_spaces(char **str, char *limit);
|
||||
int mystrtoi(char **p, int *res);
|
||||
int mystrtoll(char **p, long long *res);
|
||||
int mystrtod(char **p, double *res);
|
||||
int mystrtoi32(char **p, int base, int32_t *res);
|
||||
int32_t parse_alpha_tag(char *str);
|
||||
uint32_t parse_color_tag(char *str);
|
||||
uint32_t parse_color_header(char *str);
|
||||
char parse_bool(char *str);
|
||||
int parse_ycbcr_matrix(char *str);
|
||||
int numpad2align(int val);
|
||||
unsigned ass_utf8_get_char(char **str);
|
||||
unsigned ass_utf8_put_char(char *dest, uint32_t ch);
|
||||
void ass_utf16be_to_utf8(char *dst, size_t dst_size, uint8_t *src, size_t src_size);
|
||||
void ass_msg(ASS_Library *priv, int lvl, const char *fmt, ...);
|
||||
int lookup_style(ASS_Track *track, char *name);
|
||||
ASS_Style *lookup_style_strict(ASS_Track *track, char *name, size_t len);
|
||||
|
||||
/* defined in ass_strtod.c */
|
||||
double ass_strtod(const char *string, char **endPtr);
|
||||
|
||||
static inline size_t ass_align(size_t alignment, size_t s)
|
||||
{
|
||||
if (s > SIZE_MAX - (alignment - 1))
|
||||
return s;
|
||||
return (s + (alignment - 1)) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
static inline uint32_t ass_bswap32(uint32_t x)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _byteswap_ulong(x);
|
||||
#else
|
||||
return (x & 0x000000FF) << 24 | (x & 0x0000FF00) << 8 |
|
||||
(x & 0x00FF0000) >> 8 | (x & 0xFF000000) >> 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int d6_to_int(int x)
|
||||
{
|
||||
return (x + 32) >> 6;
|
||||
}
|
||||
static inline int d16_to_int(int x)
|
||||
{
|
||||
return (x + 32768) >> 16;
|
||||
}
|
||||
static inline int int_to_d6(int x)
|
||||
{
|
||||
return x * (1 << 6);
|
||||
}
|
||||
static inline int int_to_d16(int x)
|
||||
{
|
||||
return x * (1 << 16);
|
||||
}
|
||||
static inline int d16_to_d6(int x)
|
||||
{
|
||||
return (x + 512) >> 10;
|
||||
}
|
||||
static inline int d6_to_d16(int x)
|
||||
{
|
||||
return x * (1 << 10);
|
||||
}
|
||||
static inline double d6_to_double(int x)
|
||||
{
|
||||
return x / 64.;
|
||||
}
|
||||
static inline int double_to_d6(double x)
|
||||
{
|
||||
return (int) (x * 64);
|
||||
}
|
||||
static inline double d16_to_double(int x)
|
||||
{
|
||||
return ((double) x) / 0x10000;
|
||||
}
|
||||
static inline int double_to_d16(double x)
|
||||
{
|
||||
return (int) (x * 0x10000);
|
||||
}
|
||||
static inline double d22_to_double(int x)
|
||||
{
|
||||
return ((double) x) / 0x400000;
|
||||
}
|
||||
static inline int double_to_d22(double x)
|
||||
{
|
||||
return (int) (x * 0x400000);
|
||||
}
|
||||
|
||||
// Calculate cache key for a rotational angle in radians
|
||||
static inline int rot_key(double a)
|
||||
{
|
||||
return double_to_d22(remainder(a, 2 * M_PI));
|
||||
}
|
||||
|
||||
#define FNV1_32A_INIT 0x811c9dc5U
|
||||
#define FNV1_32A_PRIME 16777619U
|
||||
|
||||
static inline unsigned fnv_32a_buf(void *buf, size_t len, unsigned hval)
|
||||
{
|
||||
unsigned char *bp = (unsigned char*)buf;
|
||||
size_t n = (len + 3) / 4;
|
||||
|
||||
switch (len % 4) {
|
||||
case 0: do { hval ^= (unsigned) *bp++; hval *= FNV1_32A_PRIME;
|
||||
case 3: hval ^= (unsigned) *bp++; hval *= FNV1_32A_PRIME;
|
||||
case 2: hval ^= (unsigned) *bp++; hval *= FNV1_32A_PRIME;
|
||||
case 1: hval ^= (unsigned) *bp++; hval *= FNV1_32A_PRIME;
|
||||
} while (--n > 0);
|
||||
}
|
||||
|
||||
return hval;
|
||||
}
|
||||
static inline unsigned fnv_32a_str(char *str, unsigned hval)
|
||||
{
|
||||
unsigned char *s = (unsigned char *) str;
|
||||
while (*s) {
|
||||
hval ^= (unsigned) *s++;
|
||||
hval *= FNV1_32A_PRIME;
|
||||
}
|
||||
return hval;
|
||||
}
|
||||
|
||||
#endif /* LIBASS_UTILS_H */
|
|
@ -0,0 +1,687 @@
|
|||
/**
|
||||
* This file has no copyright assigned and is placed in the Public Domain.
|
||||
* This file is part of the mingw-w64 runtime package.
|
||||
* No warranty is given; refer to the file DISCLAIMER.PD within this package.
|
||||
*/
|
||||
/**
|
||||
* Stripped version. Only definitions needed by libass. Contains fixes to
|
||||
* make it compile with C. Also needed on MSVC.
|
||||
*/
|
||||
#ifndef __INC_DWRITE__
|
||||
#define __INC_DWRITE__
|
||||
|
||||
#define DWRITEAPI DECLSPEC_IMPORT
|
||||
|
||||
#include <unknwn.h>
|
||||
|
||||
typedef struct IDWriteFactory IDWriteFactory;
|
||||
typedef struct IDWriteFont IDWriteFont;
|
||||
typedef struct IDWriteFontCollection IDWriteFontCollection;
|
||||
typedef struct IDWriteFontFace IDWriteFontFace;
|
||||
typedef struct IDWriteFontFamily IDWriteFontFamily;
|
||||
typedef struct IDWriteFontList IDWriteFontList;
|
||||
typedef struct IDWriteFontFile IDWriteFontFile;
|
||||
typedef struct IDWriteFontFileLoader IDWriteFontFileLoader;
|
||||
typedef struct IDWriteFontFileStream IDWriteFontFileStream;
|
||||
typedef struct IDWriteInlineObject IDWriteInlineObject;
|
||||
typedef struct IDWriteLocalizedStrings IDWriteLocalizedStrings;
|
||||
typedef struct IDWritePixelSnapping IDWritePixelSnapping;
|
||||
typedef struct IDWriteTextFormat IDWriteTextFormat;
|
||||
typedef struct IDWriteTextLayout IDWriteTextLayout;
|
||||
typedef struct IDWriteTextRenderer IDWriteTextRenderer;
|
||||
|
||||
#include <dcommon.h>
|
||||
|
||||
typedef enum DWRITE_INFORMATIONAL_STRING_ID {
|
||||
DWRITE_INFORMATIONAL_STRING_NONE = 0,
|
||||
DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE,
|
||||
DWRITE_INFORMATIONAL_STRING_VERSION_STRINGS,
|
||||
DWRITE_INFORMATIONAL_STRING_TRADEMARK,
|
||||
DWRITE_INFORMATIONAL_STRING_MANUFACTURER,
|
||||
DWRITE_INFORMATIONAL_STRING_DESIGNER,
|
||||
DWRITE_INFORMATIONAL_STRING_DESIGNER_URL,
|
||||
DWRITE_INFORMATIONAL_STRING_DESCRIPTION,
|
||||
DWRITE_INFORMATIONAL_STRING_FONT_VENDOR_URL,
|
||||
DWRITE_INFORMATIONAL_STRING_LICENSE_DESCRIPTION,
|
||||
DWRITE_INFORMATIONAL_STRING_LICENSE_INFO_URL,
|
||||
DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES,
|
||||
DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES,
|
||||
DWRITE_INFORMATIONAL_STRING_PREFERRED_FAMILY_NAMES,
|
||||
DWRITE_INFORMATIONAL_STRING_PREFERRED_SUBFAMILY_NAMES,
|
||||
DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT,
|
||||
DWRITE_INFORMATIONAL_STRING_FULL_NAME,
|
||||
DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME,
|
||||
DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME
|
||||
} DWRITE_INFORMATIONAL_STRING_ID;
|
||||
|
||||
typedef enum DWRITE_FACTORY_TYPE {
|
||||
DWRITE_FACTORY_TYPE_SHARED = 0,
|
||||
DWRITE_FACTORY_TYPE_ISOLATED
|
||||
} DWRITE_FACTORY_TYPE;
|
||||
|
||||
typedef enum DWRITE_FONT_FACE_TYPE {
|
||||
DWRITE_FONT_FACE_TYPE_CFF = 0,
|
||||
DWRITE_FONT_FACE_TYPE_TRUETYPE,
|
||||
DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION,
|
||||
DWRITE_FONT_FACE_TYPE_TYPE1,
|
||||
DWRITE_FONT_FACE_TYPE_VECTOR,
|
||||
DWRITE_FONT_FACE_TYPE_BITMAP,
|
||||
DWRITE_FONT_FACE_TYPE_UNKNOWN,
|
||||
DWRITE_FONT_FACE_TYPE_RAW_CFF
|
||||
} DWRITE_FONT_FACE_TYPE;
|
||||
|
||||
typedef enum DWRITE_FONT_SIMULATIONS {
|
||||
DWRITE_FONT_SIMULATIONS_NONE = 0x0000,
|
||||
DWRITE_FONT_SIMULATIONS_BOLD = 0x0001,
|
||||
DWRITE_FONT_SIMULATIONS_OBLIQUE = 0x0002
|
||||
} DWRITE_FONT_SIMULATIONS;
|
||||
|
||||
typedef enum DWRITE_FONT_STRETCH {
|
||||
DWRITE_FONT_STRETCH_UNDEFINED = 0,
|
||||
DWRITE_FONT_STRETCH_ULTRA_CONDENSED = 1,
|
||||
DWRITE_FONT_STRETCH_EXTRA_CONDENSED = 2,
|
||||
DWRITE_FONT_STRETCH_CONDENSED = 3,
|
||||
DWRITE_FONT_STRETCH_SEMI_CONDENSED = 4,
|
||||
DWRITE_FONT_STRETCH_NORMAL = 5,
|
||||
DWRITE_FONT_STRETCH_MEDIUM = 5,
|
||||
DWRITE_FONT_STRETCH_SEMI_EXPANDED = 6,
|
||||
DWRITE_FONT_STRETCH_EXPANDED = 7,
|
||||
DWRITE_FONT_STRETCH_EXTRA_EXPANDED = 8,
|
||||
DWRITE_FONT_STRETCH_ULTRA_EXPANDED = 9
|
||||
} DWRITE_FONT_STRETCH;
|
||||
|
||||
typedef enum DWRITE_FONT_STYLE {
|
||||
DWRITE_FONT_STYLE_NORMAL = 0,
|
||||
DWRITE_FONT_STYLE_OBLIQUE,
|
||||
DWRITE_FONT_STYLE_ITALIC
|
||||
} DWRITE_FONT_STYLE;
|
||||
|
||||
typedef enum DWRITE_FONT_WEIGHT {
|
||||
DWRITE_FONT_WEIGHT_MEDIUM = 500,
|
||||
/* rest dropped */
|
||||
} DWRITE_FONT_WEIGHT;
|
||||
|
||||
typedef struct DWRITE_FONT_METRICS {
|
||||
UINT16 designUnitsPerEm;
|
||||
UINT16 ascent;
|
||||
UINT16 descent;
|
||||
INT16 lineGap;
|
||||
UINT16 capHeight;
|
||||
UINT16 xHeight;
|
||||
INT16 underlinePosition;
|
||||
UINT16 underlineThickness;
|
||||
INT16 strikethroughPosition;
|
||||
UINT16 strikethroughThickness;
|
||||
} DWRITE_FONT_METRICS;
|
||||
|
||||
typedef struct DWRITE_GLYPH_OFFSET DWRITE_GLYPH_OFFSET;
|
||||
|
||||
typedef struct DWRITE_GLYPH_RUN {
|
||||
IDWriteFontFace *fontFace;
|
||||
FLOAT fontEmSize;
|
||||
UINT32 glyphCount;
|
||||
const UINT16 *glyphIndices;
|
||||
const FLOAT *glyphAdvances;
|
||||
const DWRITE_GLYPH_OFFSET *glyphOffsets;
|
||||
BOOL isSideways;
|
||||
UINT32 bidiLevel;
|
||||
} DWRITE_GLYPH_RUN;
|
||||
|
||||
typedef struct DWRITE_GLYPH_RUN_DESCRIPTION DWRITE_GLYPH_RUN_DESCRIPTION;
|
||||
typedef struct DWRITE_HIT_TEST_METRICS DWRITE_HIT_TEST_METRICS;
|
||||
typedef struct DWRITE_LINE_METRICS DWRITE_LINE_METRICS;
|
||||
typedef struct DWRITE_MATRIX DWRITE_MATRIX;
|
||||
typedef struct DWRITE_STRIKETHROUGH DWRITE_STRIKETHROUGH;
|
||||
typedef struct DWRITE_TEXT_METRICS DWRITE_TEXT_METRICS;
|
||||
|
||||
typedef struct DWRITE_TEXT_RANGE {
|
||||
UINT32 startPosition;
|
||||
UINT32 length;
|
||||
} DWRITE_TEXT_RANGE;
|
||||
|
||||
typedef struct DWRITE_TRIMMING DWRITE_TRIMMING;
|
||||
typedef struct DWRITE_UNDERLINE DWRITE_UNDERLINE;
|
||||
|
||||
#ifndef __MINGW_DEF_ARG_VAL
|
||||
#ifdef __cplusplus
|
||||
#define __MINGW_DEF_ARG_VAL(x) = x
|
||||
#else
|
||||
#define __MINGW_DEF_ARG_VAL(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IDWriteFactory
|
||||
DECLARE_INTERFACE_(IDWriteFactory,IUnknown)
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* IUnknown methods */
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
|
||||
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
#endif
|
||||
|
||||
/* IDWriteFactory methods */
|
||||
STDMETHOD(GetSystemFontCollection)(THIS_
|
||||
IDWriteFontCollection **fontCollection,
|
||||
BOOL checkForUpdates __MINGW_DEF_ARG_VAL(FALSE)) PURE;
|
||||
|
||||
STDMETHOD(dummy1)(THIS);
|
||||
STDMETHOD(dummy2)(THIS);
|
||||
STDMETHOD(dummy3)(THIS);
|
||||
STDMETHOD(dummy4)(THIS);
|
||||
STDMETHOD(dummy5)(THIS);
|
||||
STDMETHOD(dummy6)(THIS);
|
||||
STDMETHOD(dummy7)(THIS);
|
||||
STDMETHOD(dummy8)(THIS);
|
||||
STDMETHOD(dummy9)(THIS);
|
||||
STDMETHOD(dummy10)(THIS);
|
||||
STDMETHOD(dummy11)(THIS);
|
||||
|
||||
STDMETHOD(CreateTextFormat)(THIS_
|
||||
WCHAR const *fontFamilyName,
|
||||
IDWriteFontCollection *fontCollection,
|
||||
DWRITE_FONT_WEIGHT fontWeight,
|
||||
DWRITE_FONT_STYLE fontStyle,
|
||||
DWRITE_FONT_STRETCH fontStretch,
|
||||
FLOAT fontSize,
|
||||
WCHAR const *localeName,
|
||||
IDWriteTextFormat **textFormat) PURE;
|
||||
|
||||
STDMETHOD(dummy12)(THIS);
|
||||
STDMETHOD(dummy13)(THIS);
|
||||
|
||||
STDMETHOD(CreateTextLayout)(THIS_
|
||||
WCHAR const *string,
|
||||
UINT32 stringLength,
|
||||
IDWriteTextFormat *textFormat,
|
||||
FLOAT maxWidth,
|
||||
FLOAT maxHeight,
|
||||
IDWriteTextLayout **textLayout) PURE;
|
||||
|
||||
/* remainder dropped */
|
||||
END_INTERFACE
|
||||
};
|
||||
#ifdef COBJMACROS
|
||||
#define IDWriteFactory_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
|
||||
#define IDWriteFactory_AddRef(This) (This)->lpVtbl->AddRef(This)
|
||||
#define IDWriteFactory_Release(This) (This)->lpVtbl->Release(This)
|
||||
#define IDWriteFactory_GetSystemFontCollection(This,fontCollection,checkForUpdates) (This)->lpVtbl->GetSystemFontCollection(This,fontCollection,checkForUpdates)
|
||||
#define IDWriteFactory_CreateTextFormat(This,fontFamilyName,fontCollection,fontWeight,fontStyle,fontStretch,fontSize,localeName,textFormat) (This)->lpVtbl->CreateTextFormat(This,fontFamilyName,fontCollection,fontWeight,fontStyle,fontStretch,fontSize,localeName,textFormat)
|
||||
#define IDWriteFactory_CreateTextLayout(This,string,stringLength,textFormat,maxWidth,maxHeight,textLayout) (This)->lpVtbl->CreateTextLayout(This,string,stringLength,textFormat,maxWidth,maxHeight,textLayout)
|
||||
#endif /*COBJMACROS*/
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IDWriteFont
|
||||
DECLARE_INTERFACE_(IDWriteFont,IUnknown)
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* IUnknown methods */
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
|
||||
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
#endif
|
||||
|
||||
/* IDWriteFont methods */
|
||||
STDMETHOD(GetFontFamily)(THIS_
|
||||
IDWriteFontFamily **fontFamily) PURE;
|
||||
|
||||
STDMETHOD_(DWRITE_FONT_WEIGHT, GetWeight)(THIS) PURE;
|
||||
STDMETHOD_(DWRITE_FONT_STRETCH, GetStretch)(THIS) PURE;
|
||||
STDMETHOD_(DWRITE_FONT_STYLE, GetStyle)(THIS) PURE;
|
||||
STDMETHOD_(BOOL, IsSymbolFont)(THIS) PURE;
|
||||
|
||||
STDMETHOD(GetFaceNames)(THIS_
|
||||
IDWriteLocalizedStrings **names) PURE;
|
||||
|
||||
STDMETHOD(GetInformationalStrings)(THIS_
|
||||
DWRITE_INFORMATIONAL_STRING_ID informationalStringID,
|
||||
IDWriteLocalizedStrings **informationalStrings,
|
||||
BOOL *exists) PURE;
|
||||
|
||||
STDMETHOD_(DWRITE_FONT_SIMULATIONS, GetSimulations)(THIS) PURE;
|
||||
|
||||
STDMETHOD_(void, GetMetrics)(THIS_
|
||||
DWRITE_FONT_METRICS *fontMetrics) PURE;
|
||||
|
||||
STDMETHOD(HasCharacter)(THIS_
|
||||
UINT32 unicodeValue,
|
||||
BOOL *exists) PURE;
|
||||
|
||||
STDMETHOD(CreateFontFace)(THIS_
|
||||
IDWriteFontFace **fontFace) PURE;
|
||||
|
||||
END_INTERFACE
|
||||
};
|
||||
#ifdef COBJMACROS
|
||||
#define IDWriteFont_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
|
||||
#define IDWriteFont_AddRef(This) (This)->lpVtbl->AddRef(This)
|
||||
#define IDWriteFont_Release(This) (This)->lpVtbl->Release(This)
|
||||
#define IDWriteFont_CreateFontFace(This,fontFace) (This)->lpVtbl->CreateFontFace(This,fontFace)
|
||||
#define IDWriteFont_GetFaceNames(This,names) (This)->lpVtbl->GetFaceNames(This,names)
|
||||
#define IDWriteFont_GetFontFamily(This,fontFamily) (This)->lpVtbl->GetFontFamily(This,fontFamily)
|
||||
#define IDWriteFont_GetInformationalStrings(This,informationalStringID,informationalStrings,exists) (This)->lpVtbl->GetInformationalStrings(This,informationalStringID,informationalStrings,exists)
|
||||
#define IDWriteFont_GetMetrics(This,fontMetrics) (This)->lpVtbl->GetMetrics(This,fontMetrics)
|
||||
#define IDWriteFont_GetSimulations(This) (This)->lpVtbl->GetSimulations(This)
|
||||
#define IDWriteFont_GetStretch(This) (This)->lpVtbl->GetStretch(This)
|
||||
#define IDWriteFont_GetStyle(This) (This)->lpVtbl->GetStyle(This)
|
||||
#define IDWriteFont_GetWeight(This) (This)->lpVtbl->GetWeight(This)
|
||||
#define IDWriteFont_HasCharacter(This,unicodeValue,exists) (This)->lpVtbl->HasCharacter(This,unicodeValue,exists)
|
||||
#define IDWriteFont_IsSymbolFont(This) (This)->lpVtbl->IsSymbolFont(This)
|
||||
#endif /*COBJMACROS*/
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IDWriteFontCollection
|
||||
DECLARE_INTERFACE_(IDWriteFontCollection,IUnknown)
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* IUnknown methods */
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
|
||||
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
#endif
|
||||
|
||||
/* IDWriteFontCollection methods */
|
||||
STDMETHOD_(UINT32, GetFontFamilyCount)(THIS) PURE;
|
||||
|
||||
STDMETHOD(GetFontFamily)(THIS_
|
||||
UINT32 index,
|
||||
IDWriteFontFamily **fontFamily) PURE;
|
||||
|
||||
STDMETHOD(FindFamilyName)(THIS_
|
||||
WCHAR const *familyName,
|
||||
UINT32 *index,
|
||||
BOOL *exists) PURE;
|
||||
|
||||
STDMETHOD(GetFontFromFontFace)(THIS_
|
||||
IDWriteFontFace* fontFace,
|
||||
IDWriteFont **font) PURE;
|
||||
|
||||
END_INTERFACE
|
||||
};
|
||||
#ifdef COBJMACROS
|
||||
#define IDWriteFontCollection_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
|
||||
#define IDWriteFontCollection_AddRef(This) (This)->lpVtbl->AddRef(This)
|
||||
#define IDWriteFontCollection_Release(This) (This)->lpVtbl->Release(This)
|
||||
#define IDWriteFontCollection_FindFamilyName(This,familyName,index,exists) (This)->lpVtbl->FindFamilyName(This,familyName,index,exists)
|
||||
#define IDWriteFontCollection_GetFontFamily(This,index,fontFamily) (This)->lpVtbl->GetFontFamily(This,index,fontFamily)
|
||||
#define IDWriteFontCollection_GetFontFamilyCount(This) (This)->lpVtbl->GetFontFamilyCount(This)
|
||||
#define IDWriteFontCollection_GetFontFromFontFace(This,fontFace,font) (This)->lpVtbl->GetFontFromFontFace(This,fontFace,font)
|
||||
#endif /*COBJMACROS*/
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IDWriteFontFace
|
||||
DECLARE_INTERFACE_(IDWriteFontFace,IUnknown)
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* IUnknown methods */
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
|
||||
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
#endif
|
||||
|
||||
/* IDWriteFontFace methods */
|
||||
STDMETHOD_(DWRITE_FONT_FACE_TYPE, GetType)(THIS) PURE;
|
||||
|
||||
STDMETHOD(GetFiles)(THIS_
|
||||
UINT32 *numberOfFiles,
|
||||
IDWriteFontFile **fontFiles) PURE;
|
||||
|
||||
STDMETHOD_(UINT32, GetIndex)(THIS) PURE;
|
||||
|
||||
/* rest dropped */
|
||||
END_INTERFACE
|
||||
};
|
||||
#ifdef COBJMACROS
|
||||
#define IDWriteFontFace_Release(This) (This)->lpVtbl->Release(This)
|
||||
#define IDWriteFontFace_GetType(This) (This)->lpVtbl->GetType(This)
|
||||
#define IDWriteFontFace_GetFiles(This,fontFiles,b) (This)->lpVtbl->GetFiles(This,fontFiles,b)
|
||||
#define IDWriteFontFace_GetIndex(This) (This)->lpVtbl->GetIndex(This)
|
||||
#endif /*COBJMACROS*/
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IDWriteFontFamily
|
||||
DECLARE_INTERFACE_(IDWriteFontFamily,IDWriteFontList)
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* IUnknown methods */
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
|
||||
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
|
||||
/* IDWriteFontList methods */
|
||||
STDMETHOD(GetFontCollection)(THIS_
|
||||
IDWriteFontCollection** fontCollection) PURE;
|
||||
|
||||
STDMETHOD_(UINT32, GetFontCount)(THIS) PURE;
|
||||
|
||||
STDMETHOD(GetFont)(THIS_
|
||||
UINT32 index,
|
||||
IDWriteFont **font) PURE;
|
||||
#endif
|
||||
|
||||
/* IDWriteFontFamily methods */
|
||||
STDMETHOD(GetFamilyNames)(THIS_
|
||||
IDWriteLocalizedStrings **names) PURE;
|
||||
|
||||
/* rest dropped */
|
||||
END_INTERFACE
|
||||
};
|
||||
#ifdef COBJMACROS
|
||||
#define IDWriteFontFamily_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
|
||||
#define IDWriteFontFamily_AddRef(This) (This)->lpVtbl->AddRef(This)
|
||||
#define IDWriteFontFamily_Release(This) (This)->lpVtbl->Release(This)
|
||||
#define IDWriteFontFamily_GetFont(This,index,font) (This)->lpVtbl->GetFont(This,index,font)
|
||||
#define IDWriteFontFamily_GetFontCount(This) (This)->lpVtbl->GetFontCount(This)
|
||||
#define IDWriteFontFamily_GetFamilyNames(This,names) (This)->lpVtbl->GetFamilyNames(This,names)
|
||||
#endif /*COBJMACROS*/
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IDWriteFontFile
|
||||
DECLARE_INTERFACE_(IDWriteFontFile,IUnknown)
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* IUnknown methods */
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
|
||||
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
#endif
|
||||
|
||||
/* IDWriteFontFile methods */
|
||||
STDMETHOD(GetReferenceKey)(THIS_
|
||||
void const **fontFileReferenceKey,
|
||||
UINT32 *fontFileReferenceKeySize) PURE;
|
||||
|
||||
STDMETHOD(GetLoader)(THIS_
|
||||
IDWriteFontFileLoader **fontFileLoader) PURE;
|
||||
|
||||
/* rest dropped */
|
||||
END_INTERFACE
|
||||
};
|
||||
#ifdef COBJMACROS
|
||||
#define IDWriteFontFile_Release(This) (This)->lpVtbl->Release(This)
|
||||
#define IDWriteFontFile_GetLoader(This,fontFileLoader) (This)->lpVtbl->GetLoader(This,fontFileLoader)
|
||||
#define IDWriteFontFile_GetReferenceKey(This,fontFileReferenceKey,fontFileReferenceKeySize) (This)->lpVtbl->GetReferenceKey(This,fontFileReferenceKey,fontFileReferenceKeySize)
|
||||
#endif /*COBJMACROS*/
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IDWriteFontFileLoader
|
||||
DECLARE_INTERFACE_(IDWriteFontFileLoader,IUnknown)
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* IUnknown methods */
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
|
||||
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
#endif
|
||||
|
||||
/* IDWriteFontFileLoader methods */
|
||||
STDMETHOD(CreateStreamFromKey)(THIS_
|
||||
void const *fontFileReferenceKey,
|
||||
UINT32 fontFileReferenceKeySize,
|
||||
IDWriteFontFileStream **fontFileStream) PURE;
|
||||
|
||||
END_INTERFACE
|
||||
};
|
||||
#ifdef COBJMACROS
|
||||
#define IDWriteFontFileLoader_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
|
||||
#define IDWriteFontFileLoader_AddRef(This) (This)->lpVtbl->AddRef(This)
|
||||
#define IDWriteFontFileLoader_Release(This) (This)->lpVtbl->Release(This)
|
||||
#define IDWriteFontFileLoader_CreateStreamFromKey(This,fontFileReferenceKey,fontFileReferenceKeySize,fontFileStream) (This)->lpVtbl->CreateStreamFromKey(This,fontFileReferenceKey,fontFileReferenceKeySize,fontFileStream)
|
||||
#endif /*COBJMACROS*/
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IDWriteFontFileStream
|
||||
DECLARE_INTERFACE_(IDWriteFontFileStream,IUnknown)
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* IUnknown methods */
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
|
||||
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
#endif
|
||||
|
||||
/* IDWriteFontFileStream methods */
|
||||
STDMETHOD(ReadFileFragment)(THIS_
|
||||
void const **fragmentStart,
|
||||
UINT64 fileOffset,
|
||||
UINT64 fragmentSize,
|
||||
void** fragmentContext) PURE;
|
||||
|
||||
STDMETHOD_(void, ReleaseFileFragment)(THIS_
|
||||
void *fragmentContext) PURE;
|
||||
|
||||
STDMETHOD(GetFileSize)(THIS_
|
||||
UINT64 *fileSize) PURE;
|
||||
|
||||
STDMETHOD(GetLastWriteTime)(THIS_
|
||||
UINT64 *lastWriteTime) PURE;
|
||||
|
||||
END_INTERFACE
|
||||
};
|
||||
#ifdef COBJMACROS
|
||||
#define IDWriteFontFileStream_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
|
||||
#define IDWriteFontFileStream_AddRef(This) (This)->lpVtbl->AddRef(This)
|
||||
#define IDWriteFontFileStream_Release(This) (This)->lpVtbl->Release(This)
|
||||
#define IDWriteFontFileStream_GetFileSize(This,fileSize) (This)->lpVtbl->GetFileSize(This,fileSize)
|
||||
#define IDWriteFontFileStream_ReadFileFragment(This,fragmentStart,fileOffset,fragmentSize,fragmentContext) (This)->lpVtbl->ReadFileFragment(This,fragmentStart,fileOffset,fragmentSize,fragmentContext)
|
||||
#define IDWriteFontFileStream_ReleaseFileFragment(This,fragmentContext) (This)->lpVtbl->ReleaseFileFragment(This,fragmentContext)
|
||||
#endif /*COBJMACROS*/
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IDWriteLocalizedStrings
|
||||
DECLARE_INTERFACE_(IDWriteLocalizedStrings,IUnknown)
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* IUnknown methods */
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
|
||||
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
#endif
|
||||
|
||||
/* IDWriteLocalizedStrings methods */
|
||||
STDMETHOD_(UINT32, GetCount)(THIS) PURE;
|
||||
|
||||
STDMETHOD(dummy1)(THIS);
|
||||
STDMETHOD(dummy2)(THIS);
|
||||
STDMETHOD(dummy3)(THIS);
|
||||
STDMETHOD(dummy4)(THIS);
|
||||
|
||||
STDMETHOD(GetString)(THIS_
|
||||
UINT32 index,
|
||||
WCHAR *stringBuffer,
|
||||
UINT32 size) PURE;
|
||||
|
||||
END_INTERFACE
|
||||
};
|
||||
#ifdef COBJMACROS
|
||||
#define IDWriteLocalizedStrings_Release(This) (This)->lpVtbl->Release(This)
|
||||
#define IDWriteLocalizedStrings_GetCount(This) (This)->lpVtbl->GetCount(This)
|
||||
#define IDWriteLocalizedStrings_GetString(This,index,stringBuffer,size) (This)->lpVtbl->GetString(This,index,stringBuffer,size)
|
||||
#endif /*COBJMACROS*/
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IDWriteTextFormat
|
||||
DECLARE_INTERFACE_(IDWriteTextFormat,IUnknown)
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* IUnknown methods */
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
|
||||
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
#endif
|
||||
|
||||
/* IDWriteTextFormat methods */
|
||||
/* rest dropped */
|
||||
END_INTERFACE
|
||||
};
|
||||
#ifdef COBJMACROS
|
||||
#define IDWriteTextFormat_Release(This) (This)->lpVtbl->Release(This)
|
||||
#endif /*COBJMACROS*/
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IDWriteTextLayout
|
||||
DECLARE_INTERFACE_(IDWriteTextLayout,IDWriteTextFormat)
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* IUnknown methods */
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
|
||||
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
|
||||
/* IDWriteTextFormat methods */
|
||||
STDMETHOD(dummy1)(THIS);
|
||||
STDMETHOD(dummy2)(THIS);
|
||||
STDMETHOD(dummy3)(THIS);
|
||||
STDMETHOD(dummy4)(THIS);
|
||||
STDMETHOD(dummy5)(THIS);
|
||||
STDMETHOD(dummy6)(THIS);
|
||||
STDMETHOD(dummy7)(THIS);
|
||||
STDMETHOD(dummy8)(THIS);
|
||||
STDMETHOD(dummy9)(THIS);
|
||||
STDMETHOD(dummy10)(THIS);
|
||||
STDMETHOD(dummy11)(THIS);
|
||||
STDMETHOD(dummy12)(THIS);
|
||||
STDMETHOD(dummy13)(THIS);
|
||||
STDMETHOD(dummy14)(THIS);
|
||||
STDMETHOD(dummy15)(THIS);
|
||||
STDMETHOD(dummy16)(THIS);
|
||||
STDMETHOD(dummy17)(THIS);
|
||||
STDMETHOD(dummy18)(THIS);
|
||||
STDMETHOD(dummy19)(THIS);
|
||||
STDMETHOD(dummy20)(THIS);
|
||||
STDMETHOD(dummy21)(THIS);
|
||||
STDMETHOD(dummy22)(THIS);
|
||||
STDMETHOD(dummy23)(THIS);
|
||||
STDMETHOD(dummy24)(THIS);
|
||||
STDMETHOD(dummy25)(THIS);
|
||||
#endif
|
||||
|
||||
/* IDWriteTextLayout methods */
|
||||
STDMETHOD(dummy26)(THIS);
|
||||
STDMETHOD(dummy27)(THIS);
|
||||
STDMETHOD(dummy28)(THIS);
|
||||
STDMETHOD(dummy29)(THIS);
|
||||
STDMETHOD(dummy30)(THIS);
|
||||
STDMETHOD(dummy31)(THIS);
|
||||
STDMETHOD(dummy32)(THIS);
|
||||
STDMETHOD(dummy33)(THIS);
|
||||
STDMETHOD(dummy34)(THIS);
|
||||
STDMETHOD(dummy35)(THIS);
|
||||
STDMETHOD(dummy36)(THIS);
|
||||
STDMETHOD(dummy37)(THIS);
|
||||
STDMETHOD(dummy38)(THIS);
|
||||
STDMETHOD(dummy39)(THIS);
|
||||
STDMETHOD(dummy40)(THIS);
|
||||
STDMETHOD(dummy41)(THIS);
|
||||
STDMETHOD(dummy42)(THIS);
|
||||
STDMETHOD(dummy43)(THIS);
|
||||
STDMETHOD(dummy44)(THIS);
|
||||
STDMETHOD(dummy45)(THIS);
|
||||
STDMETHOD(dummy46)(THIS);
|
||||
STDMETHOD(dummy47)(THIS);
|
||||
STDMETHOD(dummy48)(THIS);
|
||||
STDMETHOD(dummy49)(THIS);
|
||||
STDMETHOD(dummy50)(THIS);
|
||||
STDMETHOD(dummy51)(THIS);
|
||||
STDMETHOD(dummy52)(THIS);
|
||||
STDMETHOD(dummy53)(THIS);
|
||||
STDMETHOD(dummy54)(THIS);
|
||||
STDMETHOD(dummy55)(THIS);
|
||||
STDMETHOD(Draw)(THIS_
|
||||
void *clientDrawingContext,
|
||||
IDWriteTextRenderer *renderer,
|
||||
FLOAT originX,
|
||||
FLOAT originY) PURE;
|
||||
/* rest dropped */
|
||||
END_INTERFACE
|
||||
};
|
||||
#ifdef COBJMACROS
|
||||
#define IDWriteTextLayout_Release(This) (This)->lpVtbl->Release(This)
|
||||
#define IDWriteTextLayout_Draw(This,clientDrawingContext,renderer,originX,originY) (This)->lpVtbl->Draw(This,clientDrawingContext,renderer,originX,originY)
|
||||
#endif /*COBJMACROS*/
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IDWriteTextRenderer
|
||||
DECLARE_INTERFACE_(IDWriteTextRenderer,IDWritePixelSnapping)
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* IUnknown methods */
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
|
||||
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
|
||||
/* IDWritePixelSnapping methods */
|
||||
STDMETHOD(IsPixelSnappingDisabled)(THIS_
|
||||
void *clientDrawingContext,
|
||||
BOOL *isDisabled) PURE;
|
||||
STDMETHOD(GetCurrentTransform)(THIS_
|
||||
void *clientDrawingContext,
|
||||
DWRITE_MATRIX *transform) PURE;
|
||||
STDMETHOD(GetPixelsPerDip)(THIS_
|
||||
void *clientDrawingContext,
|
||||
FLOAT *pixelsPerDip) PURE;
|
||||
#endif
|
||||
|
||||
/* IDWriteTextRenderer methods */
|
||||
STDMETHOD(DrawGlyphRun)(THIS_
|
||||
void *clientDrawingContext,
|
||||
FLOAT baselineOriginX,
|
||||
FLOAT baselineOriginY,
|
||||
DWRITE_MEASURING_MODE measuringMode,
|
||||
DWRITE_GLYPH_RUN const *glyphRun,
|
||||
DWRITE_GLYPH_RUN_DESCRIPTION const *glyphRunDescription,
|
||||
IUnknown* clientDrawingEffect) PURE;
|
||||
STDMETHOD(DrawUnderline)(THIS_
|
||||
void *clientDrawingContext,
|
||||
FLOAT baselineOriginX,
|
||||
FLOAT baselineOriginY,
|
||||
DWRITE_UNDERLINE const *underline,
|
||||
IUnknown *clientDrawingEffect) PURE;
|
||||
STDMETHOD(DrawStrikethrough)(THIS_
|
||||
void *clientDrawingContext,
|
||||
FLOAT baselineOriginX,
|
||||
FLOAT baselineOriginY,
|
||||
DWRITE_STRIKETHROUGH const *strikethrough,
|
||||
IUnknown* clientDrawingEffect) PURE;
|
||||
STDMETHOD(DrawInlineObject)(THIS_
|
||||
void *clientDrawingContext,
|
||||
FLOAT originX,
|
||||
FLOAT originY,
|
||||
IDWriteInlineObject *inlineObject,
|
||||
BOOL isSideways,
|
||||
BOOL isRightToLeft,
|
||||
IUnknown *clientDrawingEffect) PURE;
|
||||
|
||||
END_INTERFACE
|
||||
};
|
||||
|
||||
DEFINE_GUID(IID_IDWriteFactory, 0xb859ee5a,0xd838,0x4b5b,0xa2,0xe8,0x1a,0xdc,0x7d,0x93,0xdb,0x48);
|
||||
DEFINE_GUID(IID_IDWritePixelSnapping, 0xeaf3a2da,0xecf4,0x4d24,0xb6,0x44,0xb3,0x4f,0x68,0x42,0x02,0x4b);
|
||||
DEFINE_GUID(IID_IDWriteTextRenderer, 0xef8a8135,0x5cc6,0x45fe,0x88,0x25,0xc5,0xa0,0x72,0x4e,0xb8,0x19);
|
||||
|
||||
#endif /* __INC_DWRITE__ */
|
|
@ -0,0 +1,45 @@
|
|||
ass_library_init
|
||||
ass_library_done
|
||||
ass_library_version
|
||||
ass_set_fonts_dir
|
||||
ass_set_extract_fonts
|
||||
ass_set_style_overrides
|
||||
ass_renderer_init
|
||||
ass_renderer_done
|
||||
ass_set_frame_size
|
||||
ass_set_storage_size
|
||||
ass_set_margins
|
||||
ass_set_use_margins
|
||||
ass_set_aspect_ratio
|
||||
ass_set_font_scale
|
||||
ass_set_hinting
|
||||
ass_set_line_spacing
|
||||
ass_get_available_font_providers
|
||||
ass_set_fonts
|
||||
ass_render_frame
|
||||
ass_new_track
|
||||
ass_free_track
|
||||
ass_alloc_style
|
||||
ass_alloc_event
|
||||
ass_free_style
|
||||
ass_free_event
|
||||
ass_process_data
|
||||
ass_process_codec_private
|
||||
ass_process_chunk
|
||||
ass_read_file
|
||||
ass_read_memory
|
||||
ass_read_styles
|
||||
ass_add_font
|
||||
ass_clear_fonts
|
||||
ass_step_sub
|
||||
ass_process_force_style
|
||||
ass_set_message_cb
|
||||
ass_fonts_update
|
||||
ass_set_cache_limits
|
||||
ass_flush_events
|
||||
ass_set_shaper
|
||||
ass_set_line_position
|
||||
ass_set_pixel_aspect
|
||||
ass_set_selective_style_override_enabled
|
||||
ass_set_selective_style_override
|
||||
ass_set_check_readorder
|
|
@ -0,0 +1,254 @@
|
|||
;******************************************************************************
|
||||
;* be_blur.asm: SSE2 \be blur
|
||||
;******************************************************************************
|
||||
;* Copyright (C) 2013 Rodger Combs <rcombs@rcombs.me>
|
||||
;*
|
||||
;* This file is part of libass.
|
||||
;*
|
||||
;* Permission to use, copy, modify, and distribute this software for any
|
||||
;* purpose with or without fee is hereby granted, provided that the above
|
||||
;* copyright notice and this permission notice appear in all copies.
|
||||
;*
|
||||
;* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
;* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
;* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
;* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
;* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
;* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
;* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
;******************************************************************************
|
||||
|
||||
%include "x86/x86inc.asm"
|
||||
|
||||
SECTION_RODATA 32
|
||||
low_word_zero: dd 0xFFFF0000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
|
||||
|
||||
SECTION .text
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; void be_blur_pass( uint8_t *buf, unsigned width,
|
||||
; unsigned height, unsigned stride,
|
||||
; uint16_t *tmp);
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
INIT_XMM sse2
|
||||
cglobal be_blur, 5,15,9
|
||||
.skip_prologue:
|
||||
mov r6, 2 ; int x = 2;
|
||||
pxor xmm6, xmm6 ; __m128i temp3 = 0;
|
||||
mov r7, r0 ; unsigned char *src=buf;
|
||||
movzx r8, byte [r7 + 1] ; int old_pix = src[1];
|
||||
movzx r9, byte [r7] ; int old_sum = src[0];
|
||||
add r9, r8 ; old_sum += old_pix;
|
||||
lea r12, [r4 + r3 * 2] ; unsigned char *col_sum_buf = tmp + stride * 2;
|
||||
lea r14, [r1 - 2] ; tmpreg = (w-2);
|
||||
and r14, -8 ; tmpreg &= (~7);
|
||||
.first_loop:
|
||||
movzx r10, byte [r7 + r6] ; int temp1 = src[x];
|
||||
lea r11, [r8 + r10] ; int temp2 = old_pix + temp1;
|
||||
mov r8, r10 ; old_pix = temp1;
|
||||
lea r10, [r9 + r11] ; temp1 = old_sum + temp2;
|
||||
mov r9, r11 ; old_sum = temp2;
|
||||
mov word [r4 + r6 * 2], r10w ; col_pix_buf[x] = temp1;
|
||||
inc r6 ; x++
|
||||
cmp r6, r1 ; x < w
|
||||
jl .first_loop
|
||||
mov r6, 2 ; int x = 2;
|
||||
lea r7, [r0 + r3] ; unsigned char *src=buf+stride;
|
||||
movzx r8, byte [r7 + 1] ; int old_pix = src[1];
|
||||
movzx r9, byte [r7] ; int old_sum = src[0];
|
||||
add r9, r8 ; old_sum += old_pix
|
||||
.second_loop:
|
||||
movzx r10, byte [r7 + r6] ; int temp1 = src[x];
|
||||
lea r11, [r8 + r10] ; int temp2 = old_pix + temp1;
|
||||
mov r8, r10 ; old_pix = temp1;
|
||||
lea r10, [r9 + r11] ; temp1 = old_sum + temp2;
|
||||
mov r9, r11 ; old_sum = temp2;
|
||||
movzx r11, word [r4 + r6 * 2] ; temp2 = col_pix_buf[x];
|
||||
add r11, r10 ; temp2 += temp1;
|
||||
mov word [r4 + r6 * 2], r10w ; col_pix_buf[x] = temp1;
|
||||
mov word [r12 + r6 * 2], r11w ; col_sum_buf[x] = temp2;
|
||||
inc r6 ; x++
|
||||
cmp r6, r1 ; x < w
|
||||
jl .second_loop
|
||||
mov r5, 2 ; int y = 2;
|
||||
.height_loop:
|
||||
mov r10, r5; int tmpreg = y;
|
||||
imul r10, r3; tmpreg *= stride;
|
||||
lea r7, [r0 + r10] ; unsigned char *src=buf+y*stride;
|
||||
sub r10, r3 ; tmpreg -= stride;
|
||||
lea r13, [r0 + r10]; unsigned char *dst=buf+(y-1)*stride;
|
||||
mov r6, 2 ; int x = 2;
|
||||
movzx r10, byte [r7] ; temp1 = src[0];
|
||||
movzx r11, byte [r7 + 1] ; temp2 = src[1];
|
||||
add r10, r11; temp1 += temp2
|
||||
movd xm0, r10d; __m128i old_pix_128 = temp2;
|
||||
movd xm1, r11d; __m128i old_sum_128 = temp1;
|
||||
.width_loop:
|
||||
movq xmm2, [r7 + r6]; __m128i new_pix = (src+x);
|
||||
punpcklbw xmm2, xmm6 ; new_pix = _mm_unpacklo_epi8(new_pix, temp3);
|
||||
movdqa xmm3, xmm2 ; __m128i temp = new_pix;
|
||||
pslldq xmm3, 2 ; temp = temp << 2 * 8;
|
||||
paddw xmm3, xmm0 ; temp = _mm_add_epi16(temp, old_pix_128);
|
||||
paddw xmm3, xmm2 ; temp = _mm_add_epi16(temp, new_pix);
|
||||
movdqa xmm0, xmm2 ; old_pix_128 = new_pix;
|
||||
psrldq xmm0, 14 ; old_pix_128 = old_pix_128 >> 14 * 8;
|
||||
movdqa xmm2, xmm3 ; new_pix = temp;
|
||||
pslldq xmm2, 2 ; new_pix = new_pix << 2 * 8;
|
||||
paddw xmm2, xmm1 ; new_pix = _mm_add_epi16(new_pix, old_sum_128);
|
||||
paddw xmm2, xmm3 ; new_pix = _mm_add_epi16(new_pix, temp);
|
||||
movdqa xmm1, xmm3 ; old_sum_128 = temp;
|
||||
psrldq xmm1, 14 ; old_sum_128 = old_sum_128 >> 14 * 8;
|
||||
movdqu xmm4, [r4 + r6 * 2] ; __m128i old_col_pix = *(col_pix_buf+x);
|
||||
movdqu [r4 + r6 * 2], xmm2 ; *(col_pix_buf+x) = new_pix ;
|
||||
movdqu xmm5, [r12 + r6 * 2] ; __m128i old_col_sum = *(col_pix_sum+x);
|
||||
movdqa xmm3, xmm2 ; temp = new_pix;
|
||||
paddw xmm3, xmm4 ; temp = _mm_add_epi16(temp, old_col_pix);
|
||||
movdqu [r12 + r6 * 2], xmm3 ; *(col_sum_buf+x) = temp;
|
||||
paddw xmm5, xmm3 ; old_col_sum = _mm_add_epi16(old_col_sum, temp);
|
||||
psrlw xmm5, 4 ; old_col_sum = old_col_sum >> 4;
|
||||
packuswb xmm5, xmm5 ; old_col_sum = _mm_packus_epi16(old_col_sum, old_col_sum);
|
||||
movq qword [r13 + r6 - 1], xmm5 ; *(dst+x-1) = old_col_sum;
|
||||
add r6, 8; x += 8;
|
||||
cmp r6, r14; x < ((w - 2) & (~7));
|
||||
jl .width_loop
|
||||
movzx r8, byte [r7 + r6 - 1] ; old_pix = src[x-1];
|
||||
movzx r9, byte [r7 + r6 - 2] ; old_sum = old_pix + src[x-2];
|
||||
add r9, r8
|
||||
jmp .final_width_check
|
||||
.final_width_loop:
|
||||
movzx r10, byte [r7 + r6] ; temp1 = src[x];
|
||||
lea r11, [r8 + r10] ; temp2 = old_pix + temp1;
|
||||
mov r8, r10 ; old_pix = temp1;
|
||||
lea r10, [r9 + r11] ; temp1 = old_sum + temp2;
|
||||
mov r9, r11 ; old_sum = temp2;
|
||||
movzx r11, word [r4 + r6 * 2] ; temp2 = col_pix_buf[x];
|
||||
add r11, r10 ; temp2 += temp1;
|
||||
mov word [r4 + r6 * 2], r10w ; col_pix_buf[x] = temp1;
|
||||
movzx r10, word [r12 + r6 * 2] ; temp1 = col_sum_buf[x];
|
||||
add r10, r11 ; temp1 += temp2;
|
||||
shr r10, 4 ; temp1 >>= 4;
|
||||
mov byte [r13 + r6 - 1], r10b ; dst[x-1] = temp1
|
||||
mov [r12 + r6 * 2], r11w ; col_sum_buf[x] = temp2;
|
||||
inc r6 ; x++
|
||||
.final_width_check:
|
||||
cmp r6, r1 ; x < w
|
||||
jl .final_width_loop
|
||||
inc r5 ; y++;
|
||||
cmp r5, r2 ; y < h;
|
||||
jl .height_loop
|
||||
RET
|
||||
|
||||
INIT_YMM avx2
|
||||
cglobal be_blur, 5,15,9
|
||||
cmp r1, 32
|
||||
jl be_blur_sse2.skip_prologue
|
||||
mov r6, 2 ; int x = 2;
|
||||
vpxor ymm6, ymm6 ; __m128i temp3 = 0;
|
||||
mov r7, r0 ; unsigned char *src=buf;
|
||||
movzx r8, byte [r7 + 1] ; int old_pix = src[1];
|
||||
movzx r9, byte [r7] ; int old_sum = src[0];
|
||||
add r9, r8 ; old_sum += old_pix;
|
||||
lea r12, [r4 + r3 * 2] ; unsigned char *col_sum_buf = tmp + stride * 2;
|
||||
lea r14, [r1 - 2] ; tmpreg = (w-2);
|
||||
and r14, -16 ; tmpreg &= (~15);
|
||||
vmovdqa ymm7, [low_word_zero]
|
||||
.first_loop:
|
||||
movzx r10, byte [r7 + r6] ; int temp1 = src[x];
|
||||
lea r11, [r8 + r10] ; int temp2 = old_pix + temp1;
|
||||
mov r8, r10 ; old_pix = temp1;
|
||||
lea r10, [r9 + r11] ; temp1 = old_sum + temp2;
|
||||
mov r9, r11 ; old_sum = temp2;
|
||||
mov word [r4 + r6 * 2], r10w ; col_pix_buf[x] = temp1;
|
||||
inc r6 ; x++
|
||||
cmp r6, r1 ; x < w
|
||||
jl .first_loop
|
||||
mov r6, 2 ; int x = 2;
|
||||
lea r7, [r0 + r3] ; unsigned char *src=buf+stride;
|
||||
movzx r8, byte [r7 + 1] ; int old_pix = src[1];
|
||||
movzx r9, byte [r7] ; int old_sum = src[0];
|
||||
add r9, r8 ; old_sum += old_pix
|
||||
.second_loop:
|
||||
movzx r10, byte [r7 + r6] ; int temp1 = src[x];
|
||||
lea r11, [r8 + r10] ; int temp2 = old_pix + temp1;
|
||||
mov r8, r10 ; old_pix = temp1;
|
||||
lea r10, [r9 + r11] ; temp1 = old_sum + temp2;
|
||||
mov r9, r11 ; old_sum = temp2;
|
||||
movzx r11, word [r4 + r6 * 2] ; temp2 = col_pix_buf[x];
|
||||
add r11, r10 ; temp2 += temp1;
|
||||
mov word [r4 + r6 * 2], r10w ; col_pix_buf[x] = temp1;
|
||||
mov word [r12 + r6 * 2], r11w ; col_sum_buf[x] = temp2;
|
||||
inc r6 ; x++
|
||||
cmp r6, r1 ; x < w
|
||||
jl .second_loop
|
||||
mov r5, 2 ; int y = 2;
|
||||
.height_loop:
|
||||
mov r10, r5; int tmpreg = y;
|
||||
imul r10, r3; tmpreg *= stride;
|
||||
lea r7, [r0 + r10] ; unsigned char *src=buf+y*stride;
|
||||
sub r10, r3 ; tmpreg -= stride;
|
||||
lea r13, [r0 + r10]; unsigned char *dst=buf+(y-1)*stride;
|
||||
mov r6, 2 ; int x = 2;
|
||||
movzx r10, byte [r7] ; temp1 = src[0];
|
||||
movzx r11, byte [r7 + 1] ; temp2 = src[1];
|
||||
add r10, r11; temp1 += temp2
|
||||
vmovd xmm0, r10d; __m128i old_pix_128 = temp2;
|
||||
vmovd xmm1, r11d; __m128i old_sum_128 = temp1;
|
||||
.width_loop:
|
||||
vpermq ymm2, [r7 + r6], 0x10
|
||||
vpunpcklbw ymm2, ymm2, ymm6 ; new_pix = _mm_unpacklo_epi8(new_pix, temp3);
|
||||
vpermq ymm8, ymm2, 0x4e
|
||||
vpalignr ymm3, ymm2, ymm8, 14
|
||||
vpand ymm3, ymm3, ymm7
|
||||
vpaddw ymm3, ymm0 ; temp = _mm_add_epi16(temp, old_pix_128);
|
||||
vpaddw ymm3, ymm2 ; temp = _mm_add_epi16(temp, new_pix);
|
||||
vperm2i128 ymm0, ymm2, ymm6, 0x21
|
||||
vpsrldq ymm0, ymm0, 14; temp = temp >> 14 * 8;
|
||||
vpermq ymm8, ymm3, 0x4e
|
||||
vpand ymm8, ymm8, ymm7;
|
||||
vpalignr ymm2, ymm3, ymm8, 14
|
||||
vpand ymm2, ymm2, ymm7
|
||||
vpaddw ymm2, ymm1 ; new_pix = _mm_add_epi16(new_pix, old_sum_128);
|
||||
vpaddw ymm2, ymm3 ; new_pix = _mm_add_epi16(new_pix, temp);
|
||||
vperm2i128 ymm1, ymm3, ymm6, 0x21
|
||||
vpsrldq ymm1, ymm1, 14; temp = temp << 2 * 8;
|
||||
vmovdqu ymm4, [r4 + r6 * 2] ; __m128i old_col_pix = *(col_pix_buf+x);
|
||||
vmovdqu [r4 + r6 * 2], ymm2 ; *(col_pix_buf+x) = new_pix ;
|
||||
vmovdqu ymm5, [r12 + r6 * 2] ; __m128i old_col_sum = *(col_pix_sum+x);
|
||||
vpaddw ymm3, ymm2, ymm4
|
||||
vmovdqu [r12 + r6 * 2], ymm3 ; *(col_sum_buf+x) = temp;
|
||||
vpaddw ymm5, ymm3 ; old_col_sum = _mm_add_epi16(old_col_sum, temp);
|
||||
vpsrlw ymm5, 4 ; old_col_sum = old_col_sum >> 4;
|
||||
vpackuswb ymm5, ymm5 ; old_col_sum = _mm_packus_epi16(old_col_sum, old_col_sum);
|
||||
vpermq ymm5, ymm5, 11_01_10_00b
|
||||
vmovdqu [r13 + r6 - 1], xmm5 ; *(dst+x-1) = old_col_sum;
|
||||
add r6, 16; x += 16;
|
||||
cmp r6, r14; x < ((w - 2) & (~15));
|
||||
jl .width_loop
|
||||
movzx r8, byte [r7 + r6 - 1] ; old_pix = src[x-1];
|
||||
movzx r9, byte [r7 + r6 - 2] ; old_sum = old_pix + src[x-2];
|
||||
add r9, r8
|
||||
jmp .final_width_check
|
||||
.final_width_loop:
|
||||
movzx r10, byte [r7 + r6] ; temp1 = src[x];
|
||||
lea r11, [r8 + r10] ; temp2 = old_pix + temp1;
|
||||
mov r8, r10 ; old_pix = temp1;
|
||||
lea r10, [r9 + r11] ; temp1 = old_sum + temp2;
|
||||
mov r9, r11 ; old_sum = temp2;
|
||||
movzx r11, word [r4 + r6 * 2] ; temp2 = col_pix_buf[x];
|
||||
add r11, r10 ; temp2 += temp1;
|
||||
mov word [r4 + r6 * 2], r10w ; col_pix_buf[x] = temp1;
|
||||
movzx r10, word [r12 + r6 * 2] ; temp1 = col_sum_buf[x];
|
||||
add r10, r11 ; temp1 += temp2;
|
||||
shr r10, 4 ; temp1 >>= 4;
|
||||
mov byte [r13 + r6 - 1], r10b ; dst[x-1] = temp1
|
||||
mov [r12 + r6 * 2], r11w ; col_sum_buf[x] = temp2;
|
||||
inc r6 ; x++
|
||||
.final_width_check:
|
||||
cmp r6, r1 ; x < w
|
||||
jl .final_width_loop
|
||||
inc r5 ; y++;
|
||||
cmp r5, r2 ; y < h;
|
||||
jl .height_loop
|
||||
RET
|
||||
|
|
@ -0,0 +1,305 @@
|
|||
;******************************************************************************
|
||||
;* add_bitmaps.asm: SSE2 and x86 add_bitmaps
|
||||
;******************************************************************************
|
||||
;* Copyright (C) 2013 Rodger Combs <rcombs@rcombs.me>
|
||||
;*
|
||||
;* This file is part of libass.
|
||||
;*
|
||||
;* Permission to use, copy, modify, and distribute this software for any
|
||||
;* purpose with or without fee is hereby granted, provided that the above
|
||||
;* copyright notice and this permission notice appear in all copies.
|
||||
;*
|
||||
;* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
;* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
;* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
;* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
;* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
;* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
;* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
;******************************************************************************
|
||||
|
||||
%include "x86/x86inc.asm"
|
||||
|
||||
SECTION_RODATA 32
|
||||
|
||||
words_255: dw 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
|
||||
|
||||
SECTION .text
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; void add_bitmaps( uint8_t *dst, intptr_t dst_stride,
|
||||
; uint8_t *src, intptr_t src_stride,
|
||||
; intptr_t height, intptr_t width );
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
INIT_XMM
|
||||
cglobal add_bitmaps_x86, 6,7
|
||||
.skip_prologue:
|
||||
imul r4, r3
|
||||
add r4, r2
|
||||
PUSH r4
|
||||
mov r4, r3
|
||||
.height_loop:
|
||||
xor r6, r6 ; x offset
|
||||
.stride_loop:
|
||||
movzx r3, byte [r0 + r6]
|
||||
add r3b, byte [r2 + r6]
|
||||
jnc .continue
|
||||
mov r3b, 0xff
|
||||
.continue:
|
||||
mov byte [r0 + r6], r3b
|
||||
inc r6
|
||||
cmp r6, r5
|
||||
jl .stride_loop ; still in scan line
|
||||
add r0, r1
|
||||
add r2, r4
|
||||
cmp r2, [rsp]
|
||||
jl .height_loop
|
||||
ADD rsp, gprsize
|
||||
RET
|
||||
|
||||
%macro ADD_BITMAPS 0
|
||||
cglobal add_bitmaps, 6,7
|
||||
.skip_prologue:
|
||||
cmp r5, mmsize
|
||||
%if mmsize == 16
|
||||
jl add_bitmaps_x86.skip_prologue
|
||||
%else
|
||||
jl add_bitmaps_sse2.skip_prologue
|
||||
%endif
|
||||
%if mmsize == 32
|
||||
vzeroupper
|
||||
%endif
|
||||
imul r4, r3
|
||||
add r4, r2 ; last address
|
||||
.height_loop:
|
||||
xor r6, r6 ; x offset
|
||||
.stride_loop:
|
||||
movu m0, [r0 + r6]
|
||||
paddusb m0, [r2 + r6]
|
||||
movu [r0 + r6], m0
|
||||
add r6, mmsize
|
||||
cmp r6, r5
|
||||
jl .stride_loop ; still in scan line
|
||||
add r0, r1
|
||||
add r2, r3
|
||||
cmp r2, r4
|
||||
jl .height_loop
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
INIT_XMM sse2
|
||||
ADD_BITMAPS
|
||||
INIT_YMM avx2
|
||||
ADD_BITMAPS
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; void sub_bitmaps( uint8_t *dst, intptr_t dst_stride,
|
||||
; uint8_t *src, intptr_t src_stride,
|
||||
; intptr_t height, intptr_t width );
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
INIT_XMM
|
||||
cglobal sub_bitmaps_x86, 6,10
|
||||
.skip_prologue:
|
||||
imul r4, r3
|
||||
add r4, r2 ; last address
|
||||
PUSH r4
|
||||
mov r4, r3
|
||||
.height_loop:
|
||||
xor r6, r6 ; x offset
|
||||
.stride_loop:
|
||||
mov r3b, byte [r0 + r6]
|
||||
sub r3b, byte [r2 + r6]
|
||||
jnc .continue
|
||||
mov r3b, 0x0
|
||||
.continue:
|
||||
mov byte [r0 + r6], r3b
|
||||
inc r6
|
||||
cmp r6, r5
|
||||
jl .stride_loop ; still in scan line
|
||||
add r0, r1
|
||||
add r2, r4
|
||||
cmp r2, [rsp]
|
||||
jl .height_loop
|
||||
ADD rsp, gprsize
|
||||
RET
|
||||
|
||||
%if ARCH_X86_64
|
||||
|
||||
%macro SUB_BITMAPS 0
|
||||
cglobal sub_bitmaps, 6,10
|
||||
.skip_prologue:
|
||||
cmp r5, mmsize
|
||||
%if mmsize == 16
|
||||
jl sub_bitmaps_x86.skip_prologue
|
||||
%else
|
||||
jl sub_bitmaps_sse2.skip_prologue
|
||||
%endif
|
||||
%if mmsize == 32
|
||||
vzeroupper
|
||||
%endif
|
||||
imul r4, r3
|
||||
add r4, r2 ; last address
|
||||
mov r7, r5
|
||||
and r7, -mmsize ; &= (16);
|
||||
xor r9, r9
|
||||
.height_loop:
|
||||
xor r6, r6 ; x offset
|
||||
.stride_loop:
|
||||
movu m0, [r0 + r6]
|
||||
movu m1, [r2 + r6]
|
||||
psubusb m0, m1
|
||||
movu [r0 + r6], m0
|
||||
add r6, mmsize
|
||||
cmp r6, r7
|
||||
jl .stride_loop ; still in scan line
|
||||
.stride_loop2:
|
||||
cmp r6, r5
|
||||
jge .finish
|
||||
movzx r8, byte [r0 + r6]
|
||||
sub r8b, byte [r2 + r6]
|
||||
cmovc r8, r9
|
||||
mov byte [r0 + r6], r8b
|
||||
inc r6
|
||||
jmp .stride_loop2
|
||||
.finish:
|
||||
add r0, r1
|
||||
add r2, r3
|
||||
cmp r2, r4
|
||||
jl .height_loop
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
INIT_XMM sse2
|
||||
SUB_BITMAPS
|
||||
INIT_YMM avx2
|
||||
SUB_BITMAPS
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; void mul_bitmaps( uint8_t *dst, intptr_t dst_stride,
|
||||
; uint8_t *src1, intptr_t src1_stride,
|
||||
; uint8_t *src2, intptr_t src2_stride,
|
||||
; intptr_t width, intptr_t height );
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
INIT_XMM
|
||||
cglobal mul_bitmaps_x86, 8,12
|
||||
.skip_prologue:
|
||||
imul r7, r3
|
||||
add r7, r2 ; last address
|
||||
.height_loop:
|
||||
xor r8, r8 ; x offset
|
||||
.stride_loop:
|
||||
movzx r9, byte [r2 + r8]
|
||||
movzx r10, byte [r4 + r8]
|
||||
imul r9, r10
|
||||
add r9, 255
|
||||
shr r9, 8
|
||||
mov byte [r0 + r8], r9b
|
||||
inc r8
|
||||
cmp r8, r6
|
||||
jl .stride_loop ; still in scan line
|
||||
add r0, r1
|
||||
add r2, r3
|
||||
add r4, r5
|
||||
cmp r2, r7
|
||||
jl .height_loop
|
||||
RET
|
||||
|
||||
INIT_XMM sse2
|
||||
cglobal mul_bitmaps, 8,12
|
||||
.skip_prologue:
|
||||
cmp r6, 8
|
||||
jl mul_bitmaps_x86.skip_prologue
|
||||
imul r7, r3
|
||||
add r7, r2 ; last address
|
||||
pxor xmm2, xmm2
|
||||
movdqa xmm3, [words_255]
|
||||
mov r9, r6
|
||||
and r9, -8 ; &= (~8);
|
||||
.height_loop:
|
||||
xor r8, r8 ; x offset
|
||||
.stride_loop:
|
||||
movq xmm0, [r2 + r8]
|
||||
movq xmm1, [r4 + r8]
|
||||
punpcklbw xmm0, xmm2
|
||||
punpcklbw xmm1, xmm2
|
||||
pmullw xmm0, xmm1
|
||||
paddw xmm0, xmm3
|
||||
psrlw xmm0, 0x08
|
||||
packuswb xmm0, xmm0
|
||||
movq [r0 + r8], xmm0
|
||||
add r8, 8
|
||||
cmp r8, r9
|
||||
jl .stride_loop ; still in scan line
|
||||
.stride_loop2:
|
||||
cmp r8, r6
|
||||
jge .finish
|
||||
movzx r10, byte [r2 + r8]
|
||||
movzx r11, byte [r4 + r8]
|
||||
imul r10, r11
|
||||
add r10, 255
|
||||
shr r10, 8
|
||||
mov byte [r0 + r8], r10b
|
||||
inc r8
|
||||
jmp .stride_loop2
|
||||
.finish:
|
||||
add r0, r1
|
||||
add r2, r3
|
||||
add r4, r5
|
||||
cmp r2, r7
|
||||
jl .height_loop
|
||||
RET
|
||||
|
||||
INIT_YMM avx2
|
||||
cglobal mul_bitmaps, 8,12
|
||||
cmp r6, 16
|
||||
jl mul_bitmaps_sse2.skip_prologue
|
||||
%if mmsize == 32
|
||||
vzeroupper
|
||||
%endif
|
||||
imul r7, r3
|
||||
add r7, r2 ; last address
|
||||
vpxor ymm2, ymm2
|
||||
vmovdqa ymm3, [words_255]
|
||||
mov r9, r6
|
||||
and r9, -16 ; &= (~16);
|
||||
.height_loop:
|
||||
xor r8, r8 ; x offset
|
||||
.stride_loop:
|
||||
vmovdqu xmm0, [r2 + r8]
|
||||
vpermq ymm0, ymm0, 0x10
|
||||
vmovdqu xmm1, [r4 + r8]
|
||||
vpermq ymm1, ymm1, 0x10
|
||||
vpunpcklbw ymm0, ymm0, ymm2
|
||||
vpunpcklbw ymm1, ymm1, ymm2
|
||||
vpmullw ymm0, ymm0, ymm1
|
||||
vpaddw ymm0, ymm0, ymm3
|
||||
vpsrlw ymm0, ymm0, 0x08
|
||||
vextracti128 xmm4, ymm0, 0x1
|
||||
vpackuswb ymm0, ymm0, ymm4
|
||||
vmovdqa [r0 + r8], xmm0
|
||||
add r8, 16
|
||||
cmp r8, r9
|
||||
jl .stride_loop ; still in scan line
|
||||
.stride_loop2:
|
||||
cmp r8, r6
|
||||
jge .finish
|
||||
movzx r10, byte [r2 + r8]
|
||||
movzx r11, byte [r4 + r8]
|
||||
imul r10, r11
|
||||
add r10, 255
|
||||
shr r10, 8
|
||||
mov byte [r0 + r8], r10b
|
||||
inc r8
|
||||
jmp .stride_loop2
|
||||
.finish:
|
||||
add r0, r1
|
||||
add r2, r3
|
||||
add r4, r5
|
||||
cmp r2, r7
|
||||
jl .height_loop
|
||||
RET
|
||||
|
||||
%endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,64 @@
|
|||
;******************************************************************************
|
||||
;* add_bitmaps.asm: SSE2 and x86 add_bitmaps
|
||||
;******************************************************************************
|
||||
;* Copyright (C) 2013 Rodger Combs <rcombs@rcombs.me>
|
||||
;*
|
||||
;* This file is part of libass.
|
||||
;*
|
||||
;* Permission to use, copy, modify, and distribute this software for any
|
||||
;* purpose with or without fee is hereby granted, provided that the above
|
||||
;* copyright notice and this permission notice appear in all copies.
|
||||
;*
|
||||
;* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
;* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
;* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
;* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
;* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
;* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
;* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
;******************************************************************************
|
||||
|
||||
%include "x86/x86inc.asm"
|
||||
|
||||
SECTION .text
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; void get_cpuid( uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
INIT_XMM
|
||||
cglobal get_cpuid, 4, 5, 0
|
||||
push rbx
|
||||
push r3
|
||||
push r2
|
||||
push r1
|
||||
push r0
|
||||
mov eax, [r0]
|
||||
xor ecx, ecx
|
||||
cpuid
|
||||
pop r4
|
||||
mov [r4], eax
|
||||
pop r4
|
||||
mov [r4], ebx
|
||||
pop r4
|
||||
mov [r4], ecx
|
||||
pop r4
|
||||
mov [r4], edx
|
||||
pop rbx
|
||||
RET
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; void get_xgetbv( uint32_t op, uint32_t *eax, uint32_t *edx )
|
||||
;-----------------------------------------------------------------------------
|
||||
|
||||
INIT_XMM
|
||||
cglobal get_xgetbv, 3, 7, 0
|
||||
push r2
|
||||
push r1
|
||||
mov ecx, r0d
|
||||
xgetbv
|
||||
pop r4
|
||||
mov [r4], eax
|
||||
pop r4
|
||||
mov [r4], edx
|
||||
RET
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (C) 2013 Rodger Combs <rcombs@rcombs.me>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef INTEL_CPUID_H
|
||||
#define INTEL_CPUID_H
|
||||
|
||||
void ass_get_cpuid( uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
|
||||
void ass_get_xgetbv( uint32_t op, uint32_t *eax, uint32_t *edx );
|
||||
|
||||
#endif
|
|
@ -0,0 +1,858 @@
|
|||
;******************************************************************************
|
||||
;* rasterizer.asm: SSE2/AVX2 tile rasterization
|
||||
;******************************************************************************
|
||||
;* Copyright (C) 2014 Vabishchevich Nikolay <vabnick@gmail.com>
|
||||
;*
|
||||
;* This file is part of libass.
|
||||
;*
|
||||
;* Permission to use, copy, modify, and distribute this software for any
|
||||
;* purpose with or without fee is hereby granted, provided that the above
|
||||
;* copyright notice and this permission notice appear in all copies.
|
||||
;*
|
||||
;* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
;* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
;* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
;* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
;* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
;* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
;* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
;******************************************************************************
|
||||
|
||||
%include "x86/utils.asm"
|
||||
|
||||
SECTION_RODATA 32
|
||||
|
||||
words_index: dw 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F
|
||||
words_tile16: times 16 dw 1024
|
||||
words_tile32: times 16 dw 512
|
||||
|
||||
SECTION .text
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; FILL_LINE 1:dst, 2:m_src, 3:size
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
%macro FILL_LINE 3
|
||||
%if ((%3) & (mmsize - 1)) == 0
|
||||
%assign %%i 0
|
||||
%rep (%3) / mmsize
|
||||
mova [%1 + %%i], m%2
|
||||
%assign %%i %%i + mmsize
|
||||
%endrep
|
||||
%elif (%3) == 16
|
||||
mova [%1], xm%2
|
||||
%else
|
||||
%error "invalid line size"
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; FILL_SOLID_TILE 1:tile_order, 2:suffix
|
||||
; void fill_solid_tile%2(uint8_t *buf, ptrdiff_t stride, int set);
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
%macro FILL_SOLID_TILE 2
|
||||
cglobal fill_solid_tile%2, 3,4,1
|
||||
mov r3d, -1
|
||||
test r2d, r2d
|
||||
cmovnz r2d, r3d
|
||||
movd xm0, r2d
|
||||
%if mmsize == 32
|
||||
vpbroadcastd m0, xm0
|
||||
%else
|
||||
pshufd m0, m0, q0000
|
||||
%endif
|
||||
|
||||
%rep (1 << %1) - 1
|
||||
FILL_LINE r0, 0, 1 << %1
|
||||
add r0, r1
|
||||
%endrep
|
||||
FILL_LINE r0, 0, 1 << %1
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
INIT_XMM sse2
|
||||
FILL_SOLID_TILE 4,16
|
||||
FILL_SOLID_TILE 5,32
|
||||
INIT_YMM avx2
|
||||
FILL_SOLID_TILE 4,16
|
||||
FILL_SOLID_TILE 5,32
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; CALC_LINE 1:tile_order, 2:m_dst, 3:m_src, 4:m_delta,
|
||||
; 5:m_zero, 6:m_full, 7:m_tmp
|
||||
; Calculate line using antialiased halfplane algorithm
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
%macro CALC_LINE 7
|
||||
paddw m%7, m%3, m%4
|
||||
pmaxsw m%2, m%3, m%5
|
||||
pmaxsw m%7, m%5
|
||||
pminsw m%2, m%6
|
||||
pminsw m%7, m%6
|
||||
paddw m%2, m%7
|
||||
psraw m%2, 7 - %1
|
||||
%endmacro
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; DEF_A_SHIFT 1:tile_order
|
||||
; If single mm-register is enough to store the whole line
|
||||
; then sets a_shift = 0,
|
||||
; else sets a_shift = log2(mmsize / sizeof(int16_t)).
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
%macro DEF_A_SHIFT 1
|
||||
%if mmsize >= (2 << %1)
|
||||
%define a_shift 0
|
||||
%elif mmsize == 32
|
||||
%define a_shift 4
|
||||
%elif mmsize == 16
|
||||
%define a_shift 3
|
||||
%else
|
||||
%error "invalid mmsize"
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; FILL_HALFPLANE_TILE 1:tile_order, 2:suffix
|
||||
; void fill_halfplane_tile%2(uint8_t *buf, ptrdiff_t stride,
|
||||
; int32_t a, int32_t b, int64_t c, int32_t scale);
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
%macro FILL_HALFPLANE_TILE 2
|
||||
DEF_A_SHIFT %1
|
||||
%if ARCH_X86_64 && a_shift
|
||||
cglobal fill_halfplane_tile%2, 6,7,9
|
||||
%else
|
||||
cglobal fill_halfplane_tile%2, 6,7,8
|
||||
%endif
|
||||
%if a_shift == 0
|
||||
SWAP 3, 8
|
||||
%endif
|
||||
|
||||
%if ARCH_X86_64
|
||||
movsxd r2, r2d ; a
|
||||
movsxd r3, r3d ; b
|
||||
sar r4, 7 + %1 ; c >> (tile_order + 7)
|
||||
movsxd r5, r5d ; scale
|
||||
mov r6, 1 << (45 + %1)
|
||||
imul r2, r5
|
||||
add r2, r6
|
||||
sar r2, 46 + %1 ; aa
|
||||
imul r3, r5
|
||||
add r3, r6
|
||||
sar r3, 46 + %1 ; bb
|
||||
imul r4, r5
|
||||
shr r6, 1 + %1
|
||||
add r4, r6
|
||||
sar r4, 45 ; cc
|
||||
%else
|
||||
mov r0d, r4m ; c_lo
|
||||
mov r2d, r5m ; c_hi
|
||||
mov r1d, r6m ; scale
|
||||
mov r5d, 1 << 12
|
||||
shr r0d, 7 + %1
|
||||
shl r2d, 25 - %1
|
||||
or r0d, r2d ; r0d (eax) = c >> (tile_order + 7)
|
||||
imul r1d ; r2d (edx) = (c >> ...) * scale >> 32
|
||||
add r2d, r5d
|
||||
sar r2d, 13
|
||||
mov r4d, r2d ; cc
|
||||
shl r5d, 1 + %1
|
||||
mov r0d, r3m ; r0d (eax) = b
|
||||
imul r1d ; r2d (edx) = b * scale >> 32
|
||||
add r2d, r5d
|
||||
sar r2d, 14 + %1
|
||||
mov r3d, r2d ; bb
|
||||
mov r0d, r2m ; r0d (eax) = a
|
||||
imul r1d ; r2d (edx) = a * scale >> 32
|
||||
add r2d, r5d
|
||||
sar r2d, 14 + %1 ; aa
|
||||
mov r0d, r0m
|
||||
mov r1d, r1m
|
||||
%endif
|
||||
add r4d, 1 << (13 - %1)
|
||||
mov r6d, r2d
|
||||
add r6d, r3d
|
||||
sar r6d, 1
|
||||
sub r4d, r6d
|
||||
|
||||
BCASTW 1, r4d ; cc
|
||||
BCASTW 2, r2d ; aa
|
||||
%if a_shift
|
||||
psllw m3, m2, a_shift ; aa * (mmsize / 2)
|
||||
%endif
|
||||
pmullw m2, [words_index]
|
||||
psubw m1, m2 ; cc - aa * i
|
||||
|
||||
mov r4d, r2d ; aa
|
||||
mov r6d, r4d
|
||||
sar r6d, 31
|
||||
xor r4d, r6d
|
||||
sub r4d, r6d ; abs_a
|
||||
mov r5d, r3d ; bb
|
||||
mov r6d, r5d
|
||||
sar r6d, 31
|
||||
xor r5d, r6d
|
||||
sub r5d, r6d ; abs_b
|
||||
cmp r4d, r5d
|
||||
cmovg r4d, r5d
|
||||
add r4d, 2
|
||||
sar r4d, 2 ; delta
|
||||
BCASTW 2, r4d
|
||||
psubw m1, m2 ; c1 = cc - aa * i - delta
|
||||
paddw m2, m2 ; 2 * delta
|
||||
|
||||
%if a_shift
|
||||
MUL r2d, (1 << %1) - (mmsize / 2)
|
||||
sub r3d, r2d ; bb - (tile_size - mmsize / 2) * aa
|
||||
%endif
|
||||
%if ARCH_X86_64 || a_shift == 0
|
||||
BCASTW 8, r3d
|
||||
%endif
|
||||
|
||||
pxor m0, m0
|
||||
mova m4, [words_tile%2]
|
||||
mov r2d, (1 << %1)
|
||||
jmp .loop_entry
|
||||
|
||||
.loop_start:
|
||||
add r0, r1
|
||||
%if ARCH_X86_64 || a_shift == 0
|
||||
psubw m1, m8
|
||||
%else
|
||||
BCASTW 7, r3d
|
||||
psubw m1, m7
|
||||
%endif
|
||||
.loop_entry:
|
||||
%assign i 0
|
||||
%rep (1 << %1) / mmsize
|
||||
%if i
|
||||
psubw m1, m3
|
||||
%endif
|
||||
CALC_LINE %1, 5, 1,2, 0,4, 7
|
||||
psubw m1, m3
|
||||
CALC_LINE %1, 6, 1,2, 0,4, 7
|
||||
packuswb m5, m6
|
||||
%if mmsize == 32
|
||||
vpermq m5, m5, q3120
|
||||
%endif
|
||||
mova [r0 + i], m5
|
||||
%assign i i + mmsize
|
||||
%endrep
|
||||
%if (1 << %1) < mmsize
|
||||
CALC_LINE %1, 5, 1,2, 0,4, 7
|
||||
packuswb m5, m6
|
||||
vpermq m5, m5, q3120
|
||||
mova [r0 + i], xm5
|
||||
%endif
|
||||
sub r2d,1
|
||||
jnz .loop_start
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
INIT_XMM sse2
|
||||
FILL_HALFPLANE_TILE 4,16
|
||||
FILL_HALFPLANE_TILE 5,32
|
||||
INIT_YMM avx2
|
||||
FILL_HALFPLANE_TILE 4,16
|
||||
FILL_HALFPLANE_TILE 5,32
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; struct segment {
|
||||
; int64_t c;
|
||||
; int32_t a, b, scale, flags;
|
||||
; int32_t x_min, x_max, y_min, y_max;
|
||||
; };
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
struc line
|
||||
.c: resq 1
|
||||
.a: resd 1
|
||||
.b: resd 1
|
||||
.scale: resd 1
|
||||
.flags: resd 1
|
||||
.x_min: resd 1
|
||||
.x_max: resd 1
|
||||
.y_min: resd 1
|
||||
.y_max: resd 1
|
||||
endstruc
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; ZEROFILL 1:dst, 2:size, 3:tmp
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
%macro ZEROFILL 3
|
||||
%assign %%n 128 / mmsize
|
||||
mov %3, (%2) / 128
|
||||
%%zerofill_loop:
|
||||
%assign %%i 0
|
||||
%rep %%n
|
||||
mova [%1 + %%i], mm_zero
|
||||
%assign %%i %%i + mmsize
|
||||
%endrep
|
||||
add %1, 128
|
||||
sub %3, 1
|
||||
jnz %%zerofill_loop
|
||||
%assign %%i 0
|
||||
%rep ((%2) / mmsize) & (%%n - 1)
|
||||
mova [%1 + %%i], mm_zero
|
||||
%assign %%i %%i + mmsize
|
||||
%endrep
|
||||
%endmacro
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; CALC_DELTA_FLAG 1:res, 2:line, 3-4:tmp
|
||||
; Set bits of result register (res):
|
||||
; bit 3 - for nonzero up_delta,
|
||||
; bit 2 - for nonzero dn_delta.
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
%macro CALC_DELTA_FLAG 4
|
||||
mov %3d, [%2 + line.flags]
|
||||
xor %4d, %4d
|
||||
cmp %4d, [%2 + line.x_min]
|
||||
cmovz %4d, %3d
|
||||
xor %1d, %1d
|
||||
test %3d, 2 ; SEGFLAG_UL_DR
|
||||
cmovnz %1d, %4d
|
||||
shl %3d, 2
|
||||
xor %1d, %3d
|
||||
and %4d, 4
|
||||
and %1d, 4
|
||||
lea %1d, [%1d + 2 * %1d]
|
||||
xor %1d, %4d
|
||||
%endmacro
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; UPDATE_DELTA 1:dn/up, 2:dst, 3:flag, 4:pos, 5:tmp
|
||||
; Update delta array
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
%macro UPDATE_DELTA 5
|
||||
%ifidn %1, dn
|
||||
%define %%op add
|
||||
%define %%opi sub
|
||||
%assign %%flag 1 << 2
|
||||
%elifidn %1, up
|
||||
%define %%op sub
|
||||
%define %%opi add
|
||||
%assign %%flag 1 << 3
|
||||
%else
|
||||
%error "dn/up expected"
|
||||
%endif
|
||||
|
||||
test %3d, %%flag
|
||||
jz %%skip
|
||||
lea %5d, [4 * %4d - 256]
|
||||
%%opi [%2], %5w
|
||||
lea %5d, [4 * %4d]
|
||||
%%op [%2 + 2], %5w
|
||||
%%skip:
|
||||
%endmacro
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; CALC_VBA 1:tile_order, 2:b
|
||||
; Calculate b - (tile_size - (mmsize / sizeof(int16_t))) * a
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
%macro CALC_VBA 2
|
||||
BCASTW m_vba, %2d
|
||||
%rep (2 << %1) / mmsize - 1
|
||||
psubw mm_vba, mm_van
|
||||
%endrep
|
||||
%endmacro
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; FILL_BORDER_LINE 1:tile_order, 2:res, 3:abs_a[abs_ab], 4:b, 5:[abs_b],
|
||||
; 6:size, 7:sum, 8-9:tmp, 10-14:m_tmp, 15:[m_tmp]
|
||||
; Render top/bottom line of the trapezium with antialiasing
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
%macro FILL_BORDER_LINE 15
|
||||
mov %8d, %6d
|
||||
shl %8d, 8 - %1 ; size << (8 - tile_order)
|
||||
xor %9d, %9d
|
||||
%if ARCH_X86_64
|
||||
sub %8d, %3d ; abs_a
|
||||
cmovg %8d, %9d
|
||||
add %8d, 1 << (14 - %1)
|
||||
shl %8d, 2 * %1 - 5 ; w
|
||||
BCASTW %15, %8d
|
||||
|
||||
mov %9d, %5d ; abs_b
|
||||
imul %9d, %6d
|
||||
sar %9d, 6 ; dc_b
|
||||
cmp %9d, %3d ; abs_a
|
||||
cmovg %9d, %3d
|
||||
%else
|
||||
sub %8w, %3w ; abs_a
|
||||
cmovg %8d, %9d
|
||||
add %8w, 1 << (14 - %1)
|
||||
shl %8d, 2 * %1 - 5 ; w
|
||||
|
||||
mov %9d, %3d ; abs_ab
|
||||
shr %9d, 16 ; abs_b
|
||||
imul %9d, %6d
|
||||
sar %9d, 6 ; dc_b
|
||||
cmp %9w, %3w
|
||||
cmovg %9w, %3w
|
||||
%endif
|
||||
add %9d, 2
|
||||
sar %9d, 2 ; dc
|
||||
|
||||
imul %7d, %4d ; sum * b
|
||||
sar %7d, 7 ; avg * b
|
||||
add %7d, %9d ; avg * b + dc
|
||||
add %9d, %9d ; 2 * dc
|
||||
|
||||
imul %7d, %8d
|
||||
sar %7d, 16
|
||||
sub %7d, %6d ; -offs1
|
||||
BCASTW %10, %7d
|
||||
imul %9d, %8d
|
||||
sar %9d, 16 ; offs2 - offs1
|
||||
BCASTW %11, %9d
|
||||
add %6d, %6d
|
||||
BCASTW %12, %6d
|
||||
|
||||
%assign %%i 0
|
||||
%rep (2 << %1) / mmsize
|
||||
%if %%i
|
||||
psubw mm_c, mm_van
|
||||
%endif
|
||||
%if ARCH_X86_64
|
||||
pmulhw m%13, mm_c, m%15
|
||||
%else
|
||||
BCASTW %14, %8d
|
||||
pmulhw m%13, mm_c, m%14
|
||||
%endif
|
||||
psubw m%13, m%10 ; c1
|
||||
paddw m%14, m%13, m%11 ; c2
|
||||
pmaxsw m%13, mm_zero
|
||||
pmaxsw m%14, mm_zero
|
||||
pminsw m%13, m%12
|
||||
pminsw m%14, m%12
|
||||
paddw m%13, m%14
|
||||
paddw m%13, [%2 + %%i]
|
||||
mova [%2 + %%i], m%13
|
||||
%assign %%i %%i + mmsize
|
||||
%endrep
|
||||
%endmacro
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; SAVE_RESULT 1:tile_order, 2:buf, 3:stride, 4:src, 5:delta,
|
||||
; 6-7:tmp, 8-11:m_tmp
|
||||
; Convert and store internal buffer (with delta array) in the result buffer
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
%macro SAVE_RESULT 11
|
||||
mov %6d, 1 << %1
|
||||
xor %7d, %7d
|
||||
%%save_loop:
|
||||
add %7w, [%5]
|
||||
BCASTW %10, %7d
|
||||
add %5, 2
|
||||
|
||||
%assign %%i 0
|
||||
%rep (1 << %1) / mmsize
|
||||
paddw m%8, m%10, [%4 + 2 * %%i]
|
||||
PABSW %8, %11
|
||||
paddw m%9, m%10, [%4 + 2 * %%i + mmsize]
|
||||
PABSW %9, %11
|
||||
packuswb m%8, m%9
|
||||
%if mmsize == 32
|
||||
vpermq m%8, m%8, q3120
|
||||
%endif
|
||||
mova [%2 + %%i], m%8
|
||||
%assign %%i %%i + mmsize
|
||||
%endrep
|
||||
%if (1 << %1) < mmsize
|
||||
paddw m%8, m%10, [%4 + 2 * %%i]
|
||||
PABSW %8, %11
|
||||
packuswb m%8, m%8
|
||||
vpermq m%8, m%8, q3120
|
||||
mova [%2 + %%i], xm%8
|
||||
%endif
|
||||
|
||||
add %2, %3
|
||||
add %4, 2 << %1
|
||||
sub %6d, 1
|
||||
jnz %%save_loop
|
||||
%endmacro
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; GET_RES_ADDR 1:dst
|
||||
; CALC_RES_ADDR 1:tile_order, 2:dst/index, 3:tmp, 4:[skip_calc]
|
||||
; Calculate position of line in the internal buffer
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
%macro GET_RES_ADDR 1
|
||||
%if mmsize <= 16 && HAVE_ALIGNED_STACK
|
||||
mov %1, rstk
|
||||
%else
|
||||
lea %1, [rstk + mmsize - 1]
|
||||
and %1, ~(mmsize - 1)
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
%macro CALC_RES_ADDR 3-4 noskip
|
||||
shl %2d, 1 + %1
|
||||
%if mmsize <= 16 && HAVE_ALIGNED_STACK
|
||||
add %2, rstk
|
||||
%else
|
||||
%ifidn %4, noskip
|
||||
lea %3, [rstk + mmsize - 1]
|
||||
and %3, ~(mmsize - 1)
|
||||
%endif
|
||||
add %2, %3
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; FILL_GENERIC_TILE 1:tile_order, 2:suffix
|
||||
; void fill_generic_tile%2(uint8_t *buf, ptrdiff_t stride,
|
||||
; const struct segment *line, size_t n_lines,
|
||||
; int winding);
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
%macro FILL_GENERIC_TILE 2
|
||||
; t3=line t4=up/cur t5=dn/end t6=dn_pos t7=up_pos
|
||||
; t8=a/abs_a/abs_ab t9=b t10=c/abs_b
|
||||
%if ARCH_X86_64
|
||||
DECLARE_REG_TMP 10,11,5,2, 4,9,6,7, 8,12,13
|
||||
%else
|
||||
DECLARE_REG_TMP 0,1,5,3, 4,6,6,0, 2,3,5
|
||||
%endif
|
||||
|
||||
%assign tile_size 1 << %1
|
||||
%assign delta_offs 2 * tile_size * tile_size
|
||||
%assign alloc_size 2 * tile_size * (tile_size + 1) + 4
|
||||
%assign buf_size 2 * tile_size * (tile_size + 1)
|
||||
DEF_A_SHIFT %1
|
||||
|
||||
%if ARCH_X86_64
|
||||
%define m_zero 6
|
||||
%define m_full 7
|
||||
%define mm_index m8
|
||||
%define m_c 9
|
||||
%define m_vba 10
|
||||
%if a_shift
|
||||
%define m_van 11
|
||||
cglobal fill_generic_tile%2, 5,14,12
|
||||
%else
|
||||
cglobal fill_generic_tile%2, 5,14,11
|
||||
%endif
|
||||
|
||||
%else
|
||||
%define m_zero 5
|
||||
%define m_full 4 ; tmp
|
||||
%define mm_index [words_index]
|
||||
%define m_c 7
|
||||
%if a_shift
|
||||
%define m_van 6
|
||||
%define m_vba 3 ; tmp
|
||||
%else
|
||||
%define m_vba 6
|
||||
%endif
|
||||
|
||||
%assign alloc_size alloc_size + 8
|
||||
cglobal fill_generic_tile%2, 0,7,8
|
||||
%endif
|
||||
|
||||
%define mm_zero m %+ m_zero
|
||||
%define mm_full m %+ m_full
|
||||
%define mm_c m %+ m_c
|
||||
%define mm_vba m %+ m_vba
|
||||
%if a_shift
|
||||
%define mm_van m %+ m_van
|
||||
%endif
|
||||
|
||||
%if mmsize <= 16 && HAVE_ALIGNED_STACK
|
||||
%assign alloc_size alloc_size + stack_offset + gprsize + (mmsize - 1)
|
||||
%assign alloc_size (alloc_size & ~(mmsize - 1)) - stack_offset - gprsize
|
||||
%else
|
||||
%assign alloc_size alloc_size + 2 * mmsize
|
||||
%assign delta_offs delta_offs + mmsize
|
||||
%assign buf_size buf_size + mmsize
|
||||
%endif
|
||||
SUB rstk, alloc_size
|
||||
|
||||
GET_RES_ADDR t0
|
||||
pxor mm_zero, mm_zero
|
||||
ZEROFILL t0, buf_size, t1
|
||||
|
||||
%if ARCH_X86_64 == 0
|
||||
mov r4d, r4m
|
||||
%endif
|
||||
shl r4d, 8
|
||||
mov [rstk + delta_offs], r4w
|
||||
|
||||
%if ARCH_X86_64
|
||||
mova mm_index, [words_index]
|
||||
mova mm_full, [words_tile%2]
|
||||
%define dn_addr t5
|
||||
%else
|
||||
%define dn_addr [rstk + delta_offs + 2 * tile_size + 4]
|
||||
%define dn_pos [rstk + delta_offs + 2 * tile_size + 8]
|
||||
%endif
|
||||
|
||||
.line_loop:
|
||||
%if ARCH_X86_64 == 0
|
||||
mov t3, r2m
|
||||
lea t0, [t3 + line_size]
|
||||
mov r2m, t0
|
||||
%endif
|
||||
CALC_DELTA_FLAG t0, t3, t1,t2
|
||||
|
||||
mov t4d, [t3 + line.y_min]
|
||||
mov t2d, [t3 + line.y_max]
|
||||
%if ARCH_X86_64
|
||||
mov t8d, t4d
|
||||
mov t6d, t4d
|
||||
and t6d, 63 ; up_pos
|
||||
shr t4d, 6 ; up
|
||||
mov t5d, t2d
|
||||
mov t7d, t2d
|
||||
and t7d, 63 ; dn_pos
|
||||
shr t5d, 6 ; dn
|
||||
|
||||
UPDATE_DELTA up, rstk + 2 * t4 + delta_offs, t0,t6, t1
|
||||
UPDATE_DELTA dn, rstk + 2 * t5 + delta_offs, t0,t7, t1
|
||||
cmp t8d, t2d
|
||||
%else
|
||||
lea t1d, [t0d + 1]
|
||||
cmp t4d, t2d
|
||||
cmovnz t0d, t1d ; bit 0 -- not horz line
|
||||
|
||||
mov t6d, t2d
|
||||
and t6d, 63 ; dn_pos
|
||||
shr t2d, 6 ; dn
|
||||
UPDATE_DELTA dn, rstk + 2 * t2 + delta_offs, t0,t6, t1
|
||||
|
||||
CALC_RES_ADDR %1, t2, t1
|
||||
mov dn_addr, t2
|
||||
mov dn_pos, t6d
|
||||
|
||||
mov t6d, t4d
|
||||
and t6d, 63 ; up_pos
|
||||
shr t4d, 6 ; up
|
||||
UPDATE_DELTA up, rstk + 2 * t4 + delta_offs, t0,t6, t1
|
||||
test t0d, 1
|
||||
%endif
|
||||
jz .end_line_loop
|
||||
|
||||
%if ARCH_X86_64
|
||||
movsxd t8, dword [t3 + line.a]
|
||||
movsxd t9, dword [t3 + line.b]
|
||||
mov t10, [t3 + line.c]
|
||||
sar t10, 7 + %1 ; c >> (tile_order + 7)
|
||||
movsxd t0, dword [t3 + line.scale]
|
||||
mov t1, 1 << (45 + %1)
|
||||
imul t8, t0
|
||||
add t8, t1
|
||||
sar t8, 46 + %1 ; a
|
||||
imul t9, t0
|
||||
add t9, t1
|
||||
sar t9, 46 + %1 ; b
|
||||
imul t10, t0
|
||||
shr t1, 1 + %1
|
||||
add t10, t1
|
||||
sar t10, 45 ; c
|
||||
%else
|
||||
mov r0d, [t3 + line.c]
|
||||
mov r2d, [t3 + line.c + 4]
|
||||
mov r1d, [t3 + line.scale]
|
||||
shr r0d, 7 + %1
|
||||
shl r2d, 25 - %1
|
||||
or r0d, r2d ; r0d (eax) = c >> (tile_order + 7)
|
||||
imul r1d ; r2d (edx) = (c >> ...) * scale >> 32
|
||||
add r2d, 1 << 12
|
||||
sar r2d, 13
|
||||
mov t10d, r2d ; c
|
||||
mov r0d, [t3 + line.b] ; r0d (eax)
|
||||
imul r1d ; r2d (edx) = b * scale >> 32
|
||||
add r2d, 1 << (13 + %1)
|
||||
sar r2d, 14 + %1
|
||||
mov r0d, [t3 + line.a] ; r0d (eax)
|
||||
mov t9d, r2d ; b (overrides t3)
|
||||
imul r1d ; r2d (edx) = a * scale >> 32
|
||||
add r2d, 1 << (13 + %1)
|
||||
sar r2d, 14 + %1 ; a (t8d)
|
||||
%endif
|
||||
|
||||
mov t0d, t8d ; a
|
||||
sar t0d, 1
|
||||
sub t10d, t0d
|
||||
mov t0d, t9d ; b
|
||||
imul t0d, t4d
|
||||
sub t10d, t0d
|
||||
BCASTW m_c, t10d
|
||||
|
||||
BCASTW 0, t8d
|
||||
%if a_shift
|
||||
psllw mm_van, m0, a_shift ; a * (mmsize / 2)
|
||||
%endif
|
||||
pmullw m0, mm_index
|
||||
psubw mm_c, m0 ; c - a * i
|
||||
|
||||
mov t0d, t8d ; a
|
||||
sar t0d, 31
|
||||
xor t8d, t0d
|
||||
sub t8d, t0d ; abs_a
|
||||
mov t0d, t9d ; b
|
||||
mov t10d, t9d
|
||||
sar t0d, 31
|
||||
xor t10d, t0d
|
||||
sub t10d, t0d ; abs_b
|
||||
%if ARCH_X86_64 == 0
|
||||
shl t10d, 16
|
||||
or t8d, t10d ; abs_ab
|
||||
%endif
|
||||
|
||||
CALC_RES_ADDR %1, t4, t0
|
||||
%if ARCH_X86_64
|
||||
CALC_RES_ADDR %1, t5, t0, skip
|
||||
%endif
|
||||
cmp t4, dn_addr
|
||||
jz .single_line
|
||||
|
||||
%if ARCH_X86_64 || a_shift == 0
|
||||
CALC_VBA %1, t9
|
||||
%endif
|
||||
|
||||
test t6d, t6d
|
||||
jz .generic_fist
|
||||
mov t2d, 64
|
||||
sub t2d, t6d ; 64 - up_pos
|
||||
add t6d, 64 ; 64 + up_pos
|
||||
FILL_BORDER_LINE %1, t4,t8,t9,t10,t2,t6, t0,t1, 0,1,2,3,4,5
|
||||
|
||||
%if ARCH_X86_64 == 0
|
||||
mov t5, dn_addr
|
||||
%if a_shift
|
||||
CALC_VBA %1, t9
|
||||
%endif
|
||||
%endif
|
||||
|
||||
psubw mm_c, mm_vba
|
||||
add t4, 2 << %1
|
||||
cmp t4, t5
|
||||
jge .end_loop
|
||||
%if ARCH_X86_64 == 0
|
||||
jmp .bulk_fill
|
||||
%endif
|
||||
|
||||
.generic_fist:
|
||||
%if ARCH_X86_64 == 0
|
||||
mov t5, dn_addr
|
||||
%if a_shift
|
||||
CALC_VBA %1, t9
|
||||
%endif
|
||||
%endif
|
||||
|
||||
.bulk_fill:
|
||||
mov t2d, 1 << (13 - %1)
|
||||
mov t0d, t9d ; b
|
||||
sar t0d, 1
|
||||
sub t2d, t0d ; base
|
||||
%if ARCH_X86_64
|
||||
mov t0d, t10d ; abs_b
|
||||
cmp t0d, t8d ; abs_a
|
||||
cmovg t0d, t8d
|
||||
%else
|
||||
mov t0d, t8d ; abs_ab
|
||||
shr t0d, 16 ; abs_b
|
||||
cmp t0w, t8w
|
||||
cmovg t0w, t8w
|
||||
%endif
|
||||
add t0d, 2
|
||||
sar t0d, 2 ; dc
|
||||
%if ARCH_X86_64
|
||||
sub t2d, t0d ; base - dc
|
||||
%else
|
||||
sub t2w, t0w ; base - dc
|
||||
%endif
|
||||
add t0d, t0d ; 2 * dc
|
||||
BCASTW 2, t0d
|
||||
|
||||
%if ARCH_X86_64
|
||||
BCASTW 3, t2d
|
||||
paddw mm_c, m3
|
||||
%else
|
||||
BCASTW 0, t2d
|
||||
paddw mm_c, m0
|
||||
|
||||
mova mm_full, [words_tile%2]
|
||||
%endif
|
||||
.internal_loop:
|
||||
%assign i 0
|
||||
%rep (2 << %1) / mmsize
|
||||
%if i
|
||||
psubw mm_c, mm_van
|
||||
%endif
|
||||
CALC_LINE %1, 0, m_c,2, m_zero,m_full, 1
|
||||
paddw m0, [t4 + i]
|
||||
mova [t4 + i], m0
|
||||
%assign i i + mmsize
|
||||
%endrep
|
||||
psubw mm_c, mm_vba
|
||||
add t4, 2 << %1
|
||||
cmp t4, t5
|
||||
jl .internal_loop
|
||||
%if ARCH_X86_64
|
||||
psubw mm_c, m3
|
||||
%else
|
||||
BCASTW 0, t2d
|
||||
psubw mm_c, m0
|
||||
%endif
|
||||
|
||||
.end_loop:
|
||||
%if ARCH_X86_64
|
||||
test t7d, t7d
|
||||
jz .end_line_loop
|
||||
xor t6d, t6d
|
||||
%else
|
||||
mov t2d, dn_pos
|
||||
test t2d, t2d
|
||||
jz .end_line_loop
|
||||
mov t6d, t2d
|
||||
jmp .last_line
|
||||
%endif
|
||||
|
||||
.single_line:
|
||||
%if ARCH_X86_64 == 0
|
||||
mov t7d, dn_pos
|
||||
%endif
|
||||
mov t2d, t7d
|
||||
sub t2d, t6d ; dn_pos - up_pos
|
||||
add t6d, t7d ; dn_pos + up_pos
|
||||
.last_line:
|
||||
FILL_BORDER_LINE %1, t4,t8,t9,t10,t2,t6, t0,t1, 0,1,2,3,4,5
|
||||
|
||||
.end_line_loop:
|
||||
%if ARCH_X86_64
|
||||
add r2, line_size
|
||||
sub r3, 1
|
||||
%else
|
||||
sub dword r3m, 1
|
||||
%endif
|
||||
jnz .line_loop
|
||||
|
||||
%if ARCH_X86_64 == 0
|
||||
mov r0, r0m
|
||||
mov r1, r1m
|
||||
%endif
|
||||
GET_RES_ADDR r2
|
||||
lea r3, [rstk + delta_offs]
|
||||
SAVE_RESULT %1, r0,r1,r2,r3, r4,t2, 0,1,2,3
|
||||
ADD rstk, alloc_size
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
INIT_XMM sse2
|
||||
FILL_GENERIC_TILE 4,16
|
||||
FILL_GENERIC_TILE 5,32
|
||||
INIT_YMM avx2
|
||||
FILL_GENERIC_TILE 4,16
|
||||
FILL_GENERIC_TILE 5,32
|
|
@ -0,0 +1,85 @@
|
|||
;******************************************************************************
|
||||
;* utils.asm: helper macros
|
||||
;******************************************************************************
|
||||
;* Copyright (C) 2014 Vabishchevich Nikolay <vabnick@gmail.com>
|
||||
;*
|
||||
;* This file is part of libass.
|
||||
;*
|
||||
;* Permission to use, copy, modify, and distribute this software for any
|
||||
;* purpose with or without fee is hereby granted, provided that the above
|
||||
;* copyright notice and this permission notice appear in all copies.
|
||||
;*
|
||||
;* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
;* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
;* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
;* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
;* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
;* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
;* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
;******************************************************************************
|
||||
|
||||
%include "x86/x86inc.asm"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; MUL 1:reg, 2:num
|
||||
; Multiply by constant
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
%macro MUL 2
|
||||
%if (%2) == 0
|
||||
xor %1, %1
|
||||
%elif (%2) == 1
|
||||
%elif (%2) == 2
|
||||
add %1, %1 ; lea %1, [%1 + %1]
|
||||
%elif (%2) == 3
|
||||
lea %1, [%1 + 2 * %1]
|
||||
%elif (%2) == 4
|
||||
lea %1, [4 * %1] ; shl %1, 2
|
||||
%elif (%2) == 5
|
||||
lea %1, [%1 + 4 * %1]
|
||||
%elif (%2) == 8
|
||||
lea %1, [8 * %1] ; shl %1, 3
|
||||
%elif (%2) == 9
|
||||
lea %1, [%1 + 8 * %1]
|
||||
%elif (%2) == 16
|
||||
shl %1, 4
|
||||
%elif (%2) == 32
|
||||
shl %1, 5
|
||||
%elif (%2) == 64
|
||||
shl %1, 6
|
||||
%elif (%2) == 128
|
||||
shl %1, 7
|
||||
%elif (%2) == 256
|
||||
shl %1, 8
|
||||
%else
|
||||
imul %1, %2
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; BCASTW 1:m_dst, 2:r_src
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
%macro BCASTW 2
|
||||
movd xm%1, %2
|
||||
%if mmsize == 32
|
||||
vpbroadcastw m%1, xm%1
|
||||
%elif mmsize == 16
|
||||
punpcklwd m%1, m%1
|
||||
pshufd m%1, m%1, q0000
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; PABSW 1:m_reg, 2:m_tmp
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
%macro PABSW 2
|
||||
%if cpuflag(ssse3)
|
||||
pabsw m%1, m%1
|
||||
%else
|
||||
pxor m%2, m%2
|
||||
psubw m%2, m%1
|
||||
pmaxsw m%1, m%2
|
||||
%endif
|
||||
%endmacro
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,437 @@
|
|||
# Helper functions for option handling. -*- Autoconf -*-
|
||||
#
|
||||
# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
|
||||
# Foundation, Inc.
|
||||
# Written by Gary V. Vaughan, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 8 ltoptions.m4
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
|
||||
|
||||
|
||||
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
|
||||
# ------------------------------------------
|
||||
m4_define([_LT_MANGLE_OPTION],
|
||||
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
|
||||
|
||||
|
||||
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
|
||||
# ---------------------------------------
|
||||
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
|
||||
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
|
||||
# saved as a flag.
|
||||
m4_define([_LT_SET_OPTION],
|
||||
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
|
||||
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
|
||||
_LT_MANGLE_DEFUN([$1], [$2]),
|
||||
[m4_warning([Unknown $1 option '$2'])])[]dnl
|
||||
])
|
||||
|
||||
|
||||
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
|
||||
# ------------------------------------------------------------
|
||||
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
|
||||
m4_define([_LT_IF_OPTION],
|
||||
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
|
||||
|
||||
|
||||
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
|
||||
# -------------------------------------------------------
|
||||
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
|
||||
# are set.
|
||||
m4_define([_LT_UNLESS_OPTIONS],
|
||||
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
|
||||
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
|
||||
[m4_define([$0_found])])])[]dnl
|
||||
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
|
||||
])[]dnl
|
||||
])
|
||||
|
||||
|
||||
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
|
||||
# ----------------------------------------
|
||||
# OPTION-LIST is a space-separated list of Libtool options associated
|
||||
# with MACRO-NAME. If any OPTION has a matching handler declared with
|
||||
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
|
||||
# the unknown option and exit.
|
||||
m4_defun([_LT_SET_OPTIONS],
|
||||
[# Set options
|
||||
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
|
||||
[_LT_SET_OPTION([$1], _LT_Option)])
|
||||
|
||||
m4_if([$1],[LT_INIT],[
|
||||
dnl
|
||||
dnl Simply set some default values (i.e off) if boolean options were not
|
||||
dnl specified:
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
|
||||
])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
|
||||
])
|
||||
dnl
|
||||
dnl If no reference was made to various pairs of opposing options, then
|
||||
dnl we run the default mode handler for the pair. For example, if neither
|
||||
dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
|
||||
dnl archives by default:
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
|
||||
[_LT_ENABLE_FAST_INSTALL])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
|
||||
[_LT_WITH_AIX_SONAME([aix])])
|
||||
])
|
||||
])# _LT_SET_OPTIONS
|
||||
|
||||
|
||||
## --------------------------------- ##
|
||||
## Macros to handle LT_INIT options. ##
|
||||
## --------------------------------- ##
|
||||
|
||||
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
|
||||
# -----------------------------------------
|
||||
m4_define([_LT_MANGLE_DEFUN],
|
||||
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
|
||||
|
||||
|
||||
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
|
||||
# -----------------------------------------------
|
||||
m4_define([LT_OPTION_DEFINE],
|
||||
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
|
||||
])# LT_OPTION_DEFINE
|
||||
|
||||
|
||||
# dlopen
|
||||
# ------
|
||||
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
|
||||
])
|
||||
|
||||
AU_DEFUN([AC_LIBTOOL_DLOPEN],
|
||||
[_LT_SET_OPTION([LT_INIT], [dlopen])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the 'dlopen' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
|
||||
|
||||
|
||||
# win32-dll
|
||||
# ---------
|
||||
# Declare package support for building win32 dll's.
|
||||
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
|
||||
[enable_win32_dll=yes
|
||||
|
||||
case $host in
|
||||
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
|
||||
AC_CHECK_TOOL(AS, as, false)
|
||||
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
|
||||
AC_CHECK_TOOL(OBJDUMP, objdump, false)
|
||||
;;
|
||||
esac
|
||||
|
||||
test -z "$AS" && AS=as
|
||||
_LT_DECL([], [AS], [1], [Assembler program])dnl
|
||||
|
||||
test -z "$DLLTOOL" && DLLTOOL=dlltool
|
||||
_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
|
||||
|
||||
test -z "$OBJDUMP" && OBJDUMP=objdump
|
||||
_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
|
||||
])# win32-dll
|
||||
|
||||
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
|
||||
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
|
||||
_LT_SET_OPTION([LT_INIT], [win32-dll])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the 'win32-dll' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
|
||||
|
||||
|
||||
# _LT_ENABLE_SHARED([DEFAULT])
|
||||
# ----------------------------
|
||||
# implement the --enable-shared flag, and supports the 'shared' and
|
||||
# 'disable-shared' LT_INIT options.
|
||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
|
||||
m4_define([_LT_ENABLE_SHARED],
|
||||
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([shared],
|
||||
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
|
||||
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_shared=yes ;;
|
||||
no) enable_shared=no ;;
|
||||
*)
|
||||
enable_shared=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
||||
for pkg in $enableval; do
|
||||
IFS=$lt_save_ifs
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_shared=yes
|
||||
fi
|
||||
done
|
||||
IFS=$lt_save_ifs
|
||||
;;
|
||||
esac],
|
||||
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
|
||||
|
||||
_LT_DECL([build_libtool_libs], [enable_shared], [0],
|
||||
[Whether or not to build shared libraries])
|
||||
])# _LT_ENABLE_SHARED
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
|
||||
|
||||
# Old names:
|
||||
AC_DEFUN([AC_ENABLE_SHARED],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
|
||||
])
|
||||
|
||||
AC_DEFUN([AC_DISABLE_SHARED],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-shared])
|
||||
])
|
||||
|
||||
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
|
||||
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
|
||||
|
||||
|
||||
|
||||
# _LT_ENABLE_STATIC([DEFAULT])
|
||||
# ----------------------------
|
||||
# implement the --enable-static flag, and support the 'static' and
|
||||
# 'disable-static' LT_INIT options.
|
||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
|
||||
m4_define([_LT_ENABLE_STATIC],
|
||||
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([static],
|
||||
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
|
||||
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_static=yes ;;
|
||||
no) enable_static=no ;;
|
||||
*)
|
||||
enable_static=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
||||
for pkg in $enableval; do
|
||||
IFS=$lt_save_ifs
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_static=yes
|
||||
fi
|
||||
done
|
||||
IFS=$lt_save_ifs
|
||||
;;
|
||||
esac],
|
||||
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
|
||||
|
||||
_LT_DECL([build_old_libs], [enable_static], [0],
|
||||
[Whether or not to build static libraries])
|
||||
])# _LT_ENABLE_STATIC
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
|
||||
|
||||
# Old names:
|
||||
AC_DEFUN([AC_ENABLE_STATIC],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
|
||||
])
|
||||
|
||||
AC_DEFUN([AC_DISABLE_STATIC],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-static])
|
||||
])
|
||||
|
||||
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
|
||||
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
|
||||
|
||||
|
||||
|
||||
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
|
||||
# ----------------------------------
|
||||
# implement the --enable-fast-install flag, and support the 'fast-install'
|
||||
# and 'disable-fast-install' LT_INIT options.
|
||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
|
||||
m4_define([_LT_ENABLE_FAST_INSTALL],
|
||||
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([fast-install],
|
||||
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
|
||||
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_fast_install=yes ;;
|
||||
no) enable_fast_install=no ;;
|
||||
*)
|
||||
enable_fast_install=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
||||
for pkg in $enableval; do
|
||||
IFS=$lt_save_ifs
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_fast_install=yes
|
||||
fi
|
||||
done
|
||||
IFS=$lt_save_ifs
|
||||
;;
|
||||
esac],
|
||||
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
|
||||
|
||||
_LT_DECL([fast_install], [enable_fast_install], [0],
|
||||
[Whether or not to optimize for fast installation])dnl
|
||||
])# _LT_ENABLE_FAST_INSTALL
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
|
||||
|
||||
# Old names:
|
||||
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
|
||||
the 'fast-install' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
|
||||
the 'disable-fast-install' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
|
||||
|
||||
|
||||
# _LT_WITH_AIX_SONAME([DEFAULT])
|
||||
# ----------------------------------
|
||||
# implement the --with-aix-soname flag, and support the `aix-soname=aix'
|
||||
# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
|
||||
# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'.
|
||||
m4_define([_LT_WITH_AIX_SONAME],
|
||||
[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
|
||||
shared_archive_member_spec=
|
||||
case $host,$enable_shared in
|
||||
power*-*-aix[[5-9]]*,yes)
|
||||
AC_MSG_CHECKING([which variant of shared library versioning to provide])
|
||||
AC_ARG_WITH([aix-soname],
|
||||
[AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
|
||||
[shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
|
||||
[case $withval in
|
||||
aix|svr4|both)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([Unknown argument to --with-aix-soname])
|
||||
;;
|
||||
esac
|
||||
lt_cv_with_aix_soname=$with_aix_soname],
|
||||
[AC_CACHE_VAL([lt_cv_with_aix_soname],
|
||||
[lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
|
||||
with_aix_soname=$lt_cv_with_aix_soname])
|
||||
AC_MSG_RESULT([$with_aix_soname])
|
||||
if test aix != "$with_aix_soname"; then
|
||||
# For the AIX way of multilib, we name the shared archive member
|
||||
# based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
|
||||
# and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
|
||||
# Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
|
||||
# the AIX toolchain works better with OBJECT_MODE set (default 32).
|
||||
if test 64 = "${OBJECT_MODE-32}"; then
|
||||
shared_archive_member_spec=shr_64
|
||||
else
|
||||
shared_archive_member_spec=shr
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
with_aix_soname=aix
|
||||
;;
|
||||
esac
|
||||
|
||||
_LT_DECL([], [shared_archive_member_spec], [0],
|
||||
[Shared archive member basename, for filename based shared library versioning on AIX])dnl
|
||||
])# _LT_WITH_AIX_SONAME
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
|
||||
|
||||
|
||||
# _LT_WITH_PIC([MODE])
|
||||
# --------------------
|
||||
# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
|
||||
# LT_INIT options.
|
||||
# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'.
|
||||
m4_define([_LT_WITH_PIC],
|
||||
[AC_ARG_WITH([pic],
|
||||
[AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
|
||||
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
|
||||
[lt_p=${PACKAGE-default}
|
||||
case $withval in
|
||||
yes|no) pic_mode=$withval ;;
|
||||
*)
|
||||
pic_mode=default
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
||||
for lt_pkg in $withval; do
|
||||
IFS=$lt_save_ifs
|
||||
if test "X$lt_pkg" = "X$lt_p"; then
|
||||
pic_mode=yes
|
||||
fi
|
||||
done
|
||||
IFS=$lt_save_ifs
|
||||
;;
|
||||
esac],
|
||||
[pic_mode=m4_default([$1], [default])])
|
||||
|
||||
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
|
||||
])# _LT_WITH_PIC
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
|
||||
|
||||
# Old name:
|
||||
AU_DEFUN([AC_LIBTOOL_PICMODE],
|
||||
[_LT_SET_OPTION([LT_INIT], [pic-only])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the 'pic-only' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
|
||||
|
||||
## ----------------- ##
|
||||
## LTDL_INIT Options ##
|
||||
## ----------------- ##
|
||||
|
||||
m4_define([_LTDL_MODE], [])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
|
||||
[m4_define([_LTDL_MODE], [nonrecursive])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
|
||||
[m4_define([_LTDL_MODE], [recursive])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
|
||||
[m4_define([_LTDL_MODE], [subproject])])
|
||||
|
||||
m4_define([_LTDL_TYPE], [])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [installable],
|
||||
[m4_define([_LTDL_TYPE], [installable])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
|
||||
[m4_define([_LTDL_TYPE], [convenience])])
|
|
@ -0,0 +1,124 @@
|
|||
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
|
||||
#
|
||||
# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
|
||||
# Foundation, Inc.
|
||||
# Written by Gary V. Vaughan, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 6 ltsugar.m4
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
|
||||
|
||||
|
||||
# lt_join(SEP, ARG1, [ARG2...])
|
||||
# -----------------------------
|
||||
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
|
||||
# associated separator.
|
||||
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
|
||||
# versions in m4sugar had bugs.
|
||||
m4_define([lt_join],
|
||||
[m4_if([$#], [1], [],
|
||||
[$#], [2], [[$2]],
|
||||
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
|
||||
m4_define([_lt_join],
|
||||
[m4_if([$#$2], [2], [],
|
||||
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
|
||||
|
||||
|
||||
# lt_car(LIST)
|
||||
# lt_cdr(LIST)
|
||||
# ------------
|
||||
# Manipulate m4 lists.
|
||||
# These macros are necessary as long as will still need to support
|
||||
# Autoconf-2.59, which quotes differently.
|
||||
m4_define([lt_car], [[$1]])
|
||||
m4_define([lt_cdr],
|
||||
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
|
||||
[$#], 1, [],
|
||||
[m4_dquote(m4_shift($@))])])
|
||||
m4_define([lt_unquote], $1)
|
||||
|
||||
|
||||
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
|
||||
# ------------------------------------------
|
||||
# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
|
||||
# Note that neither SEPARATOR nor STRING are expanded; they are appended
|
||||
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
|
||||
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
|
||||
# than defined and empty).
|
||||
#
|
||||
# This macro is needed until we can rely on Autoconf 2.62, since earlier
|
||||
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
|
||||
m4_define([lt_append],
|
||||
[m4_define([$1],
|
||||
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
|
||||
|
||||
|
||||
|
||||
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
|
||||
# ----------------------------------------------------------
|
||||
# Produce a SEP delimited list of all paired combinations of elements of
|
||||
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
|
||||
# has the form PREFIXmINFIXSUFFIXn.
|
||||
# Needed until we can rely on m4_combine added in Autoconf 2.62.
|
||||
m4_define([lt_combine],
|
||||
[m4_if(m4_eval([$# > 3]), [1],
|
||||
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
|
||||
[[m4_foreach([_Lt_prefix], [$2],
|
||||
[m4_foreach([_Lt_suffix],
|
||||
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
|
||||
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
|
||||
|
||||
|
||||
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
|
||||
# -----------------------------------------------------------------------
|
||||
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
|
||||
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
|
||||
m4_define([lt_if_append_uniq],
|
||||
[m4_ifdef([$1],
|
||||
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
|
||||
[lt_append([$1], [$2], [$3])$4],
|
||||
[$5])],
|
||||
[lt_append([$1], [$2], [$3])$4])])
|
||||
|
||||
|
||||
# lt_dict_add(DICT, KEY, VALUE)
|
||||
# -----------------------------
|
||||
m4_define([lt_dict_add],
|
||||
[m4_define([$1($2)], [$3])])
|
||||
|
||||
|
||||
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
|
||||
# --------------------------------------------
|
||||
m4_define([lt_dict_add_subkey],
|
||||
[m4_define([$1($2:$3)], [$4])])
|
||||
|
||||
|
||||
# lt_dict_fetch(DICT, KEY, [SUBKEY])
|
||||
# ----------------------------------
|
||||
m4_define([lt_dict_fetch],
|
||||
[m4_ifval([$3],
|
||||
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
|
||||
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
|
||||
|
||||
|
||||
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
|
||||
# -----------------------------------------------------------------
|
||||
m4_define([lt_if_dict_fetch],
|
||||
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
|
||||
[$5],
|
||||
[$6])])
|
||||
|
||||
|
||||
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
|
||||
# --------------------------------------------------------------
|
||||
m4_define([lt_dict_filter],
|
||||
[m4_if([$5], [], [],
|
||||
[lt_join(m4_quote(m4_default([$4], [[, ]])),
|
||||
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
|
||||
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
|
||||
])
|
|
@ -0,0 +1,23 @@
|
|||
# ltversion.m4 -- version numbers -*- Autoconf -*-
|
||||
#
|
||||
# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
|
||||
# Written by Scott James Remnant, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# @configure_input@
|
||||
|
||||
# serial 4179 ltversion.m4
|
||||
# This file is part of GNU Libtool
|
||||
|
||||
m4_define([LT_PACKAGE_VERSION], [2.4.6])
|
||||
m4_define([LT_PACKAGE_REVISION], [2.4.6])
|
||||
|
||||
AC_DEFUN([LTVERSION_VERSION],
|
||||
[macro_version='2.4.6'
|
||||
macro_revision='2.4.6'
|
||||
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
|
||||
_LT_DECL(, macro_revision, 0)
|
||||
])
|
|
@ -0,0 +1,99 @@
|
|||
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
|
||||
#
|
||||
# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
|
||||
# Foundation, Inc.
|
||||
# Written by Scott James Remnant, 2004.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 5 lt~obsolete.m4
|
||||
|
||||
# These exist entirely to fool aclocal when bootstrapping libtool.
|
||||
#
|
||||
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
|
||||
# which have later been changed to m4_define as they aren't part of the
|
||||
# exported API, or moved to Autoconf or Automake where they belong.
|
||||
#
|
||||
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
|
||||
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
|
||||
# using a macro with the same name in our local m4/libtool.m4 it'll
|
||||
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
|
||||
# and doesn't know about Autoconf macros at all.)
|
||||
#
|
||||
# So we provide this file, which has a silly filename so it's always
|
||||
# included after everything else. This provides aclocal with the
|
||||
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
|
||||
# because those macros already exist, or will be overwritten later.
|
||||
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
|
||||
#
|
||||
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
|
||||
# Yes, that means every name once taken will need to remain here until
|
||||
# we give up compatibility with versions before 1.7, at which point
|
||||
# we need to keep only those names which we still refer to.
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
|
||||
|
||||
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
|
||||
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
|
||||
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
|
||||
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
|
||||
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
|
||||
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
|
||||
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
|
||||
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
|
||||
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
|
||||
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
|
||||
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
|
||||
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
|
||||
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
|
||||
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
|
||||
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
|
||||
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
|
||||
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
|
||||
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
|
||||
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
|
||||
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
|
||||
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
|
||||
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
|
||||
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
|
||||
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
|
||||
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
|
||||
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
|
||||
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
|
||||
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
|
||||
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
|
||||
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
|
||||
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
|
||||
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
|
||||
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
|
||||
m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
|
||||
m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
|
||||
m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
|
||||
m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
|
||||
m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
|
||||
m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
|
||||
m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
|
|
@ -0,0 +1,215 @@
|
|||
#! /bin/sh
|
||||
# Common wrapper for a few potentially missing GNU programs.
|
||||
|
||||
scriptversion=2013-10-28.13; # UTC
|
||||
|
||||
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
|
||||
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
if test $# -eq 0; then
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
|
||||
--is-lightweight)
|
||||
# Used by our autoconf macros to check whether the available missing
|
||||
# script is modern enough.
|
||||
exit 0
|
||||
;;
|
||||
|
||||
--run)
|
||||
# Back-compat with the calling convention used by older automake.
|
||||
shift
|
||||
;;
|
||||
|
||||
-h|--h|--he|--hel|--help)
|
||||
echo "\
|
||||
$0 [OPTION]... PROGRAM [ARGUMENT]...
|
||||
|
||||
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
|
||||
to PROGRAM being missing or too old.
|
||||
|
||||
Options:
|
||||
-h, --help display this help and exit
|
||||
-v, --version output version information and exit
|
||||
|
||||
Supported PROGRAM values:
|
||||
aclocal autoconf autoheader autom4te automake makeinfo
|
||||
bison yacc flex lex help2man
|
||||
|
||||
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
|
||||
'g' are ignored when checking the name.
|
||||
|
||||
Send bug reports to <bug-automake@gnu.org>."
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "missing $scriptversion (GNU Automake)"
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-*)
|
||||
echo 1>&2 "$0: unknown '$1' option"
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
# Run the given program, remember its exit status.
|
||||
"$@"; st=$?
|
||||
|
||||
# If it succeeded, we are done.
|
||||
test $st -eq 0 && exit 0
|
||||
|
||||
# Also exit now if we it failed (or wasn't found), and '--version' was
|
||||
# passed; such an option is passed most likely to detect whether the
|
||||
# program is present and works.
|
||||
case $2 in --version|--help) exit $st;; esac
|
||||
|
||||
# Exit code 63 means version mismatch. This often happens when the user
|
||||
# tries to use an ancient version of a tool on a file that requires a
|
||||
# minimum version.
|
||||
if test $st -eq 63; then
|
||||
msg="probably too old"
|
||||
elif test $st -eq 127; then
|
||||
# Program was missing.
|
||||
msg="missing on your system"
|
||||
else
|
||||
# Program was found and executed, but failed. Give up.
|
||||
exit $st
|
||||
fi
|
||||
|
||||
perl_URL=http://www.perl.org/
|
||||
flex_URL=http://flex.sourceforge.net/
|
||||
gnu_software_URL=http://www.gnu.org/software
|
||||
|
||||
program_details ()
|
||||
{
|
||||
case $1 in
|
||||
aclocal|automake)
|
||||
echo "The '$1' program is part of the GNU Automake package:"
|
||||
echo "<$gnu_software_URL/automake>"
|
||||
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/autoconf>"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
autoconf|autom4te|autoheader)
|
||||
echo "The '$1' program is part of the GNU Autoconf package:"
|
||||
echo "<$gnu_software_URL/autoconf/>"
|
||||
echo "It also requires GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice ()
|
||||
{
|
||||
# Normalize program name to check for.
|
||||
normalized_program=`echo "$1" | sed '
|
||||
s/^gnu-//; t
|
||||
s/^gnu//; t
|
||||
s/^g//; t'`
|
||||
|
||||
printf '%s\n' "'$1' is $msg."
|
||||
|
||||
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
|
||||
case $normalized_program in
|
||||
autoconf*)
|
||||
echo "You should only need it if you modified 'configure.ac',"
|
||||
echo "or m4 files included by it."
|
||||
program_details 'autoconf'
|
||||
;;
|
||||
autoheader*)
|
||||
echo "You should only need it if you modified 'acconfig.h' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'autoheader'
|
||||
;;
|
||||
automake*)
|
||||
echo "You should only need it if you modified 'Makefile.am' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'automake'
|
||||
;;
|
||||
aclocal*)
|
||||
echo "You should only need it if you modified 'acinclude.m4' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'aclocal'
|
||||
;;
|
||||
autom4te*)
|
||||
echo "You might have modified some maintainer files that require"
|
||||
echo "the 'autom4te' program to be rebuilt."
|
||||
program_details 'autom4te'
|
||||
;;
|
||||
bison*|yacc*)
|
||||
echo "You should only need it if you modified a '.y' file."
|
||||
echo "You may want to install the GNU Bison package:"
|
||||
echo "<$gnu_software_URL/bison/>"
|
||||
;;
|
||||
lex*|flex*)
|
||||
echo "You should only need it if you modified a '.l' file."
|
||||
echo "You may want to install the Fast Lexical Analyzer package:"
|
||||
echo "<$flex_URL>"
|
||||
;;
|
||||
help2man*)
|
||||
echo "You should only need it if you modified a dependency" \
|
||||
"of a man page."
|
||||
echo "You may want to install the GNU Help2man package:"
|
||||
echo "<$gnu_software_URL/help2man/>"
|
||||
;;
|
||||
makeinfo*)
|
||||
echo "You should only need it if you modified a '.texi' file, or"
|
||||
echo "any other file indirectly affecting the aspect of the manual."
|
||||
echo "You might want to install the Texinfo package:"
|
||||
echo "<$gnu_software_URL/texinfo/>"
|
||||
echo "The spurious makeinfo call might also be the consequence of"
|
||||
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
|
||||
echo "want to install GNU make:"
|
||||
echo "<$gnu_software_URL/make/>"
|
||||
;;
|
||||
*)
|
||||
echo "You might have modified some files without having the proper"
|
||||
echo "tools for further handling them. Check the 'README' file, it"
|
||||
echo "often tells you about the needed prerequisites for installing"
|
||||
echo "this package. You may also peek at any GNU archive site, in"
|
||||
echo "case some other package contains this missing '$1' program."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice "$1" | sed -e '1s/^/WARNING: /' \
|
||||
-e '2,$s/^/ /' >&2
|
||||
|
||||
# Propagate the correct exit status (expected to be 127 for a program
|
||||
# not found, 63 for a program that failed due to version mismatch).
|
||||
exit $st
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
|
@ -0,0 +1,7 @@
|
|||
AM_CFLAGS = -Wall
|
||||
|
||||
noinst_PROGRAMS = profile
|
||||
profile_SOURCES = profile.c
|
||||
profile_CPPFLAGS = -I$(top_srcdir)/libass
|
||||
profile_LDADD = $(top_builddir)/libass/.libs/libass.a
|
||||
profile_LDFLAGS = $(AM_LDFLAGS) -static
|
|
@ -0,0 +1,625 @@
|
|||
# Makefile.in generated by automake 1.15 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2014 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
*) echo "am__make_running_with_option: internal error: invalid" \
|
||||
"target option '$${target_option-}' specified" >&2; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
has_opt=no; \
|
||||
sane_makeflags=$$MAKEFLAGS; \
|
||||
if $(am__is_gnu_make); then \
|
||||
sane_makeflags=$$MFLAGS; \
|
||||
else \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
bs=\\; \
|
||||
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
|
||||
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
|
||||
esac; \
|
||||
fi; \
|
||||
skip_next=no; \
|
||||
strip_trailopt () \
|
||||
{ \
|
||||
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
|
||||
}; \
|
||||
for flg in $$sane_makeflags; do \
|
||||
test $$skip_next = yes && { skip_next=no; continue; }; \
|
||||
case $$flg in \
|
||||
*=*|--*) continue;; \
|
||||
-*I) strip_trailopt 'I'; skip_next=yes;; \
|
||||
-*I?*) strip_trailopt 'I';; \
|
||||
-*O) strip_trailopt 'O'; skip_next=yes;; \
|
||||
-*O?*) strip_trailopt 'O';; \
|
||||
-*l) strip_trailopt 'l'; skip_next=yes;; \
|
||||
-*l?*) strip_trailopt 'l';; \
|
||||
-[dEDm]) skip_next=yes;; \
|
||||
-[JT]) skip_next=yes;; \
|
||||
esac; \
|
||||
case $$flg in \
|
||||
*$$target_option*) has_opt=yes; break;; \
|
||||
esac; \
|
||||
done; \
|
||||
test $$has_opt = yes
|
||||
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
|
||||
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
noinst_PROGRAMS = profile$(EXEEXT)
|
||||
subdir = profile
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
|
||||
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
|
||||
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
PROGRAMS = $(noinst_PROGRAMS)
|
||||
am_profile_OBJECTS = profile-profile.$(OBJEXT)
|
||||
profile_OBJECTS = $(am_profile_OBJECTS)
|
||||
profile_DEPENDENCIES = $(top_builddir)/libass/.libs/libass.a
|
||||
AM_V_lt = $(am__v_lt_@AM_V@)
|
||||
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
|
||||
am__v_lt_0 = --silent
|
||||
am__v_lt_1 =
|
||||
profile_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(profile_LDFLAGS) $(LDFLAGS) -o $@
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
|
||||
am__v_P_0 = false
|
||||
am__v_P_1 = :
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_GEN_1 =
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
am__v_at_1 =
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
|
||||
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
am__mv = mv -f
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
|
||||
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
|
||||
$(AM_CFLAGS) $(CFLAGS)
|
||||
AM_V_CC = $(am__v_CC_@AM_V@)
|
||||
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
|
||||
am__v_CC_0 = @echo " CC " $@;
|
||||
am__v_CC_1 =
|
||||
CCLD = $(CC)
|
||||
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
|
||||
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
|
||||
am__v_CCLD_0 = @echo " CCLD " $@;
|
||||
am__v_CCLD_1 =
|
||||
SOURCES = $(profile_SOURCES)
|
||||
DIST_SOURCES = $(profile_SOURCES)
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
|
||||
# Read a list of newline-separated strings from the standard input,
|
||||
# and print each of them once, without duplicates. Input order is
|
||||
# *not* preserved.
|
||||
am__uniquify_input = $(AWK) '\
|
||||
BEGIN { nonempty = 0; } \
|
||||
{ items[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in items) print i; }; } \
|
||||
'
|
||||
# Make sure the list of sources is unique. This is necessary because,
|
||||
# e.g., the same source file might be shared among _SOURCES variables
|
||||
# for different programs/libraries.
|
||||
am__define_uniq_tagged_files = \
|
||||
list='$(am__tagged_files)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | $(am__uniquify_input)`
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
AS = @AS@
|
||||
ASFLAGS = @ASFLAGS@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCAS = @CCAS@
|
||||
CCASDEPMODE = @CCASDEPMODE@
|
||||
CCASFLAGS = @CCASFLAGS@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
|
||||
FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
|
||||
FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
|
||||
FREETYPE_LIBS = @FREETYPE_LIBS@
|
||||
FRIBIDI_CFLAGS = @FRIBIDI_CFLAGS@
|
||||
FRIBIDI_LIBS = @FRIBIDI_LIBS@
|
||||
GREP = @GREP@
|
||||
HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@
|
||||
HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
|
||||
LIBPNG_LIBS = @LIBPNG_LIBS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PKG_CONFIG = @PKG_CONFIG@
|
||||
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
|
||||
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
|
||||
PKG_LIBS_DEFAULT = @PKG_LIBS_DEFAULT@
|
||||
PKG_LIBS_PRIVATE = @PKG_LIBS_PRIVATE@
|
||||
PKG_REQUIRES_DEFAULT = @PKG_REQUIRES_DEFAULT@
|
||||
PKG_REQUIRES_PRIVATE = @PKG_REQUIRES_PRIVATE@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
nasm_check = @nasm_check@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
AM_CFLAGS = -Wall
|
||||
profile_SOURCES = profile.c
|
||||
profile_CPPFLAGS = -I$(top_srcdir)/libass
|
||||
profile_LDADD = $(top_builddir)/libass/.libs/libass.a
|
||||
profile_LDFLAGS = $(AM_LDFLAGS) -static
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .lo .o .obj
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu profile/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --gnu profile/Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
clean-noinstPROGRAMS:
|
||||
@list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
|
||||
echo " rm -f" $$list; \
|
||||
rm -f $$list || exit $$?; \
|
||||
test -n "$(EXEEXT)" || exit 0; \
|
||||
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
|
||||
echo " rm -f" $$list; \
|
||||
rm -f $$list
|
||||
|
||||
profile$(EXEEXT): $(profile_OBJECTS) $(profile_DEPENDENCIES) $(EXTRA_profile_DEPENDENCIES)
|
||||
@rm -f profile$(EXEEXT)
|
||||
$(AM_V_CCLD)$(profile_LINK) $(profile_OBJECTS) $(profile_LDADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profile-profile.Po@am__quote@
|
||||
|
||||
.c.o:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
|
||||
|
||||
.c.obj:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
|
||||
.c.lo:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
|
||||
|
||||
profile-profile.o: profile.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(profile_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profile-profile.o -MD -MP -MF $(DEPDIR)/profile-profile.Tpo -c -o profile-profile.o `test -f 'profile.c' || echo '$(srcdir)/'`profile.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/profile-profile.Tpo $(DEPDIR)/profile-profile.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profile.c' object='profile-profile.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(profile_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profile-profile.o `test -f 'profile.c' || echo '$(srcdir)/'`profile.c
|
||||
|
||||
profile-profile.obj: profile.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(profile_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profile-profile.obj -MD -MP -MF $(DEPDIR)/profile-profile.Tpo -c -o profile-profile.obj `if test -f 'profile.c'; then $(CYGPATH_W) 'profile.c'; else $(CYGPATH_W) '$(srcdir)/profile.c'; fi`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/profile-profile.Tpo $(DEPDIR)/profile-profile.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profile.c' object='profile-profile.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(profile_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profile-profile.obj `if test -f 'profile.c'; then $(CYGPATH_W) 'profile.c'; else $(CYGPATH_W) '$(srcdir)/profile.c'; fi`
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
ID: $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); mkid -fID $$unique
|
||||
tags: tags-am
|
||||
TAGS: tags
|
||||
|
||||
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
$(am__define_uniq_tagged_files); \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: ctags-am
|
||||
|
||||
CTAGS: ctags
|
||||
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
cscopelist: cscopelist-am
|
||||
|
||||
cscopelist-am: $(am__tagged_files)
|
||||
list='$(am__tagged_files)'; \
|
||||
case "$(srcdir)" in \
|
||||
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
|
||||
*) sdir=$(subdir)/$(srcdir) ;; \
|
||||
esac; \
|
||||
for i in $$list; do \
|
||||
if test -f "$$i"; then \
|
||||
echo "$(subdir)/$$i"; \
|
||||
else \
|
||||
echo "$$sdir/$$i"; \
|
||||
fi; \
|
||||
done >> $(top_builddir)/cscope.files
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(PROGRAMS)
|
||||
installdirs:
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
|
||||
mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am:
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
|
||||
clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \
|
||||
ctags-am distclean distclean-compile distclean-generic \
|
||||
distclean-libtool distclean-tags distdir dvi dvi-am html \
|
||||
html-am info info-am install install-am install-data \
|
||||
install-data-am install-dvi install-dvi-am install-exec \
|
||||
install-exec-am install-html install-html-am install-info \
|
||||
install-info-am install-man install-pdf install-pdf-am \
|
||||
install-ps install-ps-am install-strip installcheck \
|
||||
installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
tags tags-am uninstall uninstall-am
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
||||
* Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
|
||||
* Copyright (C) 2013 Rodger Combs <rcombs@rcombs.me>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include "../libass/ass.h"
|
||||
|
||||
typedef struct image_s {
|
||||
int width, height, stride;
|
||||
unsigned char *buffer; // RGB24
|
||||
} image_t;
|
||||
|
||||
ASS_Library *ass_library;
|
||||
ASS_Renderer *ass_renderer;
|
||||
|
||||
void msg_callback(int level, const char *fmt, va_list va, void *data)
|
||||
{
|
||||
if (level > 6)
|
||||
return;
|
||||
printf("libass: ");
|
||||
vprintf(fmt, va);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void init(int frame_w, int frame_h)
|
||||
{
|
||||
ass_library = ass_library_init();
|
||||
if (!ass_library) {
|
||||
printf("ass_library_init failed!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ass_set_message_cb(ass_library, msg_callback, NULL);
|
||||
|
||||
ass_renderer = ass_renderer_init(ass_library);
|
||||
if (!ass_renderer) {
|
||||
printf("ass_renderer_init failed!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ass_set_frame_size(ass_renderer, frame_w, frame_h);
|
||||
ass_set_fonts(ass_renderer, NULL, "Sans", 1, NULL, 1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const int frame_w = 1280;
|
||||
const int frame_h = 720;
|
||||
|
||||
if (argc < 5) {
|
||||
printf("usage: %s <subtitle file> <start time> <fps> <time to render>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
char *subfile = argv[1];
|
||||
double tm = strtod(argv[2], 0);
|
||||
double fps = strtod(argv[3], 0);
|
||||
double time = strtod(argv[4], 0);
|
||||
|
||||
if(fps == 0){
|
||||
printf("fps cannot equal 0\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
init(frame_w, frame_h);
|
||||
ASS_Track *track = ass_read_file(ass_library, subfile, NULL);
|
||||
if (!track) {
|
||||
printf("track init failed!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while(tm < time){
|
||||
ass_render_frame(ass_renderer, track, (int) (tm * 1000), NULL);
|
||||
tm += 1 / fps;
|
||||
}
|
||||
|
||||
ass_free_track(track);
|
||||
ass_renderer_done(ass_renderer);
|
||||
ass_library_done(ass_library);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
AM_CFLAGS = -Wall
|
||||
|
||||
noinst_PROGRAMS = test
|
||||
test_SOURCES = test.c
|
||||
test_CPPFLAGS = -I$(top_srcdir)/libass
|
||||
test_LDADD = $(top_builddir)/libass/.libs/libass.a
|
||||
test_LDFLAGS = $(AM_LDFLAGS) $(LIBPNG_LIBS) -static
|
|
@ -0,0 +1,625 @@
|
|||
# Makefile.in generated by automake 1.15 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2014 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
*) echo "am__make_running_with_option: internal error: invalid" \
|
||||
"target option '$${target_option-}' specified" >&2; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
has_opt=no; \
|
||||
sane_makeflags=$$MAKEFLAGS; \
|
||||
if $(am__is_gnu_make); then \
|
||||
sane_makeflags=$$MFLAGS; \
|
||||
else \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
bs=\\; \
|
||||
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
|
||||
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
|
||||
esac; \
|
||||
fi; \
|
||||
skip_next=no; \
|
||||
strip_trailopt () \
|
||||
{ \
|
||||
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
|
||||
}; \
|
||||
for flg in $$sane_makeflags; do \
|
||||
test $$skip_next = yes && { skip_next=no; continue; }; \
|
||||
case $$flg in \
|
||||
*=*|--*) continue;; \
|
||||
-*I) strip_trailopt 'I'; skip_next=yes;; \
|
||||
-*I?*) strip_trailopt 'I';; \
|
||||
-*O) strip_trailopt 'O'; skip_next=yes;; \
|
||||
-*O?*) strip_trailopt 'O';; \
|
||||
-*l) strip_trailopt 'l'; skip_next=yes;; \
|
||||
-*l?*) strip_trailopt 'l';; \
|
||||
-[dEDm]) skip_next=yes;; \
|
||||
-[JT]) skip_next=yes;; \
|
||||
esac; \
|
||||
case $$flg in \
|
||||
*$$target_option*) has_opt=yes; break;; \
|
||||
esac; \
|
||||
done; \
|
||||
test $$has_opt = yes
|
||||
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
|
||||
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
noinst_PROGRAMS = test$(EXEEXT)
|
||||
subdir = test
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
|
||||
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
|
||||
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
PROGRAMS = $(noinst_PROGRAMS)
|
||||
am_test_OBJECTS = test-test.$(OBJEXT)
|
||||
test_OBJECTS = $(am_test_OBJECTS)
|
||||
test_DEPENDENCIES = $(top_builddir)/libass/.libs/libass.a
|
||||
AM_V_lt = $(am__v_lt_@AM_V@)
|
||||
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
|
||||
am__v_lt_0 = --silent
|
||||
am__v_lt_1 =
|
||||
test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(test_LDFLAGS) $(LDFLAGS) -o $@
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
|
||||
am__v_P_0 = false
|
||||
am__v_P_1 = :
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_GEN_1 =
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
am__v_at_1 =
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
|
||||
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
am__mv = mv -f
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
|
||||
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
|
||||
$(AM_CFLAGS) $(CFLAGS)
|
||||
AM_V_CC = $(am__v_CC_@AM_V@)
|
||||
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
|
||||
am__v_CC_0 = @echo " CC " $@;
|
||||
am__v_CC_1 =
|
||||
CCLD = $(CC)
|
||||
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
|
||||
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
|
||||
am__v_CCLD_0 = @echo " CCLD " $@;
|
||||
am__v_CCLD_1 =
|
||||
SOURCES = $(test_SOURCES)
|
||||
DIST_SOURCES = $(test_SOURCES)
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
|
||||
# Read a list of newline-separated strings from the standard input,
|
||||
# and print each of them once, without duplicates. Input order is
|
||||
# *not* preserved.
|
||||
am__uniquify_input = $(AWK) '\
|
||||
BEGIN { nonempty = 0; } \
|
||||
{ items[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in items) print i; }; } \
|
||||
'
|
||||
# Make sure the list of sources is unique. This is necessary because,
|
||||
# e.g., the same source file might be shared among _SOURCES variables
|
||||
# for different programs/libraries.
|
||||
am__define_uniq_tagged_files = \
|
||||
list='$(am__tagged_files)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | $(am__uniquify_input)`
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
AS = @AS@
|
||||
ASFLAGS = @ASFLAGS@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCAS = @CCAS@
|
||||
CCASDEPMODE = @CCASDEPMODE@
|
||||
CCASFLAGS = @CCASFLAGS@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
|
||||
FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
|
||||
FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
|
||||
FREETYPE_LIBS = @FREETYPE_LIBS@
|
||||
FRIBIDI_CFLAGS = @FRIBIDI_CFLAGS@
|
||||
FRIBIDI_LIBS = @FRIBIDI_LIBS@
|
||||
GREP = @GREP@
|
||||
HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@
|
||||
HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
|
||||
LIBPNG_LIBS = @LIBPNG_LIBS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PKG_CONFIG = @PKG_CONFIG@
|
||||
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
|
||||
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
|
||||
PKG_LIBS_DEFAULT = @PKG_LIBS_DEFAULT@
|
||||
PKG_LIBS_PRIVATE = @PKG_LIBS_PRIVATE@
|
||||
PKG_REQUIRES_DEFAULT = @PKG_REQUIRES_DEFAULT@
|
||||
PKG_REQUIRES_PRIVATE = @PKG_REQUIRES_PRIVATE@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
nasm_check = @nasm_check@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
AM_CFLAGS = -Wall
|
||||
test_SOURCES = test.c
|
||||
test_CPPFLAGS = -I$(top_srcdir)/libass
|
||||
test_LDADD = $(top_builddir)/libass/.libs/libass.a
|
||||
test_LDFLAGS = $(AM_LDFLAGS) $(LIBPNG_LIBS) -static
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .lo .o .obj
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --gnu test/Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
clean-noinstPROGRAMS:
|
||||
@list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
|
||||
echo " rm -f" $$list; \
|
||||
rm -f $$list || exit $$?; \
|
||||
test -n "$(EXEEXT)" || exit 0; \
|
||||
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
|
||||
echo " rm -f" $$list; \
|
||||
rm -f $$list
|
||||
|
||||
test$(EXEEXT): $(test_OBJECTS) $(test_DEPENDENCIES) $(EXTRA_test_DEPENDENCIES)
|
||||
@rm -f test$(EXEEXT)
|
||||
$(AM_V_CCLD)$(test_LINK) $(test_OBJECTS) $(test_LDADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-test.Po@am__quote@
|
||||
|
||||
.c.o:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
|
||||
|
||||
.c.obj:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
|
||||
.c.lo:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
|
||||
|
||||
test-test.o: test.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test-test.o -MD -MP -MF $(DEPDIR)/test-test.Tpo -c -o test-test.o `test -f 'test.c' || echo '$(srcdir)/'`test.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test-test.Tpo $(DEPDIR)/test-test.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test.c' object='test-test.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test-test.o `test -f 'test.c' || echo '$(srcdir)/'`test.c
|
||||
|
||||
test-test.obj: test.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test-test.obj -MD -MP -MF $(DEPDIR)/test-test.Tpo -c -o test-test.obj `if test -f 'test.c'; then $(CYGPATH_W) 'test.c'; else $(CYGPATH_W) '$(srcdir)/test.c'; fi`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test-test.Tpo $(DEPDIR)/test-test.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test.c' object='test-test.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test-test.obj `if test -f 'test.c'; then $(CYGPATH_W) 'test.c'; else $(CYGPATH_W) '$(srcdir)/test.c'; fi`
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
ID: $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); mkid -fID $$unique
|
||||
tags: tags-am
|
||||
TAGS: tags
|
||||
|
||||
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
$(am__define_uniq_tagged_files); \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: ctags-am
|
||||
|
||||
CTAGS: ctags
|
||||
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
cscopelist: cscopelist-am
|
||||
|
||||
cscopelist-am: $(am__tagged_files)
|
||||
list='$(am__tagged_files)'; \
|
||||
case "$(srcdir)" in \
|
||||
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
|
||||
*) sdir=$(subdir)/$(srcdir) ;; \
|
||||
esac; \
|
||||
for i in $$list; do \
|
||||
if test -f "$$i"; then \
|
||||
echo "$(subdir)/$$i"; \
|
||||
else \
|
||||
echo "$$sdir/$$i"; \
|
||||
fi; \
|
||||
done >> $(top_builddir)/cscope.files
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(PROGRAMS)
|
||||
installdirs:
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
|
||||
mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am:
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
|
||||
clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \
|
||||
ctags-am distclean distclean-compile distclean-generic \
|
||||
distclean-libtool distclean-tags distdir dvi dvi-am html \
|
||||
html-am info info-am install install-am install-data \
|
||||
install-data-am install-dvi install-dvi-am install-exec \
|
||||
install-exec-am install-html install-html-am install-info \
|
||||
install-info-am install-man install-pdf install-pdf-am \
|
||||
install-ps install-ps-am install-strip installcheck \
|
||||
installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
tags tags-am uninstall uninstall-am
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
|
||||
* Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
|
||||
*
|
||||
* This file is part of libass.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "../libass/ass.h"
|
||||
#include <png.h>
|
||||
|
||||
typedef struct image_s {
|
||||
int width, height, stride;
|
||||
unsigned char *buffer; // RGB24
|
||||
} image_t;
|
||||
|
||||
ASS_Library *ass_library;
|
||||
ASS_Renderer *ass_renderer;
|
||||
|
||||
void msg_callback(int level, const char *fmt, va_list va, void *data)
|
||||
{
|
||||
if (level > 6)
|
||||
return;
|
||||
printf("libass: ");
|
||||
vprintf(fmt, va);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void write_png(char *fname, image_t *img)
|
||||
{
|
||||
FILE *fp;
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
png_byte **row_pointers;
|
||||
int k;
|
||||
|
||||
png_ptr =
|
||||
png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
fp = NULL;
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
fp = fopen(fname, "wb");
|
||||
if (fp == NULL) {
|
||||
printf("PNG Error opening %s for writing!\n", fname);
|
||||
return;
|
||||
}
|
||||
|
||||
png_init_io(png_ptr, fp);
|
||||
png_set_compression_level(png_ptr, 0);
|
||||
|
||||
png_set_IHDR(png_ptr, info_ptr, img->width, img->height,
|
||||
8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
||||
png_set_bgr(png_ptr);
|
||||
|
||||
row_pointers = (png_byte **) malloc(img->height * sizeof(png_byte *));
|
||||
for (k = 0; k < img->height; k++)
|
||||
row_pointers[k] = img->buffer + img->stride * k;
|
||||
|
||||
png_write_image(png_ptr, row_pointers);
|
||||
png_write_end(png_ptr, info_ptr);
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
|
||||
free(row_pointers);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static void init(int frame_w, int frame_h)
|
||||
{
|
||||
ass_library = ass_library_init();
|
||||
if (!ass_library) {
|
||||
printf("ass_library_init failed!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ass_set_message_cb(ass_library, msg_callback, NULL);
|
||||
|
||||
ass_renderer = ass_renderer_init(ass_library);
|
||||
if (!ass_renderer) {
|
||||
printf("ass_renderer_init failed!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ass_set_frame_size(ass_renderer, frame_w, frame_h);
|
||||
ass_set_fonts(ass_renderer, NULL, "sans-serif",
|
||||
ASS_FONTPROVIDER_AUTODETECT, NULL, 1);
|
||||
}
|
||||
|
||||
static image_t *gen_image(int width, int height)
|
||||
{
|
||||
image_t *img = malloc(sizeof(image_t));
|
||||
img->width = width;
|
||||
img->height = height;
|
||||
img->stride = width * 3;
|
||||
img->buffer = (unsigned char *) calloc(1, height * width * 3);
|
||||
memset(img->buffer, 63, img->stride * img->height);
|
||||
//for (int i = 0; i < height * width * 3; ++i)
|
||||
// img->buffer[i] = (i/3/50) % 100;
|
||||
return img;
|
||||
}
|
||||
|
||||
#define _r(c) ((c)>>24)
|
||||
#define _g(c) (((c)>>16)&0xFF)
|
||||
#define _b(c) (((c)>>8)&0xFF)
|
||||
#define _a(c) ((c)&0xFF)
|
||||
|
||||
static void blend_single(image_t * frame, ASS_Image *img)
|
||||
{
|
||||
int x, y;
|
||||
unsigned char opacity = 255 - _a(img->color);
|
||||
unsigned char r = _r(img->color);
|
||||
unsigned char g = _g(img->color);
|
||||
unsigned char b = _b(img->color);
|
||||
|
||||
unsigned char *src;
|
||||
unsigned char *dst;
|
||||
|
||||
src = img->bitmap;
|
||||
dst = frame->buffer + img->dst_y * frame->stride + img->dst_x * 3;
|
||||
for (y = 0; y < img->h; ++y) {
|
||||
for (x = 0; x < img->w; ++x) {
|
||||
unsigned k = ((unsigned) src[x]) * opacity / 255;
|
||||
// possible endianness problems
|
||||
dst[x * 3] = (k * b + (255 - k) * dst[x * 3]) / 255;
|
||||
dst[x * 3 + 1] = (k * g + (255 - k) * dst[x * 3 + 1]) / 255;
|
||||
dst[x * 3 + 2] = (k * r + (255 - k) * dst[x * 3 + 2]) / 255;
|
||||
}
|
||||
src += img->stride;
|
||||
dst += frame->stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void blend(image_t * frame, ASS_Image *img)
|
||||
{
|
||||
int cnt = 0;
|
||||
while (img) {
|
||||
blend_single(frame, img);
|
||||
++cnt;
|
||||
img = img->next;
|
||||
}
|
||||
printf("%d images blended\n", cnt);
|
||||
}
|
||||
|
||||
char *font_provider_labels[] = {
|
||||
[ASS_FONTPROVIDER_NONE] = "None",
|
||||
[ASS_FONTPROVIDER_AUTODETECT] = "Autodetect",
|
||||
[ASS_FONTPROVIDER_CORETEXT] = "CoreText",
|
||||
[ASS_FONTPROVIDER_FONTCONFIG] = "Fontconfig",
|
||||
[ASS_FONTPROVIDER_DIRECTWRITE]= "DirectWrite",
|
||||
};
|
||||
|
||||
static void print_font_providers(ASS_Library *ass_library)
|
||||
{
|
||||
int i;
|
||||
ASS_DefaultFontProvider *providers;
|
||||
size_t providers_size = 0;
|
||||
ass_get_available_font_providers(ass_library, &providers, &providers_size);
|
||||
printf("test.c: Available font providers (%zu): ", providers_size);
|
||||
for (i = 0; i < providers_size; i++) {
|
||||
const char *separator = i > 0 ? ", ": "";
|
||||
printf("%s'%s'", separator, font_provider_labels[providers[i]]);
|
||||
}
|
||||
printf(".\n");
|
||||
free(providers);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const int frame_w = 1280;
|
||||
const int frame_h = 720;
|
||||
|
||||
if (argc < 4) {
|
||||
printf("usage: %s <image file> <subtitle file> <time>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
char *imgfile = argv[1];
|
||||
char *subfile = argv[2];
|
||||
double tm = strtod(argv[3], 0);
|
||||
|
||||
print_font_providers(ass_library);
|
||||
|
||||
init(frame_w, frame_h);
|
||||
ASS_Track *track = ass_read_file(ass_library, subfile, NULL);
|
||||
if (!track) {
|
||||
printf("track init failed!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ASS_Image *img =
|
||||
ass_render_frame(ass_renderer, track, (int) (tm * 1000), NULL);
|
||||
image_t *frame = gen_image(frame_w, frame_h);
|
||||
blend(frame, img);
|
||||
|
||||
ass_free_track(track);
|
||||
ass_renderer_done(ass_renderer);
|
||||
ass_library_done(ass_library);
|
||||
|
||||
write_png(imgfile, frame);
|
||||
free(frame->buffer);
|
||||
free(frame);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue