MacOS: finer control of the compilation conditions under which Core text and ATSU are used or not.

The compilation conditions depend on the targeted architecture, what version of the SDK is used,
and what MacOS deployment version is used. Under most conditions, a single API is possible,
and no pointer-to-member function is used.
But the code supports building apps that can run both APIs depending on the version of the
running MacOS.

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3-porting@12025 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Manolo Gouy 2016-10-14 09:17:15 +00:00
parent 2b5fbbacfc
commit 7a81273a0c
3 changed files with 144 additions and 68 deletions

View File

@ -30,7 +30,8 @@
#include <ApplicationServices/ApplicationServices.h>
// condition for the ATSU API to be available at compile time
#define HAS_ATSU (!defined(__LP64__) || !__LP64__) && MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11
#define HAS_ATSU ((!defined(__LP64__) || !__LP64__) && MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11 && \
MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
struct Fl_Fontdesc;
@ -152,33 +153,35 @@ protected:
virtual const char *font_name(int num);
virtual void font_name(int num, const char *name);
Fl_Fontdesc* calc_fl_fonts(void);
enum {use_CoreText = 1, use_ATSU};
static int CoreText_or_ATSU;
static void init_CoreText_or_ATSU();
// Next group of functions have alternative CoreText- and ATSU-based implementations.
virtual void text_extents(const char*, int n, int& dx, int& dy, int& w, int& h);
virtual Fl_Font set_fonts(const char* xstarname);
void set_fontname_in_fontdesc(Fl_Fontdesc *f);
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
#if HAS_ATSU && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
enum {use_CoreText = 1, use_ATSU};
static int CoreText_or_ATSU;
static void init_CoreText_or_ATSU();
void draw_CoreText(const char *str, int n, float x, float y);
double width_CoreText(const UniChar* txt, int n);
void text_extents_CoreText(const char*, int n, int& dx, int& dy, int& w, int& h);
void descriptor_init_CoreText(const char* name, Fl_Fontsize Size, Fl_Font_Descriptor *d);
void text_extents_CoreText(const char*, int n, int& dx, int& dy, int& w, int& h);
Fl_Font set_fonts_CoreText(const char* xstarname);
#endif
#if HAS_ATSU
void draw_ATSU(const char *str, int n, float x, float y);
double width_ATSU(const UniChar* txt, int n);
void text_extents_ATSU(const char*, int n, int& dx, int& dy, int& w, int& h);
void descriptor_init_ATSU(const char* name, Fl_Fontsize Size, Fl_Font_Descriptor *d);
void text_extents_ATSU(const char*, int n, int& dx, int& dy, int& w, int& h);
Fl_Font set_fonts_ATSU(const char* xstarname);
#endif
// end of function group
// define 2 kinds of pointers to member function
typedef void (Fl_Quartz_Graphics_Driver::*pter_to_draw_member)(const char *str, int n, float x, float y);
typedef double (Fl_Quartz_Graphics_Driver::*pter_to_width_member)(const UniChar *str, int n);
static pter_to_draw_member CoreText_or_ATSU_draw;
static pter_to_width_member CoreText_or_ATSU_width;
#else
void descriptor_init(const char* name, Fl_Fontsize Size, Fl_Font_Descriptor *d);
#endif
};
class Fl_Quartz_Printer_Graphics_Driver : public Fl_Quartz_Graphics_Driver {

View File

@ -21,6 +21,7 @@
#include "../Darwin/Fl_Darwin_System_Driver.H"
#include <FL/x.H>
#if HAS_ATSU && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
Fl_Quartz_Graphics_Driver::pter_to_draw_member Fl_Quartz_Graphics_Driver::CoreText_or_ATSU_draw;
Fl_Quartz_Graphics_Driver::pter_to_width_member Fl_Quartz_Graphics_Driver::CoreText_or_ATSU_width;
@ -28,7 +29,6 @@ int Fl_Quartz_Graphics_Driver::CoreText_or_ATSU = 0;
void Fl_Quartz_Graphics_Driver::init_CoreText_or_ATSU()
{
#if HAS_ATSU && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
if (Fl_Darwin_System_Driver::calc_mac_os_version() < 100500) {
// before Mac OS 10.5, only ATSU is available
CoreText_or_ATSU = use_ATSU;
@ -39,16 +39,8 @@ void Fl_Quartz_Graphics_Driver::init_CoreText_or_ATSU()
CoreText_or_ATSU_draw = &Fl_Quartz_Graphics_Driver::draw_CoreText;
CoreText_or_ATSU_width = &Fl_Quartz_Graphics_Driver::width_CoreText;
}
#elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
CoreText_or_ATSU = use_ATSU;
CoreText_or_ATSU_draw = &Fl_Quartz_Graphics_Driver::draw_ATSU;
CoreText_or_ATSU_width = &Fl_Quartz_Graphics_Driver::width_ATSU;
#else
CoreText_or_ATSU = use_CoreText;
CoreText_or_ATSU_draw = &Fl_Quartz_Graphics_Driver::draw_CoreText;
CoreText_or_ATSU_width = &Fl_Quartz_Graphics_Driver::width_CoreText;
#endif
}
#endif
/*
* By linking this module, the following static method will instantiate the
@ -66,7 +58,9 @@ Fl_Quartz_Graphics_Driver::Fl_Quartz_Graphics_Driver() : Fl_Graphics_Driver(), g
quartz_line_pattern = 0;
quartz_line_pattern_size = 0;
high_resolution_ = false;
#if HAS_ATSU && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
if (!CoreText_or_ATSU) init_CoreText_or_ATSU();
#endif
}
char Fl_Quartz_Graphics_Driver::can_do_alpha_blending() {

View File

@ -16,6 +16,62 @@
// http://www.fltk.org/str.php
//
/* Implementation of support for two text drawing APIs: Core Text (current) and ATSU (legacy)
The HAS_ATSU macro (defined in Fl_Quartz_Graphics_Driver.H) is true
if and only if ATSU is available at compile time.
The condition
#if HAS_ATSU && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
is true if and only if both APIs are available at compile time.
Depending on what MacOS SDK and what deployment target are used, the code can be
compiled in 2 ways:
1) both APIs are available at compile time and which one is used
is determined at runtime,
or
2) only one API is available.
When both APIs are compiled in, the choice of which one is used at runtime is done
the first time the Fl_Quartz_Graphics_Driver constructor runs, and remains unchanged.
Core Text is selected if the running Mac OS version is 10.5.
The static function init_CoreText_or_ATSU() does this by setting the value
of the class variable CoreText_or_ATSU to either use_CoreText or use_ATSU.
If both APIs are available, several member functions come in groups of 3.
For example, functions draw(), draw_CoreText() and draw_ATSU() are defined. The only
task of draw() is to call either draw_CoreText() or draw_ATSU() depending on
what API has been selected at program start.
If the compilation condition authorizes a single API, one member function
is defined instead of 3 in the other case. For example, a single draw() function
is compiled, and contains the same code as what is called either draw_CoreText()
or draw_ATSU() in the other case.
The ADD_SUFFIX(name, suffix) macro is used so that each function has the
short (e.g., draw) or long (e.g., draw_CoreText) name adequate for
each compilation condition.
The 2 most often used text functions are draw() and width(). Two pointers to member
function are defined. Function init_CoreText_or_ATSU() assigns one with either
draw_CoreText() or draw_ATSU(), and the other with either width_CoreText() or width_ATSU().
The draw() and width() functions only have to dereference one pointer to member
function to call the adequate code.
If the compilation condition authorizes a single text API, only the code related
to this API (say, CoreText) is compiled whereas all code related to the other API
(thus, ATSU) is excluded from compilation. Furthermore, none of the code to
choose API at runtime and to select which member function is called is compiled.
Consequently, no pointer to member function is used.
The condition for both APIs to be compiled-in is
- target i386 or ppc architectures
and
- use SDK 10.5 and < 10.11
and
- set MacOS deployment target < 10.5 (through the -mmacosx-version-min= compilation option)
*/
#include "../../config_lib.h"
#ifdef FL_CFG_GFX_QUARTZ
@ -33,6 +89,12 @@ static CGAffineTransform font_mx = { 1, 0, 0, -1, 0, 0 };
static int fl_free_font = FL_FREE_FONT;
#if HAS_ATSU && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
# define ADD_SUFFIX(name, suffix) name##suffix
#else
# define ADD_SUFFIX(name, suffix) name
#endif
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
static CFMutableDictionaryRef attributes = NULL;
@ -131,14 +193,14 @@ Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name, Fl_Fontsize Size) {
layout = NULL;
#endif
Fl_Quartz_Graphics_Driver *driver = (Fl_Quartz_Graphics_Driver*)&Fl_Graphics_Driver::default_driver();
#if HAS_ATSU
#if HAS_ATSU && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
if (Fl_Quartz_Graphics_Driver::CoreText_or_ATSU == Fl_Quartz_Graphics_Driver::use_ATSU) {
driver->descriptor_init_ATSU(name, size, this);
return;
}
#endif
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
driver->descriptor_init_CoreText(name, size, this);
#else
driver->descriptor_init(name, size, this);
#endif
}
@ -233,14 +295,6 @@ int Fl_Quartz_Graphics_Driver::descent() {
return fl_fontsize->descent + 1;
}
void Fl_Quartz_Graphics_Driver::draw(const char *str, int n, float x, float y) {
(this->*CoreText_or_ATSU_draw)(str, n, x, y);
}
double Fl_Quartz_Graphics_Driver::width(const UniChar* txt, int n) {
return (this->*CoreText_or_ATSU_width)(txt, n);
}
void Fl_Quartz_Graphics_Driver::draw(const char* str, int n, int x, int y) {
draw(str, n, (float)x, y+0.5f);
}
@ -278,14 +332,8 @@ double Fl_Quartz_Graphics_Driver::width(unsigned int wc) {
}
void Fl_Quartz_Graphics_Driver::set_fontname_in_fontdesc(Fl_Fontdesc *f) {
#if HAS_ATSU
if (CoreText_or_ATSU == use_ATSU) {
strlcpy(f->fontname, f->name, ENDOFBUFFER);
return;
}
#endif
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
static void set_fontname_CoreText(Fl_Fontdesc *f) {
CFStringRef cfname = CFStringCreateWithCString(NULL, f->name, kCFStringEncodingUTF8);
CTFontRef ctfont = CTFontCreateWithName(cfname, 0, NULL);
CFRelease(cfname);
@ -293,6 +341,19 @@ void Fl_Quartz_Graphics_Driver::set_fontname_in_fontdesc(Fl_Fontdesc *f) {
CFRelease(ctfont);
CFStringGetCString(cfname, f->fontname, ENDOFBUFFER, kCFStringEncodingUTF8);
CFRelease(cfname);
}
#endif
void Fl_Quartz_Graphics_Driver::set_fontname_in_fontdesc(Fl_Fontdesc *f) {
#if HAS_ATSU && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
if (CoreText_or_ATSU == use_ATSU)
strlcpy(f->fontname, f->name, ENDOFBUFFER);
else
set_fontname_CoreText(f);
#elif HAS_ATSU
strlcpy(f->fontname, f->name, ENDOFBUFFER);
#else
set_fontname_CoreText(f);
#endif
}
@ -323,44 +384,51 @@ void Fl_Quartz_Graphics_Driver::font_name(int num, const char *name) {
Fl_Fontdesc* Fl_Quartz_Graphics_Driver::calc_fl_fonts(void)
{
#if HAS_ATSU
#if HAS_ATSU && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
if (CoreText_or_ATSU == use_ATSU) return built_in_table_full;
#endif
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
return built_in_table_PS;
#elif HAS_ATSU
return built_in_table_full;
#else
return built_in_table_PS;
#endif
}
Fl_Font Fl_Quartz_Graphics_Driver::set_fonts(const char* xstarname)
{
#if HAS_ATSU
if (CoreText_or_ATSU == use_ATSU) return set_fonts_ATSU(xstarname);
#endif
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
return set_fonts_CoreText(xstarname);
#endif
#if HAS_ATSU && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
void Fl_Quartz_Graphics_Driver::draw(const char *str, int n, float x, float y) {
(this->*CoreText_or_ATSU_draw)(str, n, x, y);
}
double Fl_Quartz_Graphics_Driver::width(const UniChar* txt, int n) {
return (this->*CoreText_or_ATSU_width)(txt, n);
}
Fl_Font Fl_Quartz_Graphics_Driver::set_fonts(const char* xstarname)
{
if (CoreText_or_ATSU == use_ATSU) return set_fonts_ATSU(xstarname);
return set_fonts_CoreText(xstarname);
}
void Fl_Quartz_Graphics_Driver::text_extents(const char* txt, int n, int& dx, int& dy, int& w, int& h)
{
#if HAS_ATSU
if (CoreText_or_ATSU == use_ATSU) {
text_extents_ATSU(txt, n, dx, dy, w, h);
return;
}
#endif
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
text_extents_CoreText(txt, n, dx, dy, w, h);
#endif
}
#endif
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
/// CoreText-based code
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
void Fl_Quartz_Graphics_Driver::descriptor_init_CoreText(const char* name, Fl_Fontsize size, Fl_Font_Descriptor *d) {
void Fl_Quartz_Graphics_Driver::ADD_SUFFIX(descriptor_init, _CoreText)(const char* name,
Fl_Fontsize size, Fl_Font_Descriptor *d)
{
CFStringRef str = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8);
d->fontref = CTFontCreateWithName(str, size, NULL);
CGGlyph glyph[2];
@ -441,7 +509,8 @@ static CGFloat variation_selector_width(CFStringRef str16, Fl_Font_Descriptor *f
return retval;
}
double Fl_Quartz_Graphics_Driver::width_CoreText(const UniChar* txt, int n) {
double Fl_Quartz_Graphics_Driver::ADD_SUFFIX(width, _CoreText)(const UniChar* txt, int n)
{
double retval = 0;
UniChar uni;
int i;
@ -511,7 +580,8 @@ double Fl_Quartz_Graphics_Driver::width_CoreText(const UniChar* txt, int n) {
// text extent calculation
void Fl_Quartz_Graphics_Driver::text_extents_CoreText(const char *str8, int n, int &dx, int &dy, int &w, int &h) {
void Fl_Quartz_Graphics_Driver::ADD_SUFFIX(text_extents, _CoreText)(const char *str8, int n,
int &dx, int &dy, int &w, int &h) {
Fl_Font_Descriptor *fl_fontsize = valid_font_descriptor();
UniChar *txt = mac_Utf8_to_Utf16(str8, n, &n);
CFStringRef str16 = CFStringCreateWithCharactersNoCopy(NULL, txt, n, kCFAllocatorNull);
@ -544,7 +614,8 @@ static CGColorRef flcolortocgcolor(Fl_Color i)
return CGColorCreate(cspace, components);
}
void Fl_Quartz_Graphics_Driver::draw_CoreText(const char *str, int n, float x, float y) {
void Fl_Quartz_Graphics_Driver::ADD_SUFFIX(draw, _CoreText)(const char *str, int n, float x, float y)
{
Fl_Font_Descriptor *fl_fontsize = valid_font_descriptor();
// convert to UTF-16 first
UniChar *uniStr = mac_Utf8_to_Utf16(str, n, &n);
@ -601,7 +672,8 @@ static int name_compare(const void *a, const void *b)
}
}
Fl_Font Fl_Quartz_Graphics_Driver::set_fonts_CoreText(const char* xstarname) {
Fl_Font Fl_Quartz_Graphics_Driver::ADD_SUFFIX(set_fonts, _CoreText)(const char* xstarname)
{
#pragma unused ( xstarname )
if (fl_free_font > FL_FREE_FONT) return (Fl_Font)fl_free_font; // if already called
@ -639,10 +711,13 @@ Fl_Font Fl_Quartz_Graphics_Driver::set_fonts_CoreText(const char* xstarname) {
#endif // >= 10.5
#if HAS_ATSU
/// ATSU-based code to support Mac OS < 10.5
void Fl_Quartz_Graphics_Driver::descriptor_init_ATSU(const char* name, Fl_Fontsize size, Fl_Font_Descriptor *d) {
/// ATSU-based code to support Mac OS < 10.5
#if HAS_ATSU
void Fl_Quartz_Graphics_Driver::ADD_SUFFIX(descriptor_init, _ATSU)(const char* name,
Fl_Fontsize size, Fl_Font_Descriptor *d)
{
OSStatus err;
// fill our structure with a few default values
d->ascent = size*3/4.;
@ -695,7 +770,8 @@ void Fl_Quartz_Graphics_Driver::descriptor_init_ATSU(const char* name, Fl_Fontsi
ATSUSetTransientFontMatching (d->layout, true);
}
void Fl_Quartz_Graphics_Driver::draw_ATSU(const char *str, int n, float x, float y) {
void Fl_Quartz_Graphics_Driver::ADD_SUFFIX(draw, _ATSU)(const char *str, int n, float x, float y)
{
Fl_Font_Descriptor *fl_fontsize = valid_font_descriptor();
// convert to UTF-16 first
UniChar *uniStr = mac_Utf8_to_Utf16(str, n, &n);
@ -715,7 +791,7 @@ void Fl_Quartz_Graphics_Driver::draw_ATSU(const char *str, int n, float x, float
CGContextSetShouldAntialias(gc, false);
}
double Fl_Quartz_Graphics_Driver::width_ATSU(const UniChar* txt, int n) {
double Fl_Quartz_Graphics_Driver::ADD_SUFFIX(width, _ATSU)(const UniChar* txt, int n) {
OSStatus err;
Fixed bBefore, bAfter, bAscent, bDescent;
ATSUTextLayout layout;
@ -741,7 +817,9 @@ double Fl_Quartz_Graphics_Driver::width_ATSU(const UniChar* txt, int n) {
return len;
}
void Fl_Quartz_Graphics_Driver::text_extents_ATSU(const char *str8, int n, int &dx, int &dy, int &w, int &h) {
void Fl_Quartz_Graphics_Driver::ADD_SUFFIX(text_extents, _ATSU)(const char *str8, int n,
int &dx, int &dy, int &w, int &h)
{
Fl_Font_Descriptor *fl_fontsize = valid_font_descriptor();
UniChar *txt = mac_Utf8_to_Utf16(str8, n, &n);
OSStatus err;
@ -770,7 +848,8 @@ void Fl_Quartz_Graphics_Driver::text_extents_ATSU(const char *str8, int n, int &
//printf("r: %d l: %d t: %d b: %d w: %d h: %d\n", bbox.right, bbox.left, bbox.top, bbox.bottom, w, h);
}
Fl_Font Fl_Quartz_Graphics_Driver::set_fonts_ATSU(const char* xstarname) {
Fl_Font Fl_Quartz_Graphics_Driver::ADD_SUFFIX(set_fonts, _ATSU)(const char* xstarname)
{
#pragma unused ( xstarname )
if (fl_free_font > FL_FREE_FONT) return (Fl_Font)fl_free_font; // if already called