Alternatively,thecontentsofthisfilemaybeusedunderthetermsofthe MozillaPublicLicense(http://mozilla.org/MPL) or the GNU General Public License,aspublishedbytheFreeSoftwareFoundation,eitherversion2 oftheLicenseor(atyouroption)anylaterversion.
*/ /*--------------------------------------------------------------------*//*:Ignore this sentence.
File: TtfUtil.cpp
Responsibility: Alan Ward
Last reviewed: Not yet.
Description
Implements the methods for TtfUtil class. This file should remain portable to any C++
environment by only using standard C++ and the TTF structurs defined in Tt.h.
-------------------------------------------------------------------------------*//*:End Ignore*/
/* Note on error processing: The code guards against bad glyph ids being used to look up data inopenendedtables(loca,hmtx).Iftheglyphidcomesfromacmapthisshouldn'thappen butitseemsprudenttocheckforusererrorshere.Thecodedoesassumethatdataobtained fromtheTTFfileisvalidotherwise(thoughtheCheckTablemethodseekstocheckfor obviousproblemsthatmightaccompanyachangeintableversions).Forexampleaninvalid offsetinthelocatablewhichcouldexceedthesizeoftheglyftableisNOTtrapped. LikewiseifnumberOf_LongHorMetricsinthehheatableiswrong,thiswillNOTbetrapped, whichcouldcausealookupinthehmtxtabletoexceedthetablelength.Ofcourse,TTFtables
that are completely corrupt will cause unpredictable results. */
/* Note on composite glyphs: Glyphs that have components that are themselves composites arenotsupported.IsDeepCompositecanbeusedtotestforthis.Falseisreturnedfrommany ofthemethodsinthiscases.Itisunclearhowtobuildcompositeglyphsinsomecases, sothiscoderepresentsmybestguessuntiltestcasescanbefound.Seenotesonthehigh-
level GlyfPoints method. */ namespace graphite2
{ namespace TtfUtil
{
case Tag::post: // post
{ const Sfnt::PostScriptGlyphName * const pPost
= reinterpret_cast<const Sfnt::PostScriptGlyphName *>(pTable); if (lTableSize < sizeof(Sfnt::PostScriptGlyphName)) returnfalse; const fixed format = be::swap(pPost->format); bool r = format == PostScriptGlyphName::Format1
|| format == PostScriptGlyphName::Format2
|| format == PostScriptGlyphName::Format3
|| format == PostScriptGlyphName::Format25; return r;
}
if (be::swap(pTable->index_to_loc_format)
== Sfnt::FontHeader::ShortIndexLocFormat) // loca entries are two bytes and have been divided by two return (lLocaSize >> 1) - 1;
if (be::swap(pTable->index_to_loc_format)
== Sfnt::FontHeader::LongIndexLocFormat) // loca entries are four bytes return (lLocaSize >> 2) - 1;
return -1; //throw std::domain_error("head table in inconsistent state. The font may be corrupted");
} #endif
if (format == PostScriptGlyphName::Format3)
{ // format 3 - no Postscript glyph info in font return -2;
}
// search for given Postscript name among the standard names int iPostName = -1; // index in standard names for (int i = 0; i < kcPostNames; i++)
{ if (!strcmp(pPostName, rgPostName[i]))
{
iPostName = i; break;
}
}
if (format == PostScriptGlyphName::Format1)
{ // format 1 - use standard Postscript names return iPostName;
}
if (format == PostScriptGlyphName::Format25)
{ if (iPostName == -1) return -1;
const PostScriptGlyphName25 * pTable25
= static_cast<const PostScriptGlyphName25 *>(pTable); int cnGlyphs = GlyphCount(pMaxp); for (gid16 nGlyphId = 0; nGlyphId < cnGlyphs && nGlyphId < kcPostNames;
nGlyphId++)
{ // glyph_name_index25 contains bytes so no byte swapping needed // search for first glyph id that uses the standard name if (nGlyphId + pTable25->offset[nGlyphId] == iPostName) return nGlyphId;
}
}
if (format == PostScriptGlyphName::Format2)
{ // format 2 const PostScriptGlyphName2 * pTable2
= static_cast<const PostScriptGlyphName2 *>(pTable);
int cnGlyphs = be::swap(pTable2->number_of_glyphs);
if (iPostName != -1)
{ // did match a standard name, look for first glyph id mapped to that name for (gid16 nGlyphId = 0; nGlyphId < cnGlyphs; nGlyphId++)
{ if (be::swap(pTable2->glyph_name_index[nGlyphId]) == iPostName) return nGlyphId;
}
}
{ // did not match a standard name, search font specific names
size_t nStrSizeGoal = strlen(pPostName); constchar * pFirstGlyphName = reinterpret_cast<constchar *>(
&pTable2->glyph_name_index[0] + cnGlyphs); constchar * pGlyphName = pFirstGlyphName; int iInNames = 0; // index in font specific names bool fFound = false; constchar * const endOfTable
= reinterpret_cast<constchar *>(pTable2) + lPostSize; while (pGlyphName < endOfTable && !fFound)
{ // search Pascal strings for first matching name
size_t nStringSize = size_t(*pGlyphName); if (nStrSizeGoal != nStringSize ||
strncmp(pGlyphName + 1, pPostName, nStringSize))
{ // did not match
++iInNames;
pGlyphName += nStringSize + 1;
} else
{ // did match
fFound = true;
}
} if (!fFound) return -1; // no font specific name matches request
iInNames += kcPostNames; for (gid16 nGlyphId = 0; nGlyphId < cnGlyphs; nGlyphId++)
{ // search for first glyph id that maps to the found string index if (be::swap(pTable2->glyph_name_index[nGlyphId]) == iInNames) return nGlyphId;
} return -1; // no glyph mapped to this index (very strange)
}
}
if (rangeKey)
{
pMid = &(pTable->end_code[rangeKey]);
chEnd = be::peek<uint16>(pMid);
} else
{ // Binary search of the endCode[] array
pLeft = &(pTable->end_code[0]);
n = nSeg; while (n > 0)
{
cMid = n >> 1; // Pick an element in the middle
pMid = pLeft + cMid;
chEnd = be::peek<uint16>(pMid); if (nUnicodeId <= chEnd)
{ if (cMid == 0 || nUnicodeId > be::peek<uint16>(pMid -1)) break; // Must be this seg or none!
n = cMid; // Continue on left side, omitting mid point
} else
{
pLeft = pMid + 1; // Continue on right side, omitting mid point
n -= (cMid + 1);
}
}
if (!n) return0;
}
// Ok, we're down to one segment and pMid points to the endCode element // Either this is it or none is.
const uint16 * pStartCode = &(pTable->end_code[0])
+ nRange // length of end code array
+ 1; // reserved word
if (nUnicodePrev == 0)
{ // return the first codepoint. if (pRangeKey)
*pRangeKey = 0; return be::peek<uint16>(pStartCode);
} elseif (nUnicodePrev >= 0xFFFF)
{ if (pRangeKey)
*pRangeKey = nRange - 1; return0xFFFF;
}
int iRange = (pRangeKey) ? *pRangeKey : 0; // Just in case we have a bad key: while (iRange > 0 && be::peek<uint16>(pStartCode + iRange) > nUnicodePrev)
iRange--; while (iRange < nRange - 1 && be::peek<uint16>(pTable->end_code + iRange) < nUnicodePrev)
iRange++;
// Now iRange is the range containing nUnicodePrev. unsignedint nStartCode = be::peek<uint16>(pStartCode + iRange); unsignedint nEndCode = be::peek<uint16>(pTable->end_code + iRange);
if (nStartCode > nUnicodePrev) // Oops, nUnicodePrev is not in the cmap! Adjust so we get a reasonable // answer this time around.
nUnicodePrev = nStartCode - 1;
if (nEndCode > nUnicodePrev)
{ // Next is in the same range; it is the next successive codepoint. if (pRangeKey)
*pRangeKey = iRange; return nUnicodePrev + 1;
}
// Otherwise the next codepoint is the first one in the next range. // There is guaranteed to be a next range because there must be one that // ends with 0xFFFF. if (pRangeKey)
*pRangeKey = iRange + 1; return (iRange + 1 >= nRange) ? 0xFFFF : be::peek<uint16>(pStartCode + iRange + 1);
}
/*---------------------------------------------------------------------------------------------- ChecktheMicrosoftUCS-4subtableforexpectedvalues.
----------------------------------------------------------------------------------------------*/ bool CheckCmapSubtable12(constvoid *pCmapSubtable12, constvoid *pCmapEnd /*, unsigned int maxgid*/)
{
size_t table_len = (const byte *)pCmapEnd - (const byte *)pCmapSubtable12; if (!pCmapSubtable12) returnfalse; const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable12); if (table_len < sizeof(*pTable) || be::swap(pTable->format) != 12) returnfalse; const Sfnt::CmapSubTableFormat12 * pTable12 = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmapSubtable12); if (table_len < sizeof(*pTable12)) returnfalse;
uint32 length = be::swap(pTable12->length); if (length > table_len) returnfalse; if (length < sizeof(Sfnt::CmapSubTableFormat12)) returnfalse;
uint32 num_groups = be::swap(pTable12->num_groups); if (num_groups > 0x10000000 || length != (sizeof(Sfnt::CmapSubTableFormat12) + (num_groups - 1) * sizeof(uint32) * 3)) returnfalse; #if0 for (unsignedint i = 0; i < num_groups; ++i)
{ if (be::swap(pTable12->group[i].end_char_code) - be::swap(pTable12->group[i].start_char_code) + be::swap(pTable12->group[i].start_glyph_id) > maxgid) returnfalse; if (i > 0 && be::swap(pTable12->group[i].start_char_code) <= be::swap(pTable12->group[i-1].end_char_code)) returnfalse;
} #endif returntrue;
}
if (nUnicodePrev == 0)
{ // return the first codepoint. if (pRangeKey)
*pRangeKey = 0; return be::swap(pTable->group[0].start_char_code);
} elseif (nUnicodePrev >= 0x10FFFF)
{ if (pRangeKey)
*pRangeKey = nRange; return0x10FFFF;
}
int iRange = (pRangeKey) ? *pRangeKey : 0; // Just in case we have a bad key: while (iRange > 0 && be::swap(pTable->group[iRange].start_char_code) > nUnicodePrev)
iRange--; while (iRange < nRange - 1 && be::swap(pTable->group[iRange].end_char_code) < nUnicodePrev)
iRange++;
// Now iRange is the range containing nUnicodePrev.
if (nStartCode > nUnicodePrev) // Oops, nUnicodePrev is not in the cmap! Adjust so we get a reasonable // answer this time around.
nUnicodePrev = nStartCode - 1;
if (nEndCode > nUnicodePrev)
{ // Next is in the same range; it is the next successive codepoint. if (pRangeKey)
*pRangeKey = iRange; return nUnicodePrev + 1;
}
// Otherwise the next codepoint is the first one in the next range, or 10FFFF if we're done. if (pRangeKey)
*pRangeKey = iRange + 1; return (iRange + 1 >= nRange) ? 0x10FFFF : be::swap(pTable->group[iRange + 1].start_char_code);
}
/*---------------------------------------------------------------------------------------------- Getthepointnumbersfortheendpointsoftheglyphcontoursforasimple glyfentry(non-composite). cnPointsTotal-countofcontoursfromGlyfContourCount();(sameasnumberofendpoints) prgnContourEndPoints-shouldpointtoabufferlargeenoughtoholdcnPointsintegers cnPoints-countofpointsplacedinaboverange Returntrueifsuccessful,falseotherwise. Falsecouldindicateamulti-levelcompositeglyphs.
----------------------------------------------------------------------------------------------*/ bool GlyfContourEndPoints(constvoid * pSimpleGlyf, int * prgnContourEndPoint, int cnPointsTotal, int & cnPoints)
{ const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf);
int cContours = be::swap(pGlyph->number_of_contours); if (cContours < 0) returnfalse; // this method isn't supposed handle composite glyphs
for (int i = 0; i < cContours && i < cnPointsTotal; i++)
{
prgnContourEndPoint[i] = be::swap(pGlyph->end_pts_of_contours[i]);
}
cnPoints = cContours; returntrue;
}
/*---------------------------------------------------------------------------------------------- Getthepointsforasimpleglyfentry(non-composite) cnPointsTotal-countofpointsfromlargestendpointobtainedfromGlyfContourEndPoints prgnX&prgnY-shouldpointtobufferslargeenoughtoholdcnPointsTotalintegers Therangesareparallelsothatcoordinatesforpoint(n)arefoundatoffsetninboth ranges.Thisisrawpointdatawithrelativecoordinates. prgbFlag-shouldpointtoabufferalargeenoughtoholdcnPointsTotalbytes ThisrangeisparalleltotheprgnX&prgnY cnPoints-countofpointsplacedinaboveranges Returntrueifsuccessful,falseotherwise. Falsecouldindicateacompositeglyph
----------------------------------------------------------------------------------------------*/ bool GlyfPoints(constvoid * pSimpleGlyf, int * prgnX, int * prgnY, char * prgbFlag, int cnPointsTotal, int & cnPoints)
{ usingnamespace Sfnt;
const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf); int cContours = be::swap(pGlyph->number_of_contours); // return false for composite glyph if (cContours <= 0) returnfalse; int cPts = be::swap(pGlyph->end_pts_of_contours[cContours - 1]) + 1; if (cPts > cnPointsTotal) returnfalse;
// skip over bounding box data & point to byte count of instructions (hints) const uint8 * pbGlyph = reinterpret_cast<const uint8 *>
(&pGlyph->end_pts_of_contours[cContours]);
// skip over hints & point to first flag int cbHints = be::swap(*(uint16 *)pbGlyph);
pbGlyph += sizeof(uint16);
pbGlyph += cbHints;
// load flags & point to first x coordinate int iFlag = 0; while (iFlag < cPts)
{ if (!(*pbGlyph & SimpleGlyph::Repeat))
{ // flag isn't repeated
prgbFlag[iFlag] = (char)*pbGlyph;
pbGlyph++;
iFlag++;
} else
{ // flag is repeated; count specified by next byte char chFlag = (char)*pbGlyph;
pbGlyph++; int cFlags = (int)*pbGlyph;
pbGlyph++;
prgbFlag[iFlag] = chFlag;
iFlag++; for (int i = 0; i < cFlags; i++)
{
prgbFlag[iFlag + i] = chFlag;
}
iFlag += cFlags;
}
} if (iFlag != cPts) returnfalse;
// load x coordinates
iFlag = 0; while (iFlag < cPts)
{ if (prgbFlag[iFlag] & SimpleGlyph::XShort)
{
prgnX[iFlag] = *pbGlyph; if (!(prgbFlag[iFlag] & SimpleGlyph::XIsPos))
{
prgnX[iFlag] = -prgnX[iFlag];
}
pbGlyph++;
} else
{ if (prgbFlag[iFlag] & SimpleGlyph::XIsSame)
{
prgnX[iFlag] = 0; // do NOT increment pbGlyph
} else
{
prgnX[iFlag] = be::swap(*(int16 *)pbGlyph);
pbGlyph += sizeof(int16);
}
}
iFlag++;
}
// load y coordinates
iFlag = 0; while (iFlag < cPts)
{ if (prgbFlag[iFlag] & SimpleGlyph::YShort)
{
prgnY[iFlag] = *pbGlyph; if (!(prgbFlag[iFlag] & SimpleGlyph::YIsPos))
{
prgnY[iFlag] = -prgnY[iFlag];
}
pbGlyph++;
} else
{ if (prgbFlag[iFlag] & SimpleGlyph::YIsSame)
{
prgnY[iFlag] = 0; // do NOT increment pbGlyph
} else
{
prgnY[iFlag] = be::swap(*(int16 *)pbGlyph);
pbGlyph += sizeof(int16);
}
}
iFlag++;
}
if (GlyfContourCount(pSimpleGlyf) >= 0) returnfalse;
const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf); // for a composite glyph, the special data begins here const uint8 * pbGlyph = reinterpret_cast<const uint8 *>(&pGlyph->end_pts_of_contours[0]);
/*---------------------------------------------------------------------------------------------- Returninfoonhowacomponentglyphistobeplaced pSimpleGlyph-assumedtopointtoacompositeglyph nCompId-glyphidforcomponentofinterest bOffset-iftrue,a&barethex&yoffsetsforthiscomponent iffalse,bisthepointonthiscomponentthatisattachingtopointaonthe precedingglyph Returntrueifsuccessful,falseotherwise Falsecouldindicateanon-compositeglyphorthatcomponentwasn'tfound
----------------------------------------------------------------------------------------------*/ bool GetComponentPlacement(constvoid * pSimpleGlyf, int nCompId, bool fOffset, int & a, int & b)
{ usingnamespace Sfnt;
if (GlyfContourCount(pSimpleGlyf) >= 0) returnfalse;
const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf); // for a composite glyph, the special data begins here const uint8 * pbGlyph = reinterpret_cast<const uint8 *>(&pGlyph->end_pts_of_contours[0]);
uint16 GlyphFlags; do
{
GlyphFlags = be::swap(*((uint16 *)pbGlyph));
pbGlyph += sizeof(uint16); if (be::swap(*((uint16 *)pbGlyph)) == nCompId)
{
pbGlyph += sizeof(uint16); // skip over glyph id of component
fOffset = (GlyphFlags & CompoundGlyph::ArgsAreXYValues) == CompoundGlyph::ArgsAreXYValues;
if (GlyphFlags & CompoundGlyph::Arg1Arg2Words )
{
a = be::swap(*(int16 *)pbGlyph);
pbGlyph += sizeof(int16);
b = be::swap(*(int16 *)pbGlyph);
pbGlyph += sizeof(int16);
} else
{ // args are signed bytes
a = *pbGlyph++;
b = *pbGlyph++;
} returntrue;
}
pbGlyph += sizeof(uint16); // skip over glyph id of component int nOffset = 0;
nOffset += GlyphFlags & CompoundGlyph::Arg1Arg2Words ? 4 : 2;
nOffset += GlyphFlags & CompoundGlyph::HaveScale ? 2 : 0;
nOffset += GlyphFlags & CompoundGlyph::HaveXAndYScale ? 4 : 0;
nOffset += GlyphFlags & CompoundGlyph::HaveTwoByTwo ? 8 : 0;
pbGlyph += nOffset;
} while (GlyphFlags & CompoundGlyph::MoreComponents);
// didn't find requested component
fOffset = true;
a = 0;
b = 0; returnfalse;
}
if (GlyfContourCount(pSimpleGlyf) >= 0) returnfalse;
const Sfnt::SimpleGlyph * pGlyph = reinterpret_cast<const Sfnt::SimpleGlyph *>(pSimpleGlyf); // for a composite glyph, the special data begins here const uint8 * pbGlyph = reinterpret_cast<const uint8 *>(&pGlyph->end_pts_of_contours[0]);
uint16 GlyphFlags; do
{
GlyphFlags = be::swap(*((uint16 *)pbGlyph));
pbGlyph += sizeof(uint16); if (be::swap(*((uint16 *)pbGlyph)) == nCompId)
{
pbGlyph += sizeof(uint16); // skip over glyph id of component
pbGlyph += GlyphFlags & CompoundGlyph::Arg1Arg2Words ? 4 : 2; // skip over placement data
if (fTransOffset) // MS rasterizer
fTransOffset = !(GlyphFlags & CompoundGlyph::UnscaledOffset); else// Apple rasterizer
fTransOffset = (GlyphFlags & CompoundGlyph::ScaledOffset) != 0;
if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::ShortIndexLocFormat)
{ // loca entries are two bytes (and have been divided by two) if (nGlyphId >= (lLocaSize >> 1) - 1) // don't allow nGlyphId to access sentinel
{ // throw std::out_of_range("glyph id out of range for font"); return NULL;
}
} if (be::swap(pTable->index_to_loc_format) == Sfnt::FontHeader::LongIndexLocFormat)
{ // loca entries are four bytes if (nGlyphId >= (lLocaSize >> 2) - 1)
{ // throw std::out_of_range("glyph id out of range for font"); return NULL;
}
}
// the +1 should always work because there is a sentinel value at the end of the loca table
size_t lNextGlyfOffset = LocaLookup(nGlyphId + 1, pLoca, lLocaSize, pHead);
void * pSimpleGlyf = GlyfLookup(nGlyphId, pGlyf, pLoca, lGlyfSize, lLocaSize, pHead); if (pSimpleGlyf == NULL) returnfalse; // no way to really indicate an error occured here
if (GlyfContourCount(pSimpleGlyf) >= 0) returnfalse;
int rgnCompId[kMaxGlyphComponents]; // assumes only a limited number of glyph components
size_t cCompIdTotal = kMaxGlyphComponents;
size_t cCompId = 0;
if (!GetComponentGlyphIds(pSimpleGlyf, rgnCompId, cCompIdTotal, cCompId)) returnfalse;
for (size_t i = 0; i < cCompId; i++)
{
pSimpleGlyf = GlyfLookup(static_cast<gid16>(rgnCompId[i]),
pGlyf, pLoca, lGlyfSize, lLocaSize, pHead); if (pSimpleGlyf == NULL) {returnfalse;}
if (GlyfContourCount(pSimpleGlyf) < 0) returntrue;
}
int cRtnContours = GlyfContourCount(pSimpleGlyf); if (cRtnContours >= 0)
{
cnContours = size_t(cRtnContours); returntrue;
}
//handle composite glyphs
int rgnCompId[kMaxGlyphComponents]; // assumes no glyph will be made of more than 8 components
size_t cCompIdTotal = kMaxGlyphComponents;
size_t cCompId = 0;
if (!GetComponentGlyphIds(pSimpleGlyf, rgnCompId, cCompIdTotal, cCompId)) returnfalse;
cRtnContours = 0; int cTmp = 0; for (size_t i = 0; i < cCompId; i++)
{ if (IsSpace(static_cast<gid16>(rgnCompId[i]), pLoca, lLocaSize, pHead)) {returnfalse;}
pSimpleGlyf = GlyfLookup(static_cast<gid16>(rgnCompId[i]),
pGlyf, pLoca, lGlyfSize, lLocaSize, pHead); if (pSimpleGlyf == 0) {returnfalse;} // return false on multi-level composite if ((cTmp = GlyfContourCount(pSimpleGlyf)) < 0) returnfalse;
cRtnContours += cTmp;
}
int cContours = GlyfContourCount(pSimpleGlyf); int cActualPts = 0; if (cContours > 0) return GlyfContourEndPoints(pSimpleGlyf, prgnContourEndPoint, cnPoints, cActualPts);
// handle composite glyphs
int rgnCompId[kMaxGlyphComponents]; // assumes no glyph will be made of more than 8 components
size_t cCompIdTotal = kMaxGlyphComponents;
size_t cCompId = 0;
if (!GetComponentGlyphIds(pSimpleGlyf, rgnCompId, cCompIdTotal, cCompId)) returnfalse;
int * prgnCurrentEndPoint = prgnContourEndPoint; int cCurrentPoints = cnPoints; int nPrevPt = 0; for (size_t i = 0; i < cCompId; i++)
{ if (IsSpace(static_cast<gid16>(rgnCompId[i]), pLoca, lLocaSize, pHead)) {returnfalse;}
pSimpleGlyf = GlyfLookup(static_cast<gid16>(rgnCompId[i]), pGlyf, pLoca, lGlyfSize, lLocaSize, pHead); if (pSimpleGlyf == NULL) {returnfalse;} // returns false on multi-level composite if (!GlyfContourEndPoints(pSimpleGlyf, prgnCurrentEndPoint, cCurrentPoints, cActualPts)) returnfalse; // points in composite are numbered sequentially as components are added // must adjust end point numbers for new point numbers for (int j = 0; j < cActualPts; j++)
prgnCurrentEndPoint[j] += nPrevPt;
nPrevPt = prgnCurrentEndPoint[cActualPts - 1] + 1;
int cContours = GlyfContourCount(pSimpleGlyf); int cActualPts; if (cContours > 0)
{ if (!GlyfPoints(pSimpleGlyf, prgnX, prgnY, (char *)prgfOnCurve, cnPoints, cActualPts)) returnfalse;
CalcAbsolutePoints(prgnX, prgnY, cnPoints);
SimplifyFlags((char *)prgfOnCurve, cnPoints); returntrue;
}
// handle composite glyphs int rgnCompId[kMaxGlyphComponents]; // assumes no glyph will be made of more than 8 components
size_t cCompIdTotal = kMaxGlyphComponents;
size_t cCompId = 0;
// this will fail if there are more components than there is room for if (!GetComponentGlyphIds(pSimpleGlyf, rgnCompId, cCompIdTotal, cCompId)) returnfalse;
int * prgnCurrentX = prgnX; int * prgnCurrentY = prgnY; char * prgbCurrentFlag = (char *)prgfOnCurve; // converting bool to char should be safe int cCurrentPoints = cnPoints; bool fOffset = true, fTransOff = true; int a, b; float flt11, flt12, flt21, flt22; // int * prgnPrevX = prgnX; // in case first att pt number relative to preceding glyph // int * prgnPrevY = prgnY; for (size_t i = 0; i < cCompId; i++)
{ if (IsSpace(static_cast<gid16>(rgnCompId[i]), pLoca, lLocaSize, pHead)) {returnfalse;} void * pCompGlyf = GlyfLookup(static_cast<gid16>(rgnCompId[i]), pGlyf, pLoca, lGlyfSize, lLocaSize, pHead); if (pCompGlyf == NULL) {returnfalse;} // returns false on multi-level composite if (!GlyfPoints(pCompGlyf, prgnCurrentX, prgnCurrentY, prgbCurrentFlag,
cCurrentPoints, cActualPts)) returnfalse; if (!GetComponentPlacement(pSimpleGlyf, rgnCompId[i], fOffset, a, b)) returnfalse; if (!GetComponentTransform(pSimpleGlyf, rgnCompId[i],
flt11, flt12, flt21, flt22, fTransOff)) returnfalse; bool fIdTrans = flt11 == 1.0 && flt12 == 0.0 && flt21 == 0.0 && flt22 == 1.0;
// convert points to absolute coordinates // do before transform and attachment point placement are applied
CalcAbsolutePoints(prgnCurrentX, prgnCurrentY, cActualPts);
// apply transform - see main method note above // do before attachment point calcs if (!fIdTrans) for (int j = 0; j < cActualPts; j++)
{ int x = prgnCurrentX[j]; // store before transform applied int y = prgnCurrentY[j];
prgnCurrentX[j] = (int)(x * flt11 + y * flt12);
prgnCurrentY[j] = (int)(x * flt21 + y * flt22);
}
// apply placement - see main method note above int nXOff, nYOff; if (fOffset) // explicit x & y offsets
{ /* ignore fTransOff for now if(fTransOff&&!fIdTrans) {// transform x & y offsets nXOff=(int)(a*flt11+b*flt12); nYOff=(int)(a*flt21+b*flt22); }
else */
{ // don't transform offset
nXOff = a;
nYOff = b;
}
} else// attachment points
{ // in case first point is relative to preceding glyph and second relative to current // nXOff = prgnPrevX[a] - prgnCurrentX[b]; // nYOff = prgnPrevY[a] - prgnCurrentY[b]; // first point number relative to whole composite, second relative to current glyph
nXOff = prgnX[a] - prgnCurrentX[b];
nYOff = prgnY[a] - prgnCurrentY[b];
} for (int j = 0; j < cActualPts; j++)
{
prgnCurrentX[j] += nXOff;
prgnCurrentY[j] += nYOff;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.