diff options
Diffstat (limited to 'Build/source/texk/web2c/xetexdir/XeTeX_mac.c')
-rw-r--r-- | Build/source/texk/web2c/xetexdir/XeTeX_mac.c | 1362 |
1 files changed, 619 insertions, 743 deletions
diff --git a/Build/source/texk/web2c/xetexdir/XeTeX_mac.c b/Build/source/texk/web2c/xetexdir/XeTeX_mac.c index 02fdc428c05..f3e78cb588b 100644 --- a/Build/source/texk/web2c/xetexdir/XeTeX_mac.c +++ b/Build/source/texk/web2c/xetexdir/XeTeX_mac.c @@ -48,496 +48,497 @@ authorization from the copyright holders. static inline double TeXtoPSPoints(double pts) { - return pts * 72.0 / 72.27; + return pts * 72.0 / 72.27; } static inline double PStoTeXPoints(double pts) { - return pts * 72.27 / 72.0; + return pts * 72.27 / 72.0; } static inline Fixed FixedPStoTeXPoints(double pts) { - return D2Fix(PStoTeXPoints(pts)); + return D2Fix(PStoTeXPoints(pts)); } CTFontRef fontFromAttributes(CFDictionaryRef attributes) { - return CFDictionaryGetValue(attributes, kCTFontAttributeName); + return CFDictionaryGetValue(attributes, kCTFontAttributeName); } CTFontRef fontFromInteger(integer font) { - CFDictionaryRef attributes = (CFDictionaryRef) fontlayoutengine[font]; - return fontFromAttributes(attributes); + CFDictionaryRef attributes = (CFDictionaryRef) fontlayoutengine[font]; + return fontFromAttributes(attributes); } void DoAATLayout(void* p, int justify) { - CFArrayRef glyphRuns; - CFIndex i, j, runCount; - CFIndex totalGlyphCount = 0; - UInt16* glyphIDs; - Fixed* glyphAdvances; - void* glyph_info; - FixedPoint* locations; - Fixed lsUnit, lsDelta; - CGFloat width; - - long txtLen; - const UniChar* txtPtr; - - CFDictionaryRef attributes; - CFStringRef string; - CFAttributedStringRef attrString; - CTTypesetterRef typesetter; - CTLineRef line; - - memoryword* node = (memoryword*)p; - - unsigned f = native_font(node); - if (fontarea[f] != AAT_FONT_FLAG) { - fprintf(stderr, "internal error: DoAATLayout called for non-AAT font\n"); - exit(1); - } - - txtLen = native_length(node); - txtPtr = (UniChar*)(node + native_node_size); - - attributes = fontlayoutengine[native_font(node)]; - string = CFStringCreateWithCharactersNoCopy(NULL, txtPtr, txtLen, kCFAllocatorNull); - attrString = CFAttributedStringCreate(NULL, string, attributes); - CFRelease(string); - - typesetter = CTTypesetterCreateWithAttributedString(attrString); - line = CTTypesetterCreateLine(typesetter, CFRangeMake(0, txtLen)); - if (justify) { - CGFloat lineWidth = TeXtoPSPoints(Fix2D(node_width(node))); - CTLineRef justifiedLine = CTLineCreateJustifiedLine(line, TeXtoPSPoints(Fix2D(fract1)), lineWidth); - // TODO(jjgod): how to handle the case when justification failed? for - // now we just fallback to use the original line. - if (justifiedLine) { - CFRelease(line); - line = justifiedLine; - } - } - - glyphRuns = CTLineGetGlyphRuns(line); - runCount = CFArrayGetCount(glyphRuns); - totalGlyphCount = CTLineGetGlyphCount(line); - - if (totalGlyphCount > 0) { - glyph_info = xmalloc(totalGlyphCount * native_glyph_info_size); - locations = (FixedPoint*)glyph_info; - glyphIDs = (UInt16*)(locations + totalGlyphCount); - glyphAdvances = xmalloc(totalGlyphCount * sizeof(Fixed)); - totalGlyphCount = 0; - - width = 0; - for (i = 0; i < runCount; i++) { - CTRunRef run = CFArrayGetValueAtIndex(glyphRuns, i); - CFIndex count = CTRunGetGlyphCount(run); - CFDictionaryRef runAttributes = CTRunGetAttributes(run); - CFBooleanRef vertical = CFDictionaryGetValue(runAttributes, kCTVerticalFormsAttributeName); - // TODO(jjgod): Avoid unnecessary allocation with CTRunGetFoosPtr(). - CGGlyph* glyphs = (CGGlyph*) xmalloc(count * sizeof(CGGlyph)); - CGPoint* positions = (CGPoint*) xmalloc(count * sizeof(CGPoint)); - CGSize* advances = (CGSize*) xmalloc(count * sizeof(CGSize)); - CGFloat runWidth = CTRunGetTypographicBounds(run, CFRangeMake(0, 0), NULL, NULL, NULL); - CTRunGetGlyphs(run, CFRangeMake(0, 0), glyphs); - CTRunGetPositions(run, CFRangeMake(0, 0), positions); - CTRunGetAdvances(run, CFRangeMake(0, 0), advances); - for (j = 0; j < count; j++) { - // XXX Core Text has that font cascading thing that will do - // font substitution for missing glyphs, which we do not want - // but I can not find a way to disable it yet, so if the font - // of the resulting run is not the same font we asked for, use - // the glyph at index 0 (usually .notdef) instead or we will be - // showing garbage or even invalid glyphs - char *ps_name1 = getNameFromCTFont(fontFromAttributes(attributes), kCTFontPostScriptNameKey); - char *ps_name2 = getNameFromCTFont(fontFromAttributes(runAttributes), kCTFontPostScriptNameKey); - if (strcmp(ps_name1, ps_name2) != 0) - glyphIDs[totalGlyphCount] = 0; - else - glyphIDs[totalGlyphCount] = glyphs[j]; - - // Swap X and Y when doing vertical layout - if (vertical == kCFBooleanTrue) { - locations[totalGlyphCount].x = FixedPStoTeXPoints(-positions[j].y); - // XXX trasformation matrix changes y positions! - //locations[totalGlyphCount].y = FixedPStoTeXPoints(-positions[j].x); - locations[totalGlyphCount].y = 0; - } else { - locations[totalGlyphCount].x = FixedPStoTeXPoints(positions[j].x); - // XXX trasformation matrix changes y positions! - //locations[totalGlyphCount].y = FixedPStoTeXPoints(positions[j].y); - locations[totalGlyphCount].y = 0; - } - glyphAdvances[totalGlyphCount] = advances[j].width; - totalGlyphCount++; - } - width += FixedPStoTeXPoints(runWidth); - free(glyphs); - free(positions); - } - } - - native_glyph_count(node) = totalGlyphCount; - native_glyph_info_ptr(node) = glyph_info; - - if (!justify) { - node_width(node) = width; - - if (totalGlyphCount > 0) { - /* this is essentially a copy from similar code in XeTeX_ext.c, easier - * to be done here */ - if (fontletterspace[f] != 0) { - Fixed lsDelta = 0; - Fixed lsUnit = fontletterspace[f]; - int i; - for (i = 0; i < totalGlyphCount; ++i) { - if (glyphAdvances[i] == 0 && lsDelta != 0) - lsDelta -= lsUnit; - locations[i].x += lsDelta; - lsDelta += lsUnit; - } - if (lsDelta != 0) { - lsDelta -= lsUnit; - node_width(node) += lsDelta; - } - } - } - } - - CFRelease(line); - CFRelease(typesetter); + CFArrayRef glyphRuns; + CFIndex i, j, runCount; + CFIndex totalGlyphCount = 0; + UInt16* glyphIDs; + Fixed* glyphAdvances; + void* glyph_info; + FixedPoint* locations; + Fixed lsUnit, lsDelta; + CGFloat width; + + long txtLen; + const UniChar* txtPtr; + + CFDictionaryRef attributes; + CFStringRef string; + CFAttributedStringRef attrString; + CTTypesetterRef typesetter; + CTLineRef line; + + memoryword* node = (memoryword*)p; + + unsigned f = native_font(node); + if (fontarea[f] != AAT_FONT_FLAG) { + fprintf(stderr, "internal error: DoAATLayout called for non-AAT font\n"); + exit(1); + } + + txtLen = native_length(node); + txtPtr = (UniChar*)(node + native_node_size); + + attributes = fontlayoutengine[native_font(node)]; + string = CFStringCreateWithCharactersNoCopy(NULL, txtPtr, txtLen, kCFAllocatorNull); + attrString = CFAttributedStringCreate(NULL, string, attributes); + CFRelease(string); + + typesetter = CTTypesetterCreateWithAttributedString(attrString); + CFRelease(attrString); + line = CTTypesetterCreateLine(typesetter, CFRangeMake(0, txtLen)); + if (justify) { + CGFloat lineWidth = TeXtoPSPoints(Fix2D(node_width(node))); + CTLineRef justifiedLine = CTLineCreateJustifiedLine(line, TeXtoPSPoints(Fix2D(fract1)), lineWidth); + // TODO(jjgod): how to handle the case when justification failed? for + // now we just fallback to use the original line. + if (justifiedLine) { + CFRelease(line); + line = justifiedLine; + } + } + + glyphRuns = CTLineGetGlyphRuns(line); + runCount = CFArrayGetCount(glyphRuns); + totalGlyphCount = CTLineGetGlyphCount(line); + + if (totalGlyphCount > 0) { + glyph_info = xmalloc(totalGlyphCount * native_glyph_info_size); + locations = (FixedPoint*)glyph_info; + glyphIDs = (UInt16*)(locations + totalGlyphCount); + glyphAdvances = xmalloc(totalGlyphCount * sizeof(Fixed)); + totalGlyphCount = 0; + + width = 0; + for (i = 0; i < runCount; i++) { + CTRunRef run = CFArrayGetValueAtIndex(glyphRuns, i); + CFIndex count = CTRunGetGlyphCount(run); + CFDictionaryRef runAttributes = CTRunGetAttributes(run); + CFBooleanRef vertical = CFDictionaryGetValue(runAttributes, kCTVerticalFormsAttributeName); + // TODO(jjgod): Avoid unnecessary allocation with CTRunGetFoosPtr(). + CGGlyph* glyphs = (CGGlyph*) xmalloc(count * sizeof(CGGlyph)); + CGPoint* positions = (CGPoint*) xmalloc(count * sizeof(CGPoint)); + CGSize* advances = (CGSize*) xmalloc(count * sizeof(CGSize)); + CGFloat runWidth = CTRunGetTypographicBounds(run, CFRangeMake(0, 0), NULL, NULL, NULL); + CTRunGetGlyphs(run, CFRangeMake(0, 0), glyphs); + CTRunGetPositions(run, CFRangeMake(0, 0), positions); + CTRunGetAdvances(run, CFRangeMake(0, 0), advances); + for (j = 0; j < count; j++) { + // XXX Core Text has that font cascading thing that will do + // font substitution for missing glyphs, which we do not want + // but I can not find a way to disable it yet, so if the font + // of the resulting run is not the same font we asked for, use + // the glyph at index 0 (usually .notdef) instead or we will be + // showing garbage or even invalid glyphs + if (!CFEqual(fontFromAttributes(attributes), fontFromAttributes(runAttributes))) + glyphIDs[totalGlyphCount] = 0; + else + glyphIDs[totalGlyphCount] = glyphs[j]; + + // Swap X and Y when doing vertical layout + if (vertical == kCFBooleanTrue) { + locations[totalGlyphCount].x = FixedPStoTeXPoints(-positions[j].y); + // XXX trasformation matrix changes y positions! + //locations[totalGlyphCount].y = FixedPStoTeXPoints(-positions[j].x); + locations[totalGlyphCount].y = 0; + } else { + locations[totalGlyphCount].x = FixedPStoTeXPoints(positions[j].x); + // XXX trasformation matrix changes y positions! + //locations[totalGlyphCount].y = FixedPStoTeXPoints(positions[j].y); + locations[totalGlyphCount].y = 0; + } + glyphAdvances[totalGlyphCount] = advances[j].width; + totalGlyphCount++; + } + width += FixedPStoTeXPoints(runWidth); + free(glyphs); + free(positions); + free(advances); + } + } + + native_glyph_count(node) = totalGlyphCount; + native_glyph_info_ptr(node) = glyph_info; + + if (!justify) { + node_width(node) = width; + + if (totalGlyphCount > 0) { + /* this is essentially a copy from similar code in XeTeX_ext.c, easier + * to be done here */ + if (fontletterspace[f] != 0) { + Fixed lsDelta = 0; + Fixed lsUnit = fontletterspace[f]; + int i; + for (i = 0; i < totalGlyphCount; ++i) { + if (glyphAdvances[i] == 0 && lsDelta != 0) + lsDelta -= lsUnit; + locations[i].x += lsDelta; + lsDelta += lsUnit; + } + if (lsDelta != 0) { + lsDelta -= lsUnit; + node_width(node) += lsDelta; + } + } + } + } + + free(glyphAdvances); + CFRelease(line); + CFRelease(typesetter); } static void getGlyphBBoxFromCTFont(CTFontRef font, UInt16 gid, GlyphBBox* bbox) { - CGRect rect; - - bbox->xMin = 65536.0; - bbox->yMin = 65536.0; - bbox->xMax = -65536.0; - bbox->yMax = -65536.0; - - rect = CTFontGetBoundingRectsForGlyphs(font, - 0, /* Use default orientation for now, handle vertical later */ - (const CGGlyph *) &gid, NULL, 1); - - if (CGRectIsNull(rect)) - bbox->xMin = bbox->yMin = bbox->xMax = bbox->yMax = 0; - else { - bbox->yMin = PStoTeXPoints(rect.origin.y); - bbox->yMax = PStoTeXPoints(rect.origin.y + rect.size.height); - bbox->xMin = PStoTeXPoints(rect.origin.x); - bbox->xMax = PStoTeXPoints(rect.origin.x + rect.size.width); - } + CGRect rect; + + bbox->xMin = 65536.0; + bbox->yMin = 65536.0; + bbox->xMax = -65536.0; + bbox->yMax = -65536.0; + + rect = CTFontGetBoundingRectsForGlyphs(font, + 0, /* Use default orientation for now, handle vertical later */ + (const CGGlyph *) &gid, NULL, 1); + + if (CGRectIsNull(rect)) + bbox->xMin = bbox->yMin = bbox->xMax = bbox->yMax = 0; + else { + bbox->yMin = PStoTeXPoints(rect.origin.y); + bbox->yMax = PStoTeXPoints(rect.origin.y + rect.size.height); + bbox->xMin = PStoTeXPoints(rect.origin.x); + bbox->xMax = PStoTeXPoints(rect.origin.x + rect.size.width); + } } void GetGlyphBBox_AAT(CFDictionaryRef attributes, UInt16 gid, GlyphBBox* bbox) - /* returns glyph bounding box in TeX points */ + /* returns glyph bounding box in TeX points */ { - CTFontRef font = fontFromAttributes(attributes); - return getGlyphBBoxFromCTFont(font, gid, bbox); + CTFontRef font = fontFromAttributes(attributes); + return getGlyphBBoxFromCTFont(font, gid, bbox); } static double getGlyphWidthFromCTFont(CTFontRef font, UInt16 gid) { - CGSize advances[1] = { CGSizeMake(0, 0) }; - return PStoTeXPoints(CTFontGetAdvancesForGlyphs(font, 0, &gid, advances, 1)); + return PStoTeXPoints(CTFontGetAdvancesForGlyphs(font, kCTFontHorizontalOrientation, &gid, NULL, 1)); } double GetGlyphWidth_AAT(CFDictionaryRef attributes, UInt16 gid) - /* returns TeX points */ + /* returns TeX points */ { - CTFontRef font = fontFromAttributes(attributes); - return getGlyphWidthFromCTFont(font, gid); + CTFontRef font = fontFromAttributes(attributes); + return getGlyphWidthFromCTFont(font, gid); } void GetGlyphHeightDepth_AAT(CFDictionaryRef attributes, UInt16 gid, float* ht, float* dp) - /* returns TeX points */ + /* returns TeX points */ { - GlyphBBox bbox; - - GetGlyphBBox_AAT(attributes, gid, &bbox); + GlyphBBox bbox; - *ht = bbox.yMax; - *dp = -bbox.yMin; + GetGlyphBBox_AAT(attributes, gid, &bbox); + + *ht = bbox.yMax; + *dp = -bbox.yMin; } void GetGlyphSidebearings_AAT(CFDictionaryRef attributes, UInt16 gid, float* lsb, float* rsb) - /* returns TeX points */ + /* returns TeX points */ { - CTFontRef font = fontFromAttributes(attributes); - CGSize advances[1] = { CGSizeMake(0, 0) }; - double advance = CTFontGetAdvancesForGlyphs(font, 0, &gid, advances, 1); - GlyphBBox bbox; - getGlyphBBoxFromCTFont(font, gid, &bbox); - *lsb = bbox.xMin; - *rsb = PStoTeXPoints(advance) - bbox.xMax; + CTFontRef font = fontFromAttributes(attributes); + CGSize advances[1] = { CGSizeMake(0, 0) }; + double advance = CTFontGetAdvancesForGlyphs(font, 0, &gid, advances, 1); + GlyphBBox bbox; + getGlyphBBoxFromCTFont(font, gid, &bbox); + *lsb = bbox.xMin; + *rsb = PStoTeXPoints(advance) - bbox.xMax; } double GetGlyphItalCorr_AAT(CFDictionaryRef attributes, UInt16 gid) { - CTFontRef font = fontFromAttributes(attributes); - CGSize advances[1] = { CGSizeMake(0, 0) }; - double advance = CTFontGetAdvancesForGlyphs(font, 0, &gid, advances, 1); + CTFontRef font = fontFromAttributes(attributes); + CGSize advances[1] = { CGSizeMake(0, 0) }; + double advance = CTFontGetAdvancesForGlyphs(font, 0, &gid, advances, 1); - GlyphBBox bbox; - getGlyphBBoxFromCTFont(font, gid, &bbox); + GlyphBBox bbox; + getGlyphBBoxFromCTFont(font, gid, &bbox); - if (bbox.xMax > PStoTeXPoints(advance)) - return bbox.xMax - PStoTeXPoints(advance); - return 0; + if (bbox.xMax > PStoTeXPoints(advance)) + return bbox.xMax - PStoTeXPoints(advance); + return 0; } static int mapCharToGlyphFromCTFont(CTFontRef font, UInt32 ch) { - CGGlyph glyphs[2] = { 0 }; - UniChar txt[2]; - int len = 1; - - if (ch > 0xffff) { - ch -= 0x10000; - txt[0] = 0xd800 + ch / 1024; - txt[1] = 0xdc00 + ch % 1024; - len = 2; - } else { - txt[0] = ch; - } - - if (CTFontGetGlyphsForCharacters(font, txt, glyphs, len)) - return glyphs[0]; - - return 0; + CGGlyph glyphs[2] = { 0 }; + UniChar txt[2]; + int len = 1; + + if (ch > 0xffff) { + ch -= 0x10000; + txt[0] = 0xd800 + ch / 1024; + txt[1] = 0xdc00 + ch % 1024; + len = 2; + } else { + txt[0] = ch; + } + + if (CTFontGetGlyphsForCharacters(font, txt, glyphs, len)) + return glyphs[0]; + + return 0; } int MapCharToGlyph_AAT(CFDictionaryRef attributes, UInt32 ch) { - CTFontRef font = fontFromAttributes(attributes); - return mapCharToGlyphFromCTFont(font, ch); + CTFontRef font = fontFromAttributes(attributes); + return mapCharToGlyphFromCTFont(font, ch); } static int GetGlyphIDFromCTFont(CTFontRef ctFontRef, const char* glyphName) { - CFStringRef glyphname = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, - glyphName, - kCFStringEncodingUTF8, - kCFAllocatorNull); - int rval = CTFontGetGlyphWithName(ctFontRef, glyphname); - CFRelease(glyphname); - return rval; + CFStringRef glyphname = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, + glyphName, + kCFStringEncodingUTF8, + kCFAllocatorNull); + int rval = CTFontGetGlyphWithName(ctFontRef, glyphname); + CFRelease(glyphname); + return rval; } int MapGlyphToIndex_AAT(CFDictionaryRef attributes, const char* glyphName) { - CTFontRef font = fontFromAttributes(attributes); - return GetGlyphIDFromCTFont(font, glyphName); + CTFontRef font = fontFromAttributes(attributes); + return GetGlyphIDFromCTFont(font, glyphName); } char* GetGlyphNameFromCTFont(CTFontRef ctFontRef, UInt16 gid, int* len) { - CGFontRef cgfont; - static char buffer[256]; - buffer[0] = 0; - *len = 0; - - cgfont = CTFontCopyGraphicsFont(ctFontRef, 0); - if (cgfont && gid < CGFontGetNumberOfGlyphs(cgfont)) { - CFStringRef glyphname = CGFontCopyGlyphNameForGlyph(cgfont, gid); - if (glyphname) { - if (CFStringGetCString(glyphname, buffer, 256, kCFStringEncodingUTF8)) { - *len = strlen(buffer); - } - CFRelease(glyphname); - } - CGFontRelease(cgfont); - } - - return &buffer[0]; + CGFontRef cgfont; + static char buffer[256]; + buffer[0] = 0; + *len = 0; + + cgfont = CTFontCopyGraphicsFont(ctFontRef, 0); + if (cgfont && gid < CGFontGetNumberOfGlyphs(cgfont)) { + CFStringRef glyphname = CGFontCopyGlyphNameForGlyph(cgfont, gid); + if (glyphname) { + if (CFStringGetCString(glyphname, buffer, 256, kCFStringEncodingUTF8)) { + *len = strlen(buffer); + } + CFRelease(glyphname); + } + CGFontRelease(cgfont); + } + + return &buffer[0]; } int GetFontCharRange_AAT(CFDictionaryRef attributes, int reqFirst) { - if (reqFirst) { - int ch = 0; - while (MapCharToGlyph_AAT(attributes, ch) == 0 && ch < 0x10ffff) - ++ch; - return ch; - } else { - int ch = 0x10ffff; - while (MapCharToGlyph_AAT(attributes, ch) == 0 && ch > 0) - --ch; - return ch; - } + if (reqFirst) { + int ch = 0; + while (MapCharToGlyph_AAT(attributes, ch) == 0 && ch < 0x10ffff) + ++ch; + return ch; + } else { + int ch = 0x10ffff; + while (MapCharToGlyph_AAT(attributes, ch) == 0 && ch > 0) + --ch; + return ch; + } } char* getNameFromCTFont(CTFontRef ctFontRef, CFStringRef nameKey) { - char *buf; - CFStringRef name = CTFontCopyName(ctFontRef, nameKey); - CFIndex len = CFStringGetLength(name); - len = len * 6 + 1; - buf = xmalloc(len); - if (CFStringGetCString(name, buf, len, kCFStringEncodingUTF8)) - return buf; - free(buf); - return 0; + char *buf; + CFStringRef name = CTFontCopyName(ctFontRef, nameKey); + CFIndex len = CFStringGetLength(name); + len = len * 6 + 1; + buf = xmalloc(len); + if (CFStringGetCString(name, buf, len, kCFStringEncodingUTF8)) + return buf; + free(buf); + return NULL; } char* getFileNameFromCTFont(CTFontRef ctFontRef, int *index) { - char *ret = NULL; - CFURLRef url = NULL; + char *ret = NULL; + CFURLRef url = NULL; #if !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 - /* kCTFontURLAttribute was not avialable before 10.6 */ - ATSFontRef atsFont; - FSRef fsref; - OSStatus status; - atsFont = CTFontGetPlatformFont(ctFontRef, NULL); - status = ATSFontGetFileReference(atsFont, &fsref); - if (status == noErr) - url = CFURLCreateFromFSRef(NULL, &fsref); + /* kCTFontURLAttribute was not avialable before 10.6 */ + ATSFontRef atsFont; + FSRef fsref; + OSStatus status; + atsFont = CTFontGetPlatformFont(ctFontRef, NULL); + status = ATSFontGetFileReference(atsFont, &fsref); + if (status == noErr) + url = CFURLCreateFromFSRef(NULL, &fsref); #else - url = (CFURLRef) CTFontCopyAttribute(ctFontRef, kCTFontURLAttribute); + url = (CFURLRef) CTFontCopyAttribute(ctFontRef, kCTFontURLAttribute); #endif - if (url) { - UInt8 pathname[PATH_MAX]; - if (CFURLGetFileSystemRepresentation(url, true, pathname, PATH_MAX)) { - FT_Error error; - FT_Face face; - - *index = 0; - - if (!gFreeTypeLibrary) { - error = FT_Init_FreeType(&gFreeTypeLibrary); - if (error) { - fprintf(stderr, "FreeType initialization failed! (%d)\n", error); - exit(1); - } - } - - error = FT_New_Face(gFreeTypeLibrary, (char *) pathname, 0, &face); - if (!error) { - if (face->num_faces > 1) { - int num_faces = face->num_faces; - char *ps_name1 = getNameFromCTFont(ctFontRef, kCTFontPostScriptNameKey); - int i; - *index = -1; - FT_Done_Face (face); - for (i = 0; i < num_faces; i++) { - error = FT_New_Face (gFreeTypeLibrary, (char *) pathname, i, &face); - if (!error) { - const char *ps_name2 = FT_Get_Postscript_Name(face); - if (strcmp(ps_name1, ps_name2) == 0) { - *index = i; - break; - } - FT_Done_Face (face); - } - } - } - } - - if (*index != -1) - ret = strdup((char *) pathname); - } - CFRelease(url); - } - - return ret; + if (url) { + UInt8 pathname[PATH_MAX]; + if (CFURLGetFileSystemRepresentation(url, true, pathname, PATH_MAX)) { + FT_Error error; + FT_Face face; + + *index = 0; + + if (!gFreeTypeLibrary) { + error = FT_Init_FreeType(&gFreeTypeLibrary); + if (error) { + fprintf(stderr, "FreeType initialization failed! (%d)\n", error); + exit(1); + } + } + + error = FT_New_Face(gFreeTypeLibrary, (char *) pathname, 0, &face); + if (!error) { + if (face->num_faces > 1) { + int num_faces = face->num_faces; + char *ps_name1 = getNameFromCTFont(ctFontRef, kCTFontPostScriptNameKey); + int i; + *index = -1; + FT_Done_Face (face); + for (i = 0; i < num_faces; i++) { + error = FT_New_Face (gFreeTypeLibrary, (char *) pathname, i, &face); + if (!error) { + const char *ps_name2 = FT_Get_Postscript_Name(face); + if (strcmp(ps_name1, ps_name2) == 0) { + *index = i; + break; + } + FT_Done_Face (face); + } + } + free(ps_name1); + } + } + + if (*index != -1) + ret = strdup((char *) pathname); + } + CFRelease(url); + } + + return ret; } CFDictionaryRef findDictionaryInArrayWithIdentifier(CFArrayRef array, const void* identifierKey, int identifier) { - CFDictionaryRef dict = NULL; - - if (array) { - int value = -1; - CFIndex i; - for (i = 0; i < CFArrayGetCount(array); i++) { - CFDictionaryRef item = CFArrayGetValueAtIndex(array, i); - CFNumberRef itemId = CFDictionaryGetValue(item, identifierKey); - if (itemId) { - CFNumberGetValue(itemId, kCFNumberIntType, &value); - if (value == identifier) { - dict = item; - break; - } - } - } - } - return dict; + CFDictionaryRef dict = NULL; + + if (array) { + int value = -1; + CFIndex i; + for (i = 0; i < CFArrayGetCount(array); i++) { + CFDictionaryRef item = CFArrayGetValueAtIndex(array, i); + CFNumberRef itemId = CFDictionaryGetValue(item, identifierKey); + if (itemId) { + CFNumberGetValue(itemId, kCFNumberIntType, &value); + if (value == identifier) { + dict = item; + break; + } + } + } + } + return dict; } CFDictionaryRef findDictionaryInArray(CFArrayRef array, const void* nameKey, const char* name, int nameLength) { - CFDictionaryRef dict = NULL; - - if (array) { - CFStringRef itemName; - CFIndex i; - itemName = CFStringCreateWithBytes(NULL, (UInt8 *) name, nameLength, - kCFStringEncodingUTF8, false); - for (i = 0; i < CFArrayGetCount(array); i++) { - CFDictionaryRef item = CFArrayGetValueAtIndex(array, i); - CFStringRef iName = CFDictionaryGetValue(item, nameKey); - if (iName && !CFStringCompare(itemName, iName, kCFCompareCaseInsensitive)) { - dict = item; - break; - } - } - CFRelease(itemName); - } - return dict; + CFDictionaryRef dict = NULL; + + if (array) { + CFStringRef itemName; + CFIndex i; + itemName = CFStringCreateWithBytes(NULL, (UInt8 *) name, nameLength, + kCFStringEncodingUTF8, false); + for (i = 0; i < CFArrayGetCount(array); i++) { + CFDictionaryRef item = CFArrayGetValueAtIndex(array, i); + CFStringRef iName = CFDictionaryGetValue(item, nameKey); + if (iName && !CFStringCompare(itemName, iName, kCFCompareCaseInsensitive)) { + dict = item; + break; + } + } + CFRelease(itemName); + } + return dict; } CFNumberRef findSelectorByName(CFDictionaryRef feature, const char* name, int nameLength) { - CFNumberRef selector = NULL; - CFArrayRef selectors = CFDictionaryGetValue(feature, kCTFontFeatureTypeSelectorsKey); - if (selectors) { - CFDictionaryRef s = findDictionaryInArray(selectors, kCTFontFeatureSelectorNameKey, name, nameLength); - if (s) - selector = CFDictionaryGetValue(s, kCTFontFeatureSelectorIdentifierKey); - } - return selector; + CFNumberRef selector = NULL; + CFArrayRef selectors = CFDictionaryGetValue(feature, kCTFontFeatureTypeSelectorsKey); + if (selectors) { + CFDictionaryRef s = findDictionaryInArray(selectors, kCTFontFeatureSelectorNameKey, name, nameLength); + if (s) + selector = CFDictionaryGetValue(s, kCTFontFeatureSelectorIdentifierKey); + } + return selector; } static CFDictionaryRef createFeatureSettingDictionary(CFNumberRef featureTypeIdentifier, CFNumberRef featureSelectorIdentifier) { - const void* settingKeys[] = { kCTFontFeatureTypeIdentifierKey, kCTFontFeatureSelectorIdentifierKey }; - const void* settingValues[] = { featureTypeIdentifier, featureSelectorIdentifier }; + const void* settingKeys[] = { kCTFontFeatureTypeIdentifierKey, kCTFontFeatureSelectorIdentifierKey }; + const void* settingValues[] = { featureTypeIdentifier, featureSelectorIdentifier }; - return CFDictionaryCreate(kCFAllocatorDefault, settingKeys, settingValues, 2, - &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + return CFDictionaryCreate(kCFAllocatorDefault, settingKeys, settingValues, 2, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } const CFStringRef kXeTeXEmboldenAttributeName = CFSTR("XeTeXEmbolden"); @@ -545,385 +546,260 @@ const CFStringRef kXeTeXEmboldenAttributeName = CFSTR("XeTeXEmbolden"); void* loadAATfont(CTFontDescriptorRef descriptor, integer scaled_size, const char* cp1) { - CTFontRef font, actualFont; - CGFloat ctSize; - CFMutableDictionaryRef stringAttributes, attributes; - CGAffineTransform matrix; - CFMutableArrayRef cascadeList; - CTFontDescriptorRef lastResort; - double tracking = 0.0; - float extend = 1.0; - float slant = 0.0; - float embolden = 0.0; - float letterspace = 0.0; - uint32_t rgbValue; - - // create a base font instance for applying further attributes - ctSize = TeXtoPSPoints(Fix2D(scaled_size)); - font = CTFontCreateWithFontDescriptor(descriptor, ctSize, NULL); - if (!font) - return NULL; - - stringAttributes = CFDictionaryCreateMutable(NULL, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - attributes = CFDictionaryCreateMutable(NULL, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (cp1) { - CFArrayRef features = CTFontCopyFeatures(font); - CFArrayRef axes = CTFontCopyVariationAxes(font); - CFMutableArrayRef featureSettings = - CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - CFMutableDictionaryRef variation = - CFDictionaryCreateMutable(NULL, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - // interpret features & variations following ":" - while (*cp1) { - CFDictionaryRef feature, axis; - int ret; - const char* cp2; - const char* cp3; - // 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 - cp2 = cp1; - while (*cp2 && (*cp2 != ';') && (*cp2 != ':')) - ++cp2; - - // look for the '=' separator - 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 - feature = findDictionaryInArray(features, kCTFontFeatureTypeNameKey, cp1, cp3 - cp1); - if (feature) { - // look past the '=' separator for setting names - int featLen = cp3 - cp1; - int zeroInteger = 0; - CFNumberRef zero = CFNumberCreate(NULL, kCFNumberIntType, &zeroInteger); - ++cp3; - while (cp3 < cp2) { - CFNumberRef selector; - int disable = 0; - const char* cp4; - // skip leading whitespace - while (*cp3 == ' ' || *cp3 == '\t') - ++cp3; - - // possibly multiple settings... - if (*cp3 == '!') { // check for negation - disable = 1; - ++cp3; - } - - // scan for end of setting name - cp4 = cp3; - while (cp4 < cp2 && *cp4 != ',') - ++cp4; - - // now cp3 points to name, cp4 to ',' or ';' or null - selector = findSelectorByName(feature, cp3, cp4 - cp3); - if (selector && CFNumberCompare(selector, zero, NULL) >= 0) { - CFNumberRef featureType = CFDictionaryGetValue(feature, kCTFontFeatureTypeIdentifierKey); - CFDictionaryRef featureSetting = createFeatureSettingDictionary(featureType, selector); - CFArrayAppendValue(featureSettings, featureSetting); - CFRelease(featureSetting); - } else { - fontfeaturewarning(cp1, featLen, cp3, cp4 - cp3); - } - - // point beyond setting name terminator - cp3 = cp4 + 1; - } - CFRelease(zero); - - goto next_option; - } - - // try to find a variation by this name - axis = findDictionaryInArray(axes, kCTFontVariationAxisNameKey, cp1, cp3 - cp1); - if (axis) { - CFNumberRef axisIdentifier, axisValue; - double value = 0.0, decimal = 1.0; - bool negate = false; - // look past the '=' separator for the value - ++cp3; - 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; - - axisIdentifier = CFDictionaryGetValue(axis, kCTFontVariationAxisIdentifierKey); - axisValue = CFNumberCreate(NULL, kCFNumberDoubleType, &value); - CFDictionaryAddValue(variation, axisIdentifier, axisValue); - CFRelease(axisValue); - - goto next_option; - } - - // didn't find feature or variation, try other options... - ret = readCommonFeatures(cp1, cp2, &extend, &slant, &embolden, &letterspace, &rgbValue); - if (ret == 1) - goto next_option; - else if (ret == -1) - goto bad_option; - - if (strncmp(cp1, "tracking", 8) == 0) { - CFNumberRef trackingNumber; - cp3 = cp1 + 8; - if (*cp3 != '=') - goto bad_option; - ++cp3; - tracking = read_double(&cp3); - trackingNumber = CFNumberCreate(NULL, kCFNumberDoubleType, &tracking); - CFDictionaryAddValue(stringAttributes, kCTKernAttributeName, trackingNumber); - CFRelease(trackingNumber); - 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) { - int orientation = kCTFontVerticalOrientation; - CFNumberRef orientationNumber = CFNumberCreate(NULL, kCFNumberIntType, &orientation); - CFDictionaryAddValue(attributes, kCTFontOrientationAttribute, orientationNumber); - CFRelease(orientationNumber); - CFDictionaryAddValue(stringAttributes, kCTVerticalFormsAttributeName, kCFBooleanTrue); - goto next_option; - } - } - - fontfeaturewarning(cp1, cp2 - cp1, 0, 0); - - next_option: - // go to next name=value pair - cp1 = cp2; - } - - if (features) - CFRelease(features); - if (axes) - CFRelease(axes); - - if (CFArrayGetCount(featureSettings)) - CFDictionaryAddValue(attributes, kCTFontFeatureSettingsAttribute, featureSettings); - CFRelease(featureSettings); - - if (CFDictionaryGetCount(variation)) - CFDictionaryAddValue(attributes, kCTFontVariationAttribute, variation); - CFRelease(variation); - } - - if ((loadedfontflags & FONT_FLAGS_COLORED) != 0) { - CGFloat red = ((rgbValue & 0xFF000000) >> 24) / 255.0; - CGFloat green = ((rgbValue & 0x00FF0000) >> 16) / 255.0; - CGFloat blue = ((rgbValue & 0x0000FF00) >> 8 ) / 255.0; - CGFloat alpha = ((rgbValue & 0x000000FF) ) / 255.0; - CGColorRef color = CGColorCreateGenericRGB(red, green, blue, alpha); - CFDictionaryAddValue(stringAttributes, kCTForegroundColorAttributeName, color); - CGColorRelease(color); - } - - matrix = CGAffineTransformIdentity; - // XXX this breaks y glyph positioning - if (extend != 1.0 || slant != 0.0) - matrix = CGAffineTransformMake(extend, slant, 0, 1.0, 0, 0); - - if (embolden != 0.0) { - CFNumberRef emboldenNumber; - embolden = embolden * Fix2D(scaled_size) / 100.0; - emboldenNumber = CFNumberCreate(NULL, kCFNumberFloatType, &embolden); - CFDictionaryAddValue(stringAttributes, kXeTeXEmboldenAttributeName, emboldenNumber); - CFRelease(emboldenNumber); - } - - if (letterspace != 0.0) - loadedfontletterspace = (letterspace / 100.0) * scaled_size; - - // Disable Core Text font fallback (cascading) with only the last resort font - // in the cascade list. - cascadeList = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks); - lastResort = CTFontDescriptorCreateWithNameAndSize(CFSTR("LastResort"), 0); - CFArrayAppendValue(cascadeList, lastResort); - CFRelease(lastResort); - CFDictionaryAddValue(attributes, kCTFontCascadeListAttribute, cascadeList); - CFRelease(cascadeList); - - descriptor = CTFontDescriptorCreateWithAttributes(attributes); - CFRelease(attributes); - actualFont = CTFontCreateCopyWithAttributes(font, ctSize, &matrix, descriptor); - CFRelease(font); - CFDictionaryAddValue(stringAttributes, kCTFontAttributeName, actualFont); - CFRelease(actualFont); - - nativefonttypeflag = AAT_FONT_FLAG; - return (void *) stringAttributes; -} - -int -countpdffilepages() -{ - int rval = 0; - - char* pic_path = kpse_find_file((char*)nameoffile + 1, kpse_pict_format, 1); - CFURLRef picFileURL = NULL; - if (pic_path) { - picFileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8*)pic_path, strlen(pic_path), false); - if (picFileURL != NULL) { - FSRef picFileRef; - CGPDFDocumentRef document; - CFURLGetFSRef(picFileURL, &picFileRef); - document = CGPDFDocumentCreateWithURL(picFileURL); - if (document != NULL) { - rval = CGPDFDocumentGetNumberOfPages(document); - CGPDFDocumentRelease(document); - } - CFRelease(picFileURL); - } - free(pic_path); - } - - return rval; -} - -int -find_pic_file(char** path, realrect* bounds, int pdfBoxType, int page) - /* returns bounds in TeX points */ -{ - OSStatus result = fnfErr; - char* pic_path = kpse_find_file((char*)nameoffile + 1, kpse_pict_format, 1); - CFURLRef picFileURL = NULL; - - *path = NULL; - - if (pic_path) { - picFileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8*)pic_path, strlen(pic_path), false); - - if (picFileURL != NULL) { - if (pdfBoxType > 0) { - CGPDFDocumentRef document = CGPDFDocumentCreateWithURL(picFileURL); - if (document != NULL) { - CGPDFPageRef pageRef; - CGRect r; - CGPDFBox boxType; - int nPages = CGPDFDocumentGetNumberOfPages(document); - if (page < 0) - page = nPages + 1 + page; - if (page < 1) - page = 1; - if (page > nPages) - page = nPages; - - pageRef = CGPDFDocumentGetPage(document, page); - switch (pdfBoxType) { - case pdfbox_crop: - default: - boxType = kCGPDFCropBox; - break; - case pdfbox_media: - boxType = kCGPDFMediaBox; - break; - case pdfbox_bleed: - boxType = kCGPDFBleedBox; - break; - case pdfbox_trim: - boxType = kCGPDFTrimBox; - break; - case pdfbox_art: - boxType = kCGPDFArtBox; - break; - } - r = CGPDFPageGetBoxRect(pageRef, boxType); - - bounds->x = r.origin.x * 72.27 / 72.0; - bounds->y = r.origin.y * 72.27 / 72.0; - bounds->wd = r.size.width * 72.27 / 72.0; - bounds->ht = r.size.height * 72.27 / 72.0; - CGPDFDocumentRelease(document); - result = noErr; - } - } else { - CGImageSourceRef picFileSource = CGImageSourceCreateWithURL(picFileURL, NULL); - if (picFileSource) { - CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(picFileSource, 0, NULL); - - CFNumberRef imageWidth = CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth); - CFNumberRef imageHeight = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight); - CFNumberRef DPIWidth = CFDictionaryGetValue(properties, kCGImagePropertyDPIWidth); - CFNumberRef DPIHeight = CFDictionaryGetValue(properties, kCGImagePropertyDPIHeight); - - if (imageWidth && imageHeight) { - int w = 0, h = 0, hRes = 72, vRes = 72; - CFNumberGetValue(imageWidth, kCFNumberIntType, &w); - CFNumberGetValue(imageHeight, kCFNumberIntType, &h); - if (DPIWidth) - CFNumberGetValue(DPIWidth, kCFNumberIntType, &hRes); - if (DPIHeight) - CFNumberGetValue(DPIHeight, kCFNumberIntType, &vRes); - - bounds->x = 0; - bounds->y = 0; - bounds->wd = w * 72.27 / hRes; - bounds->ht = h * 72.27 / vRes; - CFRelease(properties); - CFRelease(picFileSource); - result = noErr; - } - } - } - - CFRelease(picFileURL); - } - - /* if we couldn't import it, toss the pathname as we'll be returning an error */ - if (result != noErr) - free(pic_path); - else - *path = (char*)pic_path; - } - - return result; + CTFontRef font, actualFont; + CGFloat ctSize; + CFMutableDictionaryRef stringAttributes, attributes; + CGAffineTransform matrix; + CFMutableArrayRef cascadeList; + CTFontDescriptorRef lastResort; + double tracking = 0.0; + float extend = 1.0; + float slant = 0.0; + float embolden = 0.0; + float letterspace = 0.0; + uint32_t rgbValue; + + // create a base font instance for applying further attributes + ctSize = TeXtoPSPoints(Fix2D(scaled_size)); + font = CTFontCreateWithFontDescriptor(descriptor, ctSize, NULL); + if (!font) + return NULL; + + stringAttributes = CFDictionaryCreateMutable(NULL, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + attributes = CFDictionaryCreateMutable(NULL, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (cp1) { + CFArrayRef features = CTFontCopyFeatures(font); + CFArrayRef axes = CTFontCopyVariationAxes(font); + CFMutableArrayRef featureSettings = + CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + CFMutableDictionaryRef variation = + CFDictionaryCreateMutable(NULL, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + // interpret features & variations following ":" + while (*cp1) { + CFDictionaryRef feature, axis; + int ret; + const char* cp2; + const char* cp3; + // 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 + cp2 = cp1; + while (*cp2 && (*cp2 != ';') && (*cp2 != ':')) + ++cp2; + + // look for the '=' separator + 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 + feature = findDictionaryInArray(features, kCTFontFeatureTypeNameKey, cp1, cp3 - cp1); + if (feature) { + // look past the '=' separator for setting names + int featLen = cp3 - cp1; + int zeroInteger = 0; + CFNumberRef zero = CFNumberCreate(NULL, kCFNumberIntType, &zeroInteger); + ++cp3; + while (cp3 < cp2) { + CFNumberRef selector; + int disable = 0; + const char* cp4; + // skip leading whitespace + while (*cp3 == ' ' || *cp3 == '\t') + ++cp3; + + // possibly multiple settings... + if (*cp3 == '!') { // check for negation + disable = 1; + ++cp3; + } + + // scan for end of setting name + cp4 = cp3; + while (cp4 < cp2 && *cp4 != ',') + ++cp4; + + // now cp3 points to name, cp4 to ',' or ';' or null + selector = findSelectorByName(feature, cp3, cp4 - cp3); + if (selector && CFNumberCompare(selector, zero, NULL) >= 0) { + CFNumberRef featureType = CFDictionaryGetValue(feature, kCTFontFeatureTypeIdentifierKey); + CFDictionaryRef featureSetting = createFeatureSettingDictionary(featureType, selector); + CFArrayAppendValue(featureSettings, featureSetting); + CFRelease(featureSetting); + } else { + fontfeaturewarning(cp1, featLen, cp3, cp4 - cp3); + } + + // point beyond setting name terminator + cp3 = cp4 + 1; + } + CFRelease(zero); + + goto next_option; + } + + // try to find a variation by this name + axis = findDictionaryInArray(axes, kCTFontVariationAxisNameKey, cp1, cp3 - cp1); + if (axis) { + CFNumberRef axisIdentifier, axisValue; + double value = 0.0, decimal = 1.0; + bool negate = false; + // look past the '=' separator for the value + ++cp3; + 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; + + axisIdentifier = CFDictionaryGetValue(axis, kCTFontVariationAxisIdentifierKey); + axisValue = CFNumberCreate(NULL, kCFNumberDoubleType, &value); + CFDictionaryAddValue(variation, axisIdentifier, axisValue); + CFRelease(axisValue); + + goto next_option; + } + + // didn't find feature or variation, try other options... + ret = readCommonFeatures(cp1, cp2, &extend, &slant, &embolden, &letterspace, &rgbValue); + if (ret == 1) + goto next_option; + else if (ret == -1) + goto bad_option; + + if (strncmp(cp1, "tracking", 8) == 0) { + CFNumberRef trackingNumber; + cp3 = cp1 + 8; + if (*cp3 != '=') + goto bad_option; + ++cp3; + tracking = read_double(&cp3); + trackingNumber = CFNumberCreate(NULL, kCFNumberDoubleType, &tracking); + CFDictionaryAddValue(stringAttributes, kCTKernAttributeName, trackingNumber); + CFRelease(trackingNumber); + 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) { + int orientation = kCTFontVerticalOrientation; + CFNumberRef orientationNumber = CFNumberCreate(NULL, kCFNumberIntType, &orientation); + CFDictionaryAddValue(attributes, kCTFontOrientationAttribute, orientationNumber); + CFRelease(orientationNumber); + CFDictionaryAddValue(stringAttributes, kCTVerticalFormsAttributeName, kCFBooleanTrue); + goto next_option; + } + } + + fontfeaturewarning(cp1, cp2 - cp1, 0, 0); + + next_option: + // go to next name=value pair + cp1 = cp2; + } + + if (features) + CFRelease(features); + if (axes) + CFRelease(axes); + + if (CFArrayGetCount(featureSettings)) + CFDictionaryAddValue(attributes, kCTFontFeatureSettingsAttribute, featureSettings); + CFRelease(featureSettings); + + if (CFDictionaryGetCount(variation)) + CFDictionaryAddValue(attributes, kCTFontVariationAttribute, variation); + CFRelease(variation); + } + + if ((loadedfontflags & FONT_FLAGS_COLORED) != 0) { + CGFloat red = ((rgbValue & 0xFF000000) >> 24) / 255.0; + CGFloat green = ((rgbValue & 0x00FF0000) >> 16) / 255.0; + CGFloat blue = ((rgbValue & 0x0000FF00) >> 8 ) / 255.0; + CGFloat alpha = ((rgbValue & 0x000000FF) ) / 255.0; + CGColorRef color = CGColorCreateGenericRGB(red, green, blue, alpha); + CFDictionaryAddValue(stringAttributes, kCTForegroundColorAttributeName, color); + CGColorRelease(color); + } + + matrix = CGAffineTransformIdentity; + // XXX this breaks y glyph positioning + if (extend != 1.0 || slant != 0.0) + matrix = CGAffineTransformMake(extend, slant, 0, 1.0, 0, 0); + + if (embolden != 0.0) { + CFNumberRef emboldenNumber; + embolden = embolden * Fix2D(scaled_size) / 100.0; + emboldenNumber = CFNumberCreate(NULL, kCFNumberFloatType, &embolden); + CFDictionaryAddValue(stringAttributes, kXeTeXEmboldenAttributeName, emboldenNumber); + CFRelease(emboldenNumber); + } + + if (letterspace != 0.0) + loadedfontletterspace = (letterspace / 100.0) * scaled_size; + + // Disable Core Text font fallback (cascading) with only the last resort font + // in the cascade list. + cascadeList = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks); + lastResort = CTFontDescriptorCreateWithNameAndSize(CFSTR("LastResort"), 0); + CFArrayAppendValue(cascadeList, lastResort); + CFRelease(lastResort); + CFDictionaryAddValue(attributes, kCTFontCascadeListAttribute, cascadeList); + CFRelease(cascadeList); + + descriptor = CTFontDescriptorCreateWithAttributes(attributes); + CFRelease(attributes); + actualFont = CTFontCreateCopyWithAttributes(font, ctSize, &matrix, descriptor); + CFRelease(font); + CFDictionaryAddValue(stringAttributes, kCTFontAttributeName, actualFont); + CFRelease(actualFont); + + nativefonttypeflag = AAT_FONT_FLAG; + return (void *) stringAttributes; } |