diff options
author | nyamatongwe <unknown> | 2011-05-26 09:14:45 +1000 |
---|---|---|
committer | nyamatongwe <unknown> | 2011-05-26 09:14:45 +1000 |
commit | 82266f54fef82a3481bf9ec091d85c2c202df5ec (patch) | |
tree | 9478fbba514910e3648d97940ccd3771c9b64509 | |
parent | 1ef9f42a4e839bf12d454e8560e7d697e1e3b0c9 (diff) | |
download | scintilla-mirror-82266f54fef82a3481bf9ec091d85c2c202df5ec.tar.gz |
Convert text drawing and measurement to use Core Text API.
Contributed by Elizabeth Irizarry of Adobe with some modifications
by Neil Hodgson.
-rw-r--r-- | cocoa/PlatCocoa.mm | 207 | ||||
-rw-r--r-- | cocoa/QuartzTextLayout.h | 150 | ||||
-rw-r--r-- | cocoa/QuartzTextStyle.h | 114 | ||||
-rw-r--r-- | cocoa/QuartzTextStyleAttribute.h | 145 |
4 files changed, 201 insertions, 415 deletions
diff --git a/cocoa/PlatCocoa.mm b/cocoa/PlatCocoa.mm index 6e8620b0b..3a70fcd93 100644 --- a/cocoa/PlatCocoa.mm +++ b/cocoa/PlatCocoa.mm @@ -156,23 +156,15 @@ void Font::Create(const char *faceName, int characterSet, int size, bool bold, b int extraFontFlag) { // TODO: How should I handle the characterSet request? - Release(); - - QuartzTextStyle* style = new QuartzTextStyle(); - fid = style; - - // Find the font - QuartzFont font(faceName, strlen(faceName)); - - // We set Font, Size, Bold, Italic - QuartzTextSize textSize(size); - QuartzTextBold isBold(bold); - QuartzTextItalic isItalic(italic); - - // Actually set the attributes - QuartzTextStyleAttribute* attributes[] = { &font, &textSize, &isBold, &isItalic }; - style->setAttributes(attributes, sizeof(attributes) / sizeof(*attributes)); - style->setFontFeature(kLigaturesType, kCommonLigaturesOffSelector); + Release(); + + QuartzTextStyle* style = new QuartzTextStyle(); + fid = style; + + // Create the font with attributes + QuartzFont font(faceName, strlen(faceName), size, bold, italic); + CTFontRef fontRef = font.getFontID(); + style->setFontRef(fontRef); } //-------------------------------------------------------------------------------------------------- @@ -774,78 +766,49 @@ void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, int ybase, const c void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore) { - textLayout->setText (reinterpret_cast<const UInt8*>(s), len, *reinterpret_cast<QuartzTextStyle*>(font_.GetID())); - - // The Quartz RGB fill color influences the ATSUI color - FillColour(fore); - - // Draw text vertically flipped as OS X uses a coordinate system where +Y is upwards. - textLayout->draw(rc.left, ybase, true); + 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->draw(rc.left, ybase); } //-------------------------------------------------------------------------------------------------- void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positions) { - // sample at http://developer.apple.com/samplecode/ATSUICurveAccessDemo/listing1.html - // sample includes use of ATSUGetGlyphInfo which would be better for older - // OSX systems. We should expand to using that on older systems as well. - for (int i = 0; i < len; i++) - positions [i] = 0; - - // We need the right X coords, so we have to append a char to get the left coord of thast extra char - char* buf = (char*) malloc (len+1); - if (!buf) - return; - - memcpy (buf, s, len); - buf [len] = '.'; - - textLayout->setText (reinterpret_cast<const UInt8*>(buf), len+1, *reinterpret_cast<QuartzTextStyle*>(font_.GetID())); - ATSUGlyphInfoArray* theGlyphInfoArrayPtr; - ByteCount theArraySize; - - // Get the GlyphInfoArray - ATSUTextLayout layout = textLayout->getLayout(); - if ( noErr == ATSUGetGlyphInfo (layout, 0, textLayout->getLength(), &theArraySize, NULL)) - { - theGlyphInfoArrayPtr = (ATSUGlyphInfoArray *) malloc (theArraySize + sizeof(ItemCount) + sizeof(ATSUTextLayout)); - if (theGlyphInfoArrayPtr) - { - if (noErr == ATSUGetGlyphInfo (layout, 0, textLayout->getLength(), &theArraySize, theGlyphInfoArrayPtr)) - { - // do not count the first item, which is at the beginning of the line - for ( UniCharCount unicodePosition = 1, i = 0; i < len && unicodePosition < theGlyphInfoArrayPtr->numGlyphs; unicodePosition ++ ) - { - // The ideal position is the x coordinate of the glyph, relative to the beginning of the line - int position = (int)( theGlyphInfoArrayPtr->glyphs[unicodePosition].idealX + 0.5 ); // These older APIs return float values - unsigned char uch = s[i]; - positions[i++] = position; - - // If we are using unicode (UTF8), map the Unicode position back to the UTF8 characters, - // as 1 unicode character can map to multiple UTF8 characters. - // See: http://www.tbray.org/ongoing/When/200x/2003/04/26/UTF - // Or: http://www.cl.cam.ac.uk/~mgk25/unicode.html - if ( unicodeMode ) - { - unsigned char mask = 0xc0; - int count = 1; - // Add one additonal byte for each extra high order one in the byte - while ( uch >= mask && count < 8 ) - { - positions[i++] = position; - count ++; - mask = mask >> 1 | 0x80; // add an additional one in the highest order position - } - } - } - } - - // Free the GlyphInfoArray - free (theGlyphInfoArrayPtr); - } - } - free (buf); + for (int i = 0; i < len; i++) + positions [i] = 0; + textLayout->setText (reinterpret_cast<const UInt8*>(s), len, *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 + } + } + positions[i] = (int)(advance+0.5); + unicodeCharStart++; + } } int SurfaceImpl::WidthText(Font &font_, const char *s, int len) { @@ -853,19 +816,7 @@ int SurfaceImpl::WidthText(Font &font_, const char *s, int len) { { textLayout->setText (reinterpret_cast<const UInt8*>(s), len, *reinterpret_cast<QuartzTextStyle*>(font_.GetID())); - // TODO: Maybe I should add some sort of text measurement features to QuartzTextLayout? - unsigned long actualNumberOfBounds = 0; - ATSTrapezoid glyphBounds; - - // We get a single bound, since the text should only require one. If it requires more, there is an issue - if ( ATSUGetGlyphBounds( textLayout->getLayout(), 0, 0, kATSUFromTextBeginning, kATSUToTextEnd, kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds ) != noErr || actualNumberOfBounds != 1 ) - { - Platform::DebugDisplay( "ATSUGetGlyphBounds failed in WidthText" ); - return 0; - } - - //Platform::DebugPrintf( "WidthText: \"%*s\" = %ld\n", len, s, Fix2Long( glyphBounds.upperRight.x - glyphBounds.upperLeft.x ) ); - return Fix2Long( glyphBounds.upperRight.x - glyphBounds.upperLeft.x ); + return textLayout->MeasureStringWidth(); } return 1; } @@ -876,32 +827,12 @@ int SurfaceImpl::WidthChar(Font &font_, char ch) { { textLayout->setText (reinterpret_cast<const UInt8*>(str), 1, *reinterpret_cast<QuartzTextStyle*>(font_.GetID())); - // TODO: Maybe I should add some sort of text measurement features to QuartzTextLayout? - unsigned long actualNumberOfBounds = 0; - ATSTrapezoid glyphBounds; - - // We get a single bound, since the text should only require one. If it requires more, there is an issue - if ( ATSUGetGlyphBounds( textLayout->getLayout(), 0, 0, kATSUFromTextBeginning, kATSUToTextEnd, kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds ) != noErr || actualNumberOfBounds != 1 ) - { - Platform::DebugDisplay( "ATSUGetGlyphBounds failed in WidthChar" ); - return 0; - } - - return Fix2Long( glyphBounds.upperRight.x - glyphBounds.upperLeft.x ); + return textLayout->MeasureStringWidth(); } else return 1; } -// Three possible strategies for determining ascent and descent of font: -// 1) Call ATSUGetGlyphBounds with string containing all letters, numbers and punctuation. -// 2) Use the ascent and descent fields of the font. -// 3) Call ATSUGetGlyphBounds with string as 1 but also including accented capitals. -// Smallest values given by 1 and largest by 3 with 2 in between. -// Techniques 1 and 2 sometimes chop off extreme portions of ascenders and -// descenders but are mostly OK except for accented characters which are -// rarely used in code. - // This string contains a good range of characters to test for size. const char sizeString[] = "`~!@#$%^&*()-_=+\\|[]{};:\"\'<,>.?/1234567890" "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; @@ -910,16 +841,18 @@ int SurfaceImpl::Ascent(Font &font_) { if (!font_.GetID()) return 1; - ATSUTextMeasurement ascent = reinterpret_cast<QuartzTextStyle*>( font_.GetID() )->getAttribute<ATSUTextMeasurement>( kATSUAscentTag ); - return Fix2Long( ascent ); + float ascent = reinterpret_cast<QuartzTextStyle*>( font_.GetID() )->getAscent(); + return ascent + 0.5; + } int SurfaceImpl::Descent(Font &font_) { if (!font_.GetID()) return 1; - ATSUTextMeasurement descent = reinterpret_cast<QuartzTextStyle*>( font_.GetID() )->getAttribute<ATSUTextMeasurement>( kATSUDescentTag ); - return Fix2Long( descent ); + float descent = reinterpret_cast<QuartzTextStyle*>( font_.GetID() )->getDescent(); + return descent + 0.5; + } int SurfaceImpl::InternalLeading(Font &) { @@ -932,12 +865,15 @@ int SurfaceImpl::ExternalLeading(Font &font_) { if (!font_.GetID()) return 1; - ATSUTextMeasurement lineGap = reinterpret_cast<QuartzTextStyle*>( font_.GetID() )->getAttribute<ATSUTextMeasurement>( kATSULeadingTag ); - return Fix2Long( lineGap ); + float leading = reinterpret_cast<QuartzTextStyle*>( font_.GetID() )->getLeading(); + return leading + 0.5; + } int SurfaceImpl::Height(Font &font_) { - return Ascent(font_) + Descent(font_); + + int ht = Ascent(font_) + Descent(font_); + return ht; } int SurfaceImpl::AverageCharWidth(Font &font_) { @@ -949,29 +885,6 @@ int SurfaceImpl::AverageCharWidth(Font &font_) { int width = WidthText( font_, sizeString, sizeStringLength ); return (int) ((width / (float) sizeStringLength) + 0.5); - - /* - ATSUStyle textStyle = reinterpret_cast<QuartzTextStyle*>( font_.GetID() )->getATSUStyle(); - ATSUFontID fontID; - - ByteCount actualSize = 0; - if ( ATSUGetAttribute( textStyle, kATSUFontTag, sizeof( fontID ), &fontID, &actualSize ) != noErr ) - { - Platform::DebugDisplay( "ATSUGetAttribute failed" ); - return 1; - } - - ATSFontMetrics metrics; - memset( &metrics, 0, sizeof( metrics ) ); - if ( ATSFontGetHorizontalMetrics( fontID, kATSOptionFlagsDefault, &metrics ) != noErr ) - { - Platform::DebugDisplay( "ATSFontGetHorizontalMetrics failed in AverageCharWidth" ); - return 1; - } - - printf( "%f %f %f\n", metrics.avgAdvanceWidth * 32, metrics.ascent * 32, metrics.descent * 32 ); - - return (int) (metrics.avgAdvanceWidth + 0.5);*/ } int SurfaceImpl::SetPalette(Scintilla::Palette *, bool) { diff --git a/cocoa/QuartzTextLayout.h b/cocoa/QuartzTextLayout.h index 64bf492d4..033ac98fb 100644 --- a/cocoa/QuartzTextLayout.h +++ b/cocoa/QuartzTextLayout.h @@ -15,127 +15,89 @@ #include "QuartzTextStyle.h" + class QuartzTextLayout { public: /** Create a text layout for drawing on the specified context. */ - QuartzTextLayout( CGContextRef context ) : layout( NULL ), unicode_string( NULL ), unicode_length( 0 ) + QuartzTextLayout( CGContextRef context ) { - OSStatus err = ATSUCreateTextLayout( &layout ); - if (0 != err) - layout = NULL; - + mString = NULL; + mLine = NULL; setContext(context); - - ATSUAttributeTag tag = kATSULineLayoutOptionsTag; - ByteCount size = sizeof( ATSLineLayoutOptions ); - ATSLineLayoutOptions rendering = kATSLineUseDeviceMetrics; //| kATSLineFractDisable | kATSLineUseQDRendering - ATSUAttributeValuePtr valuePtr = &rendering; - err = ATSUSetLayoutControls( layout, 1, &tag, &size, &valuePtr ); } ~QuartzTextLayout() { - if (NULL != layout) - ATSUDisposeTextLayout( layout ); - layout = NULL; - - if ( unicode_string != NULL ) - { - delete[] unicode_string; - unicode_string = NULL; - unicode_length = 0; - } - } - - /** Assign a string to the text layout object. */ - // TODO: Create a UTF8 version - // TODO: Optimise the ASCII version by not copying so much - OSStatus setText( const UInt8* buffer, size_t byteLength, CFStringEncoding encoding ) - { - if (NULL == layout) - return -1; - CFStringRef str = CFStringCreateWithBytes( NULL, buffer, byteLength, encoding, false ); - if (!str) - return -1; - - unicode_length = CFStringGetLength( str ); - if (unicode_string) - delete[] unicode_string; - unicode_string = new UniChar[ unicode_length ]; - CFStringGetCharacters( str, CFRangeMake( 0, unicode_length ), unicode_string ); - - CFRelease( str ); - str = NULL; - - OSStatus err; - err = ATSUSetTextPointerLocation( layout, unicode_string, kATSUFromTextBeginning, kATSUToTextEnd, unicode_length ); - if( err != noErr ) return err; - - // Turn on the default font fallbacks - return ATSUSetTransientFontMatching( layout, true ); + if ( mString != NULL ) + { + CFRelease(mString); + mString = NULL; + } + if ( mLine != NULL ) + { + CFRelease(mLine); + mLine = NULL; + } } inline void setText( const UInt8* buffer, size_t byteLength, const QuartzTextStyle& r ) { - this->setText( buffer, byteLength, kCFStringEncodingUTF8 ); - ATSUSetRunStyle( layout, r.getATSUStyle(), 0, unicode_length ); - } - - /** Apply the specified text style on the entire range of text. */ - void setStyle( const QuartzTextStyle& style ) - { - ATSUSetRunStyle( layout, style.getATSUStyle(), kATSUFromTextBeginning, kATSUToTextEnd ); + CFStringRef str = CFStringCreateWithBytes( NULL, buffer, byteLength, kCFStringEncodingUTF8, false ); + if (!str) + return; + + CFMutableDictionaryRef stringAttribs = r.getCTStyle(); + + if (mString != NULL) + CFRelease(mString); + mString = ::CFAttributedStringCreate(NULL, str, stringAttribs); + + if (mLine != NULL) + CFRelease(mLine); + mLine = ::CTLineCreateWithAttributedString(mString); + + CFRelease( str ); } - /** Draw the text layout into the current CGContext at the specified position, flipping the CGContext's Y axis if required. + /** Draw the text layout into the current CGContext at the specified position. * @param x The x axis position to draw the baseline in the current CGContext. - * @param y The y axis position to draw the baseline in the current CGContext. - * @param flipTextYAxis If true, the CGContext's Y axis will be flipped before drawing the text, and restored afterwards. Use this when drawing in an HIView's CGContext, where the origin is the top left corner. */ - void draw( float x, float y, bool flipTextYAxis = false ) + * @param y The y axis position to draw the baseline in the current CGContext. */ + void draw( float x, float y ) { - if (NULL == layout || 0 == unicode_length) - return; - if ( flipTextYAxis ) - { - CGContextSaveGState( gc ); - CGContextScaleCTM( gc, 1.0, -1.0 ); - y = -y; - } - - OSStatus err; - err = ATSUDrawText( layout, kATSUFromTextBeginning, kATSUToTextEnd, X2Fix( x ), X2Fix( y ) ); - - if ( flipTextYAxis ) CGContextRestoreGState( gc ); + if (mLine == NULL) + return; + + ::CGContextSetTextMatrix(gc, CGAffineTransformMakeScale(1.0, -1.0)); + + // Set the text drawing position. + ::CGContextSetTextPosition(gc, x, y); + + // And finally, draw! + ::CTLineDraw(mLine, gc); } - - /** Sets a single text layout control on the ATSUTextLayout object. - * @param tag The control to set. - * @param size The size of the parameter pointed to by value. - * @param value A pointer to the new value for the control. - */ - void setControl( ATSUAttributeTag tag, ByteCount size, ATSUAttributeValuePtr value ) - { - ATSUSetLayoutControls( layout, 1, &tag, &size, &value ); + + float MeasureStringWidth() + { + if (mLine == NULL) + return 0.0f; + + return ::CTLineGetTypographicBounds(mLine, NULL, NULL, NULL); + } + + CTLineRef getCTLine() { + return mLine; } - - ATSUTextLayout getLayout() { - return layout; - } - - inline CFIndex getLength() const { return unicode_length; } + inline void setContext (CGContextRef context) { gc = context; - if (NULL != layout) - setControl( kATSUCGContextTag, sizeof( gc ), &gc ); } private: - ATSUTextLayout layout; - UniChar* unicode_string; - int unicode_length; CGContextRef gc; + CFAttributedStringRef mString; + CTLineRef mLine; }; #endif diff --git a/cocoa/QuartzTextStyle.h b/cocoa/QuartzTextStyle.h index 36729b77b..2825fbb2f 100644 --- a/cocoa/QuartzTextStyle.h +++ b/cocoa/QuartzTextStyle.h @@ -15,75 +15,63 @@ class QuartzTextStyle public: QuartzTextStyle() { - ATSUCreateStyle( &style ); + styleDict = CFDictionaryCreateMutable(NULL, 1, NULL, NULL); } ~QuartzTextStyle() { - if ( style != NULL ) - ATSUDisposeStyle( style ); - style = NULL; + if (styleDict != NULL) + { + CFRelease(styleDict); + styleDict = NULL; + } } - - void setAttribute( ATSUAttributeTag tag, ByteCount size, ATSUAttributeValuePtr value ) - { - ATSUSetAttributes( style, 1, &tag, &size, &value ); - } - - void setAttribute( QuartzTextStyleAttribute& attribute ) - { - setAttribute( attribute.getTag(), attribute.getSize(), attribute.getValuePtr() ); - } - - void getAttribute( ATSUAttributeTag tag, ByteCount size, ATSUAttributeValuePtr value, ByteCount* actualSize ) - { - ATSUGetAttribute( style, tag, size, value, actualSize ); - } - - template <class T> - T getAttribute( ATSUAttributeTag tag ) - { - T value; - ByteCount actualSize; - ATSUGetAttribute( style, tag, sizeof( T ), &value, &actualSize ); - return value; - } - - // TODO: Is calling this actually faster than calling setAttribute multiple times? - void setAttributes( QuartzTextStyleAttribute* attributes[], int number ) - { - // Create the parallel arrays and initialize them properly - ATSUAttributeTag* tags = new ATSUAttributeTag[ number ]; - ByteCount* sizes = new ByteCount[ number ]; - ATSUAttributeValuePtr* values = new ATSUAttributeValuePtr[ number ]; - - for ( int i = 0; i < number; ++ i ) - { - tags[i] = attributes[i]->getTag(); - sizes[i] = attributes[i]->getSize(); - values[i] = attributes[i]->getValuePtr(); - } - - ATSUSetAttributes( style, number, tags, sizes, values ); - - // Free the arrays that were allocated - delete[] tags; - delete[] sizes; - delete[] values; - } - - void setFontFeature( ATSUFontFeatureType featureType, ATSUFontFeatureSelector selector ) - { - ATSUSetFontFeatures( style, 1, &featureType, &selector ); - } - - const ATSUStyle& getATSUStyle() const - { - return style; - } - + + CFMutableDictionaryRef getCTStyle() const + { + return styleDict; + } + + void setCTStyleColor(CGColor* inColor ) + { + CFDictionarySetValue(styleDict, kCTForegroundColorAttributeName, inColor); + } + + float getAscent() const + { + return ::CTFontGetAscent(fontRef); + } + + float getDescent() const + { + return ::CTFontGetDescent(fontRef); + } + + float getLeading() const + { + return ::CTFontGetLeading(fontRef); + } + + void setFontRef(CTFontRef inRef) + { + fontRef = inRef; + + if (styleDict != NULL) + CFRelease(styleDict); + + styleDict = CFDictionaryCreateMutable(NULL, 1, NULL, NULL); + + CFDictionaryAddValue(styleDict, kCTFontAttributeName, fontRef); + } + + CTFontRef getFontRef() + { + return fontRef; + } + private: - ATSUStyle style; + CFMutableDictionaryRef styleDict; + CTFontRef fontRef; }; #endif diff --git a/cocoa/QuartzTextStyleAttribute.h b/cocoa/QuartzTextStyleAttribute.h index cf227e47f..41582e8ec 100644 --- a/cocoa/QuartzTextStyleAttribute.h +++ b/cocoa/QuartzTextStyleAttribute.h @@ -12,131 +12,54 @@ #ifndef _QUARTZ_TEXT_STYLE_ATTRIBUTE_H #define _QUARTZ_TEXT_STYLE_ATTRIBUTE_H -class QuartzTextStyleAttribute -{ -public: - QuartzTextStyleAttribute() {} - virtual ~QuartzTextStyleAttribute() {} - virtual ByteCount getSize() const = 0; - virtual ATSUAttributeValuePtr getValuePtr() = 0; - virtual ATSUAttributeTag getTag() const = 0; -}; - -class QuartzTextSize : public QuartzTextStyleAttribute -{ -public: - QuartzTextSize( float points ) - { - size = X2Fix( points ); - } - - ByteCount getSize() const - { - return sizeof( size ); - } - - ATSUAttributeValuePtr getValuePtr() - { - return &size; - } - - ATSUAttributeTag getTag() const - { - return kATSUSizeTag; - } - -private: - Fixed size; -}; - -class QuartzTextStyleAttributeBoolean : public QuartzTextStyleAttribute -{ -public: - QuartzTextStyleAttributeBoolean( bool newVal ) : value( newVal ) {} - - ByteCount getSize() const - { - return sizeof( value ); - } - ATSUAttributeValuePtr getValuePtr() - { - return &value; - } - - virtual ATSUAttributeTag getTag() const = 0; - -private: - Boolean value; -}; - -class QuartzTextBold : public QuartzTextStyleAttributeBoolean -{ -public: - QuartzTextBold( bool newVal ) : QuartzTextStyleAttributeBoolean( newVal ) {} - ATSUAttributeTag getTag() const - { - return kATSUQDBoldfaceTag; - } -}; - -class QuartzTextItalic : public QuartzTextStyleAttributeBoolean -{ -public: - QuartzTextItalic( bool newVal ) : QuartzTextStyleAttributeBoolean( newVal ) {} - ATSUAttributeTag getTag() const - { - return kATSUQDItalicTag; - } -}; - -class QuartzTextUnderline : public QuartzTextStyleAttributeBoolean -{ -public: - QuartzTextUnderline( bool newVal ) : QuartzTextStyleAttributeBoolean( newVal ) {} - ATSUAttributeTag getTag() const { - return kATSUQDUnderlineTag; - } -}; - -class QuartzFont : public QuartzTextStyleAttribute +class QuartzFont { public: /** Create a font style from a name. */ - QuartzFont( const char* name, int length ) + QuartzFont( const char* name, int length, float size, bool bold, bool italic ) { assert( name != NULL && length > 0 && name[length] == '\0' ); - // try to create font - OSStatus err = ATSUFindFontFromName( const_cast<char*>( name ), length, kFontFullName, (unsigned) kFontNoPlatform, kFontRomanScript, (unsigned) kFontNoLanguage, &fontid ); - // need a fallback if font isn't installed - if( err != noErr || fontid == kATSUInvalidFontID ) - ::ATSUFindFontFromName( "Lucida Grande", 13, kFontFullName, (unsigned) kFontNoPlatform, kFontRomanScript, (unsigned) kFontNoLanguage, &fontid ); + CFStringRef fontName = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingMacRoman); + assert(fontName != NULL); + + if (bold || italic) + { + CTFontSymbolicTraits desiredTrait = 0; + CTFontSymbolicTraits traitMask = 0; + + // if bold was specified, add the trait + if (bold) { + desiredTrait |= kCTFontBoldTrait; + traitMask |= kCTFontBoldTrait; + } + + // if italic was specified, add the trait + if (italic) { + desiredTrait |= kCTFontItalicTrait; + traitMask |= kCTFontItalicTrait; + } + + // create a font and then a copy of it with the sym traits + CTFontRef iFont = ::CTFontCreateWithName(fontName, size, NULL); + fontid = ::CTFontCreateCopyWithSymbolicTraits(iFont, size, NULL, desiredTrait, traitMask); + CFRelease(iFont); + } + else + { + // create the font, no traits + fontid = ::CTFontCreateWithName(fontName, size, NULL); + } } - ByteCount getSize() const - { - return sizeof( fontid ); - } - - ATSUAttributeValuePtr getValuePtr() - { - return &fontid; - } - - ATSUAttributeTag getTag() const - { - return kATSUFontTag; - } - - ATSUFontID getFontID() const + CTFontRef getFontID() { return fontid; } private: - ATSUFontID fontid; + CTFontRef fontid; }; - #endif |