diff options
author | Jonathan Kew <jfkthame@googlemail.com> | 2006-07-26 16:19:45 +0000 |
---|---|---|
committer | Jonathan Kew <jfkthame@googlemail.com> | 2006-07-26 16:19:45 +0000 |
commit | 622bf4a7c90729be28a038c49e4c237ce9f31297 (patch) | |
tree | 77466d5c0a89c433bd1c08f4cbeaf410fda7b25c /Build/source/texk/web2c/xetexdir/XeTeX_mac.c | |
parent | e88aafe4ca4779a73487925dea63e8b55dc5e251 (diff) |
added main xetex source directory
git-svn-id: svn://tug.org/texlive/trunk@1920 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/xetexdir/XeTeX_mac.c')
-rw-r--r-- | Build/source/texk/web2c/xetexdir/XeTeX_mac.c | 1022 |
1 files changed, 1022 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/xetexdir/XeTeX_mac.c b/Build/source/texk/web2c/xetexdir/XeTeX_mac.c new file mode 100644 index 00000000000..8a892be8fc4 --- /dev/null +++ b/Build/source/texk/web2c/xetexdir/XeTeX_mac.c @@ -0,0 +1,1022 @@ +/****************************************************************************\ + Part of the XeTeX typesetting system + copyright (c) 1994-2006 by SIL International + written by Jonathan Kew + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL SIL INTERNATIONAL BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of SIL International +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written +authorization from SIL International. +\****************************************************************************/ + +/* XeTeX_mac.c + * additional plain C extensions for XeTeX - MacOS-specific routines + */ + +#ifdef __POWERPC__ +#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_2 +#else +#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_4 +#endif + +#define EXTERN extern +#include "xetexd.h" + +#undef input /* this is defined in texmfmp.h, but we don't need it and it confuses the carbon headers */ +#include <Carbon/Carbon.h> +#include <Quicktime/Quicktime.h> + +#include "TECkit_Engine.h" +#include "XeTeX_ext.h" + +#include "XeTeXswap.h" + +static ATSUTextLayout sTextLayout = 0; + +static void +InitializeLayout() +{ + OSStatus status = ATSUCreateTextLayout(&sTextLayout); + ATSUFontFallbacks fallbacks; + status = ATSUCreateFontFallbacks(&fallbacks); + status = ATSUSetObjFontFallbacks(fallbacks, 0, 0, kATSULastResortOnlyFallback); + ATSUAttributeTag tag = kATSULineFontFallbacksTag; + ByteCount valueSize = sizeof(fallbacks); + ATSUAttributeValuePtr value = &fallbacks; + status = ATSUSetLayoutControls(sTextLayout, 1, &tag, &valueSize, &value); + status = ATSUSetTransientFontMatching(sTextLayout, true); +} + +static inline double +TeXtoPSPoints(double pts) +{ + return pts * 72.0 / 72.27; +} + +static inline double +PStoTeXPoints(double pts) +{ + return pts * 72.27 / 72.0; +} + +static inline Fixed +FixedTeXtoPSPoints(Fixed pts) +{ + return X2Fix(TeXtoPSPoints(Fix2X(pts))); +} + +static inline Fixed +FixedPStoTeXPoints(Fixed pts) +{ + return X2Fix(PStoTeXPoints(Fix2X(pts))); +} + +void +DoAtsuiLayout(void* p, int justify) +{ + memoryword* node = (memoryword*)p; + + unsigned f = native_font(node); + if (fontarea[f] != AAT_FONT_FLAG) { + fprintf(stderr, "internal error: do_atsui_layout called for non-ATSUI font\n"); + exit(1); + } + + if (sTextLayout == 0) + InitializeLayout(); + + OSStatus status = noErr; + + long txtLen = native_length(node); + const UniChar* txtPtr = (UniChar*)(node + native_node_size); + + status = ATSUSetTextPointerLocation(sTextLayout, txtPtr, 0, txtLen, txtLen); + + // we're using this font in AAT mode, so fontlayoutengine[f] is actually an ATSUStyle + ATSUStyle style = (ATSUStyle)(fontlayoutengine[native_font(node)]); + status = ATSUSetRunStyle(sTextLayout, style, 0, txtLen); + + ATSUAttributeTag tags[] = { kATSULineWidthTag, kATSULineJustificationFactorTag }; + ItemCount numTags = sizeof(tags) / sizeof(ATSUAttributeTag); + if (justify) { + ByteCount valSizes[] = { sizeof(Fixed), sizeof(Fract) }; + Fixed wid = FixedTeXtoPSPoints(node_width(node)); + Fract just = fract1; + ATSUAttributeValuePtr valPtrs[] = { &wid, &just }; + status = ATSUSetLayoutControls(sTextLayout, numTags, tags, valSizes, valPtrs); + } + + ItemCount count; + ATSLayoutRecord* layoutRec = NULL; + status = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(sTextLayout, 0, + kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void*)&layoutRec, &count); + + int i; + int realGlyphCount = 0; + int lastRealGlyph = 0; + for (i = 0; i < count; ++i) + if (layoutRec[i].glyphID < 0xfffe) { + lastRealGlyph = i; + ++realGlyphCount; + } + + void* glyph_info = xmalloc(realGlyphCount * native_glyph_info_size); + FixedPoint* locations = (FixedPoint*)glyph_info; + UInt16* glyphIDs = (UInt16*)(locations + realGlyphCount); + + Fixed lsUnit = justify ? 0 : fontletterspace[f]; + Fixed lsDelta = 0; + + realGlyphCount = 0; + for (i = 0; i < count; ++i) { + if (layoutRec[i].glyphID < 0xfffe) { + if ((layoutRec[i].flags & kATSGlyphInfoIsAttachment) && (lsDelta != 0)) + lsDelta -= lsUnit; + glyphIDs[realGlyphCount] = layoutRec[i].glyphID; + locations[realGlyphCount].y = 0; /* FIXME: won't handle baseline offsets */ + locations[realGlyphCount].x = FixedPStoTeXPoints(layoutRec[i].realPos) + lsDelta; + lsDelta += lsUnit; + ++realGlyphCount; + } + } + if (lsDelta != 0) + lsDelta -= lsUnit; + + native_glyph_count(node) = realGlyphCount; + native_glyph_info_ptr(node) = (long)glyph_info; + + if (!justify) + node_width(node) = FixedPStoTeXPoints(layoutRec[count-1].realPos) + lsDelta; + + ATSUDirectReleaseLayoutDataArrayPtr(NULL, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void*)&layoutRec); + + if (justify) + ATSUClearLayoutControls(sTextLayout, numTags, tags); +} + +static OSStatus QuadraticClosePath(void *callBackDataPtr) +{ + return 0; +} + +static OSStatus QuadraticCurve(const Float32Point *pt1, const Float32Point *controlPt, const Float32Point *pt2, void *callBackDataPtr) +{ + GlyphBBox* data = (GlyphBBox*)callBackDataPtr; + + if (pt1->x < data->xMin) + data->xMin = pt1->x; + if (pt1->x > data->xMax) + data->xMax = pt1->x; + if (pt1->y < data->yMin) + data->yMin = pt1->y; + if (pt1->y > data->yMax) + data->yMax = pt1->y; + + if (pt2->x < data->xMin) + data->xMin = pt2->x; + if (pt2->x > data->xMax) + data->xMax = pt2->x; + if (pt2->y < data->yMin) + data->yMin = pt2->y; + if (pt2->y > data->yMax) + data->yMax = pt2->y; + + if (controlPt->x < data->xMin) + data->xMin = controlPt->x; + if (controlPt->x > data->xMax) + data->xMax = controlPt->x; + if (controlPt->y < data->yMin) + data->yMin = controlPt->y; + if (controlPt->y > data->yMax) + data->yMax = controlPt->y; + + return 0; +} + +static OSStatus QuadraticLine(const Float32Point *pt1, const Float32Point *pt2, void *callBackDataPtr) +{ + GlyphBBox* data = (GlyphBBox*)callBackDataPtr; + + if (pt1->x < data->xMin) + data->xMin = pt1->x; + if (pt1->x > data->xMax) + data->xMax = pt1->x; + if (pt1->y < data->yMin) + data->yMin = pt1->y; + if (pt1->y > data->yMax) + data->yMax = pt1->y; + + if (pt2->x < data->xMin) + data->xMin = pt2->x; + if (pt2->x > data->xMax) + data->xMax = pt2->x; + if (pt2->y < data->yMin) + data->yMin = pt2->y; + if (pt2->y > data->yMax) + data->yMax = pt2->y; + + return 0; +} + +static OSStatus QuadraticNewPath(void *callBackDataPtr) +{ + return 0; +} + +static OSStatus CubicMoveTo(const Float32Point *pt, void *callBackDataPtr) +{ + GlyphBBox* data = (GlyphBBox*)callBackDataPtr; + + if (pt->x < data->xMin) + data->xMin = pt->x; + if (pt->x > data->xMax) + data->xMax = pt->x; + if (pt->y < data->yMin) + data->yMin = pt->y; + if (pt->y > data->yMax) + data->yMax = pt->y; + + return 0; +} + +static OSStatus CubicLineTo(const Float32Point *pt, void *callBackDataPtr) +{ + GlyphBBox* data = (GlyphBBox*)callBackDataPtr; + + if (pt->x < data->xMin) + data->xMin = pt->x; + if (pt->x > data->xMax) + data->xMax = pt->x; + if (pt->y < data->yMin) + data->yMin = pt->y; + if (pt->y > data->yMax) + data->yMax = pt->y; + + return 0; +} + +static OSStatus CubicCurveTo(const Float32Point *pt1, const Float32Point *pt2, const Float32Point *pt3, void *callBackDataPtr) +{ + GlyphBBox* data = (GlyphBBox*)callBackDataPtr; + + if (pt1->x < data->xMin) + data->xMin = pt1->x; + if (pt1->x > data->xMax) + data->xMax = pt1->x; + if (pt1->y < data->yMin) + data->yMin = pt1->y; + if (pt1->y > data->yMax) + data->yMax = pt1->y; + + if (pt2->x < data->xMin) + data->xMin = pt2->x; + if (pt2->x > data->xMax) + data->xMax = pt2->x; + if (pt2->y < data->yMin) + data->yMin = pt2->y; + if (pt2->y > data->yMax) + data->yMax = pt2->y; + + if (pt3->x < data->xMin) + data->xMin = pt3->x; + if (pt3->x > data->xMax) + data->xMax = pt3->x; + if (pt3->y < data->yMin) + data->yMin = pt3->y; + if (pt3->y > data->yMax) + data->yMax = pt3->y; + + return 0; +} + +static OSStatus CubicClosePath(void *callBackDataPtr) +{ + return 0; +} + +void GetGlyphBBox_AAT(ATSUStyle style, UInt16 gid, GlyphBBox* bbox) + /* returns glyph bounding box in TeX points */ +{ + ATSCurveType curveType; + OSStatus status; + + bbox->xMin = 65536.0; + bbox->yMin = 65536.0; + bbox->xMax = -65536.0; + bbox->yMax = -65536.0; + + status = ATSUGetNativeCurveType(style, &curveType); + if (status == noErr) { + OSStatus cbStatus; + + if (curveType == kATSCubicCurveType) { + static ATSCubicMoveToUPP cubicMoveToProc; + static ATSCubicLineToUPP cubicLineToProc; + static ATSCubicCurveToUPP cubicCurveToProc; + static ATSCubicClosePathUPP cubicClosePathProc; + if (cubicMoveToProc == NULL) { + cubicMoveToProc = NewATSCubicMoveToUPP(&CubicMoveTo); + cubicLineToProc = NewATSCubicLineToUPP(&CubicLineTo); + cubicCurveToProc = NewATSCubicCurveToUPP(&CubicCurveTo); + cubicClosePathProc = NewATSCubicClosePathUPP(&CubicClosePath); + } + status = ATSUGlyphGetCubicPaths(style, gid, + cubicMoveToProc, cubicLineToProc, cubicCurveToProc, cubicClosePathProc, + bbox, &cbStatus); + } + else { + static ATSQuadraticNewPathUPP quadraticNewPathProc; + static ATSQuadraticLineUPP quadraticLineProc; + static ATSQuadraticCurveUPP quadraticCurveProc; + static ATSQuadraticClosePathUPP quadraticClosePathProc; + if (quadraticNewPathProc == NULL) { + quadraticNewPathProc = NewATSQuadraticNewPathUPP(&QuadraticNewPath); + quadraticLineProc = NewATSQuadraticLineUPP(&QuadraticLine); + quadraticCurveProc = NewATSQuadraticCurveUPP(&QuadraticCurve); + quadraticClosePathProc = NewATSQuadraticClosePathUPP(&QuadraticClosePath); + } + status = ATSUGlyphGetQuadraticPaths(style, gid, + quadraticNewPathProc, quadraticLineProc, quadraticCurveProc, quadraticClosePathProc, + bbox, &cbStatus); + } + } + + if (status != noErr || bbox->xMin == 65536.0) + bbox->xMin = bbox->yMin = bbox->xMax = bbox->yMax = 0; + else { + // convert PS to TeX points and flip y-axis + float tmp = bbox->yMin; + bbox->yMin = -bbox->yMax * 72.27 / 72.0; + bbox->yMax = -tmp * 72.27 / 72.0; + bbox->xMin *= 72.27 / 72.0; + bbox->xMax *= 72.27 / 72.0; + } +} + +float GetGlyphWidth_AAT(ATSUStyle style, UInt16 gid) + /* returns TeX points */ +{ + ATSGlyphIdealMetrics metrics; + OSStatus status = ATSUGlyphGetIdealMetrics(style, 1, &gid, 0, &metrics); + return PStoTeXPoints(metrics.advance.x); +} + +void GetGlyphHeightDepth_AAT(ATSUStyle style, UInt16 gid, float* ht, float* dp) + /* returns TeX points */ +{ + GlyphBBox bbox; + + GetGlyphBBox_AAT(style, gid, &bbox); + + *ht = bbox.yMax; + *dp = -bbox.yMin; +} + +void GetGlyphSidebearings_AAT(ATSUStyle style, UInt16 gid, float* lsb, float* rsb) + /* returns TeX points */ +{ + ATSGlyphIdealMetrics metrics; + OSStatus status = ATSUGlyphGetIdealMetrics(style, 1, &gid, 0, &metrics); + GlyphBBox bbox; + GetGlyphBBox_AAT(style, gid, &bbox); + *lsb = bbox.xMin; + *rsb = PStoTeXPoints(metrics.advance.x) - bbox.xMax; +} + +float GetGlyphItalCorr_AAT(ATSUStyle style, UInt16 gid) +{ + float rval = 0.0; + ATSGlyphIdealMetrics metrics; + OSStatus status = ATSUGlyphGetIdealMetrics(style, 1, &gid, 0, &metrics); + GlyphBBox bbox; + GetGlyphBBox_AAT(style, gid, &bbox); + if (bbox.xMax > PStoTeXPoints(metrics.advance.x)) + rval = bbox.xMax - PStoTeXPoints(metrics.advance.x); + return rval; +} + +int MapCharToGlyph_AAT(ATSUStyle style, UInt32 ch) +{ + UniChar txt[2]; + int len = 1; + + if (sTextLayout == 0) + InitializeLayout(); + + if (ch > 0xffff) { + ch -= 0x10000; + txt[0] = 0xd800 + ch / 1024; + txt[1] = 0xdc00 + ch % 1024; + len = 2; + } + else + txt[0] = ch; + + OSStatus status = ATSUSetTextPointerLocation(sTextLayout, &txt[0], 0, len, len); + status = ATSUSetRunStyle(sTextLayout, style, 0, len); + + ByteCount bufferSize = sizeof(ATSUGlyphInfoArray); + ATSUGlyphInfoArray info; + status = ATSUGetGlyphInfo(sTextLayout, 0, len, &bufferSize, &info); + if (bufferSize > 0 && info.numGlyphs > 0) + return info.glyphs[0].glyphID; + else + return 0; +} + +int MapGlyphToIndex_AAT(ATSUStyle style, const char* glyphName) +{ + ATSUFontID fontID; + ATSUGetAttribute(style, kATSUFontTag, sizeof(ATSUFontID), &fontID, 0); + + ATSFontRef fontRef = FMGetATSFontRefFromFont(fontID); + + ByteCount length; + OSStatus status = ATSFontGetTable(fontRef, kPost, 0, 0, 0, &length); + if (status != noErr) + return 0; + + void* table = xmalloc(length); + status = ATSFontGetTable(fontRef, kPost, 0, length, table, &length); + if (status != noErr) { + free(table); + return 0; + } + + int rval = findGlyphInPostTable(table, length, glyphName); + free(table); + + return rval; +} + +ATSUFontVariationAxis +find_axis_by_name(ATSUFontID fontID, const char* name, int nameLength) +{ + ATSUFontVariationAxis result = 0; + + Str255 inName; + inName[0] = nameLength; + int i; + for (i = 0; i < inName[0]; ++i) + inName[i + 1] = name[i]; + + ItemCount varCount; + ATSUCountFontVariations(fontID, &varCount); + if (varCount > 0) { + for (i = 0; i < varCount; ++i) { + ATSUFontVariationAxis axis; + ATSUGetIndFontVariation(fontID, i, &axis, 0, 0, 0); + FontNameCode nameCode; + ATSUGetFontVariationNameCode(fontID, axis, &nameCode); + Str255 name; + ByteCount nameLen; + ATSUFindFontName(fontID, nameCode, kFontMacintoshPlatform, kFontNoScript, kFontNoLanguage, + 255, (Ptr)&name[1], &nameLen, 0); + name[0] = nameLen; + if (EqualString(inName, name, false, true)) { + result = axis; + break; + } + } + } + + return result; +} + +ATSUFontFeatureType +find_feature_by_name(ATSUFontID fontID, const char* name, int nameLength) +{ + ATSUFontFeatureType result = 0x0000FFFF; + + Str255 inName; + inName[0] = nameLength; + int i; + for (i = 0; i < inName[0]; ++i) + inName[i + 1] = name[i]; + + ItemCount typeCount; + ATSUCountFontFeatureTypes(fontID, &typeCount); + if (typeCount > 0) { + ATSUFontFeatureType* types = (ATSUFontFeatureType*)xmalloc(typeCount * sizeof(ATSUFontFeatureType)); + ATSUGetFontFeatureTypes(fontID, typeCount, types, 0); + for (i = 0; i < typeCount; ++i) { + FontNameCode nameCode; + ATSUGetFontFeatureNameCode(fontID, types[i], 0x0000FFFF, &nameCode); + Str255 name; + ByteCount nameLen; + ATSUFindFontName(fontID, nameCode, kFontMacintoshPlatform, kFontNoScript, kFontNoLanguage, + 255, (Ptr)&name[1], &nameLen, 0); + name[0] = nameLen; + if (EqualString(inName, name, false, true)) { + result = types[i]; + break; + } + } + free((char*)types); + } + + return result; +} + +ATSUFontFeatureSelector +find_selector_by_name(ATSUFontID fontID, ATSUFontFeatureType featureType, const char* name, int nameLength) +{ + ATSUFontFeatureSelector result = 0x0000FFFF; + + Str255 inName; + inName[0] = nameLength; + int i; + for (i = 0; i < inName[0]; ++i) + inName[i + 1] = name[i]; + + ItemCount selectorCount; + ATSUCountFontFeatureSelectors(fontID, featureType, &selectorCount); + if (selectorCount > 0) { + ATSUFontFeatureSelector* selectors = (ATSUFontFeatureSelector*)xmalloc(selectorCount * sizeof(ATSUFontFeatureSelector)); + ATSUGetFontFeatureSelectors(fontID, featureType, selectorCount, selectors, 0, 0, 0); + for (i = 0; i < selectorCount; ++i) { + FontNameCode nameCode; + ATSUGetFontFeatureNameCode(fontID, featureType, selectors[i], &nameCode); + Str255 name; + ByteCount nameLen; + ATSUFindFontName(fontID, nameCode, kFontMacintoshPlatform, kFontNoScript, kFontNoLanguage, + 255, (Ptr)&name[1], &nameLen, 0); + name[0] = nameLen; + if (EqualString(inName, name, false, true)) { + result = selectors[i]; + break; + } + } + free((char*)selectors); + } + + return result; +} + +void* +loadAATfont(ATSFontRef fontRef, long scaled_size, const char* cp1) +{ + ATSUFontID fontID = FMGetFontFromATSFontRef(fontRef); + ATSUStyle style = 0; + OSStatus status = ATSUCreateStyle(&style); + 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.... + + if (strncmp(cp1, "mapping", 7) == 0) { + cp3 = cp1 + 7; + if (*cp3 != '=') + goto bad_option; + loadedfontmapping = load_mapping_file(cp3 + 1, cp2); + goto next_option; + } + + if (strncmp(cp1, "color", 5) == 0) { + cp3 = cp1 + 5; + if (*cp3 != '=') + goto bad_option; + ++cp3; + rgbValue = 0; + unsigned alpha = 0; + int i; + for (i = 0; i < 6; ++i) { + if (*cp3 >= '0' && *cp3 <= '9') + rgbValue = (rgbValue << 4) + *cp3 - '0'; + else if (*cp3 >= 'A' && *cp3 <= 'F') + rgbValue = (rgbValue << 4) + *cp3 - 'A' + 10; + else if (*cp3 >= 'a' && *cp3 <= 'f') + rgbValue = (rgbValue << 4) + *cp3 - 'a' + 10; + else + goto bad_option; + ++cp3; + } + rgbValue <<= 8; + for (i = 0; i < 2; ++i) { + if (*cp3 >= '0' && *cp3 <= '9') + alpha = (alpha << 4) + *cp3 - '0'; + else if (*cp3 >= 'A' && *cp3 <= 'F') + alpha = (alpha << 4) + *cp3 - 'A' + 10; + else if (*cp3 >= 'a' && *cp3 <= 'f') + alpha = (alpha << 4) + *cp3 - 'a' + 10; + else + break; + ++cp3; + } + if (i == 2) + rgbValue += alpha; + else + rgbValue += 0xFF; + + loadedfontflags |= FONT_FLAGS_COLORED; + + goto next_option; + } + + if (strncmp(cp1, "tracking", 8) == 0) { + cp3 = cp1 + 8; + if (*cp3 != '=') + goto bad_option; + ++cp3; + + int sign = 1; + if (*cp3 == '-') { + sign = -1; + ++cp3; + } + else if (*cp3 == '+') { + ++cp3; + } + + double val = 0.0; + while (*cp3 >= '0' && *cp3 <= '9') { + val = val * 10.0 + *cp3 - '0'; + ++cp3; + } + if (*cp3 == '.' || *cp3 == ',') { + ++cp3; + double dec = 10.0; + while (*cp3 >= '0' && *cp3 <= '9') { + val = val + (*cp3 - '0') / dec; + ++cp3; + dec = dec * 10.0; + } + } + + tracking = sign * X2Fix(val); + + goto next_option; + } + + if (strncmp(cp1, "letterspace", 11) == 0) { + cp3 = cp1 + 11; + if (*cp3 != '=') + goto bad_option; + ++cp3; + + int sign = 1; + if (*cp3 == '-') { + sign = -1; + ++cp3; + } + else if (*cp3 == '+') { + ++cp3; + } + + double val = 0.0; + while (*cp3 >= '0' && *cp3 <= '9') { + val = val * 10.0 + *cp3 - '0'; + ++cp3; + } + if (*cp3 == '.' || *cp3 == ',') { + ++cp3; + double dec = 10.0; + while (*cp3 >= '0' && *cp3 <= '9') { + val = val + (*cp3 - '0') / dec; + ++cp3; + dec = dec * 10.0; + } + } + + loadedfontletterspace = sign * (val / 100.0) * scaled_size; + + 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 == ' ' || *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); + } + + if (tracking != 0x80000000) { + tags[0] = kATSUTrackingTag; + sizes[0] = sizeof(Fixed); + attrs[0] = &tracking; + ATSUSetAttributes(style, 1, tags, sizes, attrs); + } + + free((char*)featureTypes); + free((char*)selectorValues); + free((char*)axes); + free((char*)values); + } + } + + nativefonttypeflag = AAT_FONT_FLAG; + return style; +} + +int +find_pic_file(char** path, realrect* bounds, int pdfBoxType, int page) +{ + *path = NULL; + + OSStatus result = fnfErr; + 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) { + /* get an FSRef for the URL we constructed */ + FSRef picFileRef; + CFURLGetFSRef(picFileURL, &picFileRef); + + if (pdfBoxType > 0) { + CGPDFDocumentRef document = CGPDFDocumentCreateWithURL(picFileURL); + if (document != NULL) { + int nPages = CGPDFDocumentGetNumberOfPages(document); + if (page < 0) + page = nPages + 1 + page; + if (page < 1) + page = 1; + if (page > nPages) + page = nPages; + + CGRect r; +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3 + if (&CGPDFDocumentGetPage == NULL) { + switch (pdfBoxType) { + case pdfbox_crop: + default: + r = CGPDFDocumentGetCropBox(document, page); + break; + case pdfbox_media: + r = CGPDFDocumentGetMediaBox(document, page); + break; + case pdfbox_bleed: + r = CGPDFDocumentGetBleedBox(document, page); + break; + case pdfbox_trim: + r = CGPDFDocumentGetTrimBox(document, page); + break; + case pdfbox_art: + r = CGPDFDocumentGetArtBox(document, page); + break; + } + } + else +#endif + { + CGPDFPageRef pageRef = CGPDFDocumentGetPage(document, page); + CGPDFBox boxType; + 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; + bounds->y = r.origin.y; + bounds->wd = r.size.width; + bounds->ht = r.size.height; + CGPDFDocumentRelease(document); + result = noErr; + } + } + else { + /* make an FSSpec for the file, and try to import it as a pic */ + FSSpec picFileSpec; + result = FSGetCatalogInfo(&picFileRef, kFSCatInfoNone, NULL, NULL, &picFileSpec, NULL); + if (result == noErr) { + ComponentInstance ci; + result = GetGraphicsImporterForFile(&picFileSpec, &ci); + if (result == noErr) { + ImageDescriptionHandle desc = NULL; + result = GraphicsImportGetImageDescription(ci, &desc); + bounds->x = 0; + bounds->y = 0; + bounds->wd = (*desc)->width * 72.0 / Fix2X((*desc)->hRes); + bounds->ht = (*desc)->height * 72.0 / Fix2X((*desc)->vRes); + DisposeHandle((Handle)desc); + (void)CloseComponent(ci); + } + } + } + + 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; +} |