#include "Fl_Quartz_Graphics_Driver.H"
#include "Fl_Font.H"
#include <math.h>
#include <FL/Fl.H>
#include <FL/platform.H>
#include <FL/fl_utf8.h>
#include <FL/fl_string_functions.h>
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
const NSUInteger kCTFontOrientationHorizontal = kCTFontHorizontalOrientation;
#endif
Fl_Fontdesc* fl_fonts = NULL;
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;
static Fl_Fontdesc built_in_table_PS[] = { {"ArialMT"},
{"Arial-BoldMT"},
{"Arial-ItalicMT"},
{"Arial-BoldItalicMT"},
{"Courier"},
{"Courier-Bold"},
{"Courier-Oblique"},
{"Courier-BoldOblique"},
{"TimesNewRomanPSMT"},
{"TimesNewRomanPS-BoldMT"},
{"TimesNewRomanPS-ItalicMT"},
{"TimesNewRomanPS-BoldItalicMT"},
{"Symbol"},
{"Monaco"},
{"AndaleMono"}, {"ZapfDingbatsITC"}
};
#endif
#if HAS_ATSU
static Fl_Fontdesc built_in_table_full[] = { {"Arial"},
{"Arial Bold"},
{"Arial Italic"},
{"Arial Bold Italic"},
{"Courier"},
{"Courier Bold"},
{"Courier New Italic"},
{"Courier New Bold Italic"},
{"Times New Roman"},
{"Times New Roman Bold"},
{"Times New Roman Italic"},
{"Times New Roman Bold Italic"},
{"Symbol"},
{"Monaco"},
{"Andale Mono"}, {"Webdings"}
};
#endif
#define ENDOFBUFFER sizeof(fl_fonts->fontname)-1
const char* Fl_Quartz_Graphics_Driver::get_font_name(Fl_Font fnum, int* ap) {
if (!fl_fonts) fl_fonts = calc_fl_fonts();
Fl_Fontdesc *f = fl_fonts + fnum;
if (!f->fontname[0]) {
this->set_fontname_in_fontdesc(f);
const char* thisFont = f->name;
if (!thisFont || !*thisFont) {if (ap) *ap = 0; return "";}
int type = 0;
if (strstr(f->name, "Bold")) type |= FL_BOLD;
if (strstr(f->name, "Italic") || strstr(f->name, "Oblique")) type |= FL_ITALIC;
f->fontname[ENDOFBUFFER] = (char)type;
}
if (ap) *ap = f->fontname[ENDOFBUFFER];
return f->fontname;
}
int Fl_Quartz_Graphics_Driver::get_font_sizes(Fl_Font fnum, int*& sizep) {
static int array[128];
if (!fl_fonts) fl_fonts = calc_fl_fonts();
Fl_Fontdesc *s = fl_fonts+fnum;
if (!s->name) s = fl_fonts; int cnt = 0;
array[0] = 0;
sizep = array;
cnt = 1;
return cnt;
}
Fl_Quartz_Font_Descriptor::Fl_Quartz_Font_Descriptor(const char* name, Fl_Fontsize Size) : Fl_Font_Descriptor(name, Size) {
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
fontref = NULL;
#endif
#if HAS_ATSU
layout = NULL;
#endif
Fl_Quartz_Graphics_Driver *driver = (Fl_Quartz_Graphics_Driver*)&Fl_Graphics_Driver::default_driver();
#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;
}
driver->descriptor_init_CoreText(name, size, this);
#else
driver->descriptor_init(name, size, this);
#endif
}
Fl_Quartz_Font_Descriptor::~Fl_Quartz_Font_Descriptor() {
if (this == fl_graphics_driver->font_descriptor()) fl_graphics_driver->font_descriptor(NULL);
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
if (fontref) {
CFRelease(fontref);
for (unsigned i = 0; i < sizeof(width)/sizeof(float*); i++) {
if (width[i]) free(width[i]);
}
}
#endif
#if HAS_ATSU
if (layout) {
ATSUDisposeTextLayout(layout);
ATSUDisposeStyle(style);
}
#endif
}
static UniChar *utfWbuf = 0;
static unsigned utfWlen = 0;
static UniChar *mac_Utf8_to_Utf16(const char *txt, int len, int *new_len)
{
unsigned wlen = fl_utf8toUtf16(txt, len, (unsigned short*)utfWbuf, utfWlen);
if (wlen >= utfWlen)
{
utfWlen = wlen + 100;
if (utfWbuf) free(utfWbuf);
utfWbuf = (UniChar*)malloc((utfWlen)*sizeof(UniChar));
wlen = fl_utf8toUtf16(txt, len, (unsigned short*)utfWbuf, utfWlen);
}
*new_len = wlen;
return utfWbuf;
}
static Fl_Font_Descriptor* find(Fl_Font fnum, Fl_Fontsize size) {
if (!fl_fonts) fl_fonts = Fl_Graphics_Driver::default_driver().calc_fl_fonts();
Fl_Fontdesc* s = fl_fonts+fnum;
if (!s->name) s = fl_fonts; Fl_Font_Descriptor* f;
for (f = s->first; f; f = f->next)
if (f->size == size) return f;
f = new Fl_Quartz_Font_Descriptor(s->name, size);
f->next = s->first;
s->first = f;
return f;
}
void Fl_Quartz_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) {
if (fnum == -1) {
Fl_Graphics_Driver::font(0, 0);
return;
}
Fl_Graphics_Driver::font(fnum, size);
font_descriptor( find(fnum, size) );
}
Fl_Quartz_Font_Descriptor *Fl_Quartz_Graphics_Driver::valid_font_descriptor() {
if (!font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE);
return (Fl_Quartz_Font_Descriptor*)font_descriptor();
}
int Fl_Quartz_Graphics_Driver::height() {
Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor();
return fl_fontsize->ascent + fl_fontsize->descent;
}
int Fl_Quartz_Graphics_Driver::descent() {
Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor();
return fl_fontsize->descent + 1;
}
void Fl_Quartz_Graphics_Driver::draw(const char* str, int n, int x, int y) {
draw(str, n, (float)x, y+0.5f);
}
void Fl_Quartz_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) {
CGContextSaveGState(gc_);
CGContextTranslateCTM(gc_, x, y);
CGContextRotateCTM(gc_, - angle*(M_PI/180) );
draw(str, n, 0, 0);
CGContextRestoreGState(gc_);
}
void Fl_Quartz_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) {
int dx, dy, w, h;
text_extents(c, n, dx, dy, w, h);
draw(c, n, x - w - dx, y);
}
double Fl_Quartz_Graphics_Driver::width(const char* txt, int n) {
int wc_len = n;
UniChar *uniStr = mac_Utf8_to_Utf16(txt, n, &wc_len);
return width(uniStr, wc_len);
}
double Fl_Quartz_Graphics_Driver::width(unsigned int wc) {
UniChar utf16[3];
int l = 1;
if (wc <= 0xFFFF) {
*utf16 = wc;
}
else {
l = (int)fl_ucs_to_Utf16(wc, utf16, 3);
}
return width(utf16, l);
}
#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 = cfname ? CTFontCreateWithName(cfname, 0, NULL) : NULL;
if (cfname) { CFRelease(cfname); cfname = NULL; }
if (ctfont) {
cfname = CTFontCopyFullName(ctfont);
CFRelease(ctfont);
if (cfname) {
CFStringGetCString(cfname, f->fontname, ENDOFBUFFER, kCFStringEncodingUTF8);
CFRelease(cfname);
}
}
if (!cfname) strlcpy(f->fontname, f->name, ENDOFBUFFER);
}
#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
}
const char *Fl_Quartz_Graphics_Driver::font_name(int num) {
if (!fl_fonts) fl_fonts = calc_fl_fonts();
return fl_fonts[num].name;
}
void Fl_Quartz_Graphics_Driver::font_name(int num, const char *name) {
Fl_Fontdesc *s = fl_fonts + num;
if (s->name) {
if (!strcmp(s->name, name)) {s->name = name; return;}
for (Fl_Font_Descriptor* f = s->first; f;) {
Fl_Font_Descriptor* n = f->next; delete f; f = n;
}
s->first = 0;
}
s->name = name;
s->fontname[0] = 0;
s->first = 0;
}
Fl_Fontdesc* Fl_Quartz_Graphics_Driver::calc_fl_fonts(void)
{
#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;
return built_in_table_PS;
#elif HAS_ATSU
return built_in_table_full;
#else
return built_in_table_PS;
#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 (CoreText_or_ATSU == use_ATSU) {
text_extents_ATSU(txt, n, dx, dy, w, h);
return;
}
text_extents_CoreText(txt, n, dx, dy, w, h);
}
#endif
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
void Fl_Quartz_Graphics_Driver::ADD_SUFFIX(descriptor_init, _CoreText)(const char* name,
Fl_Fontsize size, Fl_Quartz_Font_Descriptor *d)
{
CFStringRef str = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8);
d->fontref = CTFontCreateWithName(str, size, NULL);
CGGlyph glyph[2];
const UniChar A[2]={'W','.'};
CTFontGetGlyphsForCharacters(d->fontref, A, glyph, 2);
CGSize advances[2];
double w;
CTFontGetAdvancesForGlyphs(d->fontref, kCTFontOrientationHorizontal, glyph, advances, 2);
w = advances[0].width;
if ( fabs(advances[0].width - advances[1].width) < 1E-2 ) { CFRelease(d->fontref);
CGFloat fsize = size / ( w/floor(w + 0.5) );
d->fontref = CTFontCreateWithName(str, fsize, NULL);
w = CTFontGetAdvancesForGlyphs(d->fontref, kCTFontOrientationHorizontal, glyph, NULL, 1);
}
CFRelease(str);
d->ascent = (short)(CTFontGetAscent(d->fontref) + 0.5);
d->descent = (short)(CTFontGetDescent(d->fontref) + 0.5);
d->q_width = w + 0.5;
for (unsigned i = 0; i < sizeof(d->width)/sizeof(float*); i++) d->width[i] = NULL;
if (!attributes) {
static CFNumberRef zero_ref;
float zero = 0.;
zero_ref = CFNumberCreate(NULL, kCFNumberFloat32Type, &zero);
attributes = CFDictionaryCreateMutable(kCFAllocatorDefault,
3,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue (attributes, kCTKernAttributeName, zero_ref);
}
if (d->ascent == 0) { CFDictionarySetValue (attributes, kCTFontAttributeName, d->fontref);
CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, CFSTR("Wj"), attributes);
CTLineRef ctline = CTLineCreateWithAttributedString(mastr);
CFRelease(mastr);
CGFloat fascent, fdescent;
CTLineGetTypographicBounds(ctline, &fascent, &fdescent, NULL);
CFRelease(ctline);
d->ascent = (short)(fascent + 0.5);
d->descent = (short)(fdescent + 0.5);
}
}
static CGFloat surrogate_width(const UniChar *txt, Fl_Quartz_Font_Descriptor *fl_fontsize)
{
CTFontRef font2 = fl_fontsize->fontref;
bool must_release = false;
CGGlyph glyphs[2];
bool b = CTFontGetGlyphsForCharacters(font2, txt, glyphs, 2);
CGSize a;
if(!b) { CFStringRef str = CFStringCreateWithCharactersNoCopy(NULL, txt, 2, kCFAllocatorNull);
font2 = CTFontCreateForString(font2, str, CFRangeMake(0,2));
must_release = true;
CFRelease(str);
b = CTFontGetGlyphsForCharacters(font2, txt, glyphs, 2);
}
if (b) CTFontGetAdvancesForGlyphs(font2, kCTFontOrientationHorizontal, glyphs, &a, 1);
else a.width = fl_fontsize->q_width;
if(must_release) CFRelease(font2);
return a.width;
}
static CGFloat variation_selector_width(CFStringRef str16, Fl_Quartz_Font_Descriptor *fl_fontsize)
{
CGFloat retval;
CFDictionarySetValue(attributes, kCTFontAttributeName, fl_fontsize->fontref);
CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str16, attributes);
CTLineRef ctline = CTLineCreateWithAttributedString(mastr);
CFRelease(mastr);
retval = CTLineGetOffsetForStringIndex(ctline, 2, NULL);
CFRelease(ctline);
return retval;
}
double Fl_Quartz_Graphics_Driver::ADD_SUFFIX(width, _CoreText)(const UniChar* txt, int n)
{
double retval = 0;
UniChar uni;
int i;
Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor();
for (i = 0; i < n; i++) { uni = txt[i];
if (uni >= 0xD800 && uni <= 0xDBFF) { retval += surrogate_width(&txt[i], fl_fontsize);
i++; continue;
}
if (i+1 < n && txt[i+1] >= 0xFE00 && txt[i+1] <= 0xFE0F) { CFStringRef substr = CFStringCreateWithCharacters(NULL, txt + i, 2);
retval += variation_selector_width(substr, fl_fontsize);
CFRelease(substr);
i++;
continue;
}
const int block = 0x10000 / (sizeof(fl_fontsize->width)/sizeof(float*)); unsigned int r = uni >> 7; if (!fl_fontsize->width[r]) { fl_fontsize->width[r] = (float*) malloc(sizeof(float) * block);
UniChar ii = r * block;
CGSize advance_size;
CGGlyph glyph;
for (int j = 0; j < block; j++) { bool b = CTFontGetGlyphsForCharacters(fl_fontsize->fontref, &ii, &glyph, 1);
if (b)
CTFontGetAdvancesForGlyphs(fl_fontsize->fontref, kCTFontOrientationHorizontal, &glyph, &advance_size, 1);
else
advance_size.width = -1e9; fl_fontsize->width[r][j] = advance_size.width;
ii++;
}
}
double wdt = fl_fontsize->width[r][uni & (block-1)];
if (wdt == -1e9) {
CGSize advance_size;
CGGlyph glyph;
CTFontRef font2 = fl_fontsize->fontref;
bool must_release = false;
bool b = CTFontGetGlyphsForCharacters(font2, &uni, &glyph, 1);
if (!b) { CFStringRef str = CFStringCreateWithCharactersNoCopy(NULL, &uni, 1, kCFAllocatorNull);
font2 = CTFontCreateForString(font2, str, CFRangeMake(0,1));
must_release = true;
CFRelease(str);
b = CTFontGetGlyphsForCharacters(font2, &uni, &glyph, 1);
}
if (b) CTFontGetAdvancesForGlyphs(font2, kCTFontOrientationHorizontal, &glyph, &advance_size, 1);
else advance_size.width = 0.;
wdt = fl_fontsize->width[r][uni & (block-1)] = advance_size.width;
if (must_release) CFRelease(font2);
}
retval += wdt;
}
return retval;
}
void Fl_Quartz_Graphics_Driver::ADD_SUFFIX(text_extents, _CoreText)(const char *str8, int n,
int &dx, int &dy, int &w, int &h) {
Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor();
UniChar *txt = mac_Utf8_to_Utf16(str8, n, &n);
CFStringRef str16 = CFStringCreateWithCharactersNoCopy(NULL, txt, n, kCFAllocatorNull);
CFDictionarySetValue (attributes, kCTFontAttributeName, fl_fontsize->fontref);
CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str16, attributes);
CFRelease(str16);
CTLineRef ctline = CTLineCreateWithAttributedString(mastr);
CFRelease(mastr);
CGContextSetTextPosition(gc_, 0, 0);
CGContextSetShouldAntialias(gc_, true);
CGRect rect = CTLineGetImageBounds(ctline, gc_);
CGContextSetShouldAntialias(gc_, false);
CFRelease(ctline);
dx = floor(rect.origin.x + 0.5);
dy = floor(- rect.origin.y - rect.size.height + 0.5);
w = rect.size.width + 0.5;
h = rect.size.height + 0.5;
}
static CGColorRef flcolortocgcolor(Fl_Color i)
{
uchar r, g, b;
Fl::get_color(i, r, g, b);
CGFloat components[4] = {r/255.0f, g/255.0f, b/255.0f, 1.};
static CGColorSpaceRef cspace = NULL;
if (cspace == NULL) {
cspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
}
return CGColorCreate(cspace, components);
}
void Fl_Quartz_Graphics_Driver::ADD_SUFFIX(draw, _CoreText)(const char *str, int n, float x, float y)
{
Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor();
UniChar *uniStr = mac_Utf8_to_Utf16(str, n, &n);
CGContextRef gc = (CGContextRef)this->gc();
CFMutableStringRef str16 = CFStringCreateMutableWithExternalCharactersNoCopy(NULL, uniStr, n, n, kCFAllocatorNull);
if (str16 == NULL) return; CGColorRef color = flcolortocgcolor(this->color());
CFDictionarySetValue (attributes, kCTFontAttributeName, fl_fontsize->fontref);
CFDictionarySetValue (attributes, kCTForegroundColorAttributeName, color);
CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str16, attributes);
CFRelease(str16);
CFRelease(color);
CTLineRef ctline = CTLineCreateWithAttributedString(mastr);
CFRelease(mastr);
CGContextSetTextMatrix(gc, font_mx);
CGContextSetTextPosition(gc, x, y);
CGContextSetShouldAntialias(gc, true);
CTLineDraw(ctline, gc);
CGContextSetShouldAntialias(gc, false);
CFRelease(ctline);
}
static char *skip(char *p, int& derived)
{
if (strncmp(p, "-BoldItalic", 11) == 0) { p += 11; derived = 3; }
else if (strncmp(p, "-BoldOblique", 12) == 0) { p += 12; derived = 3; }
else if (strncmp(p, "-Bold", 5) == 0) { p += 5; derived = 1; }
else if (strncmp(p, "-Italic", 7) == 0) { p += 7; derived = 2; }
else if (strncmp(p, "-Oblique", 8) == 0) { p += 8; derived = 2; }
else if (strncmp(p, "-Regular", 8) == 0) { p += 8; }
else if (strncmp(p, "-Roman", 6) == 0) { p += 6; }
return p;
}
static int name_compare(const void *a, const void *b)
{
char *n1 = *(char**)a;
char *n2 = *(char**)b;
int derived1 = 0;
int derived2 = 0;
while (true) {
if (*n1 == '-') n1 = skip(n1, derived1);
if (*n2 == '-') n2 = skip(n2, derived2);
if (*n1 < *n2) return -1;
if (*n1 > *n2) return +1;
if (*n1 == 0) {
return derived1 - derived2;
}
n1++; n2++;
}
}
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;
int value[1] = {1};
CFDictionaryRef dict = CFDictionaryCreate(NULL,
(const void **)kCTFontCollectionRemoveDuplicatesOption,
(const void **)&value, 1, NULL, NULL);
CTFontCollectionRef fcref = CTFontCollectionCreateFromAvailableFonts(dict);
CFRelease(dict);
CFArrayRef arrayref = CTFontCollectionCreateMatchingFontDescriptors(fcref);
CFRelease(fcref);
CFIndex count = CFArrayGetCount(arrayref);
CFIndex i;
char **tabfontnames = new char*[count];
for (i = 0; i < count; i++) {
CTFontDescriptorRef fdesc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(arrayref, i);
CTFontRef font = CTFontCreateWithFontDescriptor(fdesc, 0., NULL);
CFStringRef cfname = CTFontCopyPostScriptName(font);
CFRelease(font);
CFDataRef cfdata = CFStringCreateExternalRepresentation(NULL, cfname, kCFStringEncodingUTF8, '?');
CFIndex l = CFDataGetLength(cfdata);
tabfontnames[i] = (char*)malloc(l+1); memcpy(tabfontnames[i], CFDataGetBytePtr(cfdata), l);
tabfontnames[i][l] = 0;
CFRelease(cfdata);
CFRelease(cfname);
}
CFRelease(arrayref);
qsort(tabfontnames, count, sizeof(char*), name_compare);
for (i = 0; i < count; i++) {
Fl::set_font((Fl_Font)(fl_free_font++), tabfontnames[i]);
}
delete[] tabfontnames;
return (Fl_Font)fl_free_font;
}
#endif
#if HAS_ATSU
void Fl_Quartz_Graphics_Driver::ADD_SUFFIX(descriptor_init, _ATSU)(const char* name,
Fl_Fontsize size, Fl_Quartz_Font_Descriptor *d)
{
OSStatus err;
d->ascent = size*3/4.;
d->descent = size-d->ascent;
d->q_width = size*2/3.;
err = ATSUCreateTextLayout(&d->layout);
UniChar mTxt[2] = { 65, 0 };
err = ATSUSetTextPointerLocation(d->layout, mTxt, kATSUFromTextBeginning, 1, 1);
err = ATSUCreateStyle(&d->style);
err = ATSUSetRunStyle(d->layout, d->style, kATSUFromTextBeginning, kATSUToTextEnd);
Fixed fsize = IntToFixed(size);
ATSUFontID fontID;
ATSUFindFontFromName(name, strlen(name), kFontFullName, kFontMacintoshPlatform, kFontNoScriptCode, kFontEnglishLanguage, &fontID);
ATSUAttributeTag sTag[] = { kATSUFontTag, kATSUSizeTag, kATSUFontMatrixTag };
ByteCount sBytes[] = { sizeof(ATSUFontID), sizeof(Fixed), sizeof(CGAffineTransform) };
ATSUAttributeValuePtr sAttr[] = { &fontID, &fsize, &font_mx };
if (fontID != kATSUInvalidFontID) err = ATSUSetAttributes(d->style, 1, sTag, sBytes, sAttr); err = ATSUSetAttributes(d->style, 2, sTag + 1, sBytes + 1, sAttr + 1); ATSLineLayoutOptions llo = kATSLineUseDeviceMetrics | kATSLineDisableAllLayoutOperations;
ATSUAttributeTag aTag[] = { kATSULineLayoutOptionsTag };
ByteCount aBytes[] = { sizeof(ATSLineLayoutOptions) };
ATSUAttributeValuePtr aAttr[] = { &llo };
err = ATSUSetLineControls (d->layout, kATSUFromTextBeginning, 1, aTag, aBytes, aAttr);
Fixed bBefore, bAfter, bAscent, bDescent;
err = ATSUGetUnjustifiedBounds(d->layout, kATSUFromTextBeginning, 1, &bBefore, &bAfter, &bAscent, &bDescent);
float fa = -FixedToFloat(bAscent), fd = -FixedToFloat(bDescent);
if (fa>0.0f && fd>0.0f) {
d->ascent = int(fa); d->descent = int(fd); }
int w = FixedToInt(bAfter);
if (w)
d->q_width = FixedToInt(bAfter);
ATSUSetTransientFontMatching (d->layout, true);
}
void Fl_Quartz_Graphics_Driver::ADD_SUFFIX(draw, _ATSU)(const char *str, int n, float x, float y)
{
Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor();
UniChar *uniStr = mac_Utf8_to_Utf16(str, n, &n);
CGContextRef gc = (CGContextRef)this->gc();
OSStatus err;
ATSUTextLayout layout = fl_fontsize->layout;
ByteCount iSize = sizeof(CGContextRef);
ATSUAttributeTag iTag = kATSUCGContextTag;
ATSUAttributeValuePtr iValuePtr=&gc;
ATSUSetLayoutControls(layout, 1, &iTag, &iSize, &iValuePtr);
err = ATSUSetTextPointerLocation(layout, uniStr, kATSUFromTextBeginning, n, n);
CGContextSetShouldAntialias(gc, true);
err = ATSUDrawText(layout, kATSUFromTextBeginning, n, FloatToFixed(x), FloatToFixed(y));
CGContextSetShouldAntialias(gc, false);
}
double Fl_Quartz_Graphics_Driver::ADD_SUFFIX(width, _ATSU)(const UniChar* txt, int n) {
OSStatus err;
Fixed bBefore, bAfter, bAscent, bDescent;
ATSUTextLayout layout;
ByteCount iSize;
ATSUAttributeTag iTag;
ATSUAttributeValuePtr iValuePtr;
Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor();
layout = fl_fontsize->layout;
iSize = sizeof(CGContextRef);
iTag = kATSUCGContextTag;
CGContextRef value = (CGContextRef)fl_graphics_driver->gc();
iValuePtr = &value;
ATSUSetLayoutControls(layout, 1, &iTag, &iSize, &iValuePtr);
err = ATSUSetTextPointerLocation(layout, txt, kATSUFromTextBeginning, n, n);
err = ATSUGetUnjustifiedBounds(layout, kATSUFromTextBeginning, n, &bBefore, &bAfter, &bAscent, &bDescent);
int len = FixedToInt(bAfter);
return len;
}
void Fl_Quartz_Graphics_Driver::ADD_SUFFIX(text_extents, _ATSU)(const char *str8, int n,
int &dx, int &dy, int &w, int &h)
{
Fl_Quartz_Font_Descriptor *fl_fontsize = valid_font_descriptor();
UniChar *txt = mac_Utf8_to_Utf16(str8, n, &n);
OSStatus err;
ATSUTextLayout layout;
ByteCount iSize;
ATSUAttributeTag iTag;
ATSUAttributeValuePtr iValuePtr;
layout = fl_fontsize->layout;
iSize = sizeof(CGContextRef);
iTag = kATSUCGContextTag;
CGContextRef value = (CGContextRef)gc();
iValuePtr = &value;
ATSUSetLayoutControls(layout, 1, &iTag, &iSize, &iValuePtr);
err = ATSUSetTextPointerLocation(layout, txt, kATSUFromTextBeginning, n, n);
Rect bbox;
err = ATSUMeasureTextImage(layout, kATSUFromTextBeginning, n, 0, 0, &bbox);
w = bbox.right - bbox.left;
h = bbox.bottom - bbox.top;
dx = bbox.left;
dy = -bbox.bottom;
}
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;
ItemCount oFontCount, oCountAgain;
ATSUFontID *oFontIDs;
ATSUFontCount (&oFontCount);
oFontIDs = (ATSUFontID *)malloc((oFontCount+1) * sizeof(ATSUFontID));
ATSUGetFontIDs (oFontIDs, oFontCount, &oCountAgain);
for (ItemCount idx = 0; idx < oFontCount; idx++)
{
ByteCount actualLength = 511;
char oName[512];
ATSUFindFontName (oFontIDs[idx], kFontFullName, kFontMacintoshPlatform, kFontRomanScript, kFontEnglishLanguage,
actualLength, oName, &actualLength, &oCountAgain);
if(actualLength > 511)
oName[511] = 0;
else
oName[actualLength] = 0;
Fl::set_font((Fl_Font)(fl_free_font++), fl_strdup(oName));
}
free(oFontIDs);
return (Fl_Font)fl_free_font;
}
#endif