void QFontDatabase::load(const QFontPrivate *d, int script) { // sanity checks if(!qApp) qWarning("QFont: Must construct a QApplication before a QFont"); Q_ASSERT(script >= 0 && script < QUnicodeTables::ScriptCount); Q_UNUSED(script); QFontDef req = d->request; req.pixelSize = qt_mac_pixelsize(req, d->dpi); // set the point size to 0 to get better caching req.pointSize = 0; QFontCache::Key key = QFontCache::Key(req, QUnicodeTables::Common, d->screen); if(!(d->engineData = QFontCache::instance()->findEngineData(key))) { d->engineData = new QFontEngineData; QFontCache::instance()->insertEngineData(key, d->engineData); } else { d->engineData->ref.ref(); } if(d->engineData->engine) // already loaded return; // set it to the actual pointsize, so QFontInfo will do the right thing req.pointSize = qRound(qt_mac_pointsize(d->request, d->dpi)); QFontEngine *e = QFontCache::instance()->findEngine(key); if(!e && qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) { e = new QTestFontEngine(req.pixelSize); e->fontDef = req; } if(e) { e->ref.ref(); d->engineData->engine = e; return; // the font info and fontdef should already be filled } //find the font QStringList family_list = familyList(req); const char *stylehint = styleHint(req); if (stylehint) family_list << QLatin1String(stylehint); // add QFont::defaultFamily() to the list, for compatibility with // previous versions family_list << QApplication::font().defaultFamily(); ATSFontFamilyRef familyRef = 0; ATSFontRef fontRef = 0; QMutexLocker locker(fontDatabaseMutex()); QFontDatabasePrivate *db = privateDb(); if (!db->count) initializeDb(); for(int i = 0; i < family_list.size(); ++i) { for (int k = 0; k < db->count; ++k) { if (db->families[k]->name.compare(family_list.at(i), Qt::CaseInsensitive) == 0) { QByteArray family_name = db->families[k]->name.toUtf8(); familyRef = ATSFontFamilyFindFromName(QCFString(db->families[k]->name), kATSOptionFlagsDefault); if (familyRef) { fontRef = ATSFontFindFromName(QCFString(db->families[k]->name), kATSOptionFlagsDefault); goto FamilyFound; } else { #if defined(QT_MAC_USE_COCOA) // ATS and CT disagrees on what the family name should be, // use CT to look up the font if ATS fails. QCFString familyName = QString::fromAscii(family_name); QCFType<CTFontRef> CTfontRef = CTFontCreateWithName(familyName, 12, NULL); QCFType<CTFontDescriptorRef> fontDescriptor = CTFontCopyFontDescriptor(CTfontRef); QCFString displayName = (CFStringRef)CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontDisplayNameAttribute); familyRef = ATSFontFamilyFindFromName(displayName, kATSOptionFlagsDefault); if (familyRef) { fontRef = ATSFontFindFromName(displayName, kATSOptionFlagsDefault); goto FamilyFound; } #endif } } } } FamilyFound: //fill in the engine's font definition QFontDef fontDef = d->request; //copy.. if(fontDef.pointSize < 0) fontDef.pointSize = qt_mac_pointsize(fontDef, d->dpi); else fontDef.pixelSize = qt_mac_pixelsize(fontDef, d->dpi); #if 0 ItemCount name_count; if(ATSUCountFontNames(fontID, &name_count) == noErr && name_count) { ItemCount actualName_size; if(ATSUGetIndFontName(fontID, 0, 0, 0, &actualName_size, 0, 0, 0, 0) == noErr && actualName_size) { QByteArray actualName(actualName_size); if(ATSUGetIndFontName(fontID, 0, actualName_size, actualName.data(), &actualName_size, 0, 0, 0, 0) == noErr && actualName_size) fontDef.family = QString::fromUtf8(actualName); } } #else { QCFString actualName; if(ATSFontFamilyGetName(familyRef, kATSOptionFlagsDefault, &actualName) == noErr) fontDef.family = actualName; } #endif #ifdef QT_MAC_USE_COCOA QFontEngine *engine = new QCoreTextFontEngineMulti(familyRef, fontRef, fontDef, d->kerning); #elif 1 QFontEngine *engine = new QFontEngineMacMulti(familyRef, fontRef, fontDef, d->kerning); #else ATSFontFamilyRef atsFamily = familyRef; ATSFontFamilyRef atsFontRef = fontRef; FMFont fontID; FMFontFamily fmFamily; FMFontStyle fntStyle = 0; fmFamily = FMGetFontFamilyFromATSFontFamilyRef(atsFamily); if (fmFamily == kInvalidFontFamily) { // Use the ATSFont then... fontID = FMGetFontFromATSFontRef(atsFontRef); } else { if (fontDef.weight >= QFont::Bold) fntStyle |= ::bold; if (fontDef.style != QFont::StyleNormal) fntStyle |= ::italic; FMFontStyle intrinsicStyle; FMFont fnt = 0; if (FMGetFontFromFontFamilyInstance(fmFamily, fntStyle, &fnt, &intrinsicStyle) == noErr) fontID = FMGetATSFontRefFromFont(fnt); } OSStatus status; const int maxAttributeCount = 5; ATSUAttributeTag tags[maxAttributeCount + 1]; ByteCount sizes[maxAttributeCount + 1]; ATSUAttributeValuePtr values[maxAttributeCount + 1]; int attributeCount = 0; Fixed size = FixRatio(fontDef.pixelSize, 1); tags[attributeCount] = kATSUSizeTag; sizes[attributeCount] = sizeof(size); values[attributeCount] = &size; ++attributeCount; tags[attributeCount] = kATSUFontTag; sizes[attributeCount] = sizeof(fontID); values[attributeCount] = &fontID; ++attributeCount; CGAffineTransform transform = CGAffineTransformIdentity; if (fontDef.stretch != 100) { transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1); tags[attributeCount] = kATSUFontMatrixTag; sizes[attributeCount] = sizeof(transform); values[attributeCount] = &transform; ++attributeCount; } ATSUStyle style; status = ATSUCreateStyle(&style); Q_ASSERT(status == noErr); Q_ASSERT(attributeCount < maxAttributeCount + 1); status = ATSUSetAttributes(style, attributeCount, tags, sizes, values); Q_ASSERT(status == noErr); QFontEngine *engine = new QFontEngineMac(style, fontID, fontDef, /*multiEngine*/ 0); ATSUDisposeStyle(style); #endif d->engineData->engine = engine; engine->ref.ref(); //a ref for the engineData->engine QFontCache::instance()->insertEngine(key, engine); }
//------------------------------------------------------------------------------ bool MacCarbFont::create( const char* name, U32 size, U32 charset) { String nameStr = name; nameStr = nameStr.trim(); // create and cache the style and layout. // based on apple sample code at http://developer.apple.com/qa/qa2001/qa1027.html // note: charset is ignored on mac. -- we don't need it to get the right chars. // But do we need it to translate encodings? hmm... CFStringRef cfsName; ATSUFontID atsuFontID; ATSFontRef atsFontRef; Fixed atsuSize; ATSURGBAlphaColor black; ATSFontMetrics fontMetrics; U32 scaledSize; bool isBold = false; bool isItalic = false; bool haveModifier; do { haveModifier = false; if( nameStr.compare( "Bold", 4, String::NoCase | String::Right ) == 0 ) { isBold = true; nameStr = nameStr.substr( 0, nameStr.length() - 4 ).trim(); haveModifier = true; } if( nameStr.compare( "Italic", 6, String::NoCase | String::Right ) == 0 ) { isItalic = true; nameStr = nameStr.substr( 0, nameStr.length() - 6 ).trim(); haveModifier = true; } } while( haveModifier ); // Look up the font. We need it in 2 differnt formats, for differnt Apple APIs. cfsName = CFStringCreateWithCString( kCFAllocatorDefault, nameStr.c_str(), kCFStringEncodingUTF8); if(!cfsName) Con::errorf("Error: could not make a cfstring out of \"%s\" ",nameStr.c_str()); atsFontRef = ATSFontFindFromName( cfsName, kATSOptionFlagsDefault); atsuFontID = FMGetFontFromATSFontRef( atsFontRef); // make sure we found it. ATSFontFindFromName() appears to return 0 if it cant find anything. Apple docs contain no info on error returns. if( !atsFontRef || !atsuFontID ) { Con::errorf("MacCarbFont::create - could not load font -%s-",name); return false; } // adjust the size. win dpi = 96, mac dpi = 72. 72/96 = .75 // Interestingly enough, 0.75 is not what makes things the right size. scaledSize = size - 2 - (int)((float)size * 0.1); mSize = scaledSize; // Set up the size and color. We send these to ATSUSetAttributes(). atsuSize = IntToFixed(scaledSize); black.red = black.green = black.blue = black.alpha = 1.0; // Three parrallel arrays for setting up font, size, and color attributes. ATSUAttributeTag theTags[] = { kATSUFontTag, kATSUSizeTag, kATSURGBAlphaColorTag}; ByteCount theSizes[] = { sizeof(ATSUFontID), sizeof(Fixed), sizeof(ATSURGBAlphaColor) }; ATSUAttributeValuePtr theValues[] = { &atsuFontID, &atsuSize, &black }; // create and configure the style object. ATSUCreateStyle(&mStyle); ATSUSetAttributes( mStyle, 3, theTags, theSizes, theValues ); if( isBold ) { ATSUAttributeTag tag = kATSUQDBoldfaceTag; ByteCount size = sizeof( Boolean ); Boolean value = true; ATSUAttributeValuePtr valuePtr = &value; ATSUSetAttributes( mStyle, 1, &tag, &size, &valuePtr ); } if( isItalic ) { ATSUAttributeTag tag = kATSUQDItalicTag; ByteCount size = sizeof( Boolean ); Boolean value = true; ATSUAttributeValuePtr valuePtr = &value; ATSUSetAttributes( mStyle, 1, &tag, &size, &valuePtr ); } // create the layout object, ATSUCreateTextLayout(&mLayout); // we'll bind the layout to a bitmap context when we actually draw. // ATSUSetTextPointerLocation() - will set the text buffer // ATSUSetLayoutControls() - will set the cg context. // get font metrics, save our baseline and height ATSFontGetHorizontalMetrics(atsFontRef, kATSOptionFlagsDefault, &fontMetrics); mBaseline = scaledSize * fontMetrics.ascent; mHeight = scaledSize * ( fontMetrics.ascent - fontMetrics.descent + fontMetrics.leading ) + 1; // cache our grey color space, so we dont have to re create it every time. mColorSpace = CGColorSpaceCreateDeviceGray(); // and finally cache the font's name. We use this to cheat some antialiasing options below. mName = StringTable->insert(name); return true; }
/* PsychInitFontList() Build a list of records describing installed fonts. */ void PsychInitFontList(void) { ATSFontRef tempATSFontRef; CTFontRef tempCTFontRef; //for font structures PsychFontStructPtrType fontListHead, fontRecord, previousFontRecord; //for ATI font iteration ATSFontIterator fontIterator; OSStatus halt; //for font field names CFStringRef cfFontName; int i, j; psych_bool resultOK; //for font file OSStatus osStatus; FSSpec fontFileSpec; FSRef fontFileRef; //for the font metrics ATSFontMetrics horizontalMetrics; ATSFontMetrics verticalMetrics; //for info from Font Manager FMFontStyle fmStyle; OSStatus fmStatus; Str255 fmFontFamilyNamePString; //whatever Str255 fontFamilyQuickDrawNamePString; TextEncoding textEncoding; OSStatus scriptInfoOK; ScriptCode scriptCode; LangCode languageCode; OSStatus localOK; LocaleRef locale; psych_bool trouble = FALSE; psych_bool reportTrouble = TRUE; fontListHead=PsychFontListHeadKeeper(FALSE, NULL); //get the font list head. if(fontListHead) PsychErrorExitMsg(PsychError_internal, "Attempt to set new font list head when one is already set."); fontRecord = NULL; fontIterator = NULL; halt = ATSFontIteratorCreate(PSYCH_ATS_ITERATOR_CONTEXT, NULL, NULL, PSYCH_ATS_ITERATOR_SCOPE, &fontIterator); i = 0; while (halt==noErr) { // Give repair hints early. Experience shows we might crash during enumeration of a // corrupt OSX font database, so make sure we get out the helpful message as early as possible. Doing // this (just) at the end of enumeration might be too late - we might never get there... // However, allow user to suppress the hint, as this happens quite regularly on 32-Bit OSX: if (reportTrouble && trouble && PsychPrefStateGet_Verbosity() > 2) { reportTrouble = FALSE; // Only show this hint once, not for every invalid font. printf("\nPTB-HINT: =============================================================================================================================\n"); printf("PTB-HINT: At least one font on this system has issues and can not be accessed by Psychtoolbox. If you want to know which font(s) make\n"); printf("PTB-HINT: trouble, do a 'clear all' and rerun your script with Screen()'s verbosity level set to at least 4 for more diagnostic output.\n"); printf("PTB-HINT: The following tips may help you to resolve font issues:\n"); printf("PTB-HINT: Go to the Application folder and open the 'Font Book' application. It allows you to check and repair your font database.\n"); printf("PTB-HINT: Run its 'Validate' function on all installed fonts. Another thing you could try is downloading and running the free\n"); printf("PTB-HINT: FontNuke application (Google will find it for you) to regenerate corrupt OSX font caches. Good luck!\n"); printf("PTB-HINT: You can suppress this hint by choosing a verbosity level for Screen() of 2 or lower.\n"); printf("PTB-HINT: =============================================================================================================================\n\n"); } halt=ATSFontIteratorNext(fontIterator, &tempATSFontRef); if(halt==noErr){ //create a new font font structure. Set the next field to NULL as soon as we allocate the font so that if //we break with an error then we can find the end when we walk down the linked list. fontRecord=(PsychFontStructPtrType) calloc(1, sizeof(PsychFontStructType)); fontRecord->next=NULL; //Get FM and ATS font and font family references from the ATS font reference, which we get from iteration. fontRecord->fontATSRef=tempATSFontRef; fontRecord->fontFMRef=FMGetFontFromATSFontRef(fontRecord->fontATSRef); // Create CTFont from given ATSFontRef. Available since OSX 10.5 tempCTFontRef = CTFontCreateWithPlatformFont(fontRecord->fontATSRef, 0.0, NULL, NULL); if (tempCTFontRef) { // Get font family name from CTFont: CFStringRef cfFamilyName = CTFontCopyFamilyName(tempCTFontRef); // Retrieve symbolic traits of font -- the closest equivalent of the fmStyle from the // good'ol fontManager: CTFontSymbolicTraits ctTraits = CTFontGetSymbolicTraits(tempCTFontRef); // Remap new trait constants to old constants for later Screen('TextStyle') matching. fmStyle = 0; if (ctTraits & kCTFontBoldTrait) fmStyle |= 1; if (ctTraits & kCTFontItalicTrait) fmStyle |= 2; if (ctTraits & kCTFontCondensedTrait) fmStyle |= 32; if (ctTraits & kCTFontExpandedTrait) fmStyle |= 64; // CTFont no longer needed: CFRelease(tempCTFontRef); // Convert to C-String and assign: resultOK = cfFamilyName && CFStringGetCString(cfFamilyName, (char*) fontRecord->fontFMFamilyName, 255, kCFStringEncodingASCII); if(!resultOK){ if (cfFamilyName) CFRelease(cfFamilyName); if (PsychPrefStateGet_Verbosity() > 3) printf("PTB-WARNING: In font initialization: Failed to retrieve font family name for font... Defective font?!? Skipped this entry...\n"); trouble = TRUE; continue; } // Get ATSRef for font family: fontRecord->fontFamilyATSRef = ATSFontFamilyFindFromName(cfFamilyName, kATSOptionFlagsDefault); CFRelease(cfFamilyName); } else { if (PsychPrefStateGet_Verbosity() > 3) printf("PTB-WARNING: In font initialization: Failed to retrieve CTFontRef for font... Defective font?!? Skipped this entry...\n"); trouble = TRUE; continue; } //get the font name and set the the corresponding field of the struct if (ATSFontGetName(fontRecord->fontATSRef, kATSOptionFlagsDefault, &cfFontName)!=noErr) { if (PsychPrefStateGet_Verbosity() > 3) printf("PTB-WARNING: In font initialization: Failed to query font name in ATSFontGetName! OS-X font handling screwed up?!? Skipped this entry...\n"); trouble = TRUE; continue; } resultOK = cfFontName && CFStringGetCString(cfFontName, (char*) fontRecord->fontFMName, 255, kCFStringEncodingASCII); if(!resultOK){ if (cfFontName) CFRelease(cfFontName); if (PsychPrefStateGet_Verbosity() > 3) printf("PTB-WARNING: In font initialization: Failed to convert fontFMName CF string to char string. Defective font?!? Skipped this entry...\n"); trouble = TRUE; continue; } CFRelease(cfFontName); //get the font postscript name and set the corresponding field of the struct if (ATSFontGetPostScriptName(fontRecord->fontATSRef, kATSOptionFlagsDefault, &cfFontName)!=noErr) { if (PsychPrefStateGet_Verbosity() > 3) printf("PTB-WARNING: In font initialization: The following font makes trouble: %s. Please REMOVE the offending font file from your font folders and restart Matlab. Skipped entry for now...\n", fontRecord->fontFMName); trouble = TRUE; continue; } resultOK = cfFontName && CFStringGetCString(cfFontName, (char*) fontRecord->fontPostScriptName, 255, kCFStringEncodingASCII); //kCFStringEncodingASCII matches MATLAB for 0-127 if(!resultOK){ if (cfFontName) CFRelease(cfFontName); if (PsychPrefStateGet_Verbosity() > 3) printf("PTB-WARNING: In font initialization: Failed to convert fontPostScriptName CF string to char string for font %s. Defective font?!? Skipped this entry...\n", fontRecord->fontFMName); trouble = TRUE; continue; } CFRelease(cfFontName); // Get the QuickDraw name of the font: fontRecord->fontFamilyQuickDrawName[0] = 0; fontFamilyQuickDrawNamePString[0] = 0; ATSFontFamilyGetQuickDrawName(fontRecord->fontFamilyATSRef, fontFamilyQuickDrawNamePString); for (j = 0; j < fontFamilyQuickDrawNamePString[0]; j++) fontRecord->fontFamilyQuickDrawName[j] = fontFamilyQuickDrawNamePString[j+1]; fontRecord->fontFamilyQuickDrawName[j] = 0; osStatus = ATSFontGetFileReference(fontRecord->fontATSRef, &fontFileRef); if(osStatus != noErr) { if (PsychPrefStateGet_Verbosity() > 3) printf("PTB-WARNING: In font initialization: Failed to get the font file specifier for font %s. Defective font?!? Skipped this entry...\n", fontRecord->fontFMName); trouble = TRUE; continue; } osStatus= FSRefMakePath(&fontFileRef, (UInt8*) fontRecord->fontFile, (UInt32)(kPsychMaxFontFileNameChars - 1)); if(osStatus!=noErr){ if (PsychPrefStateGet_Verbosity() > 3) printf("PTB-WARNING: In font initialization: Failed to get the font file path for font %s. Defective font?!? Skipped this entry...\n", fontRecord->fontFMName); trouble = TRUE; continue; } //get the font metrics of this font. //Explicit copy between fields to make it clear what is going one, will likely have to mix & match between native and Psych structures for different //platforms. ATSFontGetHorizontalMetrics(fontRecord->fontATSRef, kATSOptionFlagsDefault, &horizontalMetrics); ATSFontGetVerticalMetrics(fontRecord->fontATSRef, kATSOptionFlagsDefault, &verticalMetrics); //horizontal fontRecord->horizontalMetrics.ascent= horizontalMetrics.ascent; fontRecord->horizontalMetrics.descent= horizontalMetrics.descent; fontRecord->horizontalMetrics.leading= horizontalMetrics.leading; fontRecord->horizontalMetrics.avgAdvanceWidth= horizontalMetrics.avgAdvanceWidth; fontRecord->horizontalMetrics.minLeftSideBearing= horizontalMetrics.minLeftSideBearing; fontRecord->horizontalMetrics.minRightSideBearing= horizontalMetrics.minRightSideBearing; fontRecord->horizontalMetrics.stemWidth= horizontalMetrics.stemWidth; fontRecord->horizontalMetrics.stemHeight= horizontalMetrics.stemHeight; fontRecord->horizontalMetrics.capHeight= horizontalMetrics.capHeight; fontRecord->horizontalMetrics.xHeight= horizontalMetrics.xHeight; fontRecord->horizontalMetrics.italicAngle= horizontalMetrics.italicAngle; fontRecord->horizontalMetrics.underlinePosition= horizontalMetrics.underlinePosition; fontRecord->horizontalMetrics.underlineThickness= horizontalMetrics.underlineThickness; fontRecord->horizontalMetrics.underlineThickness= horizontalMetrics.underlineThickness; //vertical fontRecord->verticalMetrics.ascent= verticalMetrics.ascent; fontRecord->verticalMetrics.descent= verticalMetrics.descent; fontRecord->verticalMetrics.leading= verticalMetrics.leading; fontRecord->verticalMetrics.avgAdvanceWidth= verticalMetrics.avgAdvanceWidth; fontRecord->verticalMetrics.minLeftSideBearing= verticalMetrics.minLeftSideBearing; fontRecord->verticalMetrics.minRightSideBearing= verticalMetrics.minRightSideBearing; fontRecord->verticalMetrics.stemWidth= verticalMetrics.stemWidth; fontRecord->verticalMetrics.stemHeight= verticalMetrics.stemHeight; fontRecord->verticalMetrics.capHeight= verticalMetrics.capHeight; fontRecord->verticalMetrics.xHeight= verticalMetrics.xHeight; fontRecord->verticalMetrics.italicAngle= verticalMetrics.italicAngle; fontRecord->verticalMetrics.underlinePosition= verticalMetrics.underlinePosition; fontRecord->verticalMetrics.underlineThickness= verticalMetrics.underlineThickness; fontRecord->verticalMetrics.underlineThickness= verticalMetrics.underlineThickness; fontRecord->fontFMStyle=fmStyle; fontRecord->fontFMNumStyles=PsychFindNumFMFontStylesFromStyle(fmStyle); fontRecord->fontFMNumStyles= fontRecord->fontFMNumStyles ? fontRecord->fontFMNumStyles : 1; //because the name is "normal" even if there are no styles. // Get the locale info which is a property of the font family: // No error checking is done here, because many (most?) fonts miss the information, // so we would error-out all the time and this is non-critical for us: textEncoding=ATSFontFamilyGetEncoding(fontRecord->fontFamilyATSRef); scriptInfoOK=RevertTextEncodingToScriptInfo(textEncoding, &scriptCode, &languageCode, NULL); localOK=LocaleRefFromLangOrRegionCode(languageCode, kTextRegionDontCare, &locale); localOK |= LocaleRefGetPartString(locale, kLocaleLanguageMask, 255, (char*) fontRecord->locale.language); fontRecord->locale.language[255]='\0'; localOK |= LocaleRefGetPartString(locale, kLocaleLanguageVariantMask, 255, (char*) fontRecord->locale.languageVariant); fontRecord->locale.languageVariant[255]='\0'; localOK |= LocaleRefGetPartString(locale, kLocaleRegionMask, 255, (char*) fontRecord->locale.region); fontRecord->locale.region[255]='\0'; localOK |= LocaleRefGetPartString(locale, kLocaleRegionVariantMask, 255, (char*) fontRecord->locale.regionVariant); fontRecord->locale.regionVariant[255]='\0'; localOK |= LocaleRefGetPartString(locale, kLocaleAllPartsMask, 255, (char*) fontRecord->locale.fullName); fontRecord->locale.fullName[255]='\0'; // Init for fontRecord (nearly) finished. // Set this fontRecord as head of font-list, or enqueue it in existing list: if(i==0) { PsychFontListHeadKeeper(TRUE, fontRecord); } else { previousFontRecord->next=fontRecord; } // Set the font number field of the struct fontRecord->fontNumber=i+1; // Increment the font index and update the next font pointer ++i; previousFontRecord=fontRecord; }else if(halt == kATSIterationScopeModified){ //exit because the font database changed during this loop. PsychFreeFontList(); if (fontIterator) ATSFontIteratorRelease(&fontIterator); PsychErrorExitMsg(PsychError_system, "The system font database was modified during font list setup. Please 'clear all' and restart your script."); } // Next parse iteration in system font database... } if (fontIterator) ATSFontIteratorRelease(&fontIterator); if (halt != kATSIterationCompleted) { PsychFreeFontList(); trouble = TRUE; if (PsychPrefStateGet_Verbosity() > 0) printf("PTB-ERROR: Font iteration during enumeration terminated prematurely. OS-X Font database corrupted?!?"); } // Did we get a hand on at least one font? if (i==0) { PsychFreeFontList(); trouble = TRUE; if (PsychPrefStateGet_Verbosity() > 0) { printf("PTB-ERROR: In font initialization: Could not even retrieve one valid font from the system! The OS-X font database must be corrupt.\n"); printf("PTB-ERROR: Will try to continue but will likely abort if your code tries to call any of the font handling or text drawing functions.\n"); } } // If there was some trouble and it wasn't reported yet, then report it now at the end if either // verbosity level is at least 3 (our default level), or if the error was especially serious and // lead to a premature abortion of font iteration or complete failure to find even a single valid // font. In the latter cases, we must report the trouble, regardless of verbosity level. In the // former case, probably only a few fonts had trouble, so we allow the user to suppress such messages // by lowering the verbosity to warning level or lower: if (reportTrouble && trouble && ((PsychPrefStateGet_Verbosity() > 2) || (halt != kATSIterationCompleted) || (i == 0))) { printf("PTB-HINT: =============================================================================================================================\n"); printf("PTB-HINT: At least one font on this system has issues and can not be accessed by Psychtoolbox. If you want to know which font(s) make\n"); printf("PTB-HINT: trouble, do a 'clear all' and rerun your script with Screen()'s verbosity level set to at least 4 for more diagnostic output.\n"); printf("PTB-HINT: The following tips may help you to resolve font issues:\n"); printf("PTB-HINT: Go to the Application folder and open the 'Font Book' application. It allows you to check and repair your font database.\n"); printf("PTB-HINT: Run its 'Validate' function on all installed fonts. Another thing you could try is downloading and running the free\n"); printf("PTB-HINT: FontNuke application (Google will find it for you) to regenerate corrupt OSX font caches. Good luck!\n"); printf("PTB-HINT: In case of non-fatal errors, you can suppress this hint by choosing a verbosity level for Screen() of 2 or lower.\n"); printf("PTB-HINT: =============================================================================================================================\n"); } // Font database ready for use. return; }
void AboutDialog (void) { OSStatus err; IBNibRef nibRef; err = CreateNibReference(kMacS9XCFString, &nibRef); if (err == noErr) { WindowRef tWindowRef; err = CreateWindowFromNib(nibRef, CFSTR("About"), &tWindowRef); if (err == noErr) { EventHandlerRef eref; EventHandlerUPP eventUPP; EventTypeSpec windowEvents[] = { { kEventClassWindow, kEventWindowClose }, { kEventClassCommand, kEventCommandUpdateStatus } }; ControlFontStyleRec frec; HIViewRef ctl, root; HIViewID cid; char text[32]; err = ChangeWindowAttributes(tWindowRef, kWindowNoAttributes, kWindowInWindowMenuAttribute); if (systemVersion >= 0x1040) frec.font = FMGetFontFromATSFontRef(ATSFontFindFromName(CFSTR("Lucida Grande"), kATSOptionFlagsDefault)); #ifdef MAC_PANTHER_SUPPORT else frec.font = kThemeSystemFont; #endif frec.just = teCenter; root = HIViewGetRoot(tWindowRef); cid.id = 0; cid.signature = 'VERS'; HIViewFindByID(root, cid, &ctl); sprintf(text, "Version %s (%s)", VERSION, MAC_VERSION); SetStaticTextCStr(ctl, text, false); frec.flags = kControlUseFontMask | kControlUseSizeMask | kControlUseJustMask; frec.size = 10; err = SetControlFontStyle(ctl, &frec); cid.signature = 'NAME'; HIViewFindByID(root, cid, &ctl); frec.flags = kControlUseFontMask | kControlUseSizeMask | kControlUseFaceMask | kControlUseJustMask; frec.size = 14; frec.style = 1; err = SetControlFontStyle(ctl, &frec); eventUPP = NewEventHandlerUPP(DefaultEventHandler); err = InstallWindowEventHandler(tWindowRef, eventUPP, GetEventTypeCount(windowEvents), windowEvents, (void *) tWindowRef, &eref); MoveWindowPosition(tWindowRef, kWindowAbout, false); ShowWindow(tWindowRef); err = RunAppModalLoopForWindow(tWindowRef); HideWindow(tWindowRef); SaveWindowPosition(tWindowRef, kWindowAbout); err = RemoveEventHandler(eref); DisposeEventHandlerUPP(eventUPP); CFRelease(tWindowRef); } DisposeNibReference(nibRef); } }
/* PsychInitFontList() Build a list of records describing installed fonts. */ void PsychInitFontList(void) { ATSFontRef tempATSFontRef; //for font structures PsychFontStructPtrType fontListHead, fontRecord, previousFontRecord; //for ATI font iteration ATSFontIterator fontIterator; OSStatus halt; //for font field names CFStringRef cfFontName; int i; psych_bool resultOK; //for font file //OSErr osError; OSStatus osStatus; FSSpec fontFileSpec; FSRef fontFileRef; //for the font metrics ATSFontMetrics horizontalMetrics; ATSFontMetrics verticalMetrics; //for info from Font Manager FMFontStyle fmStyle; OSStatus fmStatus; Str255 fmFontFamilyNamePString; //whatever Str255 fontFamilyQuickDrawNamePString; TextEncoding textEncoding; OSStatus scriptInfoOK; ScriptCode scriptCode; LangCode languageCode; OSStatus localOK; LocaleRef locale; psych_bool trouble = FALSE; fontListHead=PsychFontListHeadKeeper(FALSE, NULL); //get the font list head. if(fontListHead) PsychErrorExitMsg(PsychError_internal, "Attempt to set new font list head when one is already set."); fontRecord=NULL; halt= ATSFontIteratorCreate(PSYCH_ATS_ITERATOR_CONTEXT, NULL, NULL, PSYCH_ATS_ITERATOR_SCOPE, &fontIterator); i=0; while(halt==noErr){ halt=ATSFontIteratorNext(fontIterator, &tempATSFontRef); if(halt==noErr){ //create a new font font structure. Set the next field to NULL as soon as we allocate the font so that if //we break with an error then we can find the end when we walk down the linked list. fontRecord=(PsychFontStructPtrType)malloc(sizeof(PsychFontStructType)); fontRecord->next=NULL; //Get FM and ATS font and font family references from the ATS font reference, which we get from iteration. fontRecord->fontATSRef=tempATSFontRef; fontRecord->fontFMRef=FMGetFontFromATSFontRef(fontRecord->fontATSRef); fmStatus=FMGetFontFamilyInstanceFromFont(fontRecord->fontFMRef, &(fontRecord->fontFamilyFMRef), &fmStyle); fontRecord->fontFamilyATSRef=FMGetATSFontFamilyRefFromFontFamily(fontRecord->fontFamilyFMRef); //get the font name and set the the corresponding field of the struct if (ATSFontGetName(fontRecord->fontATSRef, kATSOptionFlagsDefault, &cfFontName)!=noErr) { if (PsychPrefStateGet_Verbosity() > 1) printf("PTB-WARNING: In font initialization: Failed to query font name in ATSFontGetName! OS-X font handling screwed up?!? Skipped this entry...\n"); trouble = TRUE; continue; } resultOK=CFStringGetCString(cfFontName, (char*) fontRecord->fontFMName, 255, kCFStringEncodingASCII); if(!resultOK){ CFRelease(cfFontName); if (PsychPrefStateGet_Verbosity() > 1) printf("PTB-WARNING: In font initialization: Failed to convert fontFMName CF string to char string. Defective font?!? Skipped this entry...\n"); trouble = TRUE; continue; } CFRelease(cfFontName); //get the font postscript name and set the corresponding field of the struct if (ATSFontGetPostScriptName(fontRecord->fontATSRef, kATSOptionFlagsDefault, &cfFontName)!=noErr) { if (PsychPrefStateGet_Verbosity() > 1) printf("PTB-WARNING: In font initialization: The following font makes trouble: %s. Please REMOVE the offending font file from your font folders and restart Matlab. Skipped entry for now...\n", fontRecord->fontFMName); trouble = TRUE; continue; } resultOK=CFStringGetCString(cfFontName, (char*) fontRecord->fontPostScriptName, 255, kCFStringEncodingASCII); //kCFStringEncodingASCII matches MATLAB for 0-127 if(!resultOK){ CFRelease(cfFontName); if (PsychPrefStateGet_Verbosity() > 1) printf("PTB-WARNING: In font initialization: Failed to convert fontPostScriptName CF string to char string for font %s. Defective font?!? Skipped this entry...\n", fontRecord->fontFMName); trouble = TRUE; continue; } CFRelease(cfFontName); //get the QuickDraw name of the font ATSFontFamilyGetQuickDrawName(fontRecord->fontFamilyATSRef, fontFamilyQuickDrawNamePString); CopyPascalStringToC(fontFamilyQuickDrawNamePString, (char*) fontRecord->fontFamilyQuickDrawName); //get the font file used for this font osStatus= ATSFontGetFileSpecification(fontRecord->fontATSRef, &fontFileSpec); if(osStatus != noErr) { if (PsychPrefStateGet_Verbosity() > 1) printf("PTB-WARNING: In font initialization: Failed to get the font file specifier for font %s. Defective font?!? Skipped this entry...\n", fontRecord->fontFMName); trouble = TRUE; continue; } FSpMakeFSRef(&fontFileSpec, &fontFileRef); osStatus= FSRefMakePath(&fontFileRef, (UInt8*) fontRecord->fontFile, (UInt32)(kPsychMaxFontFileNameChars - 1)); if(osStatus!=noErr){ if (PsychPrefStateGet_Verbosity() > 1) printf("PTB-WARNING: In font initialization: Failed to get the font file path for font %s. Defective font?!? Skipped this entry...\n", fontRecord->fontFMName); trouble = TRUE; continue; } //get the font metrics of this font. //Explicit copy between fields to make it clear what is going one, will likely have to mix & match between native and Psych structures for different //platforms. ATSFontGetHorizontalMetrics(fontRecord->fontATSRef, kATSOptionFlagsDefault, &horizontalMetrics); ATSFontGetVerticalMetrics(fontRecord->fontATSRef, kATSOptionFlagsDefault, &verticalMetrics); //horizontal fontRecord->horizontalMetrics.ascent= horizontalMetrics.ascent; fontRecord->horizontalMetrics.descent= horizontalMetrics.descent; fontRecord->horizontalMetrics.leading= horizontalMetrics.leading; fontRecord->horizontalMetrics.avgAdvanceWidth= horizontalMetrics.avgAdvanceWidth; fontRecord->horizontalMetrics.minLeftSideBearing= horizontalMetrics.minLeftSideBearing; fontRecord->horizontalMetrics.minRightSideBearing= horizontalMetrics.minRightSideBearing; fontRecord->horizontalMetrics.stemWidth= horizontalMetrics.stemWidth; fontRecord->horizontalMetrics.stemHeight= horizontalMetrics.stemHeight; fontRecord->horizontalMetrics.capHeight= horizontalMetrics.capHeight; fontRecord->horizontalMetrics.xHeight= horizontalMetrics.xHeight; fontRecord->horizontalMetrics.italicAngle= horizontalMetrics.italicAngle; fontRecord->horizontalMetrics.underlinePosition= horizontalMetrics.underlinePosition; fontRecord->horizontalMetrics.underlineThickness= horizontalMetrics.underlineThickness; fontRecord->horizontalMetrics.underlineThickness= horizontalMetrics.underlineThickness; //vertical fontRecord->verticalMetrics.ascent= verticalMetrics.ascent; fontRecord->verticalMetrics.descent= verticalMetrics.descent; fontRecord->verticalMetrics.leading= verticalMetrics.leading; fontRecord->verticalMetrics.avgAdvanceWidth= verticalMetrics.avgAdvanceWidth; fontRecord->verticalMetrics.minLeftSideBearing= verticalMetrics.minLeftSideBearing; fontRecord->verticalMetrics.minRightSideBearing= verticalMetrics.minRightSideBearing; fontRecord->verticalMetrics.stemWidth= verticalMetrics.stemWidth; fontRecord->verticalMetrics.stemHeight= verticalMetrics.stemHeight; fontRecord->verticalMetrics.capHeight= verticalMetrics.capHeight; fontRecord->verticalMetrics.xHeight= verticalMetrics.xHeight; fontRecord->verticalMetrics.italicAngle= verticalMetrics.italicAngle; fontRecord->verticalMetrics.underlinePosition= verticalMetrics.underlinePosition; fontRecord->verticalMetrics.underlineThickness= verticalMetrics.underlineThickness; fontRecord->verticalMetrics.underlineThickness= verticalMetrics.underlineThickness; //use Font Manager to get the FM font family name font style fmStatus=FMGetFontFamilyName(fontRecord->fontFamilyFMRef, fmFontFamilyNamePString); CopyPascalStringToC(fmFontFamilyNamePString, (char*) fontRecord->fontFMFamilyName); fontRecord->fontFMStyle=fmStyle; fontRecord->fontFMNumStyles=PsychFindNumFMFontStylesFromStyle(fmStyle); fontRecord->fontFMNumStyles= fontRecord->fontFMNumStyles ? fontRecord->fontFMNumStyles : 1; //because the name is "normal" even if there are no styles. //get the locale info which is a property of the font family textEncoding=ATSFontFamilyGetEncoding(fontRecord->fontFamilyATSRef); scriptInfoOK=RevertTextEncodingToScriptInfo(textEncoding, &scriptCode, &languageCode, NULL); localOK=LocaleRefFromLangOrRegionCode(languageCode, kTextRegionDontCare, &locale); localOK=LocaleRefGetPartString(locale, kLocaleLanguageMask, 255, (char*) fontRecord->locale.language); fontRecord->locale.language[255]='\0'; localOK=LocaleRefGetPartString(locale, kLocaleLanguageVariantMask, 255, (char*) fontRecord->locale.languageVariant); fontRecord->locale.languageVariant[255]='\0'; localOK=LocaleRefGetPartString(locale, kLocaleRegionMask, 255, (char*) fontRecord->locale.region); fontRecord->locale.region[255]='\0'; localOK=LocaleRefGetPartString(locale, kLocaleRegionVariantMask, 255, (char*) fontRecord->locale.regionVariant); fontRecord->locale.regionVariant[255]='\0'; localOK=LocaleRefGetPartString(locale, kLocaleAllPartsMask, 255, (char*) fontRecord->locale.fullName); fontRecord->locale.fullName[255]='\0'; // Init for fontRecord (nearly) finished. // Set this fontRecord as head of font-list, or enqueue it in existing list: if(i==0) { PsychFontListHeadKeeper(TRUE, fontRecord); } else { previousFontRecord->next=fontRecord; } // Set the font number field of the struct fontRecord->fontNumber=i+1; // Increment the font index and update the next font pointer ++i; previousFontRecord=fontRecord; }else if(halt == kATSIterationScopeModified){ //exit because the font database changed during this loop. PsychFreeFontList(); PsychErrorExitMsg(PsychError_internal, "The system font database was modified during font list setup. Please 'clear all' and restart your script."); } // Next parse iteration in system font database... } if(halt != kATSIterationCompleted){ PsychFreeFontList(); PsychErrorExitMsg(PsychError_internal, "Font iteration terminated prematurely. OS-X Font database corrupted?!?"); } // Did we get a hand on at least one font? if (i==0) { if (PsychPrefStateGet_Verbosity() > 0) { printf("PTB-ERROR: In font initialization: Could not even retrieve one valid font from the system! The OS-X font database must be corrupt.\n"); printf("PTB-ERROR: Will try to continue but will likely crash if your code tries to call any of the font handling or text drawing functions.\n"); trouble = TRUE; } } if (trouble && PsychPrefStateGet_Verbosity() > 0) { printf("PTB-HINT: Go to the Application folder and open the 'Font Book' application. It allows you to check and repair your font database.\n"); } ATSFontIteratorRelease(&fontIterator); // Font database ready for use. return; }
QFontEngineMacMulti::QFontEngineMacMulti(const ATSFontFamilyRef &atsFamily, const ATSFontRef &atsFontRef, const QFontDef &fontDef, bool kerning) : QFontEngineMulti(0) { this->fontDef = fontDef; this->kerning = kerning; FMFontFamily fmFamily; FMFontStyle fntStyle = 0; fmFamily = FMGetFontFamilyFromATSFontFamilyRef(atsFamily); if (fmFamily == kInvalidFontFamily) { // Use the ATSFont then... fontID = FMGetFontFromATSFontRef(atsFontRef); } else { if (fontDef.weight >= QFont::Bold) fntStyle |= ::bold; if (fontDef.style != QFont::StyleNormal) fntStyle |= ::italic; FMFontStyle intrinsicStyle; FMFont fnt = 0; if (FMGetFontFromFontFamilyInstance(fmFamily, fntStyle, &fnt, &intrinsicStyle) == noErr) fontID = FMGetATSFontRefFromFont(fnt); } OSStatus status; status = ATSUCreateTextLayout(&textLayout); Q_ASSERT(status == noErr); const int maxAttributeCount = 5; ATSUAttributeTag tags[maxAttributeCount + 1]; ByteCount sizes[maxAttributeCount + 1]; ATSUAttributeValuePtr values[maxAttributeCount + 1]; int attributeCount = 0; Fixed size = FixRatio(fontDef.pixelSize, 1); tags[attributeCount] = kATSUSizeTag; sizes[attributeCount] = sizeof(size); values[attributeCount] = &size; ++attributeCount; tags[attributeCount] = kATSUFontTag; sizes[attributeCount] = sizeof(fontID); values[attributeCount] = &this->fontID; ++attributeCount; transform = CGAffineTransformIdentity; if (fontDef.stretch != 100) { transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1); tags[attributeCount] = kATSUFontMatrixTag; sizes[attributeCount] = sizeof(transform); values[attributeCount] = &transform; ++attributeCount; } status = ATSUCreateStyle(&style); Q_ASSERT(status == noErr); Q_ASSERT(attributeCount < maxAttributeCount + 1); status = ATSUSetAttributes(style, attributeCount, tags, sizes, values); Q_ASSERT(status == noErr); QFontEngineMac *fe = new QFontEngineMac(style, fontID, fontDef, this); fe->ref.ref(); engines.append(fe); }
void* loadAATfont(ATSFontRef fontRef, long scaled_size, const char* cp1) { ATSUFontID fontID = FMGetFontFromATSFontRef(fontRef); ATSUStyle style = 0; OSStatus status = ATSUCreateStyle(&style); float extend = 1.0; float slant = 0.0; float embolden = 0.0; float letterspace = 0.0; int i; if (status == noErr) { UInt32 rgbValue; Fixed tracking = 0x80000000; Fixed atsuSize = FixedTeXtoPSPoints(scaled_size); ATSStyleRenderingOptions options = kATSStyleNoHinting; Fract hangInhibit = fract1; ATSUAttributeTag tags[] = { kATSUFontTag, kATSUSizeTag, kATSUStyleRenderingOptionsTag, kATSUHangingInhibitFactorTag }; ByteCount sizes[] = { sizeof(ATSUFontID), sizeof(Fixed), sizeof(ATSStyleRenderingOptions), sizeof(Fract) }; ATSUAttributeValuePtr attrs[] = { &fontID, &atsuSize, &options, &hangInhibit }; ATSUSetAttributes(style, sizeof(tags) / sizeof(ATSUAttributeTag), tags, sizes, attrs); #define FEAT_ALLOC_CHUNK 8 #define VAR_ALLOC_CHUNK 4 if (cp1 != NULL) { int allocFeats = FEAT_ALLOC_CHUNK; UInt16* featureTypes = (UInt16*)xmalloc(allocFeats * sizeof(UInt16)); UInt16* selectorValues = (UInt16*)xmalloc(allocFeats * sizeof(UInt16)); int numFeatures = 0; int allocVars = VAR_ALLOC_CHUNK; UInt32* axes = (UInt32*)xmalloc(allocVars * sizeof(UInt32)); SInt32* values = (SInt32*)xmalloc(allocVars * sizeof(SInt32)); int numVariations = 0; // interpret features & variations following ":" while (*cp1) { // locate beginning of name=value pair if (*cp1 == ':' || *cp1 == ';') // skip over separator ++cp1; while (*cp1 == ' ' || *cp1 == '\t') // skip leading whitespace ++cp1; if (*cp1 == 0) // break if end of string break; // scan to end of pair const char* cp2 = cp1; while (*cp2 && *cp2 != ';' && *cp2 != ':') ++cp2; // look for the '=' separator const char* cp3 = cp1; while (cp3 < cp2 && *cp3 != '=') ++cp3; if (cp3 == cp2) goto bad_option; // now cp1 points to option name, cp3 to '=', cp2 to ';' or null // first try for a feature by this name ATSUFontFeatureType featureType; featureType = find_feature_by_name(fontID, cp1, cp3 - cp1); if (featureType != 0x0000FFFF) { // look past the '=' separator for setting names int featLen = cp3 - cp1; ++cp3; while (cp3 < cp2) { // skip leading whitespace while (*cp3 == ' ' || *cp3 == '\t') ++cp3; // possibly multiple settings... int disable = 0; if (*cp3 == '!') { // check for negation disable = 1; ++cp3; } // scan for end of setting name const char* cp4 = cp3; while (cp4 < cp2 && *cp4 != ',') ++cp4; // now cp3 points to name, cp4 to ',' or ';' or null ATSUFontFeatureSelector selectorValue = find_selector_by_name(fontID, featureType, cp3, cp4 - cp3); if (selectorValue != 0x0000FFFF) { if (numFeatures == allocFeats) { allocFeats += FEAT_ALLOC_CHUNK; featureTypes = xrealloc(featureTypes, allocFeats * sizeof(UInt16)); selectorValues = xrealloc(selectorValues, allocFeats * sizeof(UInt16)); } featureTypes[numFeatures] = featureType; selectorValues[numFeatures] = selectorValue + disable; ++numFeatures; } else { fontfeaturewarning(cp1, featLen, cp3, cp4 - cp3); } // point beyond setting name terminator cp3 = cp4 + 1; } goto next_option; } // try to find a variation by this name ATSUFontVariationAxis axis; axis = find_axis_by_name(fontID, cp1, cp3 - cp1); if (axis != 0) { // look past the '=' separator for the value ++cp3; double value = 0.0, decimal = 1.0; bool negate = false; if (*cp3 == '-') { ++cp3; negate = true; } while (cp3 < cp2) { int v = *cp3 - '0'; if (v >= 0 && v <= 9) { if (decimal != 1.0) { value += v / decimal; decimal *= 10.0; } else value = value * 10.0 + v; } else if (*cp3 == '.') { if (decimal != 1.0) break; decimal = 10.0; } else break; ++cp3; } if (negate) value = -value; if (numVariations == allocVars) { allocVars += VAR_ALLOC_CHUNK; axes = xrealloc(axes, allocVars * sizeof(UInt32)); values = xrealloc(values, allocVars * sizeof(SInt32)); } axes[numVariations] = axis; values[numVariations] = value * 65536.0; // X2Fix(value); ++numVariations; goto next_option; } // didn't find feature or variation, try other options.... i = readCommonFeatures(cp1, cp2, &extend, &slant, &embolden, &letterspace, &rgbValue); if (i == 1) goto next_option; else if (i == -1) goto bad_option; if (strncmp(cp1, "tracking", 8) == 0) { cp3 = cp1 + 8; if (*cp3 != '=') goto bad_option; ++cp3; double val = read_double(&cp3); tracking = X2Fix(val); goto next_option; } bad_option: // not a name=value pair, or not recognized.... // check for plain "vertical" before complaining if (strncmp(cp1, "vertical", 8) == 0) { cp3 = cp2; if (*cp3 == ';' || *cp3 == ':') --cp3; while (*cp3 == '\0' || *cp3 == ' ' || *cp3 == '\t') --cp3; if (*cp3) ++cp3; if (cp3 == cp1 + 8) { ATSUVerticalCharacterType vert = kATSUStronglyVertical; tags[0] = kATSUVerticalCharacterTag; sizes[0] = sizeof(ATSUVerticalCharacterType); attrs[0] = | ATSUSetAttributes(style, 1, tags, sizes, attrs); goto next_option; } } fontfeaturewarning(cp1, cp2 - cp1, 0, 0); next_option: // go to next name=value pair cp1 = cp2; } if (numFeatures > 0) ATSUSetFontFeatures(style, numFeatures, featureTypes, selectorValues); if (numVariations > 0) ATSUSetVariations(style, numVariations, axes, values); if ((loadedfontflags & FONT_FLAGS_COLORED) != 0) { ATSURGBAlphaColor rgba; rgba.red = ((rgbValue & 0xFF000000) >> 24) / 255.0; rgba.green = ((rgbValue & 0x00FF0000) >> 16) / 255.0; rgba.blue = ((rgbValue & 0x0000FF00) >> 8 ) / 255.0; rgba.alpha = ((rgbValue & 0x000000FF) ) / 255.0; tags[0] = kATSURGBAlphaColorTag; sizes[0] = sizeof(ATSURGBAlphaColor); attrs[0] = &rgba; ATSUSetAttributes(style, 1, tags, sizes, attrs); }