summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorManolo Gouy <Manolo>2011-01-24 15:30:14 +0000
committerManolo Gouy <Manolo>2011-01-24 15:30:14 +0000
commitf9363c16d0e6518ba82d05f1f7f415e9224a8e35 (patch)
tree650061a5071eff676869e4e1da99f223932534ba /src
parent1b146a48371b72e510d6bb6277fb6256c1f9e17a (diff)
Fix STR #2530 (Mac OS only). Implements a fast algorithm for fl_width() that memorizes the
width of all characters the first time they are seen and computes the width of a string as the sum of the widths of its characters. Char widths are memorized in 256 blocks of 256 widths; only blocks used in some text are allocated and computed. The width of characters beyond U+FFFF is computed anew each time. Strings are drawn using core text, after having deactivated character kerning, so their width is the sum of the widths of their characters. This is the same algorithm as used for WIN32. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@8305 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src')
-rw-r--r--src/Fl_Font.H4
-rw-r--r--src/fl_font_mac.cxx161
2 files changed, 102 insertions, 63 deletions
diff --git a/src/Fl_Font.H b/src/Fl_Font.H
index 65b00df8e..75478b626 100644
--- a/src/Fl_Font.H
+++ b/src/Fl_Font.H
@@ -63,11 +63,11 @@ public:
ATSUTextLayout layout;
# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
CTFontRef fontref;
+ // the unicode span is divided in 256 blocks of 256 characters
+ float *width[256]; // array of arrays of character widths
# endif
ATSUStyle style;
short ascent, descent, q_width;
-// short width[256];
-// bool knowWidths;
char *q_name;
int size;
# elif USE_XFT
diff --git a/src/fl_font_mac.cxx b/src/fl_font_mac.cxx
index 93c1d7f84..291647086 100644
--- a/src/fl_font_mac.cxx
+++ b/src/fl_font_mac.cxx
@@ -34,6 +34,7 @@ extern unsigned fl_utf8toUtf16(const char* src, unsigned srclen, unsigned short*
#define check_default_font() {if (!fl_fontsize) fl_font(0, 12);}
static CGAffineTransform font_mx = { 1, 0, 0, -1, 0, 0 };
+static CFMutableDictionaryRef attributes = NULL;
Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name, Fl_Fontsize Size) {
next = 0;
@@ -59,7 +60,7 @@ if (fl_mac_os_version >= 0x1050) {//unfortunately, CTFontCreateWithName != NULL
CTFontGetAdvancesForGlyphs(fontref, kCTFontHorizontalOrientation, glyph, advances, 2);
w = advances[0].width;
if ( abs(advances[0].width - advances[1].width) < 1E-2 ) {//this is a fixed-width font
- //slightly rescale fixed-width fonts so the character width has an integral value
+ // slightly rescale fixed-width fonts so the character width has an integral value
CFRelease(fontref);
CGFloat fsize = size / ( w/floor(w + 0.5) );
fontref = CTFontCreateWithName(str, fsize, NULL);
@@ -69,7 +70,20 @@ if (fl_mac_os_version >= 0x1050) {//unfortunately, CTFontCreateWithName != NULL
ascent = (short)(CTFontGetAscent(fontref) + 0.5);
descent = (short)(CTFontGetDescent(fontref) + 0.5);
q_width = w + 0.5;
+ for (int i = 0; i < 256; i++) width[i] = NULL;
+ if (!attributes) {
+ static CFNumberRef zero_ref;
+ float zero = 0.;
+ zero_ref = CFNumberCreate(NULL, kCFNumberFloat32Type, &zero);
+ // deactivate kerning for all fonts, so that string width = sum of character widths
+ // which allows fast fl_width() implementation.
+ attributes = CFDictionaryCreateMutable(kCFAllocatorDefault,
+ 3,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ CFDictionarySetValue (attributes, kCTKernAttributeName, zero_ref);
}
+}
else {
#endif
#if ! __LP64__
@@ -165,10 +179,12 @@ Fl_Font_Descriptor::~Fl_Font_Descriptor() {
*/
if (this == fl_fontsize) fl_fontsize = 0;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
- if (fl_mac_os_version >= 0x1050) CFRelease(fontref);
-#else
- /* ATSUDisposeTextLayout(layout);
- ATSUDisposeStyle(style); */
+ if (fl_mac_os_version >= 0x1050) {
+ CFRelease(fontref);
+ for (int i = 0; i < 256; i++) {
+ if (width[i]) free(width[i]);
+ }
+ }
#endif
}
@@ -260,7 +276,24 @@ int fl_descent() {
else return -1;
}
-double fl_width(const UniChar* txt, int n) {
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+// returns width of a pair of UniChar's in the surrogate range
+static CGFloat surrogate_width(const UniChar *txt)
+{
+ CFStringRef str = CFStringCreateWithCharactersNoCopy(NULL, txt, 2, kCFAllocatorNull);
+ CTFontRef font2 = CTFontCreateForString(fl_fontsize->fontref, str, CFRangeMake(0,2));
+ CFRelease(str);
+ CGGlyph glyphs[2];
+ bool b = CTFontGetGlyphsForCharacters(font2, txt, glyphs, 2);
+ CGSize a;
+ if (b) CTFontGetAdvancesForGlyphs(font2, kCTFontHorizontalOrientation, glyphs, &a, 1);
+ else a.width = fl_fontsize->q_width;
+ CFRelease(font2);
+ return a.width;
+}
+#endif
+
+static double fl_width(const UniChar* txt, int n) {
check_default_font();
if (!fl_fontsize) {
check_default_font(); // avoid a crash!
@@ -269,38 +302,68 @@ double fl_width(const UniChar* txt, int n) {
}
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
if (fl_mac_os_version >= 0x1050) {
- CTFontRef fontref = fl_fontsize->fontref;
- CFStringRef str = CFStringCreateWithBytes(NULL, (const UInt8*)txt, n * sizeof(UniChar), kCFStringEncodingUTF16, false);
- CFAttributedStringRef astr = CFAttributedStringCreate(NULL, str, NULL);
- CFMutableAttributedStringRef mastr = CFAttributedStringCreateMutableCopy(NULL, 0, astr);
- CFRelease(astr);
- CFAttributedStringSetAttribute(mastr, CFRangeMake(0, CFStringGetLength(str)), kCTFontAttributeName, fontref);
- CFRelease(str);
- CTLineRef ctline = CTLineCreateWithAttributedString(mastr);
- CFRelease(mastr);
- double retval = CTLineGetTypographicBounds(ctline, NULL, NULL, NULL);
- CFRelease(ctline);
- return retval;
+ double retval = 0;
+ UniChar uni;
+ int i;
+ for (i = 0; i < n; i++) { // loop over txt
+ uni = txt[i];
+ if (uni >= 0xD800 && uni <= 0xDBFF) { // handles the surrogate range
+ retval += surrogate_width(txt + i);
+ i++; // because a pair of UniChar's represent a single character
+ continue;
+ }
+ unsigned int r = uni >> 8; // index of the character block containing uni
+ if (!fl_fontsize->width[r]) { // this character block has not been hit yet
+//fprintf(stderr,"r=%d size=%d name=%s\n",r,fl_fontsize->size, fl_fontsize->q_name);
+ // allocate memory to hold width of each character in the block
+ fl_fontsize->width[r] = (float*) malloc(sizeof(float) * 0x100);
+ UniChar ii = r * 0x100;
+ CGGlyph glyph;
+ CGSize advance_size;
+ for (int j = 0; j < 0x100; j++) { // loop over the block
+ CTFontRef font2 = fl_fontsize->fontref;
+ bool must_release = false;
+ // ii spans all characters of this block
+ bool b = CTFontGetGlyphsForCharacters(font2, &ii, &glyph, 1);
+ if (!b) { // the current font doesn't contain this char
+ CFStringRef str = CFStringCreateWithCharactersNoCopy(NULL, &ii, 1, kCFAllocatorNull);
+ // find a font that contains it
+ font2 = CTFontCreateForString(font2, str, CFRangeMake(0,1));
+ must_release = true;
+ CFRelease(str);
+ b = CTFontGetGlyphsForCharacters(font2, &ii, &glyph, 1);
+ }
+ if (b) CTFontGetAdvancesForGlyphs(font2, kCTFontHorizontalOrientation, &glyph, &advance_size, 1);
+ else advance_size.width = 0.;
+ // the width of one character of this block of characters
+ fl_fontsize->width[r][j] = advance_size.width;
+ if (must_release) CFRelease(font2);
+ ii++;
+ }
+ }
+ // sum the widths of all characters of txt
+ retval += fl_fontsize->width[r][uni & 0xFF];
}
-else {
+ return retval;
+} else {
#endif
#if ! __LP64__
- OSStatus err;
+ OSStatus err;
Fixed bBefore, bAfter, bAscent, bDescent;
ATSUTextLayout layout;
ByteCount iSize;
ATSUAttributeTag iTag;
ATSUAttributeValuePtr iValuePtr;
-// Here's my ATSU text measuring attempt... This seems to do the Right Thing
+ // Here's my ATSU text measuring attempt... This seems to do the Right Thing
// now collect our ATSU resources and measure our text string
layout = fl_fontsize->layout;
- // activate the current GC
+ // activate the current GC
iSize = sizeof(CGContextRef);
iTag = kATSUCGContextTag;
iValuePtr = &fl_gc;
- ATSUSetLayoutControls(layout, 1, &iTag, &iSize, &iValuePtr);
- // now measure the bounding box
+ ATSUSetLayoutControls(layout, 1, &iTag, &iSize, &iValuePtr);
+ // now measure the bounding box
err = ATSUSetTextPointerLocation(layout, txt, kATSUFromTextBeginning, n, n);
err = ATSUGetUnjustifiedBounds(layout, kATSUFromTextBeginning, n, &bBefore, &bAfter, &bAscent, &bDescent);
// If err is OK then return length, else return 0. Or something...
@@ -310,7 +373,7 @@ else {
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
}
#endif
- return 0; // FIXME: I do not understand the shuffeling of the above ifdef's and why they are here!
+ return 0;
}
double fl_width(const char* txt, int n) {
@@ -319,17 +382,13 @@ double fl_width(const char* txt, int n) {
return fl_width(uniStr, wc_len);
}
-/*double fl_width(uchar c) {
- return fl_width((const char*)(&c), 1);
-}*/
-
double fl_width(unsigned int wc) {
- UniChar uc = wc;
+ const UniChar uc = wc;
return fl_width(&uc, 1);
}
// text extent calculation
-void fl_text_extents(const UniChar* txt, int n, int &dx, int &dy, int &w, int &h) {
+void fl_text_extents(const char *str8, int n, int &dx, int &dy, int &w, int &h) {
if (!fl_fontsize) {
check_default_font(); // avoid a crash!
if (!fl_fontsize)
@@ -339,12 +398,9 @@ void fl_text_extents(const UniChar* txt, int n, int &dx, int &dy, int &w, int &h
}
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
if (fl_mac_os_version >= 0x1050) {
- CTFontRef fontref = fl_fontsize->fontref;
- CFStringRef str16 = CFStringCreateWithBytes(NULL, (const UInt8*)txt, n *sizeof(UniChar), kCFStringEncodingUTF16, false);
- CFAttributedStringRef astr = CFAttributedStringCreate(NULL, str16, NULL);
- CFMutableAttributedStringRef mastr = CFAttributedStringCreateMutableCopy(NULL, 0, astr);
- CFRelease(astr);
- CFAttributedStringSetAttribute(mastr, CFRangeMake(0, CFStringGetLength(str16)), kCTFontAttributeName, fontref);
+ CFStringRef str16 = CFStringCreateWithBytes(NULL, (const UInt8*)str8, n, kCFStringEncodingUTF8, false);
+ CFDictionarySetValue (attributes, kCTFontAttributeName, fl_fontsize->fontref);
+ CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str16, attributes);
CFRelease(str16);
CTLineRef ctline = CTLineCreateWithAttributedString(mastr);
CFRelease(mastr);
@@ -376,6 +432,7 @@ else {
iValuePtr = &fl_gc;
ATSUSetLayoutControls(layout, 1, &iTag, &iSize, &iValuePtr);
// now measure the bounding box
+ UniChar *txt = mac_Utf8_to_Utf16(str8, n, &n);
err = ATSUSetTextPointerLocation(layout, txt, kATSUFromTextBeginning, n, n);
Rect bbox;
err = ATSUMeasureTextImage(layout, kATSUFromTextBeginning, n, 0, 0, &bbox);
@@ -391,12 +448,6 @@ else {
return;
} // fl_text_extents
-void fl_text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h) {
- int wc_len = n;
- UniChar *uniStr = mac_Utf8_to_Utf16(c, n, &wc_len);
- fl_text_extents(uniStr, wc_len, dx, dy, w, h);
-} // fl_text_extents
-
void fl_draw(const char *str, int n, float x, float y);
@@ -423,27 +474,14 @@ static CGColorRef flcolortocgcolor(Fl_Color i)
void fl_draw(const char *str, int n, float x, float y) {
// avoid a crash if no font has been selected by user yet !
check_default_font();
- // convert to UTF-16 first
- UniChar *uniStr = mac_Utf8_to_Utf16(str, n, &n);
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
if (fl_mac_os_version >= 0x1050) {
- CFStringRef keys[2];
- CFTypeRef values[2];
- CFStringRef str16 = CFStringCreateWithBytes(NULL, (const UInt8*)uniStr, n * sizeof(UniChar), kCFStringEncodingUTF16, false);
+ CFStringRef str16 = CFStringCreateWithBytes(NULL, (const UInt8*)str, n, kCFStringEncodingUTF8, false);
CGColorRef color = flcolortocgcolor(fl_color());
- keys[0] = kCTFontAttributeName;
- keys[1] = kCTForegroundColorAttributeName;
- values[0] = fl_fontsize->fontref;
- values[1] = color;
- CFDictionaryRef attributes = CFDictionaryCreate(kCFAllocatorDefault,
- (const void**)&keys,
- (const void**)&values,
- 2,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
+ CFDictionarySetValue (attributes, kCTFontAttributeName, fl_fontsize->fontref);
+ CFDictionarySetValue (attributes, kCTForegroundColorAttributeName, color);
CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str16, attributes);
CFRelease(str16);
- CFRelease(attributes);
CFRelease(color);
CTLineRef ctline = CTLineCreateWithAttributedString(mastr);
CFRelease(mastr);
@@ -453,8 +491,7 @@ void fl_draw(const char *str, int n, float x, float y) {
CTLineDraw(ctline, fl_gc);
CGContextSetShouldAntialias(fl_gc, false);
CFRelease(ctline);
- }
- else {
+ } else {
#endif
#if ! __LP64__
OSStatus err;
@@ -466,6 +503,8 @@ void fl_draw(const char *str, int n, float x, float y) {
ATSUAttributeValuePtr iValuePtr=&fl_gc;
ATSUSetLayoutControls(layout, 1, &iTag, &iSize, &iValuePtr);
+ // convert to UTF-16 first
+ UniChar *uniStr = mac_Utf8_to_Utf16(str, n, &n);
err = ATSUSetTextPointerLocation(layout, uniStr, kATSUFromTextBeginning, n, n);
CGContextSetShouldAntialias(fl_gc, true);
err = ATSUDrawText(layout, kATSUFromTextBeginning, n, FloatToFixed(x), FloatToFixed(y));