Unicode isn't 16-bits - you need to allow for 20-bits.

Sent from my iPhone

On Jan 24, 2011, at 7:30 AM, [email protected] wrote:

> Author: manolo
> Date: 2011-01-24 07:30:14 -0800 (Mon, 24 Jan 2011)
> New Revision: 8305
> Log:
> 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.
> 
> Modified:
>   branches/branch-1.3/src/Fl_Font.H
>   branches/branch-1.3/src/fl_font_mac.cxx
> 
> Modified: branches/branch-1.3/src/Fl_Font.H
> ===================================================================
> --- branches/branch-1.3/src/Fl_Font.H    2011-01-23 11:20:45 UTC (rev 8304)
> +++ branches/branch-1.3/src/Fl_Font.H    2011-01-24 15:30:14 UTC (rev 8305)
> @@ -63,11 +63,11 @@
>   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
> 
> Modified: branches/branch-1.3/src/fl_font_mac.cxx
> ===================================================================
> --- branches/branch-1.3/src/fl_font_mac.cxx    2011-01-23 11:20:45 UTC (rev 
> 8304)
> +++ branches/branch-1.3/src/fl_font_mac.cxx    2011-01-24 15:30:14 UTC (rev 
> 8305)
> @@ -34,6 +34,7 @@
> #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 @@
>   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 @@
>   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 @@
>   */
>   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 @@
>   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 @@
>   }
> #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);
> +  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];
> +  }
>   return retval;
> -  }
> -else {
> +} 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 @@
> #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 @@
>   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 @@
>   }
> #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 @@
>   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,13 +448,7 @@
>   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);
> 
> void Fl_Quartz_Graphics_Driver::draw(const char* str, int n, int x, int y) {
> @@ -423,27 +474,14 @@
> 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 @@
>     CTLineDraw(ctline, fl_gc);
>     CGContextSetShouldAntialias(fl_gc, false);
>     CFRelease(ctline);
> -  }
> -  else {
> +  } else {
> #endif
> #if ! __LP64__
>   OSStatus err;
> @@ -466,6 +503,8 @@
>   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));
> 
> _______________________________________________
> fltk-commit mailing list
> [email protected]
> http://lists.easysw.com/mailman/listinfo/fltk-commit

_______________________________________________
fltk-dev mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-dev

Reply via email to