summaryrefslogtreecommitdiff
path: root/Build/source/texk/ttfdump/libttf
diff options
context:
space:
mode:
authorPeter Breitenlohner <peb@mppmu.mpg.de>2011-12-06 14:44:14 +0000
committerPeter Breitenlohner <peb@mppmu.mpg.de>2011-12-06 14:44:14 +0000
commitd4098ae6af4055044c234a33fc9f42b2e4638999 (patch)
tree9992cf0688c0850c3462a2d3ab989d73917a7b26 /Build/source/texk/ttfdump/libttf
parent6bffa98d5416f8675df7ee8cda6fc40f34be9206 (diff)
ttfdump: Complete the handling of GPOS tables
git-svn-id: svn://tug.org/texlive/trunk@24779 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/ttfdump/libttf')
-rw-r--r--Build/source/texk/ttfdump/libttf/gpos.c78
-rw-r--r--Build/source/texk/ttfdump/libttf/otfcommon.c90
2 files changed, 103 insertions, 65 deletions
diff --git a/Build/source/texk/ttfdump/libttf/gpos.c b/Build/source/texk/ttfdump/libttf/gpos.c
index 9d040298099..5ece428e110 100644
--- a/Build/source/texk/ttfdump/libttf/gpos.c
+++ b/Build/source/texk/ttfdump/libttf/gpos.c
@@ -17,7 +17,7 @@ static USHORT getValueFormat (FILE *fp)
}
static ValueRecordPtr
-gposMakeValueRecord (USHORT valueFormat, FILE *fp, ULONG offset)
+gposMakeValueRecord (USHORT valueFormat, FILE *fp)
{
int i;
ValueRecordPtr value;
@@ -31,11 +31,23 @@ gposMakeValueRecord (USHORT valueFormat, FILE *fp, ULONG offset)
value->valDesign[i] = ttfGetSHORT (fp);
for (i = 0; i < 4; i++)
if (valueFormat & (ValueFormat_XPlaDevice << i))
- ttfGetUSHORT (fp);
+ value->valDevice[i].offset = ttfGetUSHORT (fp);
return value;
}
+static void
+gposLoadValueRecord (ValueRecordPtr value, FILE *fp, ULONG offset)
+{
+ int i;
+
+ if (value == NULL)
+ return;
+ for (i = 0; i < 4; i++)
+ if (value->valDevice[i].offset)
+ value->valDevice[i].device = otfMakeDevice (fp, offset + value->valDevice[i].offset);
+}
+
static const char *txtDesign[4] = {
"XPlacement",
"YPlacement",
@@ -43,6 +55,13 @@ static const char *txtDesign[4] = {
"YAdvance"
};
+static const char *txtDevice[4] = {
+ "XPlaDevice",
+ "YPlaDevice",
+ "XAdvDevice",
+ "YAdvDevice"
+};
+
static void
gposPrintValueRecord (FILE *fp, const char *str, USHORT valueFormat, ValueRecordPtr value)
{
@@ -54,8 +73,12 @@ gposPrintValueRecord (FILE *fp, const char *str, USHORT valueFormat, ValueRecord
fprintf (fp, "%s %s = %d\n", s, txtDesign[i], value->valDesign[i]);
s = str;
}
- if (valueFormat & ValueFormat_AllDevice)
- fprintf (fp, "\t\t *** Device Table NOT YET IMPLEMENTED ***\n");
+ for (i = 0; i < 4; i++)
+ if (value->valDevice[i].device) {
+ fprintf (fp, "%s %s:", s, txtDevice[i]);
+ otfPrintDevice (fp, value->valDevice[i].device);
+ s = str;
+ }
}
static void freeValueRecord (ValueRecordPtr value)
@@ -64,8 +87,8 @@ static void freeValueRecord (ValueRecordPtr value)
int i;
for (i = 0; i < 4; i++)
- if (value->valDevice[i])
- free (value->valDevice[i]);
+ if (value->valDevice[i].device)
+ free (value->valDevice[i].device);
free (value);
}
}
@@ -214,8 +237,9 @@ static Pos11Ptr makeGPOS11 (FILE *fp, ULONG offset)
cOffset = ttfGetUSHORT (fp);
pos->valueFormat = getValueFormat (fp);
- pos->value = gposMakeValueRecord (pos->valueFormat, fp, offset);
+ pos->value = gposMakeValueRecord (pos->valueFormat, fp);
pos->coverage = otfMakeCoverage (fp, offset + cOffset);
+ gposLoadValueRecord (pos->value, fp, offset);
return pos;
}
@@ -248,8 +272,10 @@ static Pos12Ptr makeGPOS12 (FILE *fp, ULONG offset)
pos->valueCount = ttfGetUSHORT (fp);
pos->value = XCALLOC (pos->valueCount, ValueRecordPtr);
for (i = 0; i < pos->valueCount; i++)
- pos->value[i] = gposMakeValueRecord (pos->valueFormat, fp, offset);
+ pos->value[i] = gposMakeValueRecord (pos->valueFormat, fp);
pos->coverage = otfMakeCoverage (fp, offset + cOffset);
+ for (i = 0; i < pos->valueCount; i++)
+ gposLoadValueRecord (pos->value[i], fp, offset);
return pos;
}
@@ -277,19 +303,19 @@ static void freeGPOS12 (Pos12Ptr pos)
otfFreeCoverage (pos->coverage);
}
-static void gposLoadPairSet (Pos21Ptr pos, int i, FILE *fp, ULONG offset, USHORT poff)
+static void gposLoadPairSet (Pos21Ptr pos, int i, FILE *fp, ULONG offset)
{
int j;
PairSetPtr pairSet = &pos->pairSet[i];
- xfseek (fp, offset + poff, SEEK_SET, "gposLoadPairSet");
+ xfseek (fp, offset, SEEK_SET, "gposLoadPairSet");
pairSet->pairValueCount = ttfGetUSHORT (fp);
pairSet->pairValue = XCALLOC (pairSet->pairValueCount, PairValueRecord);
for (j = 0; j < pairSet->pairValueCount; j++) {
pairSet->pairValue[j].secondGlyph = ttfGetUSHORT (fp);
- pairSet->pairValue[j].value1 = gposMakeValueRecord (pos->valueFormat1, fp, offset);
- pairSet->pairValue[j].value2 = gposMakeValueRecord (pos->valueFormat2, fp, offset);
+ pairSet->pairValue[j].value1 = gposMakeValueRecord (pos->valueFormat1, fp);
+ pairSet->pairValue[j].value2 = gposMakeValueRecord (pos->valueFormat2, fp);
}
}
@@ -308,8 +334,16 @@ static Pos21Ptr makeGPOS21 (FILE *fp, ULONG offset)
pos->coverage = otfMakeCoverage (fp, offset + cOffset);
pos->pairSet = XCALLOC (pos->pairSetCount, PairSet);
for (i = 0; i < pos->pairSetCount; i++)
- gposLoadPairSet (pos, i, fp, offset, pOffset[i]);
+ gposLoadPairSet (pos, i, fp, offset + pOffset[i]);
free (pOffset);
+ for (i = 0; i < pos->pairSetCount; i++) {
+ int j;
+
+ for (j = 0; j < pos->pairSet[i].pairValueCount; j++) {
+ gposLoadValueRecord (pos->pairSet[i].pairValue[j].value1, fp, offset);
+ gposLoadValueRecord (pos->pairSet[i].pairValue[j].value2, fp, offset);
+ }
+ }
return pos;
}
@@ -324,6 +358,7 @@ static void printGPOS21 (FILE *fp, Pos21Ptr pos)
pos->valueFormat1, pos->valueFormat2, pos->pairSetCount);
for (i = 0; i < pos->pairSetCount; i++) {
int j;
+
fprintf (fp, "\t %2d. pairValueCount: %d\n", i, pos->pairSet[i].pairValueCount);
for (j = 0; j < pos->pairSet[i].pairValueCount; j++) {
fprintf (fp, "\t %2d. secondGlyph: %d\n", j,
@@ -360,7 +395,7 @@ static void freeGPOS21 (Pos21Ptr pos)
static Pos22Ptr makeGPOS22 (FILE *fp, ULONG offset)
{
- int num = 0, i;
+ int i;
USHORT cOffset, cOffset1, cOffset2;
Pos22Ptr pos = XCALLOC1 (Pos22);
@@ -372,24 +407,20 @@ static Pos22Ptr makeGPOS22 (FILE *fp, ULONG offset)
pos->class1Count = ttfGetUSHORT (fp);
pos->class2Count = ttfGetUSHORT (fp);
pos->values = XCALLOC (2 * pos->class1Count * pos->class2Count, ValueRecordPtr);
- for (i = 0; i < pos->class1Count; i++) {
- int j;
-
- for (j = 0; j < pos->class2Count; j++) {
- pos->values[num++] = gposMakeValueRecord (pos->valueFormat1, fp, offset);
- pos->values[num++] = gposMakeValueRecord (pos->valueFormat2, fp, offset);
- }
- }
+ for (i = 0; i < 2 * pos->class1Count * pos->class2Count; i++)
+ pos->values[i] = gposMakeValueRecord (i & 1 ? pos->valueFormat2 : pos->valueFormat1, fp);
pos->coverage = otfMakeCoverage (fp, offset + cOffset);
pos->classDef1 = otfMakeClassDef (fp, offset + cOffset1);
pos->classDef2 = otfMakeClassDef (fp, offset + cOffset2);
+ for (i = 0; i < 2 * pos->class1Count * pos->class2Count; i++)
+ gposLoadValueRecord (pos->values[i], fp, offset);
return pos;
}
static void printGPOS22 (FILE *fp, Pos22Ptr pos)
{
- int num = 0, i;
+ int i, num = 0;
fprintf (fp, " - Pair Adjustment Class\n\t ");
otfPrintCoverage (fp, pos->coverage);
@@ -461,6 +492,7 @@ static Pos31Ptr makeGPOS31 (FILE *fp, ULONG offset)
static void printGPOS31 (FILE *fp, Pos31Ptr pos)
{
int i, num = 0;
+
fprintf (fp, " - Cursive Attachment\n\t ");
otfPrintCoverage (fp, pos->coverage);
fprintf (fp, "\t entryExitCount: %d\n", pos->entryExitCount);
diff --git a/Build/source/texk/ttfdump/libttf/otfcommon.c b/Build/source/texk/ttfdump/libttf/otfcommon.c
index 8102aae6ab5..4642e73196a 100644
--- a/Build/source/texk/ttfdump/libttf/otfcommon.c
+++ b/Build/source/texk/ttfdump/libttf/otfcommon.c
@@ -566,33 +566,33 @@ static void loadOtfRule (OtfRulePtr otfRule, FILE *fp, ULONG offset)
static void loadOtfRuleSet (OtfRuleSetPtr otfRuleSet, FILE *fp, ULONG offset)
{
int i;
- USHORT *pOffset;
+ USHORT *rOffset;
xfseek (fp, offset, SEEK_SET, "loadOtfRuleSet");
otfRuleSet->otfRuleCount = ttfGetUSHORT (fp);
- pOffset = ttfMakeUSHORT (otfRuleSet->otfRuleCount, fp);
+ rOffset = ttfMakeUSHORT (otfRuleSet->otfRuleCount, fp);
otfRuleSet->otfRule = XCALLOC (otfRuleSet->otfRuleCount, OtfRule);
for (i = 0; i < otfRuleSet->otfRuleCount; i++)
- loadOtfRule (&otfRuleSet->otfRule[i], fp, offset + pOffset[i]);
- free (pOffset);
+ loadOtfRule (&otfRuleSet->otfRule[i], fp, offset + rOffset[i]);
+ free (rOffset);
}
OtfCtx1Ptr makeOTFCtx1 (FILE *fp, ULONG offset)
{
int i;
USHORT cOffset;
- USHORT *pOffset;
+ USHORT *rOffset;
OtfCtx1Ptr otf = XCALLOC1 (OtfCtx1);
cOffset = ttfGetUSHORT (fp);
otf->otfRuleSetCount = ttfGetUSHORT (fp);
- pOffset = ttfMakeUSHORT (otf->otfRuleSetCount, fp);
+ rOffset = ttfMakeUSHORT (otf->otfRuleSetCount, fp);
otf->otfRuleSet = XCALLOC (otf->otfRuleSetCount, OtfRuleSet);
otf->coverage = otfMakeCoverage (fp, offset + cOffset);
for (i = 0; i < otf->otfRuleSetCount; i++)
- loadOtfRuleSet (&otf->otfRuleSet[i], fp, offset + pOffset[i]);
- free (pOffset);
+ loadOtfRuleSet (&otf->otfRuleSet[i], fp, offset + rOffset[i]);
+ free (rOffset);
return otf;
}
@@ -601,7 +601,8 @@ void printOTFCtx1 (FILE *fp, OtfCtx1Ptr otf)
{
int i;
- fprintf (fp, " - Context Simple\n\t ");
+ fprintf (fp, " - Context %s Simple\n\t ",
+ otf->lookupType == 7 ? "Positioning" : "Substitution");
otfPrintCoverage (fp, otf->coverage);
fprintf (fp, "\t otfRuleSetCount: %d\n", otf->otfRuleSetCount);
for (i = 0; i < otf->otfRuleSetCount; i++) {
@@ -611,7 +612,7 @@ void printOTFCtx1 (FILE *fp, OtfCtx1Ptr otf)
for (j = 0; j < otf->otfRuleSet[i].otfRuleCount; j++) {
int k;
- fprintf (fp, "\t %2d. glyphtCount: %d ", j,
+ fprintf (fp, "\t %2d. glyphCount: %d ", j,
otf->otfRuleSet[i].otfRule[j].glyphCount);
for (k = 0; k < otf->otfRuleSet[i].otfRule[j].glyphCount - 1; k++)
fprintf (fp, k == 0 ? "- %d" : ", %d", otf->otfRuleSet[i].otfRule[j].input[k]);
@@ -653,16 +654,16 @@ static void loadOtfClassRule (OtfClassRulePtr otfClassRule, FILE *fp, ULONG offs
static void loadOtfClassSet (OtfClassSetPtr otfClassSet, FILE *fp, ULONG offset)
{
int i;
- USHORT *pOffset;
+ USHORT *sOffset;
xfseek (fp, offset, SEEK_SET, "loadOtfClassSet");
otfClassSet->otfClassRuleCnt = ttfGetUSHORT (fp);
- pOffset = ttfMakeUSHORT (otfClassSet->otfClassRuleCnt, fp);
+ sOffset = ttfMakeUSHORT (otfClassSet->otfClassRuleCnt, fp);
otfClassSet->otfClassRule = XCALLOC (otfClassSet->otfClassRuleCnt, OtfClassRule);
for (i = 0; i < otfClassSet->otfClassRuleCnt; i++)
- loadOtfClassRule (&otfClassSet->otfClassRule[i], fp, offset + pOffset[i]);
- free (pOffset);
+ loadOtfClassRule (&otfClassSet->otfClassRule[i], fp, offset + sOffset[i]);
+ free (sOffset);
}
OtfCtx2Ptr makeOTFCtx2 (FILE *fp, ULONG offset)
@@ -670,20 +671,20 @@ OtfCtx2Ptr makeOTFCtx2 (FILE *fp, ULONG offset)
int i;
USHORT cOffset;
USHORT clOffset;
- USHORT *pOffset;
+ USHORT *sOffset;
OtfCtx2Ptr otf = XCALLOC1 (OtfCtx2);
cOffset = ttfGetUSHORT (fp);
clOffset = ttfGetUSHORT (fp);
otf->otfClassSetCnt = ttfGetUSHORT (fp);
- pOffset = ttfMakeUSHORT (otf->otfClassSetCnt, fp);
+ sOffset = ttfMakeUSHORT (otf->otfClassSetCnt, fp);
otf->otfClassSet = XCALLOC (otf->otfClassSetCnt, OtfClassSet);
otf->coverage = otfMakeCoverage (fp, offset + cOffset);
otf->classDef = otfMakeClassDef (fp, offset + clOffset);
for (i = 0; i < otf->otfClassSetCnt; i++)
- if (pOffset[i])
- loadOtfClassSet (&otf->otfClassSet[i], fp, offset + pOffset[i]);
- free (pOffset);
+ if (sOffset[i])
+ loadOtfClassSet (&otf->otfClassSet[i], fp, offset + sOffset[i]);
+ free (sOffset);
return otf;
}
@@ -692,7 +693,8 @@ void printOTFCtx2 (FILE *fp, OtfCtx2Ptr otf)
{
int i;
- fprintf (fp, " - Context Class-based\n\t ");
+ fprintf (fp, " - Context %s Class-based\n\t ",
+ otf->lookupType == 7 ? "Positioning" : "Substitution");
otfPrintCoverage (fp, otf->coverage);
fprintf (fp, "\t ClassDef - ");
otfPrintClassDef (fp, otf->classDef);
@@ -704,7 +706,7 @@ void printOTFCtx2 (FILE *fp, OtfCtx2Ptr otf)
for (j = 0; j < otf->otfClassSet[i].otfClassRuleCnt; j++) {
int k;
- fprintf (fp, "\t %2d. glyphtCount: %d ", j,
+ fprintf (fp, "\t %2d. glyphCount: %d ", j,
otf->otfClassSet[i].otfClassRule[j].glyphCount);
for (k = 0; k < otf->otfClassSet[i].otfClassRule[j].glyphCount - 1; k++)
fprintf (fp, k == 0 ? "- %d" : ", %d", otf->otfClassSet[i].otfClassRule[j].class[k]);
@@ -756,7 +758,8 @@ void printOTFCtx3 (FILE *fp, OtfCtx3Ptr otf)
{
int i;
- fprintf (fp, " - Context Coverage-based\n");
+ fprintf (fp, " - Context %s Coverage-based\n",
+ otf->lookupType == 7 ? "Positioning" : "Substitution");
fprintf (fp, "\t glyphCount: %d\n", otf->glyphCount);
for (i = 0; i < otf->glyphCount; i++) {
fprintf (fp, "\t %2d. ", i);
@@ -794,33 +797,33 @@ static void
loadChainOtfRuleSet (ChainOtfRuleSetPtr chainOtfRuleSet, FILE *fp, ULONG offset)
{
int i;
- USHORT *pOffset;
+ USHORT *rOffset;
xfseek (fp, offset, SEEK_SET, "loadChainOtfRuleSet");
chainOtfRuleSet->chainOtfRuleCount = ttfGetUSHORT (fp);
- pOffset = ttfMakeUSHORT (chainOtfRuleSet->chainOtfRuleCount, fp);
+ rOffset = ttfMakeUSHORT (chainOtfRuleSet->chainOtfRuleCount, fp);
chainOtfRuleSet->chainOtfRule = XCALLOC (chainOtfRuleSet->chainOtfRuleCount, ChainOtfRule);
for (i = 0; i < chainOtfRuleSet->chainOtfRuleCount; i++)
- loadChainOtfRule (&chainOtfRuleSet->chainOtfRule[i], fp, offset + pOffset[i]);
- free (pOffset);
+ loadChainOtfRule (&chainOtfRuleSet->chainOtfRule[i], fp, offset + rOffset[i]);
+ free (rOffset);
}
OtfChn1Ptr makeOTFChn1 (FILE *fp, ULONG offset)
{
int i;
USHORT cOffset;
- USHORT *pOffset;
+ USHORT *rOffset;
OtfChn1Ptr otf = XCALLOC1 (OtfChn1);
cOffset = ttfGetUSHORT (fp);
otf->chainOtfRuleSetCount = ttfGetUSHORT (fp);
- pOffset = ttfMakeUSHORT (otf->chainOtfRuleSetCount, fp);
+ rOffset = ttfMakeUSHORT (otf->chainOtfRuleSetCount, fp);
otf->coverage = otfMakeCoverage (fp, offset + cOffset);
otf->chainOtfRuleSet = XCALLOC (otf->chainOtfRuleSetCount, ChainOtfRuleSet);
for (i = 0; i < otf->chainOtfRuleSetCount; i++)
- loadChainOtfRuleSet (&otf->chainOtfRuleSet[i], fp, offset + pOffset[i]);
- free (pOffset);
+ loadChainOtfRuleSet (&otf->chainOtfRuleSet[i], fp, offset + rOffset[i]);
+ free (rOffset);
return otf;
}
@@ -829,7 +832,8 @@ void printOTFChn1 (FILE *fp, OtfChn1Ptr otf)
{
int i;
- fprintf (fp, " - Chained Context Simple\n\t ");
+ fprintf (fp, " - Chained Context %s Simple\n\t ",
+ otf->lookupType == 8 ? "Positioning" : "Substitution");
otfPrintCoverage (fp, otf->coverage);
fprintf (fp, "\t chainOtfRuleSetCount: %d\n", otf->chainOtfRuleSetCount);
for (i = 0; i < otf->chainOtfRuleSetCount; i++) {
@@ -898,16 +902,16 @@ static void
loadChainOtfClassSet (ChainOtfClassSetPtr chainOtfClassSet, FILE *fp, ULONG offset)
{
int i;
- USHORT *pOffset;
+ USHORT *rOffset;
xfseek (fp, offset, SEEK_SET, "loadChainOtfClassSet");
chainOtfClassSet->chainOtfClassRuleCnt = ttfGetUSHORT (fp);
- pOffset = ttfMakeUSHORT (chainOtfClassSet->chainOtfClassRuleCnt, fp);
+ rOffset = ttfMakeUSHORT (chainOtfClassSet->chainOtfClassRuleCnt, fp);
chainOtfClassSet->chainOtfClassRule = XCALLOC (chainOtfClassSet->chainOtfClassRuleCnt, ChainOtfClassRule);
for (i = 0; i < chainOtfClassSet->chainOtfClassRuleCnt; i++)
- loadChainOtfClassRule (&chainOtfClassSet->chainOtfClassRule[i], fp, offset + pOffset[i]);
- free (pOffset);
+ loadChainOtfClassRule (&chainOtfClassSet->chainOtfClassRule[i], fp, offset + rOffset[i]);
+ free (rOffset);
}
OtfChn2Ptr makeOTFChn2 (FILE *fp, ULONG offset)
@@ -915,7 +919,7 @@ OtfChn2Ptr makeOTFChn2 (FILE *fp, ULONG offset)
int i;
USHORT cOffset;
USHORT bOffset, iOffset, lOffset;
- USHORT *pOffset;
+ USHORT *sOffset;
OtfChn2Ptr otf = XCALLOC1 (OtfChn2);
cOffset = ttfGetUSHORT (fp);
@@ -923,16 +927,16 @@ OtfChn2Ptr makeOTFChn2 (FILE *fp, ULONG offset)
iOffset = ttfGetUSHORT (fp);
lOffset = ttfGetUSHORT (fp);
otf->chainOtfClassSetCnt = ttfGetUSHORT (fp);
- pOffset = ttfMakeUSHORT (otf->chainOtfClassSetCnt, fp);
+ sOffset = ttfMakeUSHORT (otf->chainOtfClassSetCnt, fp);
otf->coverage = otfMakeCoverage (fp, offset + cOffset);
otf->backtrackClassDef = otfMakeClassDef (fp, offset + bOffset);
otf->inputClassDef = otfMakeClassDef (fp, offset + iOffset);
otf->lookaheadClassDef = otfMakeClassDef (fp, offset + lOffset);
otf->chainOtfClassSet = XCALLOC (otf->chainOtfClassSetCnt, ChainOtfClassSet);
for (i = 0; i < otf->chainOtfClassSetCnt; i++)
- if (pOffset[i])
- loadChainOtfClassSet (&otf->chainOtfClassSet[i], fp, offset + pOffset[i]);
- free (pOffset);
+ if (sOffset[i])
+ loadChainOtfClassSet (&otf->chainOtfClassSet[i], fp, offset + sOffset[i]);
+ free (sOffset);
return otf;
}
@@ -941,7 +945,8 @@ void printOTFChn2 (FILE *fp, OtfChn2Ptr otf)
{
int i;
- fprintf (fp, " - Chained Context Class-based\n\t ");
+ fprintf (fp, " - Chained Context %s Class-based\n\t ",
+ otf->lookupType == 8 ? "Positioning" : "Substitution");
otfPrintCoverage (fp, otf->coverage);
fprintf (fp, "\t backtrackClassDef - ");
otfPrintClassDef (fp, otf->backtrackClassDef);
@@ -1037,7 +1042,8 @@ void printOTFChn3 (FILE *fp, OtfChn3Ptr otf)
{
int i;
- fprintf (fp, " - Chained Context Coverage-based\n");
+ fprintf (fp, " - Chained Context %s Coverage-based\n",
+ otf->lookupType == 8 ? "Positioning" : "Substitution");
fprintf (fp, "\t backtrackGlyphCount: %d\n", otf->backtrackGlyphCount);
for (i = 0; i < otf->backtrackGlyphCount; i++) {
fprintf (fp, "\t %2d. backtrack", i);