STR #1305: partial fix.

FLTK on Mac with --enable-quartz now uses ATSU instead of CG to render text. First of all, it is a lot faster, but more importantly, character positions are now all at integer positions. This is not as beatiful as standard Mac text, but required by the FLTK internals. I seriously doubt that anyone who's not a typesette will notice the difference.

But - and there's always a but, isn't there?

This commit does not handle the ASCII-to-UTF16 conversion yet, so all characters above 127 are junk.

Also, there are still a lot of problems with the Quartz support in general. Most prominently, we still get a lot of messages about invalid contexts which ruins the clipping.

So in conclusion (this must be the longest SVN commit annotation ever) this modification fixes the main reason why I did not finish the Quartz port. After fixing this, there's hope that we will wrap even that dirty little corner of FLTK up for good!



git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@5171 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Matthias Melcher 2006-06-02 14:17:41 +00:00
parent b938cfb7ef
commit 4dd1f5e216
2 changed files with 68 additions and 20 deletions

View File

@ -60,9 +60,11 @@ public:
bool knowMetrics;
# elif defined(__APPLE_QUARTZ__)
FL_EXPORT Fl_FontSize(const char* fontname, int size);
ATSUTextLayout layout;
ATSUStyle style;
short ascent, descent, q_width;
char *q_name;
int size;
short ascent, descent, q_width;
# elif USE_XFT
XftFont* font;
const char* encoding;

View File

