Skip to content

Commit

Permalink
Support Core Text on Mac OS X 10.5
Browse files Browse the repository at this point in the history
Based on the logic in HarfBuzz's hb-coretext. See:
 1. harfbuzz/harfbuzz#952
 2. harfbuzz/harfbuzz#1180

Core Text was introduced in 10.5, so this is as far back as we can go.

Tested on ppc32 10.5.8 in:
libass#595 (comment)
Manrope Regular failed to be selected by full name,
but other fonts (including other faces of Manrope) worked fine,
so this should be good enough to avoid requiring Fontconfig.

I have tested that the code in the 10.5-compatible branch still works
on 10.13.6 (the newest macOS instance I have access to), but the API
involved is officially "deprecated" and produces deprecation warnings
during compilation unless the build's deployment target is set to a
version below 10.8. In addition, it's not unimaginable that it might
work worse in some specific situations now or in the future: for example,
it uses FSRef, which, according to the docs, is "designed to work
with 32-bit inode numbers", which "may result in performance issues"
on newer systems. As far as I'm aware, Apple doesn't tend to remove
APIs/ABIs completely except when combined with architecture changes,
but it seems the overall safest course of action is:
  * to prefer the newer API if it is available at runtime,
  * and to avoid referencing the older API at all
    if it's known at compile-time to be unnecessary.

To nearly maximize build-environment compatibility,
use Availability.h and CHECK_AVAILABLE:

  * Recent versions of Apple's compiler support __builtin_available for
    OS version detection, and so does modern non-Apple Clang. This is what
    Apple recommends nowadays. However, none of Apple's official compilers
    on macOS up to 10.10 have had this builtin, and no third-party
    compilers besides Clang have ever had it. Non-Clang compilers may
    have issues with Apple's more recent SDK headers anyway, but they're
    perfectly viable with older SDK releases and all the more likely
    to be used when the build is being performed on an older machine,
    e. g. when targeting that same machine, which is precisely where
    the 10.5-compatible code is most likely to be relevant.
    On 10.5 or nearby versions, the build is most likely to use one of
    Apple's old compilers or a custom-built modern upstream GCC.

    Apple's older method of checking for availability at runtime
    is to check whether the symbol's address is NULL, which works
    in all of Apple's compilers and in upstream Clang and GCC.
    We implement this in our CHECK_AVAILABLE macro.

  * There are multiple ways to determine whether the newer symbol
    is declared at all. To keep it simple, avoid a configure check
    and stick to a simple macro check.

    In older versions of Apple's SDK, Core Text headers have reacted to
    "Mac OS X version max allowed" control-knob macros and marked newer
    APIs "unavailable" (making any use of them a compilation error) even
    if they were known to that SDK. However, the exact macros differ
    between SDK versions, and this mechanism (unlike the "version min
    required") has apparently never been exposed in compiler/IDE knobs
    and possibly not publicized at all. Newer SDKs also no longer mark
    symbols unavailable in any case.

    So do the simplest thing and just check for the existence
    of a macro that was introduced in the same SDK version.

  * In 10.5-10.6 SDKs, Core Text used AvailabilityMacros.h and its
    MAC_OS_X_VERSION_MIN_REQUIRED; in later versions, it switched to
    Availability.h and its __MAC_OS_X_VERSION_MIN_REQUIRED with two
    leading underscores. Both headers are available since 10.5, and
    Availability.h is more flexible as it has version iOS macros in
    addition to macOS, which we may need for other APIs in the future,
    so just use Availability.h.
  • Loading branch information
astiob committed Aug 21, 2023
1 parent 847af2a commit 5c15c88
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 3 deletions.
4 changes: 2 additions & 2 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ AS_IF([test "x$enable_coretext" != xno], [
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM( dnl# First test for legacy include
[[#include <ApplicationServices/ApplicationServices.h>]],
[[CTFontDescriptorCopyAttribute(NULL, kCTFontURLAttribute);]]
[[CTFontDescriptorCopyAttribute(NULL, kCTFontNameAttribute);]]
)
], [
pkg_libs="$pkg_libs -framework ApplicationServices -framework CoreFoundation"
Expand All @@ -158,7 +158,7 @@ AS_IF([test "x$enable_coretext" != xno], [
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM( dnl# Otherwise check newer include style
[[#include <CoreText/CoreText.h>]],
[[CTFontDescriptorCopyAttribute(NULL, kCTFontURLAttribute);]]
[[CTFontDescriptorCopyAttribute(NULL, kCTFontNameAttribute);]]
)
], [
pkg_libs="$pkg_libs -framework CoreText -framework CoreFoundation"
Expand Down
24 changes: 23 additions & 1 deletion libass/ass_coretext.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "config.h"
#include "ass_compat.h"

#include <Availability.h>
#include <CoreFoundation/CoreFoundation.h>
#include <TargetConditionals.h>
#if TARGET_OS_IPHONE
Expand Down Expand Up @@ -88,7 +89,28 @@ static bool check_glyph(void *priv, uint32_t code)

static char *get_font_file(CTFontDescriptorRef fontd)
{
CFURLRef url = CTFontDescriptorCopyAttribute(fontd, kCTFontURLAttribute);
CFURLRef url = NULL;
if (false) {}
#ifdef __MAC_10_6
// Declared in SDKs since 10.6, including iOS SDKs
else if (CHECK_AVAILABLE(kCTFontURLAttribute, macOS 10.6, *)) {
url = CTFontDescriptorCopyAttribute(fontd, kCTFontURLAttribute);
}
#endif
#if !TARGET_OS_IPHONE && (!defined(__MAC_10_6) || __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_6)
// ATS is declared deprecated in newer macOS SDKs
// and not declared at all in iOS SDKs
else {
CTFontRef font = CTFontCreateWithFontDescriptor(fontd, 0, NULL);
if (!font)
return NULL;
ATSFontRef ats_font = CTFontGetPlatformFont(font, NULL);
FSRef fs_ref;
if (ATSFontGetFileReference(ats_font, &fs_ref) == noErr)
url = CFURLCreateFromFSRef(NULL, &fs_ref);
CFRelease(font);
}
#endif
if (!url)
return NULL;
CFStringRef path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
Expand Down

0 comments on commit 5c15c88

Please sign in to comment.