diff options
-rw-r--r-- | cocoa/PlatCocoa.mm | 82 | ||||
-rw-r--r-- | cocoa/QuartzTextLayout.h | 12 |
2 files changed, 69 insertions, 25 deletions
diff --git a/cocoa/PlatCocoa.mm b/cocoa/PlatCocoa.mm index dba386750..4465e36ae 100644 --- a/cocoa/PlatCocoa.mm +++ b/cocoa/PlatCocoa.mm @@ -149,6 +149,10 @@ Font::~Font() //-------------------------------------------------------------------------------------------------- +static int FontCharacterSet(Font &f) { + return reinterpret_cast<QuartzTextStyle *>(f.GetID())->getCharacterSet(); +} + /** * Creates a Quartz 2D font with the given properties. * TODO: rewrite to use NSFont. @@ -905,55 +909,86 @@ CFStringEncoding EncodingFromCharacterSet(bool unicode, int characterSet) void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore) { + CFStringEncoding encoding = EncodingFromCharacterSet(unicodeMode, FontCharacterSet(font_)); ColourDesired colour(fore.AsLong()); CGColorRef color = CGColorCreateGenericRGB(colour.GetRed()/255.0,colour.GetGreen()/255.0,colour.GetBlue()/255.0,1.0); QuartzTextStyle* style = reinterpret_cast<QuartzTextStyle*>(font_.GetID()); style->setCTStyleColor(color); - textLayout->setText (reinterpret_cast<const UInt8*>(s), len, *reinterpret_cast<QuartzTextStyle*>(font_.GetID())); + textLayout->setText (reinterpret_cast<const UInt8*>(s), len, encoding, *reinterpret_cast<QuartzTextStyle*>(font_.GetID())); textLayout->draw(rc.left, ybase); } +static size_t utf8LengthFromLead(unsigned char uch) { + if (uch >= (0x80 + 0x40 + 0x20 + 0x10)) { + return 4; + } else if (uch >= (0x80 + 0x40 + 0x20)) { + return 3; + } else if (uch >= (0x80)) { + return 2; + } else { + return 1; + } +} + //-------------------------------------------------------------------------------------------------- void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positions) { + CFStringEncoding encoding = EncodingFromCharacterSet(unicodeMode, FontCharacterSet(font_)); for (int i = 0; i < len; i++) positions [i] = 0; - textLayout->setText (reinterpret_cast<const UInt8*>(s), len, *reinterpret_cast<QuartzTextStyle*>(font_.GetID())); + textLayout->setText (reinterpret_cast<const UInt8*>(s), len, encoding, *reinterpret_cast<QuartzTextStyle*>(font_.GetID())); CTLineRef mLine = textLayout->getCTLine(); assert(mLine != NULL); - CGFloat* secondaryOffset= 0; - int unicodeCharStart = 0; - for ( int i = 0; i < len+1; i ++ ){ - unsigned char uch = s[i]; - CFIndex charIndex = unicodeCharStart+1; - CGFloat advance = CTLineGetOffsetForStringIndex(mLine, charIndex, secondaryOffset); - - if ( unicodeMode ) - { - unsigned char mask = 0xc0; - int lcount = 1; - // Add one additonal byte for each extra high order one in the byte - while ( uch >= mask && lcount < 8 ) - { - positions[i++] = (int)(advance+0.5); - lcount ++; - mask = mask >> 1 | 0x80; // add an additional one in the highest order position + if (unicodeMode) { + // Map the widths given for UTF-16 characters back onto the UTF-8 input string + int fit = textLayout->getStringLength(); + int ui=0; + const unsigned char *us = reinterpret_cast<const unsigned char *>(s); + int i=0; + while (ui<fit) { + size_t lenChar = utf8LengthFromLead(us[i]); + size_t codeUnits = (lenChar < 4) ? 1 : 2; + CGFloat xPosition = CTLineGetOffsetForStringIndex(mLine, ui+1, NULL); + for (unsigned int bytePos=0; (bytePos<lenChar) && (i<len); bytePos++) { + positions[i++] = lround(xPosition); } + ui += codeUnits; + } + int lastPos = 0; + if (i > 0) + lastPos = positions[i-1]; + while (i<len) { + positions[i++] = lastPos; + } + } else if (codePage) { + int ui = 0; + for (int i=0;i<len;) { + size_t lenChar = Platform::IsDBCSLeadByte(codePage, s[i]) ? 2 : 1; + CGFloat xPosition = CTLineGetOffsetForStringIndex(mLine, ui+1, NULL); + for (unsigned int bytePos=0; (bytePos<lenChar) && (i<len); bytePos++) { + positions[i++] = lround(xPosition); + } + ui++; + } + } else { // Single byte encoding + for (int i=0;i<len;i++) { + CGFloat xPosition = CTLineGetOffsetForStringIndex(mLine, i+1, NULL); + positions[i] = lround(xPosition); } - positions[i] = (int)(advance+0.5); - unicodeCharStart++; } + } int SurfaceImpl::WidthText(Font &font_, const char *s, int len) { if (font_.GetID()) { - textLayout->setText (reinterpret_cast<const UInt8*>(s), len, *reinterpret_cast<QuartzTextStyle*>(font_.GetID())); + CFStringEncoding encoding = EncodingFromCharacterSet(unicodeMode, FontCharacterSet(font_)); + textLayout->setText (reinterpret_cast<const UInt8*>(s), len, encoding, *reinterpret_cast<QuartzTextStyle*>(font_.GetID())); return textLayout->MeasureStringWidth(); } @@ -964,7 +999,8 @@ int SurfaceImpl::WidthChar(Font &font_, char ch) { char str[2] = { ch, '\0' }; if (font_.GetID()) { - textLayout->setText (reinterpret_cast<const UInt8*>(str), 1, *reinterpret_cast<QuartzTextStyle*>(font_.GetID())); + CFStringEncoding encoding = EncodingFromCharacterSet(unicodeMode, FontCharacterSet(font_)); + textLayout->setText (reinterpret_cast<const UInt8*>(str), 1, encoding, *reinterpret_cast<QuartzTextStyle*>(font_.GetID())); return textLayout->MeasureStringWidth(); } diff --git a/cocoa/QuartzTextLayout.h b/cocoa/QuartzTextLayout.h index 033ac98fb..c789ed10f 100644 --- a/cocoa/QuartzTextLayout.h +++ b/cocoa/QuartzTextLayout.h @@ -24,6 +24,7 @@ public: { mString = NULL; mLine = NULL; + stringLength = 0; setContext(context); } @@ -41,12 +42,14 @@ public: } } - inline void setText( const UInt8* buffer, size_t byteLength, const QuartzTextStyle& r ) + inline void setText( const UInt8* buffer, size_t byteLength, CFStringEncoding encoding, const QuartzTextStyle& r ) { - CFStringRef str = CFStringCreateWithBytes( NULL, buffer, byteLength, kCFStringEncodingUTF8, false ); + CFStringRef str = CFStringCreateWithBytes( NULL, buffer, byteLength, encoding, false ); if (!str) return; + stringLength = CFStringGetLength(str); + CFMutableDictionaryRef stringAttribs = r.getCTStyle(); if (mString != NULL) @@ -89,6 +92,10 @@ public: return mLine; } + CFIndex getStringLength() { + return stringLength; + } + inline void setContext (CGContextRef context) { gc = context; @@ -98,6 +105,7 @@ private: CGContextRef gc; CFAttributedStringRef mString; CTLineRef mLine; + CFIndex stringLength; }; #endif |