summaryrefslogtreecommitdiff
path: root/Build/source/texk/ttfdump/libttf/gpos.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/ttfdump/libttf/gpos.c')
-rw-r--r--Build/source/texk/ttfdump/libttf/gpos.c971
1 files changed, 971 insertions, 0 deletions
diff --git a/Build/source/texk/ttfdump/libttf/gpos.c b/Build/source/texk/ttfdump/libttf/gpos.c
new file mode 100644
index 00000000000..9d040298099
--- /dev/null
+++ b/Build/source/texk/ttfdump/libttf/gpos.c
@@ -0,0 +1,971 @@
+/* gpos.c -- Glyph Positioning Table
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include "config.h"
+#include "ttf.h"
+#include "ttfutil.h"
+
+static USHORT getValueFormat (FILE *fp)
+{
+ USHORT valueFormat = ttfGetUSHORT (fp);
+
+ if (valueFormat & ValueFormat_Reserved)
+ ttfError ("Unrecognized GPOS valueFormat\n");
+
+ return valueFormat;
+}
+
+static ValueRecordPtr
+gposMakeValueRecord (USHORT valueFormat, FILE *fp, ULONG offset)
+{
+ int i;
+ ValueRecordPtr value;
+
+ if (valueFormat == 0)
+ return NULL;
+
+ value = XCALLOC1 (ValueRecord);
+ for (i = 0; i < 4; i++)
+ if (valueFormat & (ValueFormat_XPlacement << i))
+ value->valDesign[i] = ttfGetSHORT (fp);
+ for (i = 0; i < 4; i++)
+ if (valueFormat & (ValueFormat_XPlaDevice << i))
+ ttfGetUSHORT (fp);
+
+ return value;
+}
+
+static const char *txtDesign[4] = {
+ "XPlacement",
+ "YPlacement",
+ "XAdvance",
+ "YAdvance"
+};
+
+static void
+gposPrintValueRecord (FILE *fp, const char *str, USHORT valueFormat, ValueRecordPtr value)
+{
+ const char *s = ":";
+ int i;
+
+ for (i = 0; i < 4; i++)
+ if (valueFormat & (ValueFormat_XPlacement << i)) {
+ 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");
+}
+
+static void freeValueRecord (ValueRecordPtr value)
+{
+ if (value) {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ if (value->valDevice[i])
+ free (value->valDevice[i]);
+ free (value);
+ }
+}
+
+static AnchorPtr gposMakeAnchor (FILE *fp, ULONG offset)
+{
+ AnchorPtr anchor;
+ USHORT anchorFormat;
+ USHORT xOffset, yOffset;
+
+ xfseek (fp, offset, SEEK_SET, "gposMakeAnchor");
+
+ anchorFormat = ttfGetUSHORT (fp);
+ switch (anchorFormat)
+ {
+ case 1:
+ anchor.anchor1 = XCALLOC1 (Anchor1);
+ break;
+ case 2:
+ anchor.anchor2 = XCALLOC1 (Anchor2);
+ break;
+ case 3:
+ anchor.anchor3 = XCALLOC1 (Anchor3);
+ break;
+ default:
+ ttfError ("Unrecognized GPOS anchorFormat\n");
+ }
+ anchor.anchor1->anchorFormat = anchorFormat;
+ anchor.anchor1->xCoordinate = ttfGetSHORT (fp);
+ anchor.anchor1->yCoordinate = ttfGetSHORT (fp);
+
+ switch (anchorFormat)
+ {
+ case 2:
+ anchor.anchor2->anchorPoint = ttfGetUSHORT (fp);
+ break;
+ case 3:
+ xOffset = ttfGetUSHORT (fp);
+ yOffset = ttfGetUSHORT (fp);
+ if (xOffset)
+ anchor.anchor3->xDevice = otfMakeDevice (fp, offset + xOffset);
+ if (yOffset)
+ anchor.anchor3->yDevice = otfMakeDevice (fp, offset + yOffset);
+ break;
+ }
+
+ return anchor;
+}
+
+static void
+gposPrintAnchor (FILE *fp, const char *str, AnchorPtr anchor)
+{
+ fprintf (fp, "anchorFormat = %d, xCoordinate = %d, yCoordinate = %d\n",
+ anchor.anchor1->anchorFormat, anchor.anchor1->xCoordinate, anchor.anchor1->yCoordinate);
+
+ switch (anchor.anchor1->anchorFormat)
+ {
+ case 2:
+ fprintf (fp, "%sanchorPoint = %d\n", str, anchor.anchor2->anchorPoint);
+ break;
+ case 3:
+ if (anchor.anchor3->xDevice) {
+ fprintf (fp, "%sxDevice: ", str);
+ otfPrintDevice (fp, anchor.anchor3->xDevice);
+ }
+ if (anchor.anchor3->yDevice) {
+ fprintf (fp, "%syDevice: ", str);
+ otfPrintDevice (fp, anchor.anchor3->yDevice);
+ }
+ break;
+ }
+}
+
+static void freeAnchor (AnchorPtr anchor)
+{
+ if (anchor.anchor3) {
+ if (anchor.anchor3->anchorFormat == 3) {
+ if (anchor.anchor3->xDevice)
+ free (anchor.anchor3->xDevice);
+ if (anchor.anchor3->yDevice)
+ free (anchor.anchor3->yDevice);
+ }
+ free (anchor.anchor3);
+ }
+}
+
+static MarkRecordPtr
+gposMakeMarkArray (FILE *fp, USHORT *markCount, ULONG offset)
+{
+ int i;
+ MarkRecordPtr markArray;
+ USHORT *aOffset;
+
+ xfseek (fp, offset, SEEK_SET, "gposMakeMarkArray");
+
+ *markCount = ttfGetUSHORT (fp);
+ markArray = XCALLOC (*markCount, MarkRecord);
+ aOffset = XCALLOC (*markCount, USHORT);
+ for (i = 0; i < *markCount; i++) {
+ markArray[i].class = ttfGetUSHORT (fp);
+ aOffset[i] = ttfGetUSHORT (fp);
+ }
+ for (i = 0; i < *markCount; i++)
+ markArray[i].markAnchor = gposMakeAnchor (fp, offset + aOffset[i]);
+ free (aOffset);
+
+ return markArray;
+}
+
+static void
+gposPrintMarkArray (FILE *fp, USHORT markCount, MarkRecordPtr markArray)
+{
+ int i;
+
+ for (i = 0; i < markCount; i++) {
+ fprintf (fp, "\t %2d. class: %d - ", i, markArray[i].class);
+ gposPrintAnchor (fp, "\t\t ", markArray[i].markAnchor);
+ }
+}
+
+/* Used for both pos41->baseArray and pos61->mark2Array. */
+static AnchorPtr *
+gposMakeBaseArray (FILE *fp, USHORT *baseCount, USHORT classCount, ULONG offset)
+{
+ int i;
+ AnchorPtr *baseArray;
+ USHORT *aOffset;
+
+ xfseek (fp, offset, SEEK_SET, "gposMakeBaseArray");
+
+ *baseCount = ttfGetUSHORT (fp);
+ aOffset = ttfMakeUSHORT (*baseCount * classCount, fp);
+ baseArray = XCALLOC (*baseCount * classCount, AnchorPtr);
+ for (i = 0; i < *baseCount * classCount; i++)
+ if (aOffset[i])
+ baseArray[i] = gposMakeAnchor (fp, offset + aOffset[i]);
+ free (aOffset);
+
+ return baseArray;
+}
+
+static Pos11Ptr makeGPOS11 (FILE *fp, ULONG offset)
+{
+ USHORT cOffset;
+ Pos11Ptr pos = XCALLOC1 (Pos11);
+
+ cOffset = ttfGetUSHORT (fp);
+ pos->valueFormat = getValueFormat (fp);
+ pos->value = gposMakeValueRecord (pos->valueFormat, fp, offset);
+ pos->coverage = otfMakeCoverage (fp, offset + cOffset);
+
+ return pos;
+}
+
+static void printGPOS11 (FILE *fp, Pos11Ptr pos)
+{
+ fprintf (fp, " - Single Adjustment Value\n\t ");
+ otfPrintCoverage (fp, pos->coverage);
+ fprintf (fp, "\t valueFormat: 0x%04x\n", pos->valueFormat);
+ if (pos->valueFormat) {
+ fprintf (fp, "\t value");
+ gposPrintValueRecord (fp, "\t\t", pos->valueFormat, pos->value);
+ }
+}
+
+static void freeGPOS11 (Pos11Ptr pos)
+{
+ freeValueRecord (pos->value);
+ otfFreeCoverage (pos->coverage);
+}
+
+static Pos12Ptr makeGPOS12 (FILE *fp, ULONG offset)
+{
+ int i;
+ USHORT cOffset;
+ Pos12Ptr pos = XCALLOC1 (Pos12);
+
+ cOffset = ttfGetUSHORT (fp);
+ pos->valueFormat = getValueFormat (fp);
+ 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->coverage = otfMakeCoverage (fp, offset + cOffset);
+
+ return pos;
+}
+
+static void printGPOS12 (FILE *fp, Pos12Ptr pos)
+{
+ int i;
+
+ fprintf (fp, " - Single Adjustment List\n\t ");
+ otfPrintCoverage (fp, pos->coverage);
+ fprintf (fp, "\t valueFormat: 0x%04x, valueCount: %d\n", pos->valueFormat, pos->valueCount);
+ for (i = 0; i < pos->valueCount; i++) {
+ fprintf (fp, "\t %2d. value", i);
+ gposPrintValueRecord (fp, "\t\t ", pos->valueFormat, pos->value[i]);
+ }
+}
+
+static void freeGPOS12 (Pos12Ptr pos)
+{
+ int i;
+
+ for (i = 0; i < pos->valueCount; i++)
+ freeValueRecord (pos->value[i]);
+ free (pos->value);
+ otfFreeCoverage (pos->coverage);
+}
+
+static void gposLoadPairSet (Pos21Ptr pos, int i, FILE *fp, ULONG offset, USHORT poff)
+{
+ int j;
+ PairSetPtr pairSet = &pos->pairSet[i];
+
+ xfseek (fp, offset + poff, 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);
+ }
+}
+
+static Pos21Ptr makeGPOS21 (FILE *fp, ULONG offset)
+{
+ int i;
+ USHORT cOffset;
+ USHORT *pOffset;
+ Pos21Ptr pos = XCALLOC1 (Pos21);
+
+ cOffset = ttfGetUSHORT (fp);
+ pos->valueFormat1 = getValueFormat (fp);
+ pos->valueFormat2 = getValueFormat (fp);
+ pos->pairSetCount = ttfGetUSHORT (fp);
+ pOffset = ttfMakeUSHORT (pos->pairSetCount, fp);
+ 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]);
+ free (pOffset);
+
+ return pos;
+}
+
+static void printGPOS21 (FILE *fp, Pos21Ptr pos)
+{
+ int i;
+
+ fprintf (fp, " - Pair Adjustment List\n\t ");
+ otfPrintCoverage (fp, pos->coverage);
+ fprintf (fp, "\t valueFormat1: 0x%04x, valueFormat2: 0x%04x, pairSetCount: %d\n",
+ 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,
+ pos->pairSet[i].pairValue[j].secondGlyph);
+ if (pos->valueFormat1) {
+ fprintf (fp, "\t\t value1");
+ gposPrintValueRecord (fp, "\t\t\t ", pos->valueFormat1,
+ pos->pairSet[i].pairValue[j].value1);
+ }
+ if (pos->valueFormat2) {
+ fprintf (fp, "\t\t value2");
+ gposPrintValueRecord (fp, "\t\t\t ", pos->valueFormat2,
+ pos->pairSet[i].pairValue[j].value2);
+ }
+ }
+ }
+}
+
+static void freeGPOS21 (Pos21Ptr pos)
+{
+ int i;
+
+ for (i = 0; i < pos->pairSetCount; i++) {
+ int j;
+ for (j = 0; j < pos->pairSet[i].pairValueCount; j++) {
+ freeValueRecord (pos->pairSet[i].pairValue[j].value1);
+ freeValueRecord (pos->pairSet[i].pairValue[j].value2);
+ }
+ free (pos->pairSet[i].pairValue);
+ }
+ free (pos->pairSet);
+ otfFreeCoverage (pos->coverage);
+}
+
+static Pos22Ptr makeGPOS22 (FILE *fp, ULONG offset)
+{
+ int num = 0, i;
+ USHORT cOffset, cOffset1, cOffset2;
+ Pos22Ptr pos = XCALLOC1 (Pos22);
+
+ cOffset = ttfGetUSHORT (fp);
+ pos->valueFormat1 = getValueFormat (fp);
+ pos->valueFormat2 = getValueFormat (fp);
+ cOffset1 = ttfGetUSHORT (fp);
+ cOffset2 = ttfGetUSHORT (fp);
+ 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);
+ }
+ }
+ pos->coverage = otfMakeCoverage (fp, offset + cOffset);
+ pos->classDef1 = otfMakeClassDef (fp, offset + cOffset1);
+ pos->classDef2 = otfMakeClassDef (fp, offset + cOffset2);
+
+ return pos;
+}
+
+static void printGPOS22 (FILE *fp, Pos22Ptr pos)
+{
+ int num = 0, i;
+
+ fprintf (fp, " - Pair Adjustment Class\n\t ");
+ otfPrintCoverage (fp, pos->coverage);
+ fprintf (fp, "\t valueFormat1: 0x%04x, valueFormat2: 0x%04x\n",
+ pos->valueFormat1, pos->valueFormat2);
+ fprintf (fp, "\t ClassDef1 - ");
+ otfPrintClassDef (fp, pos->classDef1);
+ fprintf (fp, "\t ClassDef2 - ");
+ otfPrintClassDef (fp, pos->classDef2);
+ fprintf (fp, "\t class1Count: %d, class2Count: %d\n",
+ pos->class1Count, pos->class2Count);
+ for (i = 0; i < pos->class1Count; i++) {
+ int j;
+ const char *s = "";
+
+ fprintf (fp, "\t %2d.", i);
+ for (j = 0; j < pos->class2Count; j++) {
+ fprintf (fp, "%s %2d.", s, j);
+ s = "\t ";
+
+ if (pos->valueFormat1) {
+ fprintf (fp, " value1");
+ gposPrintValueRecord (fp, "\t\t\t ", pos->valueFormat1,
+ pos->values[num]);
+ }
+ num++;
+ if (pos->valueFormat2) {
+ fprintf (fp, " value2");
+ gposPrintValueRecord (fp, "\t\t\t ", pos->valueFormat2,
+ pos->values[num]);
+ }
+ num++;
+ }
+ }
+}
+
+static void freeGPOS22 (Pos22Ptr pos)
+{
+ int i;
+
+ for (i = 0; i < 2 * pos->class1Count * pos->class2Count; i++)
+ freeValueRecord (pos->values[i]);
+ free (pos->values);
+ otfFreeCoverage (pos->coverage);
+ otfFreeClassDef (pos->classDef1);
+ otfFreeClassDef (pos->classDef2);
+}
+
+static Pos31Ptr makeGPOS31 (FILE *fp, ULONG offset)
+{
+ int i;
+ USHORT cOffset;
+ USHORT *eOffset;
+ Pos31Ptr pos = XCALLOC1 (Pos31);
+
+ cOffset = ttfGetUSHORT (fp);
+ pos->entryExitCount = ttfGetUSHORT (fp);
+ eOffset = ttfMakeUSHORT (2 * pos->entryExitCount, fp);
+ pos->coverage = otfMakeCoverage (fp, offset + cOffset);
+ pos->entryExit = XCALLOC (2 * pos->entryExitCount, AnchorPtr);
+ for (i = 0; i < 2 * pos->entryExitCount; i++)
+ if (eOffset[i])
+ pos->entryExit[i] = gposMakeAnchor (fp, offset + eOffset[i]);
+ free (eOffset);
+
+ return pos;
+}
+
+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);
+ for (i = 0; i < pos->entryExitCount; i++) {
+ int j;
+ const char *s = "";
+
+ fprintf (fp, "\t %2d. ", i);
+ for (j = 0; j < 2; j++) {
+ if (pos->entryExit[num].anchor1) {
+ fprintf (fp, "%s%sAnchor - ", s, j ? "exit" : "entry");
+ gposPrintAnchor (fp, "\t\t ", pos->entryExit[num]);
+ s = "\t ";
+ }
+ num++;
+ }
+ }
+}
+
+static void freeGPOS31 (Pos31Ptr pos)
+{
+ int i;
+
+ for (i = 0; i < 2 * pos->entryExitCount; i++)
+ freeAnchor (pos->entryExit[i]);
+ free (pos->entryExit);
+ otfFreeCoverage (pos->coverage);
+}
+
+static Pos41Ptr makeGPOS41 (FILE *fp, ULONG offset)
+{
+ USHORT mcOffset, bcOffset, maOffset, baOffset;
+ Pos41Ptr pos = XCALLOC1 (Pos41);
+
+ mcOffset = ttfGetUSHORT (fp);
+ bcOffset = ttfGetUSHORT (fp);
+ pos->classCount = ttfGetUSHORT (fp);
+ maOffset = ttfGetUSHORT (fp);
+ baOffset = ttfGetUSHORT (fp);
+ pos->markCoverage = otfMakeCoverage (fp, offset + mcOffset);
+ pos->baseCoverage = otfMakeCoverage (fp, offset + bcOffset);
+ pos->markArray = gposMakeMarkArray (fp, &pos->markCount, offset + maOffset);
+ pos->baseArray = gposMakeBaseArray (fp, &pos->baseCount, pos->classCount, offset + baOffset);
+
+ return pos;
+}
+
+static void printGPOS41 (FILE *fp, Pos41Ptr pos)
+{
+ int i, num = 0;
+
+ fprintf (fp, " - Mark To Base Attachment\n\t mark");
+ otfPrintCoverage (fp, pos->markCoverage);
+ fprintf (fp, "\t markArray - markCount: %d\n", pos->markCount);
+ gposPrintMarkArray (fp, pos->markCount, pos->markArray);
+ fprintf (fp, "\t base");
+ otfPrintCoverage (fp, pos->baseCoverage);
+ fprintf (fp, "\t baseArray - baseCount: %d, classCount: %d\n",
+ pos->baseCount, pos->classCount);
+ for (i = 0; i < pos->baseCount; i++) {
+ int j;
+ const char *s = "";
+
+ fprintf (fp, "\t %2d. ", i);
+ for (j = 0; j < pos->classCount; j++) {
+ if (pos->baseArray[num].anchor1) {
+ fprintf (fp, "%s%2d. ", s, j);
+ gposPrintAnchor (fp, "\t\t ", pos->baseArray[num]);
+ s = "\t ";
+ }
+ num++;
+ }
+ }
+}
+
+static void freeGPOS41 (Pos41Ptr pos)
+{
+ int i;
+
+ for (i = 0; i < pos->markCount; i++)
+ freeAnchor (pos->markArray[i].markAnchor);
+ free (pos->markArray);
+ for (i = 0; i < pos->baseCount * pos->classCount; i++)
+ freeAnchor (pos->baseArray[i]);
+ free (pos->baseArray);
+ otfFreeCoverage (pos->markCoverage);
+ otfFreeCoverage (pos->baseCoverage);
+}
+
+static void
+gposLoadLigatureArray (LigatureAttachPtr ligatureArray, USHORT classCount, FILE *fp, ULONG offset)
+{
+ int i;
+ USHORT *aOffset;
+
+ xfseek (fp, offset, SEEK_SET, "gposLoadLigatureArray");
+
+ ligatureArray->componentCount = ttfGetUSHORT (fp);
+ aOffset = ttfMakeUSHORT (ligatureArray->componentCount * classCount, fp);
+ ligatureArray->componentRecord = XCALLOC (ligatureArray->componentCount * classCount, AnchorPtr);
+ for (i = 0; i < ligatureArray->componentCount * classCount; i++)
+ if (aOffset[i])
+ ligatureArray->componentRecord[i] = gposMakeAnchor (fp, offset + aOffset[i]);
+ free (aOffset);
+}
+
+static LigatureAttachPtr
+gposMakeLigatureArray (FILE *fp, USHORT *ligatureCount, USHORT classCount, ULONG offset)
+{
+ int i;
+ LigatureAttachPtr ligatureArray;
+ USHORT *aOffset;
+
+ xfseek (fp, offset, SEEK_SET, "gposMakeLigatureArray");
+
+ *ligatureCount = ttfGetUSHORT (fp);
+ aOffset = ttfMakeUSHORT (*ligatureCount, fp);
+ ligatureArray = XCALLOC (*ligatureCount, LigatureAttach);
+ for (i = 0; i < *ligatureCount; i++)
+ gposLoadLigatureArray (&ligatureArray[i], classCount, fp, offset + aOffset[i]);
+ free (aOffset);
+
+ return ligatureArray;
+}
+
+static Pos51Ptr makeGPOS51 (FILE *fp, ULONG offset)
+{
+ USHORT mcOffset, lcOffset, maOffset, laOffset;
+ Pos51Ptr pos = XCALLOC1 (Pos51);
+
+ mcOffset = ttfGetUSHORT (fp);
+ lcOffset = ttfGetUSHORT (fp);
+ pos->classCount = ttfGetUSHORT (fp);
+ maOffset = ttfGetUSHORT (fp);
+ laOffset = ttfGetUSHORT (fp);
+ pos->markCoverage = otfMakeCoverage (fp, offset + mcOffset);
+ pos->ligatureCoverage = otfMakeCoverage (fp, offset + lcOffset);
+ pos->markArray = gposMakeMarkArray (fp, &pos->markCount, offset + maOffset);
+ pos->ligatureArray = gposMakeLigatureArray (fp, &pos->ligatureCount, pos->classCount, offset + laOffset);
+
+ return pos;
+}
+
+static void printGPOS51 (FILE *fp, Pos51Ptr pos)
+{
+ int i;
+
+ fprintf (fp, " - Mark To Ligature Attachment\n\t mark");
+ otfPrintCoverage (fp, pos->markCoverage);
+ fprintf (fp, "\t markArray - markCount: %d\n", pos->markCount);
+ gposPrintMarkArray (fp, pos->markCount, pos->markArray);
+ fprintf (fp, "\t ligature");
+ otfPrintCoverage (fp, pos->ligatureCoverage);
+ fprintf (fp, "\t ligatureArray - ligatureCount: %d\n", pos->ligatureCount);
+ for (i = 0; i < pos->ligatureCount; i++) {
+ int j, num = 0;
+
+ fprintf (fp, "\t %2d. componentCount: %d, classCount: %d\n", i,
+ pos->ligatureArray[i].componentCount, pos->classCount);
+ for (j = 0; j < pos->ligatureArray[i].componentCount; j++) {
+ int k;
+ const char *s = "";
+
+ fprintf (fp, "\t %2d. ", j);
+ for (k = 0; k < pos->classCount; k++) {
+ if (pos->ligatureArray[i].componentRecord[num].anchor1) {
+ fprintf (fp, "%s%2d. ", s, k);
+ gposPrintAnchor (fp, "\t\t ", pos->ligatureArray[i].componentRecord[num]);
+ s = "\t\t ";
+ }
+ num++;
+ }
+ }
+ }
+}
+
+static void freeGPOS51 (Pos51Ptr pos)
+{
+ int i;
+
+ for (i = 0; i < pos->markCount; i++)
+ freeAnchor (pos->markArray[i].markAnchor);
+ free (pos->markArray);
+ for (i = 0; i < pos->ligatureCount; i++) {
+ int j;
+
+ for (j = 0; j < pos->ligatureArray[i].componentCount * pos->classCount; j++)
+ freeAnchor (pos->ligatureArray[i].componentRecord[j]);
+ }
+ free (pos->ligatureArray);
+ otfFreeCoverage (pos->markCoverage);
+ otfFreeCoverage (pos->ligatureCoverage);
+}
+
+static Pos61Ptr makeGPOS61 (FILE *fp, ULONG offset)
+{
+ USHORT c1Offset, c2Offset, a1Offset, a2Offset;
+ Pos61Ptr pos = XCALLOC1 (Pos61);
+
+ c1Offset = ttfGetUSHORT (fp);
+ c2Offset = ttfGetUSHORT (fp);
+ pos->classCount = ttfGetUSHORT (fp);
+ a1Offset = ttfGetUSHORT (fp);
+ a2Offset = ttfGetUSHORT (fp);
+ pos->mark1Coverage = otfMakeCoverage (fp, offset + c1Offset);
+ pos->mark2Coverage = otfMakeCoverage (fp, offset + c2Offset);
+ pos->mark1Array = gposMakeMarkArray (fp, &pos->mark1Count, offset + a1Offset);
+ pos->mark2Array = gposMakeBaseArray (fp, &pos->mark2Count, pos->classCount, offset + a2Offset);
+
+ return pos;
+}
+
+static void printGPOS61 (FILE *fp, Pos61Ptr pos)
+{
+ int i, num = 0;
+
+ fprintf (fp, " - Mark To Mark Attachment\n\t mark1");
+ otfPrintCoverage (fp, pos->mark1Coverage);
+ fprintf (fp, "\t mark1Array - mark1Count: %d\n", pos->mark1Count);
+ gposPrintMarkArray (fp, pos->mark1Count, pos->mark1Array);
+ fprintf (fp, "\t mark2");
+ otfPrintCoverage (fp, pos->mark2Coverage);
+ fprintf (fp, "\t mark2Array - mark2Count: %d, classCount: %d\n",
+ pos->mark2Count, pos->classCount);
+ for (i = 0; i < pos->mark2Count; i++) {
+ int j;
+ const char *s = "";
+
+ fprintf (fp, "\t %2d. ", i);
+ for (j = 0; j < pos->classCount; j++) {
+ if (pos->mark2Array[num].anchor1) {
+ fprintf (fp, "%s%2d. ", s, j);
+ gposPrintAnchor (fp, "\t\t ", pos->mark2Array[num]);
+ s = "\t ";
+ }
+ num++;
+ }
+ }
+}
+
+static void freeGPOS61 (Pos61Ptr pos)
+{
+ int i;
+
+ for (i = 0; i < pos->mark1Count; i++)
+ freeAnchor (pos->mark1Array[i].markAnchor);
+ free (pos->mark1Array);
+ for (i = 0; i < pos->mark2Count * pos->classCount; i++)
+ freeAnchor (pos->mark2Array[i]);
+ free (pos->mark2Array);
+ otfFreeCoverage (pos->mark1Coverage);
+ otfFreeCoverage (pos->mark2Coverage);
+}
+
+#define makeGPOS71 makeOTFCtx1
+#define printGPOS71 printOTFCtx1
+#define freeGPOS71 freeOTFCtx1
+
+#define makeGPOS72 makeOTFCtx2
+#define printGPOS72 printOTFCtx2
+#define freeGPOS72 freeOTFCtx2
+
+#define makeGPOS73 makeOTFCtx3
+#define printGPOS73 printOTFCtx3
+#define freeGPOS73 freeOTFCtx3
+
+#define makeGPOS81 makeOTFChn1
+#define printGPOS81 printOTFChn1
+#define freeGPOS81 freeOTFChn1
+
+#define makeGPOS82 makeOTFChn2
+#define printGPOS82 printOTFChn2
+#define freeGPOS82 freeOTFChn2
+
+#define makeGPOS83 makeOTFChn3
+#define printGPOS83 printOTFChn3
+#define freeGPOS83 freeOTFChn3
+
+static LookupPtr makeGPOSLookup (FILE *fp, USHORT lookupType, ULONG offset)
+{
+ LookupPtr lookup;
+ USHORT lookupFormat;
+
+again:
+ if (lookupType == 0 || lookupType > PosLookup_Max)
+ ttfError ("Unrecognized GPOS lookupType\n");
+
+ xfseek (fp, offset, SEEK_SET, "makeGPOSLookup");
+
+ lookupFormat = ttfGetUSHORT (fp);
+ if (lookupFormat & 0xfff0)
+ lookupFormat = 0x000f;
+
+ switch (lookupType << 4 | lookupFormat)
+ {
+ case 0x011:
+ lookup.pos.pos11 = makeGPOS11 (fp, offset);
+ break;
+ case 0x012:
+ lookup.pos.pos12 = makeGPOS12 (fp, offset);
+ break;
+ case 0x021:
+ lookup.pos.pos21 = makeGPOS21 (fp, offset);
+ break;
+ case 0x022:
+ lookup.pos.pos22 = makeGPOS22 (fp, offset);
+ break;
+ case 0x031:
+ lookup.pos.pos31 = makeGPOS31 (fp, offset);
+ break;
+ case 0x041:
+ lookup.pos.pos41 = makeGPOS41 (fp, offset);
+ break;
+ case 0x051:
+ lookup.pos.pos51 = makeGPOS51 (fp, offset);
+ break;
+ case 0x061:
+ lookup.pos.pos61 = makeGPOS61 (fp, offset);
+ break;
+ case 0x071:
+ lookup.pos.pos71 = makeGPOS71 (fp, offset);
+ break;
+ case 0x072:
+ lookup.pos.pos72 = makeGPOS72 (fp, offset);
+ break;
+ case 0x073:
+ lookup.pos.pos73 = makeGPOS73 (fp, offset);
+ break;
+ case 0x081:
+ lookup.pos.pos81 = makeGPOS81 (fp, offset);
+ break;
+ case 0x082:
+ lookup.pos.pos82 = makeGPOS82 (fp, offset);
+ break;
+ case 0x083:
+ lookup.pos.pos83 = makeGPOS83 (fp, offset);
+ break;
+ case 0x091:
+ lookupType = ttfGetUSHORT (fp);
+ if (lookupType == 9)
+ ttfError ("Invalid GPOS extensionLookupType\n");
+ offset += ttfGetULONG (fp);
+ goto again;
+ default:
+ ttfError ("Unrecognized GPOS lookupFormat\n");
+ }
+
+ lookup.otf->lookupType = lookupType;
+ lookup.otf->lookupFormat = lookupFormat;
+
+ return lookup;
+}
+
+static void printGPOSLookup (FILE *fp, LookupPtr lookup)
+{
+ switch (lookup.otf->lookupType << 4 | lookup.otf->lookupFormat)
+ {
+ case 0x011:
+ printGPOS11 (fp, lookup.pos.pos11);
+ break;
+ case 0x012:
+ printGPOS12 (fp, lookup.pos.pos12);
+ break;
+ case 0x021:
+ printGPOS21 (fp, lookup.pos.pos21);
+ break;
+ case 0x022:
+ printGPOS22 (fp, lookup.pos.pos22);
+ break;
+ case 0x031:
+ printGPOS31 (fp, lookup.pos.pos31);
+ break;
+ case 0x041:
+ printGPOS41 (fp, lookup.pos.pos41);
+ break;
+ case 0x051:
+ printGPOS51 (fp, lookup.pos.pos51);
+ break;
+ case 0x061:
+ printGPOS61 (fp, lookup.pos.pos61);
+ break;
+ case 0x071:
+ printGPOS71 (fp, lookup.pos.pos71);
+ break;
+ case 0x072:
+ printGPOS72 (fp, lookup.pos.pos72);
+ break;
+ case 0x073:
+ printGPOS73 (fp, lookup.pos.pos73);
+ break;
+ case 0x081:
+ printGPOS81 (fp, lookup.pos.pos81);
+ break;
+ case 0x082:
+ printGPOS82 (fp, lookup.pos.pos82);
+ break;
+ case 0x083:
+ printGPOS83 (fp, lookup.pos.pos83);
+ break;
+ default:
+ ttfError ("Internal error: printGPOSLookup\n");
+ }
+}
+
+static void freeGPOSLookup (LookupPtr lookup)
+{
+ switch (lookup.otf->lookupType << 4 | lookup.otf->lookupFormat)
+ {
+ case 0x011:
+ freeGPOS11 (lookup.pos.pos11);
+ break;
+ case 0x012:
+ freeGPOS12 (lookup.pos.pos12);
+ break;
+ case 0x021:
+ freeGPOS21 (lookup.pos.pos21);
+ break;
+ case 0x022:
+ freeGPOS22 (lookup.pos.pos22);
+ break;
+ case 0x031:
+ freeGPOS31 (lookup.pos.pos31);
+ break;
+ case 0x041:
+ freeGPOS41 (lookup.pos.pos41);
+ break;
+ case 0x051:
+ freeGPOS51 (lookup.pos.pos51);
+ break;
+ case 0x061:
+ freeGPOS61 (lookup.pos.pos61);
+ break;
+ case 0x071:
+ freeGPOS71 (lookup.pos.pos71);
+ break;
+ case 0x072:
+ freeGPOS72 (lookup.pos.pos72);
+ break;
+ case 0x073:
+ freeGPOS73 (lookup.pos.pos73);
+ break;
+ case 0x081:
+ freeGPOS81 (lookup.pos.pos81);
+ break;
+ case 0x082:
+ freeGPOS82 (lookup.pos.pos82);
+ break;
+ case 0x083:
+ freeGPOS83 (lookup.pos.pos83);
+ break;
+ default:
+ ttfError ("Internal error: freeGPOSLookup\n");
+ }
+}
+
+static void ttfLoadGPOS (FILE *fp, GPOSPtr gpos, ULONG offset)
+{
+ USHORT sOffset, fOffset, lOffset;
+
+ xfseek (fp, offset, SEEK_SET, "ttfLoadGPOS");
+
+ gpos->version = ttfGetFixed (fp);
+ sOffset = ttfGetUSHORT (fp);
+ fOffset = ttfGetUSHORT (fp);
+ lOffset = ttfGetUSHORT (fp);
+
+ gpos->scriptList = otfMakeScriptList (fp, offset + sOffset);
+ gpos->featureList = otfMakeFeatureList (fp, offset + fOffset);
+ gpos->lookupList = otfMakeLookupList (fp, offset + lOffset, &makeGPOSLookup);
+}
+
+void ttfInitGPOS (TTFontPtr font)
+{
+ ULONG tag = FT_MAKE_TAG ('G', 'P', 'O', 'S');
+ TableDirPtr ptd;
+
+ if ((ptd = ttfLookUpTableDir (tag, font)) != NULL)
+ {
+ font->gpos = XCALLOC1 (GPOS);
+ ttfLoadGPOS (font->fp, font->gpos, ptd->offset);
+ }
+}
+
+void ttfPrintGPOS (FILE *fp, GPOSPtr gpos)
+{
+ int b[2];
+
+ FixedSplit (gpos->version, b);
+
+ fprintf (fp, "'GPOS' Table - Glyph Positioning Data\n");
+ fprintf (fp, "-------------------------------------\n");
+ fprintf (fp, "\t 'GPOS' Version:\t %d.%d\n",b[1],b[0]);
+
+ otfPrintScriptList (fp, gpos->scriptList);
+ otfPrintFeatureList (fp, gpos->featureList);
+ otfPrintLookupList (fp, gpos->lookupList, &printGPOSLookup);
+}
+
+void ttfFreeGPOS (GPOSPtr gpos)
+{
+ if (gpos != NULL)
+ {
+ otfFreeScriptList (gpos->scriptList);
+ otfFreeFeatureList (gpos->featureList);
+ otfFreeLookupList (gpos->lookupList, &freeGPOSLookup);
+ free (gpos);
+ }
+}