Exemple #1
0
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);
}
Exemple #2
0
//------------------------------------------------------------------------------
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;
}
Exemple #4
0
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);
}
Exemple #7
0
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] = &vert;
						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);
			}