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); }
static OSStatus AddFunkyVariationsAndFeatures( ATSUStyle styleToMangle ) { OSStatus err; ItemCount i; ATSUFontID fontID; ItemCount count; ItemCount selectorCount; ATSUFontVariationAxis variationAxis; ATSUFontVariationValue variationMinimum; ATSUFontVariationValue variationMaximum; ATSUFontVariationValue variationDefault; Boolean selectorMutex; ATSUFontFeatureType *typeBuffer = NULL; ATSUFontFeatureSelector *selectorBuffer = NULL; Boolean *defaultBuffer = NULL; ItemCount selectorBufferSize = 0; // get the fontID from the style err = ATSUGetAttribute( styleToMangle, kATSUFontTag, sizeof( ATSUStyle ), &fontID, NULL ); require_noerr( err, AddFunkyVariationsAndFeatures_err ); // get a count of all of the variations supported by the current font err = ATSUCountFontVariations( fontID, &count ); require_noerr( err, AddFunkyVariationsAndFeatures_err ); // loop through, setting all of the variations to the max! for ( i = 0; i < count; i++ ) { // get the settings for the variations err = ATSUGetIndFontVariation( fontID, i, &variationAxis, &variationMinimum, &variationMaximum, &variationDefault ); require_noerr( err, AddFunkyVariationsAndFeatures_err ); // set the variation for this font to the max! err = ATSUSetVariations( styleToMangle, 1, &variationAxis, &variationMaximum ); require_noerr( err, AddFunkyVariationsAndFeatures_err ); } // get a count of all of the features err = ATSUCountFontFeatureTypes( fontID, &count ); require_noerr( err, AddFunkyVariationsAndFeatures_err ); // allocate a buffer for the feature types typeBuffer = (ATSUFontFeatureType *) malloc( sizeof( ATSUFontFeatureType ) * count ); require_action( typeBuffer != NULL, AddFunkyVariationsAndFeatures_err, err = paramErr ); // get all of the font features err = ATSUGetFontFeatureTypes( fontID, count, typeBuffer, &selectorCount ); require_noerr( err, AddFunkyVariationsAndFeatures_err ); // loop through, setting all of the features for ( i = 0; i < count; i++ ) { // get the selector count err = ATSUCountFontFeatureSelectors( fontID, typeBuffer[i], &selectorCount ); require_noerr( err, AddFunkyVariationsAndFeatures_err ); // if the selector buffer size is greater than what we had before, // then allocate some new buffers. Just use realloc, as when // the buffers are pointing to NULL, it will simply act as malloc. if ( selectorBufferSize < count ) { ItemCount newCount; // set the new size to be twice the old size newCount = 2 * count; // allocate the selectorBuffer selectorBuffer = (ATSUFontFeatureSelector *) realloc( selectorBuffer, newCount * sizeof( ATSUFontFeatureSelector ) ); require_action( selectorBuffer != NULL, AddFunkyVariationsAndFeatures_err, err = memFullErr ); // allocate the defaultBuffer defaultBuffer = (Boolean *) realloc( defaultBuffer, newCount * sizeof( Boolean ) ); require_action( defaultBuffer != NULL, AddFunkyVariationsAndFeatures_err, err = memFullErr ); selectorBufferSize = newCount; } // get the font feature selectors err = ATSUGetFontFeatureSelectors( fontID, typeBuffer[i], selectorBufferSize, selectorBuffer, defaultBuffer, &selectorCount, &selectorMutex ); require_noerr( err, AddFunkyVariationsAndFeatures_err ); // if the features are not mutually exclusive, then go ahead and // set them all. if ( selectorMutex == false ) { ItemCount j; // loop through and set all of the features for ( j = 0; j < selectorCount; j++ ) { if ( defaultBuffer[j] == false ) { err = ATSUSetFontFeatures( styleToMangle, 1, &typeBuffer[i], &selectorBuffer[j] ); require_noerr( err, AddFunkyVariationsAndFeatures_err ); } } } else { // just set the last option, then since we can't set them all err = ATSUSetFontFeatures( styleToMangle, 1, &typeBuffer[i], &selectorBuffer[selectorCount - 1] ); require_noerr( err, AddFunkyVariationsAndFeatures_err ); } } // that should be enough style perversion for now! AddFunkyVariationsAndFeatures_err: if ( typeBuffer != NULL ) { free( typeBuffer ); } if ( selectorBuffer != NULL ) { free( selectorBuffer ); } if ( defaultBuffer != NULL ) { free( defaultBuffer ); } return err; }