diff options
Diffstat (limited to 'src/fl_font_mac.cxx')
-rw-r--r-- | src/fl_font_mac.cxx | 243 |
1 files changed, 158 insertions, 85 deletions
diff --git a/src/fl_font_mac.cxx b/src/fl_font_mac.cxx index ebcc5ca..b83c77f 100644 --- a/src/fl_font_mac.cxx +++ b/src/fl_font_mac.cxx @@ -1,5 +1,5 @@ // -// "$Id: fl_font_mac.cxx 4587 2005-10-09 16:27:45Z matt $" +// "$Id: fl_font_mac.cxx 5651 2007-02-01 20:13:57Z matt $" // // MacOS font selection routines for the Fast Light Tool Kit (FLTK). // @@ -27,12 +27,6 @@ #include <config.h> -//: MeasureText, FontMetrics, WidthTabHandle, GetSysFont, SysFontSize -//: TextSize, TextFont -//: GetFNum (theName: Str255; VAR familyID: Integer); -//: FUNCTION FMSwapFont (inRec: FMInput): FMOutPtr; -//: SetFractEnable - Fl_FontSize::Fl_FontSize(const char* name, int Size) { next = 0; # if HAVE_GL @@ -57,24 +51,66 @@ 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__) + knowWidths = 0; + // 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. We also set the font matrix to + // render our font up-side-down, so when rendered through our inverted CGContext, + // text will appear normal again. + Fixed fsize = IntToFixed(Size); + ATSUFontID fontID = FMGetFontFromATSFontRef(font); + static CGAffineTransform font_mx = { 1, 0, 0, -1, 0, 0 }; + ATSUAttributeTag sTag[] = { kATSUFontTag, kATSUSizeTag, kATSUFontMatrixTag }; + ByteCount sBytes[] = { sizeof(ATSUFontID), sizeof(Fixed), sizeof(CGAffineTransform) }; + ATSUAttributeValuePtr sAttr[] = { &fontID, &fsize, &font_mx }; + err = ATSUSetAttributes(style, 3, 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); + // Requesting a certain height font on Mac does not guarantee that ascent+descent + // equal the requested height. fl_height will reflect the actual height that we got. + // The font "Apple Chancery" is a pretty extreme example of overlapping letters. + float fa = -FixedToFloat(bAscent), fd = -FixedToFloat(bDescent); + if (fa>0.0f && fd>0.0f) { + //float f = Size/(fa+fd); + ascent = fa; //int(fa*f+0.5f); + descent = fd; //Size - ascent; + } + int w = FixedToInt(bAfter); + if (w) + q_width = FixedToInt(bAfter); #endif } @@ -97,7 +133,8 @@ Fl_FontSize::~Fl_FontSize() { */ if (this == fl_fontsize) fl_fontsize = 0; #ifdef __APPLE_QUARTZ__ - free(q_name); + ATSUDisposeTextLayout(layout); + ATSUDisposeStyle(style); #endif } @@ -141,6 +178,47 @@ static Fl_Fontdesc built_in_table[] = { #endif }; +#ifdef __APPLE_QUARTZ__ +static UniChar utf16lut[128] = { + 0x00c4, 0x00c5, 0x00c7, 0x00c9, 0x00d1, 0x00d6, 0x00dc, 0x00e1, + 0x00e0, 0x00e2, 0x00e4, 0x00e3, 0x00e5, 0x00e7, 0x00e9, 0x00e8, + 0x00ea, 0x00eb, 0x00ed, 0x00ec, 0x00ee, 0x00ef, 0x00f1, 0x00f3, + 0x00f2, 0x00f4, 0x00f6, 0x00f5, 0x00fa, 0x00f9, 0x00fb, 0x00fc, + 0x2020, 0x00b0, 0x00a2, 0x00a3, 0x00a7, 0x2022, 0x00b6, 0x00df, + 0x00ae, 0x00a9, 0x2122, 0x00b4, 0x00a8, 0x2260, 0x00c6, 0x00d8, + 0x221e, 0x00b1, 0x2264, 0x2265, 0x00a5, 0x00b5, 0x2202, 0x2211, + 0x220f, 0x03c0, 0x222b, 0x00aa, 0x00ba, 0x03a9, 0x00e6, 0x00f8, + 0x00bf, 0x00a1, 0x00ac, 0x221a, 0x0192, 0x2248, 0x2206, 0x00ab, + 0x00bb, 0x2026, 0x00a0, 0x00c0, 0x00c3, 0x00d5, 0x0152, 0x0153, + 0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0x00f7, 0x25ca, + 0x00ff, 0x0178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02, + 0x2021, 0x00b7, 0x201a, 0x201e, 0x2030, 0x00c2, 0x00ca, 0x00c1, + 0x00cb, 0x00c8, 0x00cd, 0x00ce, 0x00cf, 0x00cc, 0x00d3, 0x00d4, + 0xf8ff, 0x00d2, 0x00da, 0x00db, 0x00d9, 0x0131, 0x02c6, 0x02dc, + 0x00af, 0x02d8, 0x02d9, 0x02da, 0x00b8, 0x02dd, 0x02db, 0x02c7, +}; +static UniChar *utf16buf = 0; +static int utf16len = 0; +UniChar *fl_macToUtf16(const char *txt, int len) +{ + if ((len+1)>utf16len) { + utf16len = len+100; + free(utf16buf); + utf16buf = (UniChar*)malloc((utf16len+1)*sizeof(UniChar)); + } + int i; + unsigned char c; + const unsigned char *src = (unsigned char const*)txt; + UniChar *dst = utf16buf; + for (i=0; i<len; i++) { + c = *src++; + *dst++ =(c<128) ? c : utf16lut[c-128]; + } + *dst = 0; + return utf16buf; +} +#endif + Fl_Fontdesc* fl_fonts = built_in_table; void fl_font(Fl_FontSize* s) { @@ -161,9 +239,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 @@ -188,6 +264,11 @@ int fl_font_ = 0; int fl_size_ = 0; void fl_font(int fnum, int size) { + if (fnum==-1) { + fl_font_ = 0; + fl_size_ = 0; + return; + } fl_font_ = fnum; fl_size_ = size; fl_font(find(fnum, size)); @@ -203,88 +284,69 @@ int fl_descent() { else return -1; } -// MRS: The default character set is MacRoman, which is different from -// ISO-8859-1; in FLTK 2.0 we'll use UTF-8 with Quartz... - -static uchar macroman_lut[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 202, 193, 162, 163, 164, 180, 166, 164, 172, 169, 187, 199, 194, 173, 168, 248, - 161, 177, 178, 179, 171, 181, 166, 225, 252, 185, 188, 200, 188, 189, 190, 192, - 203, 231, 229, 204, 128, 129, 174, 130, 233, 131, 230, 232, 237, 234, 235, 236, - 208, 132, 241, 238, 239, 205, 133, 215, 175, 244, 242, 243, 134, 221, 222, 167, - 136, 135, 137, 139, 138, 140, 190, 141, 143, 142, 144, 145, 147, 146, 148, 149, - 240, 150, 152, 151, 153, 155, 154, 214, 191, 157, 156, 158, 159, 253, 254, 216 -}; - -static char *iso_buf = 0; -static int n_iso_buf = 0; - -// this function must be available for OpenGL character drawing as well -const char *fl_iso2macRoman(const char *s, int n) { - // do not do a text lookup for 'Symbol' or 'WebDings'. This fails - // if the user assigns a new font to these numbers though. - if (fl_font_ == 12 || fl_font_ == 15) - return s; - if (n>n_iso_buf) { - if (iso_buf) free(iso_buf); - iso_buf = (char*)malloc(n+500); - n_iso_buf = n; - } - uchar *src = (uchar*)s; - uchar *dst = (uchar*)iso_buf; - for (;n--;) { - *dst++ = macroman_lut[*src++]; - } - return iso_buf; -} - -double fl_width(const char* c, int n) { - const char *txt = fl_iso2macRoman(c, n); +double fl_width(const char* txt, int n) { #ifdef __APPLE_QD__ return (double)TextWidth( txt, 0, n ); #else - if (!fl_gc) { - Fl_Window *w = Fl::first_window(); - if (w) w->make_current(); - if (!fl_gc) return -1; + if (!fl_fontsize) { + fl_font(0, 12); // avoid a crash! + if (!fl_fontsize) + return 8*n; // user must select a font first! + } + if (!fl_fontsize->knowWidths) { + if (!fl_gc) { + Fl_Window *w = Fl::first_window(); + if (w) w->make_current(); + if (!fl_gc) { + if (fl_fontsize) return fl_fontsize->q_width*n; + return 8*n; + // We fall back to some internal QuickDraw port. + // The result should be the same. + } + } + char buf[2]; + for (int i=0; i<256; i++) { + OSStatus err; + buf[0] = (char)i; + // convert to UTF-16 first + UniChar *uniStr = fl_macToUtf16(buf, 1); + // now collect our ATSU resources + ATSUTextLayout layout = fl_fontsize->layout; + // activate the current GC + ByteCount iSize = sizeof(CGContextRef); + ATSUAttributeTag iTag = kATSUCGContextTag; + ATSUAttributeValuePtr iValuePtr=&fl_gc; + ATSUSetLayoutControls(layout, 1, &iTag, &iSize, &iValuePtr); + // now measure the bounding box + err = ATSUSetTextPointerLocation(layout, uniStr, kATSUFromTextBeginning, 1, 1); + Fixed bBefore, bAfter, bAscent, bDescent; + err = ATSUGetUnjustifiedBounds(layout, kATSUFromTextBeginning, 1, &bBefore, &bAfter, &bAscent, &bDescent); + fl_fontsize->width[i] = FixedToInt(bAfter); + } + fl_fontsize->knowWidths = 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; + int len = 0; + const char *src = txt; + for (int j=0; j<n; j++) { + unsigned char c = *src++; + len += fl_fontsize->width[c]; + } + return len; #endif } double fl_width(uchar c) { -#ifdef __APPLE_QD__ - return (double)TextWidth((const char*)(macroman_lut + c), 0, 1 ); -#else return fl_width((const char*)(&c), 1); -#endif } void fl_draw(const char *str, int n, float x, float y); void fl_draw(const char* str, int n, int x, int y) { #ifdef __APPLE_QD__ - const char *txt = fl_iso2macRoman(str, n); MoveTo(x, y); - DrawText((const char *)txt, 0, n); + DrawText((const char *)str, 0, n); #elif defined(__APPLE_QUARTZ__) - fl_draw(str, n, (float)x, (float)y); + fl_draw(str, n, (float)x-0.0f, (float)y-0.5f); #else # error : neither Quartz no Quickdraw chosen #endif @@ -294,13 +356,24 @@ 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__) - const char *txt = fl_iso2macRoman(str, n); - CGContextShowTextAtPoint(fl_gc, x, y, txt, n); + OSStatus err; + // convert to UTF-16 first + UniChar *uniStr = fl_macToUtf16(str, n); + // now collect our ATSU resources + ATSUTextLayout layout = fl_fontsize->layout; + + ByteCount iSize = sizeof(CGContextRef); + ATSUAttributeTag iTag = kATSUCGContextTag; + ATSUAttributeValuePtr iValuePtr=&fl_gc; + ATSUSetLayoutControls(layout, 1, &iTag, &iSize, &iValuePtr); + + err = ATSUSetTextPointerLocation(layout, uniStr, kATSUFromTextBeginning, n, n); + err = ATSUDrawText(layout, kATSUFromTextBeginning, n, FloatToFixed(x), FloatToFixed(y)); #else # error : neither Quartz no Quickdraw chosen #endif } // -// End of "$Id: fl_font_mac.cxx 4587 2005-10-09 16:27:45Z matt $". +// End of "$Id: fl_font_mac.cxx 5651 2007-02-01 20:13:57Z matt $". // |