summaryrefslogtreecommitdiffstats
path: root/libass
Commit message (Collapse)AuthorAgeFilesLines
* render: avoid crash on negative FontsizeOneric2022-05-011-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | Unlike for some other Style fields, VSFilters (and libass) do not clamp negative Fontsize values to zero. Instead the value remains negative throughout parsing and in rendering something close to the absolute value is used. It is not exactly the absolute value, but a bit more than it and the difference is larger than what would expected from different rounding modes. I'm not sure when this reinterpretation of negative values takes place. It's possible this happens not in VSFilters but GDI. With \fs commands it is not possible to directly specify negative fontsizes as \fs- and \fs+ already have a special different effect altering the fontsize in relation to the current one (and here negative values are discarded). Apart from the VSFilter incompatibility, negative Fontsizes also crash libass either by failing an assert or if those are disabled by a stack-overflow. To fix the crashes and come closer to VSFilter take the absolute value of the fontsize after all parsing is done. We cannot take the absolute value earlier, because tags like \fs- and \fs+ need to work with the original negative value to achieve VSFilter-like results. The crashes were initially discovered by AFL++. Samples: assert-fail_id:000000,sig:06,src:000002,time:929185,execs:48480,op:arith8,pos:343,val:-4 fuzzer_w3:id:000248,sig:06,src:000288,time:2365972,execs:107653,op:havoc,rep:8 Fixes https://github.com/libass/libass/issues/610
* doc: clarify when manual struct edits are allowedOneric2022-04-262-0/+59
|
* doc: document field values differing from ASSOneric2022-04-261-15/+15
|
* doc: state when ass_track_set_feature is legalOneric2022-04-261-0/+1
|
* drawing: remove unused includeOneric2022-04-261-2/+0
| | | | Not used since a0bf40896a4295964bba56dc7edfa020af761f5e.
* render: avoid UB on left shiftsOneric2022-04-262-2/+10
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The two shifts could be used with too large or negative shift operands which is undefined behaviour. To avoid UB but keep VSFilter compatibility, simulate the practical effects of such shifts on x86 Windows instead of directly using a simple shift. The simulated behaviour matches MSYS2's gcc. Clang, gcc and tcc were observed to exhibit different behaviour on Linux, iff the operand was a compile-time constant (they would use an arithmetic right shift instead). Ideally this should be checked against MSVC, but it seems unlikely to deviate since the related x86 instruction SHL/SAL is documented to mask the upper three bits of the count operand. The > 0 check is not present in VSFilter, but we'd like to avoid negative scales and the only possible negative value is INT32_MIN i.e. -2^31. Luckily using zero instead of the (font_scale / INT32_MIN) won't make much difference here. In guliverkli2 parsed drawing coordinates are also int32_t in canvas space and only later multiplied by (64 * m_scale{x,y}) where m_scale combines canvas and drawing scale and is a double. The result is then cast back to int32_t, meaning coordinates absolutley larger than or equal to min(2^(25 + draw_scale_exp) / canvas_scale{x,y}, INT32_MAX) will be turned into INT32_MIN. For the \p32 case this means any drawing without overflow will be at most 2×2 canvas units large. If only some coordinates overflow the result can cover more. In xy-VSFilter drawing coordinates are floating point numbers and parsed as 64-bit IEEE floats, then multiplied by 64 and cast to int32_t. Here a truncation already happens before the scaling values are applied, so any coordinate larger than 2^25 turn into INT32_MIN during initial parsing. For the \p32 this means a non-overflowing drawing is at most 1/32×1/32 canvas units large. As a consequence of this parsing difference, drawing coordinates larger than 2^25 are non-portable showing different behaviour in guliverkli2- and xy-VSFilter. Thus treating \p32 as an effective \fscx0 seems unproblematic, since even when scaling the default height of 288 up to a UHD frame size, 1/32×1/32 canvas units don't extend beyond 1/4 pixel, which unless stacked won't be too noticeable. The remaining left shifts in ass_render.c, should all be safe as they shift a constant 1 and use macros defined by us as the shift operands and blur_radius which is limited to 100. Found by AFL++ and UBSAN. Samples assert-fail+shift9999999_fuzzer_w3:id:000159,sig:04,src:000968+000719,time:452375,execs:57769,op:splice,rep:16 shift125_id:000001,sig:04,src:000008+000014,time:526595,execs:18418,op:splice,rep:8 shift-neg_id:000000,sig:04,src:000008+000014,time:466566,execs:18013,op:splice,rep:16
* parse: avoid UB on double to integer castsOneric2022-04-261-3/+3
| | | | | | | | | | | | | Casting floating point values to an integer type is undefined behaviour if it's not a regular number or the integral part cannot be represented in the integer type. This fixes issues found by UBSAN in libass' public OSS-Fuzz corpus where NAN ("be") or a too large value ("k") was casted to int. Sample IDs (one instance each there are duplicates): OSSFuzz-3617a28ea3900c2603059049ce4c70c01a535a3e OSSFuzz-292a3032ea273cc9dbaaa0a4291dd84e0cc07c65
* parse: replace argtoi with argtoi32Oneric2022-04-262-40/+25
| | | | | | | | | | | | | | | This continues our transition towards fixed-width types to improve VSFilter compatibility regardless of the platform libass is compiled for. Local variables are also switched to int32_t, but struct members are left as is for now. By dropping mystrtoi, which was only used by argtoi, we also fix float-cast-overflow issues in it identified by UBSAN in libass' public OSS-Fuzz corpus. mystroi32 does not suffer from this problem. Sample ID (one instance there are duplicates): OSSFuzz-123cf9a553c5745854037a52e87947721257f1f3fb
* utils: drop unused functionOneric2022-04-171-8/+0
| | | | mystrtoll was not used since 7913e4a64c704a3b82719d70920b5b153b43d254
* doc: mention colour mangling in ass.hOneric2022-04-171-0/+3
|
* ass: fix NULL usage in embedded font parsingOneric2022-04-131-0/+2
| | | | | | | | If fontdata hasn't been allocated yet and an empty line occured NULL was passed to memcpy which is always undefined behaviour (and there was pointer arithmetic on NULL which is also UB). Found by AFL++ and UBSAN.
* rasterizer: fix pointer arithmetic in assertOneric2022-04-131-1/+1
| | | | | | | | path->points can be NULL and any pointer arithmetic on NULL, even NULL + 0, is undefined behaviour. The rest of the function should be safe with NULL. Found by AFL++ and UBSAN.
* Fix linking against static FriBidi on WindowsOleg Oshmyan2022-04-121-0/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | On Windows, symbols from dynamic-link libraries are replaced by pointers that are filled at runtime after loading the libraries. These pointers are given names prefixed by __imp_ and declared in an "import library" that accompanies the main library and is statically linked into consumers that want to use the DLL. For a function symbol, an additional stub function is generated with the original name that simply forwards to a matching __imp_ function-pointer call. In C, an imported function can be declared in two ways: void foo(); ends up calling the stub and wasting a jump at runtime; while __declspec(dllimport) void foo(); replaces foo() calls by (*__imp_foo)() at compile-time (not link-time), which ends up being a simple optimization. For imported objects, stubs are impossible, so only the __imp_ pointers exist and dllimport is mandatory. Many libraries, including libass, export only functions and avoid dllimport in their header files for simplicity. In contrast, FriBidi exports some functions and some objects, so it cannot neglect dllimport. Its solution is to declare all symbols in its header files with dllimport except if FRIBIDI_LIB_STATIC is defined. When libass is compiled without FRIBIDI_LIB_STATIC and linked against a FriBidi static library, references to FriBidi imports try to use __imp_ symbols (due to the dllimport declarations), but they do not exist, so the linking step fails. In general, libass cannot know whether it will be linked to static or dynamic FriBidi. For example, one can build a static libass.lib to embed in a larger project that uses a shared FriBidi.dll. So we cannot tell on our own, without the builder's input, whether we would need to go through __imp_ object pointers or reference objects directly. However, libass does not use any objects from FriBidi. We use only functions, and functions are always safe to use without dllimport, because at link-time the symbol is sure to resolve either to the actual function in the static library or to the stub function in the import library. As a result, we can simply always define FRIBIDI_LIB_STATIC to drop the dllimport declarations, and we will always produce static and dynamic libraries that work equally well with static and dynamic FriBidi. This logic is Windows-specific, and it is plausible that FRIBIDI_LIB_STATIC may break other platforms, so define it only on Windows. Note: FriBidi tries to add the FRIBIDI_LIB_STATIC macro when using `pkg-config --static --cflags`. However, this works only in one of the many pkg-config implementations, pkgconf, and notably not [yet] in the original freedesktop.org pkg-config. Even if it did work consistently, we would still need either to assume we always want --static or to make a possibly incorrect guess as to what kind of linking will ultimately be used for FriBidi. And even if --static is always fine on Windows, we might want to avoid it on other platforms, complicating build logic that people using other build systems would need to replicate.
* cosmetic: fix whitespaceOneric2022-04-041-1/+1
|
* Add partial unicode support for WindowsDr.Smile2022-03-317-34/+497
|
* doc: revise statements regarding pixel_aspectOneric2022-03-281-9/+6
| | | | | | | Since the margins are taken into account and the isotropic-scaling factor cancels out during PAR calculation, calling ass_set_pixel_aspect is only required if the preferable ass_set_storage_size was not called or potentially if non-isotropic scaling is involved.
* doc: fix omissions and simple mistakesOneric2022-03-281-6/+8
| | | | | | | | | | - DirectWrite fontprovider had no doc comment - font directories are not searched recursively - storage size affects more than just PAR and blur - the formula for PAR in (only) the docs was inverted - some comments still referred to "fontconfig" when any system fontprovider was meant - ass_render_frame's change indicator can have false positives
* cosmetic: correct x86 file headersOneric2022-03-272-2/+2
|
* asm/x86: check if cpuid is available before usageOneric2022-03-273-0/+28
| | | | | | | | | | | | | | | | | | The cpuid instruction was only introduced after i486, meaning there are ix86 CPUs on which our default configuration will build but crash during runtime when cpuid is executed. To avoid this, check for the instructions availability by testing if bit 21 of EFLAGS is writable as documented by AMD, Cyrix, Intel and NexGen. AMD, p.165: https://www.amd.com/system/files/TechDocs/24594.pdf Cyrix, p.10: https://www.ardent-tool.com/CPU/docs/Cyrix/MII/94329_2.pdf Intel, ch.3 p.190: https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf NexGen: https://www.ardent-tool.com/CPU/docs/NexGen/cpuid.pdf
* asm/x86: check highest supported leaf for cpuidOneric2022-03-173-27/+33
| | | | | | | | If a higher then supported leaf is requested, at least Intel processors will silently return the data of the highest supported leaf, invalidating the following feature tests. Reported in: https://github.com/libass/libass/pull/603
* Bump LIBASS_VERSION for ASS_FEATURE_WHOLE_TEXT_LAYOUTOleg Oshmyan2022-02-211-1/+1
| | | | | | | Omission in commit c629be7d70548aea282ea4890c51094055ec66e2. This lets consumers detect whether the compile-time ASS_FEATURE_WHOLE_TEXT_LAYOUT enum constant exists.
* ass.h: fix compilation with old gccOneric2022-02-191-1/+5
| | | | | | | | | | | | | | | While the deprecated attribute wass added to GCC in https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=e23bd2185fae41772d012231e005b789b3a9e6dc first released in GCC 3.1.0, support for an argument was only added in https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=9b86d6bb25587db93a322bf5778e9892aaa8b776 first released in GCC 4.5.0. Since we did not check for argument support before, building with a GCC between the above two changes was broken. The commit assumes Clang always supported an argument, but that has not actually been verified. Reported in https://github.com/libass/libass/issues/595
* cosmetic: move deprecations to a separate lineOneric2022-02-191-2/+4
|
* Document which configuration calls are requiredOneric2022-02-191-0/+12
|
* renderer: fix handling of empty clip outlinesDr.Smile2022-02-171-3/+1
| | | | Fixes https://github.com/libass/libass/issues/594.
* Bidi: remember resolved base directionOleg Oshmyan2022-02-141-7/+24
| | | | | | | | | | | | | | | | | | | | | | | | | There used to be a FIXME comment about this, but it was removed in commit 27cc03363cfbddb9877cd547327d56405653add7. Reordering works fine without this *most of the time*, but this is still a bug. It affects one thing only: trailing whitespace in each line/run. Of course, we remove trailing U+0020 SPACE characters from each line regardless of bidi, but Unicode bidi recognizes other whitespace, and we can now also have trailing U+0020 within in-line runs. With right-to-left base direction, all trailing whitespace within each line (after line wrapping) or run are to be placed at the leftmost end in visual order (even if that whitespace is nominally part of a left-to-right embed). Conversely, with our current code that always tells FriBidi the base direction is left-to-right here, trailing whitespace is always placed at the rightmost end of each line, even if it is inside right-to-left text (which makes it appear as *leading* whitespace to the reader). We treat explicit line breaks \N as paragraph separators, where each paragraph can have its own base direction. Therefore, we must remember each paragraph's resolved direction separately.
* Reset baseline shear for each run, like VSFilter, or whole linesOleg Oshmyan2022-02-141-3/+5
| | | | | | | | | | | Without WHOLE_TEXT_LAYOUT, follow VSFilter and reset the baseline for each run. With WHOLE_TEXT_LAYOUT, try to shear each line as a whole. There are still issues though: * \fscx0 glyphs are skipped and do not contribute any shear; * applying shear to each glyph and then scaling it together with the shear makes little sense for whole lines to begin with.
* ass_shaper_shape: combine FriBidi calls that are needlessly splitOleg Oshmyan2022-02-141-9/+15
| | | | | These calls don't perform any bidi or compute anything clever. They just fetch some Unicode properties for each code point.
* Break bidi and shaping around each character with \fsp, like VSFilterOleg Oshmyan2022-02-141-2/+5
| | | | This can be reverted by enabling ASS_FEATURE_WHOLE_TEXT_LAYOUT.
* WHOLE_TEXT_LAYOUT: give HarfBuzz context to shape correctly across runsOleg Oshmyan2022-02-142-15/+23
| | | | | | | | | | | | | | | When WHOLE_TEXT_LAYOUT is disabled, keep calling HarfBuzz with no context at all. It might seem sensible to give it the whole VSFilter-run as context so it could shape Arabic correctly across font fallback in case of weird fonts, but it seems that Uniscribe doesn't behave like this in VSFilter. For testing that, I created a font with only two glyphs: an isolated ain and a medial ain; and a GSUB medi lookup that links them together. Setting \fnMyTestFont on an Arabic word with a medial ain, libass with WHOLE_TEXT_LAYOUT (i. e. HarfBuzz with context) showed the medial shape, but VSFilter (i. e. Uniscribe) showed the isolated shape. BorderStyle 3 confirmed that VSFilter was treating the string as a single run and therefore passing it to GDI/Uniscribe as a whole.
* Run bidi on each glyph run in isolation by default, like VSFilterOleg Oshmyan2022-02-145-11/+61
| | | | | | | | | | | | | | | | | | | Fixes https://code.google.com/archive/p/libass/issues/111. Fixes https://github.com/libass/libass/issues/226 if it was not fixed by commit c93cb3dbfb7357179379ffd19ff973cf062e2129 already. The old ("sane") behavior of running bidi on each event as a whole* can be restored by setting the new ASS_FEATURE_WHOLE_TEXT_LAYOUT. Additionally, in a nod to ASS files and on-the-fly format converters that use libass's nonstandard Encoding -1 for bidi base direction autodetection, make Encoding -1 force WHOLE_TEXT_LAYOUT processing for individual events even when the ASS_Feature is disabled. * Note: we treat explicit line breaks \N as paragraph separators, and effectively bidi is run on each "paragraph" separately. This is standard bidi behavior. Of particular relevance to libass, this is exactly what WebVTT mandates.
* Consistently use x86 asm code if we've built itOleg Oshmyan2022-02-124-4/+4
| | | | | | | | | | | We detect x86 and enable building asm code in `configure`. However, before this commit, we don't actually use that code unless we detect x86 via the C compiler's predefined macros. We could check more macros to support more C compilers, but what we really want is to use the same trigger for both building and using this code. To that end, add ARCH_X86 to config.h iff x86 asm is being built.
* build: use `X86` as the generic name for whole x86 familyOleg Oshmyan2022-02-122-6/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Currently, we use `INTEL` to denote any supported x86 variant and `X64` to denote specifically x86-64 (and previously used `X86` to denote 32-bit x86). `INTEL` is a subpar name for two reasons: * Intel has produced notable non-x86 architectures (Itanium). * x86-64 was designed and patented not by Intel but by AMD. This is currently only used in configure.ac and Makefile.am, so it does not matter much. However, the next commit will expose a config.h macro flagging the whole x86 family, which non-Autotools users will have to set manually, so this will cease being a purely internal choice and will start confusing users. Instead, the most generic name for the whole family that is in common use and does not suffer from such problems is "x86", so use `X86`. The switch is slightly complicated by the fact our configure.ac and Makefile.am used to use `X86` as in Microsoft's naming scheme, where "x86" means "32-bit x86". Ideally, we would use another equally good name for the family that is free from this ambiguity; however, I know no such name. (Indeed, `X86` as a name for 32-bit x86 is problematic even if one disregards x86-64, because 16-bit x86 exists as well. This commit technically leaves configure.ac to lie about 16-bit x86 by setting `X86=false`, but we have no 16-bit assembler code, so the new use of `X86` should be viewed as a name for "any *supported* variant of x86".) To somewhat highlight that we're no longer using Microsoft's scheme, also switch the name for the x86-64 architecture from `X64` to `X86_64`. This should also make it more intuitively obvious that one (X86_64) is a subset of the other (X86). This is also a more standard name with a clearer etymology, and we already use this name in our `ASFLAGS`.
* Round BorderStyle 4 box size equally in all directionsOleg Oshmyan2022-02-121-4/+4
| | | | | | | | Current code uses fractional sizes and truncates the box's coordinates to integers, so the box tends to be bigger on the left and top than on the right and bottom. Instead, lround() the sizes and add them symmetrically on all sides.
* font: handle conversion failure betterApache5532022-01-302-13/+27
| | | | | If a conversion fails for a non-Unicode font, let font fallback happen instead of displaying bogus glyphs.
* font: use iconv to handle non-unicode cmap microsoft fontsApache5532022-01-301-6/+167
| | | | | | | | | Use Windows native API to convert Unicode to MBCS on Windows, then use iconv if not on Windows and iconv is available. Do nothing if neither is available. fix: `ass_font_index_magic` now doesn't mangle codepoint if charmap isn't Microsoft's.
* refactor: do not cast allocationsOneric2022-01-202-7/+7
|
* api: do not leak deprecation macrosOneric2021-12-271-0/+3
|
* Refactor track features to bitflagsOneric2021-12-144-11/+27
| | | | | | This is purely an internal refactor. With the existing and currently planned boolean features, a bit flag will scale better.
* x86: fix AVX detectionOneric2021-12-061-3/+1
| | | | | | | | | The removed check compared some bits from the vendor string to the ones from "GenuineIntel". This blocked AVX and AVX2 from being used on AMD- and other non-Intel-CPUs and even on Intel-CPUs if run in a hypervisor or VM which changes the vendor string (eg " KVMKVMKVM "). Drop the vendor check to utilise AVX on all supporting CPUs.
* build: move private_prefix define to Makefile.amrcombs2021-12-061-1/+1
|
* x86: remove empty filercombs2021-12-061-0/+0
|
* Pass ZWJ/ZWNJ to HarfBuzz across shape run boundariesOleg Oshmyan2021-10-191-3/+22
| | | | | | | | | | | | | | | | | | | | | | | | | | | | ZWJ and the characters next to it may be separated into different shape runs by bidi, script or font-fallback splitting. Nevertheless, ZWJ must affect Arabic-script characters on both sides of itself. This is noted in the description of the Unicode bidirectional algorithm [TR9-Joiners] and matches the observed behavior of VSFilter (GDI/Uniscribe). Fixes https://github.com/libass/libass/issues/545. We could more easily pass the whole event text to HarfBuzz rather than single out ZWJ and ZWNJ, but that would produce results different from VSFilter's: it shapes each high-level run in isolation; and in the rare case that Arabic text is set in a font that is missing some glyphs, GDI/Uniscribe apply font fallback and choose isolated/initial/final letter forms for each section separately, without joining the letters from different fonts together (which HarfBuzz would do if we gave it the full surrounding context), unless an explicit ZWJ is placed in between. Unlike ZWJ, I have not been able to produce a test for ZWNJ that would confirm whether VSFilter does this for ZWNJ as well. It should not matter for Arabic as the boundaries are non-joining by default, but it might make a difference for Indic scripts or others. It seems to make sense, so in absence of evidence to the contrary, this commit applies the same treatment to ZWNJ as well. [TR9-Joiners]: https://unicode.org/reports/tr9/#Joiners
* cache: switch to wyhash for cache tablesrcombs2021-10-182-18/+8
| | | | This is dramatically faster on files with large drawings.
* Add wyhash.hrcombs2021-10-152-1/+269
| | | | | | | This is a very fast hash function for the cache system The version of the header corresponds to https://github.com/wangyi-fudan/wyhash/commit/166f35228204b97ddd8ddead6b7a00467c91fdf6
* cache: give the hash a more generic function namercombs2021-10-153-9/+10
|
* Move the cache function to ass_cache.cOneric2021-10-152-22/+22
|
* outline: refactor and add comments and assertsDr.Smile2021-10-053-117/+179
|
* renderer: eliminate FT_GlyphDr.Smile2021-10-053-45/+29
|
* renderer: consolidate processing of glyph decoration flagsDr.Smile2021-10-055-134/+147
| | | | | | Processing of DECO_ROTATE has moved after ASS_Outline conversion too. All relevant outline processing functions have moved into ass_outline.c. outline_convert() now expects preallocated outline to reduce reallocations.
* rasterizer: use correct memory alignment instead of magic numberDr.Smile2021-09-263-5/+6
|
* rasterizer: use max-blending for outline pair mergeDr.Smile2021-09-265-2/+74
| | | | | | | | | Max-blending is more correct than previous addition-blending in case of small (less than pixel) outline offsets. Fixes buffer overrun (up to 16 bytes read past rst->tile) in add_bitmaps() in case of engine->tile_order < engine->align_order (AVX2 assembly with LARGE_TILES disabled) due to insufficient padding.
* fontselect: don't leak substitution fullname array if it's emptyOleg Oshmyan2021-09-251-0/+1