@ -57,24 +57,53 @@ Fl_FontSize::Fl_FontSize(const char* name, int Size) {
for (int i=0; i<256; i++) width[i] = fOut->widMax;
minsize = maxsize = size;
#elif defined(__APPLE_QUARTZ__)
// OpenGL needs those for its font handling
q_name = strdup(name);
size = Size;
OSStatus err;
// fill our structure with a few default values
ascent = Size*3/4;
descent = Size-ascent;
q_width = Size*2/3;
minsize = maxsize = Size;
// Using ATS to get the genral Glyph size information
CFStringRef cfname = CFStringCreateWithCString(0L, q_name, kCFStringEncodingASCII);
// now use ATS to get the actual Glyph size information
CFStringRef cfname = CFStringCreateWithCString(0L, name, kCFStringEncodingASCII);
ATSFontRef font = ATSFontFindFromName(cfname, kATSOptionFlagsDefault);
if (font) {
ATSFontMetrics m = { 0 };
ATSFontGetHorizontalMetrics(font, kATSOptionFlagsDefault, &m);
if (m.avgAdvanceWidth) q_width = int(m.avgAdvanceWidth*size);
// playing with the offsets a little to make standard sizes fit
if (m.ascent) ascent = int(m.ascent*size-0.5f);
if (m.descent) descent = -int(m.descent*size-1.5f);
if (m.avgAdvanceWidth) q_width = int(m.avgAdvanceWidth*Size);
// playing with the offsets a little to make standard sizes fit
if (m.ascent) ascent = int(m.ascent*Size-0.5f);
if (m.descent) descent = -int(m.descent*Size-1.5f);
}
CFRelease(cfname);
// now we allocate everything needed to render text in this font later
// get us the default layout and style
err = ATSUCreateTextLayout(&layout);
UniChar mTxt[2] = { 65, 0 };
err = ATSUSetTextPointerLocation(layout, mTxt, kATSUFromTextBeginning, 1, 1);
err = ATSUCreateStyle(&style);
err = ATSUSetRunStyle(layout, style, kATSUFromTextBeginning, kATSUToTextEnd);
// now set the actual font, size and attributes
Fixed fsize = IntToFixed(Size);
ATSUFontID fontID = FMGetFontFromATSFontRef(font);
ATSUAttributeTag sTag[] = { kATSUFontTag, kATSUSizeTag };
ByteCount sBytes[] = { sizeof(ATSUFontID), sizeof(Fixed) };
ATSUAttributeValuePtr sAttr[] = { &fontID, &fsize };
err = ATSUSetAttributes(style, 2, sTag, sBytes, sAttr);
// next, make sure that Quartz will only render at integer coordinates
ATSLineLayoutOptions llo = kATSLineUseDeviceMetrics|kATSLineDisableAllLayoutOperations;
ATSUAttributeTag aTag[] = { kATSULineLayoutOptionsTag };
ByteCount aBytes[] = { sizeof(ATSLineLayoutOptions) };
ATSUAttributeValuePtr aAttr[] = { &llo };
err = ATSUSetLineControls (layout, kATSUFromTextBeginning, 1, aTag, aBytes, aAttr);
// now we are finally ready to measure some letter to get the bounding box
Fixed bBefore, bAfter, bAscent, bDescent;
err = ATSUGetUnjustifiedBounds(layout, kATSUFromTextBeginning, 1, &bBefore, &bAfter, &bAscent, &bDescent);
ascent = FixedToInt(bAscent);
descent = FixedToInt(bDescent);
q_width = FixedToInt(bAfter);
#endif
}
@ -97,7 +126,8 @@ Fl_FontSize::~Fl_FontSize() {
*/
if (this == fl_fontsize) fl_fontsize = 0;
#ifdef __APPLE_QUARTZ__
free(q_name);
ATSUDisposeTextLayout(layout);
ATSUDisposeStyle(style);
#endif
}
@ -161,9 +191,7 @@ void fl_font(Fl_FontSize* s) {
fl_fontsize->knowMetrics = 1;
}
#elif defined(__APPLE_QUARTZ__)
if (!s) return;
if (!fl_gc) return; // no worries, we will assign the font to the context later
CGContextSelectFont(fl_gc, s->q_name, (float)s->size, kCGEncodingMacRoman);
// we will use fl_fontsize later to access the required style and layout
#else
# error : need to defined either Quartz or Quickdraw
#endif
@ -212,14 +240,21 @@ double fl_width(const char* txt, int n) {
if (w) w->make_current();
if (!fl_gc) return -1;
}
// according to the Apple developer docs, this is the correct way to
// find the length of a rendered text...
CGContextSetTextPosition(fl_gc, 0, 0);
CGContextSetTextDrawingMode(fl_gc, kCGTextInvisible);
CGContextShowText(fl_gc, txt, n);
CGContextSetTextDrawingMode(fl_gc, kCGTextFill);
CGPoint p = CGContextGetTextPosition(fl_gc);
return p.x;
OSStatus err;
// convert to UTF-16 first
int i;
UniChar uniStr[n+1];
for (i=0; i<n; i++) {
uniStr[i] = txt[i];
}
uniStr[i] = 0;
// now collect our ATSU resources
ATSUTextLayout layout = fl_fontsize->layout;
err = ATSUSetTextPointerLocation(layout, uniStr, kATSUFromTextBeginning, n, n);
// now measure the bounding box
Fixed bBefore, bAfter, bAscent, bDescent;
err = ATSUGetUnjustifiedBounds(layout, kATSUFromTextBeginning, n, &bBefore, &bAfter, &bAscent, &bDescent);
return FixedToInt(bAfter);
#endif
}
@ -244,7 +279,18 @@ void fl_draw(const char *str, int n, float x, float y) {
#ifdef __APPLE_QD__
fl_draw(str, n, (int)x, (int)y);
#elif defined(__APPLE_QUARTZ__)
CGContextShowTextAtPoint(fl_gc, x, y, str, n);
OSStatus err;
// convert to UTF-16 first
int i;
UniChar uniStr[n+1];
for (i=0; i<n; i++) {
uniStr[i] = str[i];
}
uniStr[i] = 0;
// now collect our ATSU resources
ATSUTextLayout layout = fl_fontsize->layout;
err = ATSUSetTextPointerLocation(layout, uniStr, kATSUFromTextBeginning, n, n);
err = ATSUDrawText(layout, kATSUFromTextBeginning, n, FloatToFixed(x), FloatToFixed(y));
#else
# error : neither Quartz no Quickdraw chosen
#endif