diff options
| -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 | 
