예제 #1
0
ATSUFontID coretext_font_to_atsufontid(void *p_font)
{
    bool t_success;
    t_success = true;
    
    CTFontRef t_ctfont;
    t_ctfont = NULL;
    if (t_success)
    {
        t_ctfont = (CTFontRef)p_font;
        t_success = t_ctfont != NULL;
    }
    
    char t_name[256];
    if (t_success)
    {
        CFStringRef t_cfname;
        t_cfname = CTFontCopyPostScriptName(t_ctfont);
        t_success = t_cfname != NULL && CFStringGetCString(t_cfname, t_name, 256, kCFStringEncodingMacRoman);
        if (t_cfname != NULL)
            CFRelease(t_cfname);
    }
    
    ATSUFontID t_font_id;
    t_font_id = 0;
    if (t_success)
    {
        uint32_t t_name_length;
        t_name_length = MCCStringLength(t_name);
        t_success = ATSUFindFontFromName(t_name, t_name_length, kFontPostscriptName, kFontNoPlatform, kFontNoScript, kFontNoLanguage, &t_font_id) == noErr;
    }
    
    return t_font_id;
}
예제 #2
0
bool MCField::macmatchfontname(const char *p_font_name, char p_derived_font_name[])
{
	ATSUFontID t_font_id;
	if (ATSUFindFontFromName(p_font_name, strlen(p_font_name), kFontFullName, kFontNoPlatform, kFontNoScript, kFontNoLanguage, &t_font_id) == noErr ||
		ATSUFindFontFromName(p_font_name, strlen(p_font_name), kFontUniqueName, kFontNoPlatform, kFontNoScript, kFontNoLanguage, &t_font_id) == noErr ||
		ATSUFindFontFromName(p_font_name, strlen(p_font_name), kFontFamilyName, kFontNoPlatform, kFontNoScript, kFontNoLanguage, &t_font_id) == noErr ||
		ATSUFindFontFromName(p_font_name, strlen(p_font_name), kFontNoName, kFontNoPlatform, kFontNoScript, kFontNoLanguage, &t_font_id) == noErr)
	{
		// Fetch the style name
		char t_style_name[64];
		ByteCount t_style_name_length;
		t_style_name_length = 0;
		ATSUFindFontName(t_font_id, kFontStyleName, kFontMacintoshPlatform, kFontNoScript, kFontNoLanguage, 63, t_style_name, &t_style_name_length, NULL);
		t_style_name[t_style_name_length] = '\0';
		
		// Fetch the full name
		char t_full_name[256];
		ByteCount t_full_name_length;
		t_full_name_length = 0;
		ATSUFindFontName(t_font_id, kFontFullName, kFontMacintoshPlatform, kFontNoScript, kFontNoLanguage, 255, t_full_name, &t_full_name_length, NULL);
		t_full_name[t_full_name_length] = '\0';
		
		// MW-2011-09-02: Make sure we don't do anything at all if style is regular
		//   (output name should be fullname!)
		if (MCCStringEqualCaseless(t_style_name, "Regular"))
			p_font_name = p_font_name; // Do nothing
		else if (MCCStringEndsWithCaseless(t_full_name, "Bold Italic"))
			t_full_name[t_full_name_length - 12] = '\0';
		else if (MCCStringEndsWithCaseless(t_full_name, "Bold"))
			t_full_name[t_full_name_length - 5] = '\0';
		else if (MCCStringEndsWithCaseless(t_full_name, "Italic"))
			t_full_name[t_full_name_length - 7] = '\0';
		
		strcpy(p_derived_font_name, t_full_name);
		
		return true;
	}
	
	return false;
}
예제 #3
0
파일: main.c 프로젝트: arnelh/Examples
static
OSStatus CreateStyleObjectWithFontName(
	char		*fontName,
	Fixed		*fontSize,
	RGBColor	*fontColor,
	ATSUStyle	*newStyle )
{
	OSStatus				err;
	ATSUFontID				fontID;
	ATSUAttributeTag		tags[3];
	ByteCount				tagValueSizes[3];
	ATSUAttributeValuePtr	tagValuePtrs[3];
	
	
	// try to find the font based on the font name
	err = ATSUFindFontFromName( fontName, strlen( fontName ), kFontFullName,
		kFontNoPlatform, kFontNoScript, kFontNoLanguage, &fontID );
	require_noerr( err, CreateStyleObjectWithFontName_err );

	// first, create the new style object
	err = ATSUCreateStyle( newStyle );
	
	// set up the three tags that we are setting in the style
	tags[0] = kATSUFontTag;
	tagValueSizes[0] = sizeof( ATSUFontID );
	tagValuePtrs[0] = &fontID;
	
	tags[1] = kATSUSizeTag;
	tagValueSizes[1] = sizeof( Fixed );
	tagValuePtrs[1] = fontSize;
	
	tags[2] = kATSUColorTag;
	tagValueSizes[2] = sizeof( RGBColor );
	tagValuePtrs[2] = fontColor;
	
	// set the attributes in the style object
	err = ATSUSetAttributes( *newStyle, 3, tags, tagValueSizes, tagValuePtrs );
	check_noerr( err );
	
	// if there was an error, then dispose of the style
	if ( err != noErr ) {
		ATSUDisposeStyle( *newStyle );
	}
	
CreateStyleObjectWithFontName_err: 

	return err;
	
}
예제 #4
0
OSStatus CreateATSUIStyleFromFontFullNameAndSize (const char *fontName, int fontSize, ATSUStyle *theStyle)
{
	OSStatus	err;
	ATSUStyle	localStyle;
	ATSUFontID	atsuFont;
	Fixed		atsuSize;

	ATSUAttributeTag		theTags[]   = { kATSUFontTag,       kATSUSizeTag  };
	ByteCount				theSizes[]  = { sizeof(ATSUFontID), sizeof(Fixed) };
	ATSUAttributeValuePtr	theValues[] = { NULL,                NULL         };

	atsuFont = 0;
	atsuSize = FixRatio(fontSize, 1);
	localStyle = NULL;

	theValues[0] = &atsuFont;
	theValues[1] = &atsuSize;

	err = ATSUFindFontFromName(fontName, strlen(fontName), kFontFullName, kFontNoPlatform, kFontNoScript, kFontNoLanguage, &atsuFont);
	if (err == noErr)
	{
		err = ATSUCreateStyle(&localStyle);
		if (err == noErr)
		{
			err = ATSUSetAttributes(localStyle, sizeof(theTags) / sizeof(theTags[0]), theTags, theSizes, theValues);
			if (err == noErr)
			{
				*theStyle = localStyle;
				return (noErr);
			}
		}
	}

	if (localStyle != NULL)
		err = ATSUDisposeStyle(localStyle);

	return (err);
}
예제 #5
0
// This example is almost identical to the helloworld example, except that
// in this case, there are two styles instead of just one. ATSUSetRunStyle
// is used to apply a style to different parts of the text.
//
void DrawMultipleStylesContents(WindowRef window)
{
	CFStringRef					string;
	UniChar						*text;
	UniCharCount				length;
    UniCharArrayOffset			currentStart, currentEnd;
	ATSUStyle					style1, style2;
	ATSUTextLayout				layout;
	ATSUFontID					font;
	Fixed						pointSize;
    ATSUAttributeTag			tags[2];
    ByteCount					sizes[2];
    ATSUAttributeValuePtr		values[2];
	Fixed						lineWidth, ascent, descent;
	CGContextRef				cgContext;
	float						x, y, cgY, windowHeight;
    ItemCount					numSoftBreaks;
    UniCharArrayOffset			*theSoftBreaks;
    int							i;
    GrafPtr						port, savedPort;
	Rect						portBounds;

    // Set up the graphics port
	port = GetWindowPort(window);
    GetPort(&savedPort);
    SetPort(port);
    GetPortBounds(port, &portBounds);
    EraseRect(&portBounds);

	// Create a style object. This is one of two objects necessary to draw using ATSUI.
	// (The layout is the other.)
	verify_noerr( ATSUCreateStyle(&style1) );

    // Look up the font we are going to use, and set it in the style object, using
	// the aforementioned "triple" (tag, size, value) semantics. This is how almost
	// all settings in ATSUI are applied.
	verify_noerr( ATSUFindFontFromName(kMultipleStylesFontName, strlen(kMultipleStylesFontName), kFontFullName, kFontNoPlatform, kFontNoScript, kFontNoLanguage, &font) );
    tags[0] = kATSUFontTag;
    sizes[0] = sizeof(ATSUFontID);
    values[0] = &font;
    verify_noerr( ATSUSetAttributes(style1, 1, tags, sizes, values) );

    // Set the point size, also using a triple. You can actually set multiple triples at once,
	// since the tag, size, and value parameters are arrays. Other examples do this, such as
	// the vertical text example.
	// 
	pointSize = Long2Fix(kMultipleStylesFontSize);
	tags[0] = kATSUSizeTag;
    sizes[0] = sizeof(Fixed);
    values[0] = &pointSize;
    verify_noerr( ATSUSetAttributes(style1, 1, tags, sizes, values) );
	
	// Now we create the second of two objects necessary to draw text using ATSUI, the layout.
	// You can specify a pointer to the text buffer at layout creation time, or later using
	// the routine ATSUSetTextPointerLocation(). Below, we do it after layout creation time.
	verify_noerr( ATSUCreateTextLayout(&layout) );

	// Before assigning text to the layout, we must first convert the string we plan to draw
	// from a CFStringRef into an array of UniChar.
	string = CFStringCreateWithCString(NULL, "In this example, various parts of the text have different styles applied. The same style is used more than once.", kCFStringEncodingASCII);

    // Extract the raw Unicode from the CFString, then dispose of the CFString
    length = CFStringGetLength(string);
    text = (UniChar *)malloc(length * sizeof(UniChar));
    CFStringGetCharacters(string, CFRangeMake(0, length), text);
	CFRelease(string);

    // Attach the resulting UTF-16 Unicode text to the layout
    verify_noerr( ATSUSetTextPointerLocation(layout, text, kATSUFromTextBeginning, kATSUToTextEnd, length) );
	
	// Now we tie the two necessary objects, the layout and the style, together
	verify_noerr( ATSUSetRunStyle(layout, style1, kATSUFromTextBeginning, kATSUToTextEnd) );

	// Now, for this example we create a second style, and assign it to various runs within
	// the text. For our example, the run offsets are hard-coded for simplicity's sake. In
	// a real application, style runs are often assigned from external sources, such as user
	// selection.
	verify_noerr( ATSUCreateAndCopyStyle(style1, &style2) );

	// Change the font for the second style
	verify_noerr( ATSUFindFontFromName(kMultipleStylesFontName2, strlen(kMultipleStylesFontName2), kFontFullName, kFontNoPlatform, kFontNoScript, kFontNoLanguage, &font) );
    tags[0] = kATSUFontTag;
    sizes[0] = sizeof(ATSUFontID);
    values[0] = &font;
    verify_noerr( ATSUSetAttributes(style2, 1, tags, sizes, values) );

	// Apply the new style to the text in various places
	verify_noerr( ATSUSetRunStyle(layout, style2, 8, 7) ); // The word "example"
	verify_noerr( ATSUSetRunStyle(layout, style2, 65, 7) ); // The word "applied"
	verify_noerr( ATSUSetRunStyle(layout, style2, 83, 5) ); // The word "style"
	verify_noerr( ATSUSetRunStyle(layout, style2, 107, 4) ); // The word "once"

	// In this example, we are breaking text into lines.
	// Therefore, we need to know the width of the line.
    lineWidth = X2Fix(portBounds.right - portBounds.left - 2.0*kMultipleStylesMargin);
    tags[0] = kATSULineWidthTag;
    sizes[0] = sizeof(Fixed);
    values[0] = &lineWidth;
	verify_noerr( ATSUSetLayoutControls(layout, 1, tags, sizes, values) );

	// Prepare the CGContext for drawing
	QDBeginCGContext(port, &cgContext);
	tags[0] = kATSUCGContextTag;
	sizes[0] = sizeof(CGContextRef);
	values[0] = &cgContext;
	verify_noerr( ATSUSetLayoutControls(layout, 1, tags, sizes, values) );
	
	// Prepare the coordinates for drawing. In our example, "x" and "y" are the coordinates
	// in QD space. "cgY" contains the y coordinate in CG space.
	//
	windowHeight = portBounds.bottom - portBounds.top;
	x = kMultipleStylesMargin; // leave a small left margin
	y = kMultipleStylesMargin; // leave a small top margin
	cgY = windowHeight - y; // Subtract the y coordinate from the height of the
							// window to get the coordinate in CG-aware space.

	// Break the text into lines
	verify_noerr( ATSUBatchBreakLines(layout, kATSUFromTextBeginning, length, lineWidth, &numSoftBreaks) );
    verify_noerr( ATSUGetSoftLineBreaks(layout, kATSUFromTextBeginning, kATSUToTextEnd, 0, NULL, &numSoftBreaks) );
    theSoftBreaks = (UniCharArrayOffset *) malloc(numSoftBreaks * sizeof(UniCharArrayOffset));
    verify_noerr( ATSUGetSoftLineBreaks(layout, kATSUFromTextBeginning, kATSUToTextEnd, numSoftBreaks, theSoftBreaks, &numSoftBreaks) );
	
    // Loop over all the lines and draw them
    currentStart = 0;
    for (i=0; i <= numSoftBreaks; i++) {
        currentEnd = ((numSoftBreaks > 0 ) && (numSoftBreaks > i)) ? theSoftBreaks[i] : length;

        // This is the height of a line, the ascent and descent. Getting the values this way is the preferred method.
		ATSUGetLineControl(layout, currentStart, kATSULineAscentTag, sizeof(ATSUTextMeasurement), &ascent, NULL);
        ATSUGetLineControl(layout, currentStart, kATSULineDescentTag, sizeof(ATSUTextMeasurement), &descent, NULL);

        // Make room for the area above the baseline
		y += Fix2X(ascent);
		cgY = windowHeight - y;

		// Draw the text
        verify_noerr( ATSUDrawText(layout, currentStart, currentEnd - currentStart, X2Fix(x), X2Fix(cgY)) );

		// Make room for the area beloww the baseline
        y += Fix2X(descent);
		
		// Prepare for next line
        currentStart = currentEnd;
    }

	// This is a one-shot window, so we are now ready to dispose of all our objects.
	// Normally, we would want to keep everything around in case we needed to redraw or change
	// the text at some point.
	
    // Tear down the CGContext
	CGContextFlush(cgContext);
	QDEndCGContext(port, &cgContext);

	// Deallocate string storage
	free(text);

	// Layout and styles also need to be disposed
	verify_noerr( ATSUDisposeStyle(style1) );
	verify_noerr( ATSUDisposeStyle(style2) );
	verify_noerr( ATSUDisposeTextLayout(layout) );

    // Restore the graphics port
    SetPort(savedPort);
}
예제 #6
0
void PlatformFont::enumeratePlatformFonts( Vector< StringTableEntry >& fonts, UTF16* fontFamily )
{
   if( fontFamily )
   {
      // Determine the font ID from the family name.
      
      ATSUFontID fontID;
      if( ATSUFindFontFromName(
            fontFamily,
            dStrlen( fontFamily ) * 2,
            kFontFamilyName,
            kFontMicrosoftPlatform,
            kFontNoScriptCode,
            kFontNoLanguageCode, &fontID ) != kATSUInvalidFontErr )
      {
         // Get the number of fonts in the family.
         
         ItemCount numFonts;
         ATSUCountFontNames( fontID, &numFonts );
         
         // Read out font names.
         
         U32 bufferSize = 512;
         char* buffer = ( char* ) dMalloc( bufferSize );
         
         for( U32 i = 0; i < numFonts; ++ i )
         {
            for( U32 n = 0; n < 2; ++ n )
            {
               ByteCount actualNameLength;
               FontNameCode fontNameCode;
               FontPlatformCode fontPlatformCode;
               FontScriptCode fontScriptCode;
               FontLanguageCode fontLanguageCode;
               
               if( ATSUGetIndFontName(
                     fontID,
                     i,
                     bufferSize - 2,
                     buffer,
                     &actualNameLength,
                     &fontNameCode,
                     &fontPlatformCode,
                     &fontScriptCode,
                     &fontLanguageCode ) == noErr )
               {
                  *( ( UTF16* ) &buffer[ actualNameLength ] ) = '\0';
                  char* utf8 = convertUTF16toUTF8( ( UTF16* ) buffer );
                  fonts.push_back( StringTable->insert( utf8 ) );
                  delete [] utf8;
                  break;
               }
               
               // Allocate larger buffer.
               
               bufferSize = actualNameLength + 2;
               buffer = ( char* ) dRealloc( buffer, bufferSize );
            }
         }
         
         dFree( buffer );
      }
   }
   else
   {
      // Get the number of installed fonts.
      
      ItemCount numFonts;
      ATSUFontCount( &numFonts );
      
      // Get all the font IDs.
      
      ATSUFontID* fontIDs = new ATSUFontID[ numFonts ];
      if( ATSUGetFontIDs( fontIDs, numFonts, &numFonts ) == noErr )
      {
         U32 bufferSize = 512;
         char* buffer = ( char* ) dMalloc( bufferSize );
         
         // Read all family names.
         
         for( U32 i = 0; i < numFonts; ++ i )
         {
            for( U32 n = 0; n < 2; ++ n )
            {
               ByteCount actualNameLength;
               ItemCount fontIndex;
               
               OSStatus result = ATSUFindFontName(
                     fontIDs[ i ],
                     kFontFamilyName,
                     kFontMicrosoftPlatform,
                     kFontNoScriptCode,
                     kFontNoLanguageCode,
                     bufferSize - 2,
                     buffer,
                     &actualNameLength,
                     &fontIndex );
               
               if( result == kATSUNoFontNameErr )
                  break;
               else if( result == noErr )
               {
                  *( ( UTF16* ) &buffer[ actualNameLength ] ) = '\0';
                  char* utf8 = convertUTF16toUTF8( ( UTF16* ) buffer );
                  StringTableEntry name = StringTable->insert( utf8 );
                  delete [] utf8;
                  
                  // Avoid duplicates.
                  
                  bool duplicate = false;
                  for( U32 i = 0, num = fonts.size(); i < num; ++ i )
                     if( fonts[ i ] == name )
                     {
                        duplicate = true;
                        break;
                     }
                     
                  if( !duplicate )
                     fonts.push_back( name );
                     
                  break;
               }
               
               // Allocate larger buffer.
               
               bufferSize = actualNameLength + 2;
               buffer = ( char* ) dRealloc( buffer, bufferSize );
            }
         }
         
         dFree( buffer );
      }
      
      delete [] fontIDs;
   }
}
예제 #7
0
void IGraphicsCarbon::CreateTextEntry(IControl* pControl, IText* pText, IRECT* pTextRect, const char* pString, IParam* pParam)
{
  if (!pControl || mTextEntryView || !mIsComposited) return; // Only composited carbon supports text entry

  WindowRef window = mWindow;
  TXNFrameOptions txnFrameOptions = kTXNMonostyledTextMask | kTXNDisableDragAndDropMask | kTXNSingleLineOnlyMask;
  TXNObject txnObject = 0;
  TXNFrameID frameID = 0;
  TXNObjectRefcon txnObjectRefCon = 0;

  HIRect rct;
  HIViewGetFrame(this->mView, &rct);

  HIViewRef contentView;
  HIViewFindByID (HIViewGetRoot(this->mWindow), kHIViewWindowContentID, &contentView);
  HIViewConvertRect(&rct, HIViewGetSuperview((HIViewRef)this->mView), contentView);

  Rect rect = { rct.origin.y + pTextRect->T,
                rct.origin.x + pTextRect->L,
                rct.origin.y + pTextRect->B + 1,
                rct.origin.x + pTextRect->R + 1
              };

  if (TXNNewObject(NULL,
                   window,
                   &rect,
                   txnFrameOptions,
                   kTXNTextEditStyleFrameType,
                   kTXNSingleStylePerTextDocumentResType,
                   kTXNMacOSEncoding,
                   &txnObject,
                   &frameID,
                   txnObjectRefCon) == noErr)
  {
    TXNSetFrameBounds(txnObject, rect.top, rect.left, rect.bottom, rect.right, frameID);
    mTextEntryView = txnObject;

    // Set the text to display by defualt
    TXNSetData(mTextEntryView, kTXNTextData, pString, strlen(pString)/*+1*/, kTXNStartOffset, kTXNEndOffset); // center aligned text has problems with uneven string lengths

    RGBColor tc;
    tc.red = pText->mTextEntryFGColor.R * 257;
    tc.green = pText->mTextEntryFGColor.G * 257;
    tc.blue = pText->mTextEntryFGColor.B * 257;

    TXNBackground bg;
    bg.bgType         = kTXNBackgroundTypeRGB;
    bg.bg.color.red   = pText->mTextEntryBGColor.R * 257;
    bg.bg.color.green = pText->mTextEntryBGColor.G * 257;
    bg.bg.color.blue  = pText->mTextEntryBGColor.B * 257;

    TXNSetBackground(mTextEntryView, &bg);

    // Set justification
    SInt16 justification;
    Fract flushness;

    switch ( pText->mAlign )
    {
      case IText::kAlignCenter:
        justification = kTXNCenter;  // seems to be buggy wrt dragging and alignement with uneven string lengths
        flushness = kATSUCenterAlignment;
        break;
      case IText::kAlignFar:
        justification = kTXNFlushRight;
        flushness = kATSUEndAlignment;
        break;
      case IText::kAlignNear:
      default:
        justification = kTXNFlushLeft;
        flushness = kATSUStartAlignment;
        break;
    }

    TXNControlTag controlTag[1];
    TXNControlData controlData[1];
    controlTag[0] = kTXNJustificationTag;
    controlData[0].sValue = justification;
    TXNSetTXNObjectControls(mTextEntryView, false, 1, controlTag, controlData);

    ATSUFontID fontid = kATSUInvalidFontID;

    if (pText->mFont && pText->mFont[0])
    {
      ATSUFindFontFromName(pText->mFont, strlen(pText->mFont),
                           kFontFullName /* kFontFamilyName? */ ,
                           (FontPlatformCode)kFontNoPlatform,
                           kFontNoScriptCode,
                           kFontNoLanguageCode,
                           &fontid);
    }

    // font (NOT working)
    TXNTypeAttributes attributes[3];
    attributes[0].tag = kATSUFontTag;
    attributes[0].size = sizeof(ATSUFontID);
    attributes[0].data.dataPtr = &fontid;
    // size
    attributes[1].tag = kTXNQDFontSizeAttribute;
    attributes[1].size = kTXNFontSizeAttributeSize;
    attributes[1].data.dataValue = pText->mSize << 16;
    // color
    attributes[2].tag = kTXNQDFontColorAttribute;
    attributes[2].size = kTXNQDFontColorAttributeSize;
    attributes[2].data.dataPtr = &tc;

    // Finally set the attributes
    TXNSetTypeAttributes(mTextEntryView, 3, attributes, kTXNStartOffset, kTXNEndOffset);

    // Ensure focus remains consistent
    SetUserFocusWindow(window);
    AdvanceKeyboardFocus(window);

    // Set the focus to the edit window
    TXNFocus(txnObject, true);
    TXNSelectAll(mTextEntryView);
    TXNShowSelection(mTextEntryView, true);

    // The event types
    const static EventTypeSpec eventTypes[] =
    {
      { kEventClassMouse,    kEventMouseMoved },
      { kEventClassMouse,    kEventMouseDown },
      { kEventClassMouse,    kEventMouseUp },
      { kEventClassMouse,    kEventMouseWheelMoved },
      { kEventClassWindow,   kEventWindowClosed },
      { kEventClassWindow,   kEventWindowDeactivated },
      { kEventClassWindow,   kEventWindowFocusRelinquish },
      { kEventClassKeyboard, kEventRawKeyDown },
      { kEventClassKeyboard, kEventRawKeyRepeat }
    };

    // Install the event handler
    InstallWindowEventHandler(window, TextEntryHandler, GetEventTypeCount(eventTypes), eventTypes, this, &mTextEntryHandler);

    mEdControl = pControl;
    mEdParam = pParam;
    mTextEntryRect = *pTextRect;
  }
}
예제 #8
0
static cairo_status_t
_cairo_atsui_font_create_toy(cairo_toy_font_face_t *toy_face,
			     const cairo_matrix_t *font_matrix,
			     const cairo_matrix_t *ctm,
			     const cairo_font_options_t *options,
			     cairo_scaled_font_t **font_out)
{
    cairo_atsui_font_t *font = NULL;
    ATSUStyle style;
    ATSUFontID fontID;
    OSStatus err;
    Boolean isItalic, isBold;
    cairo_matrix_t scale;
    const char *family = toy_face->family;

    err = ATSUCreateStyle(&style);

    switch (toy_face->weight) {
    case CAIRO_FONT_WEIGHT_BOLD:
        isBold = true;
        break;
    case CAIRO_FONT_WEIGHT_NORMAL:
    default:
        isBold = false;
        break;
    }

    switch (toy_face->slant) {
    case CAIRO_FONT_SLANT_ITALIC:
        isItalic = true;
        break;
    case CAIRO_FONT_SLANT_OBLIQUE:
        isItalic = false;
        break;
    case CAIRO_FONT_SLANT_NORMAL:
    default:
        isItalic = false;
        break;
    }

    err = ATSUFindFontFromName(family, strlen(family),
                               kFontFamilyName,
                               kFontNoPlatformCode,
                               kFontRomanScript,
                               kFontNoLanguageCode, &fontID);

    if (err != noErr) {
	// couldn't get the font - remap css names and try again

	if (!strcmp(family, "serif"))
	    family = "Times";
	else if (!strcmp(family, "sans-serif"))
	    family = "Helvetica";
	else if (!strcmp(family, "cursive"))
	    family = "Apple Chancery";
	else if (!strcmp(family, "fantasy"))
	    family = "Gadget";
	else if (!strcmp(family, "monospace"))
	    family = "Courier";
	else // anything else - return error instead?
	    family = "Courier";

	err = ATSUFindFontFromName(family, strlen(family),
				   kFontFamilyName,
				   kFontNoPlatformCode,
				   kFontRomanScript,
				   kFontNoLanguageCode, &fontID);
    }


    ATSUAttributeTag styleTags[] =
        { kATSUQDItalicTag, kATSUQDBoldfaceTag, kATSUFontTag };
    ATSUAttributeValuePtr styleValues[] = { &isItalic, &isBold, &fontID };
    ByteCount styleSizes[] =
        { sizeof(Boolean), sizeof(Boolean), sizeof(ATSUFontID) };


    err = ATSUSetAttributes(style,
                            sizeof(styleTags) / sizeof(styleTags[0]),
                            styleTags, styleSizes, styleValues);

    font = malloc(sizeof(cairo_atsui_font_t));

    _cairo_scaled_font_init(&font->base, toy_face, font_matrix, ctm, options,
			    &cairo_atsui_scaled_font_backend);

    cairo_matrix_multiply(&scale, font_matrix, ctm);
    font->style = CreateSizedCopyOfStyle(style, &scale);

    Fixed theSize = FloatToFixed(1.0);
    const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag };
    const ByteCount theFontStyleSizes[] = { sizeof(Fixed) };
    ATSUAttributeValuePtr theFontStyleValues[] = { &theSize };
    err = ATSUSetAttributes(style,
                            sizeof(theFontStyleTags) /
                            sizeof(ATSUAttributeTag), theFontStyleTags,
                            theFontStyleSizes, theFontStyleValues);

    font->unscaled_style = style;

    font->fontID = fontID;
    font->scale = scale;

    *font_out = &font->base;

    return CAIRO_STATUS_SUCCESS;
}