/* Save real number arg in DICT. If not fractional save as integer. */ void cfwDictSaveReal(DICT *dict, float r) { char buf[50]; int value; /* Current nibble value */ int last = 0; /* Last nibble value */ int odd = 0; /* Flags odd nibble */ long i = (long)r; if (i == r) { /* Value was integer */ cfwDictSaveInt(dict, i); return; } /* Convert to string; 8 digits of precision is enough to accurately represent the matrix of a typical TrueType font using a 2048 unit em */ ctuDtostr(buf, r, 0, 8); *dnaNEXT(*dict) = cff_BCD; for (i = buf[0] == '0';; i++) { switch (buf[i]) { case '\0': /* Terminate number */ *dnaNEXT(*dict) = odd ? last << 4 | 0xf : 0xff; return; case '+': continue; case '-': value = 0xe; break; case '.': value = 0xa; break; case 'E': case 'e': value = (buf[++i] == '-') ? 0xc : 0xb; break; default: value = buf[i] - '0'; break; } if (odd) { *dnaNEXT(*dict) = last << 4 | value; } else { last = value; } odd = !odd; } }
/* Save real number arg in DICT. If not fractional save as integer. */ void cfwDictSaveReal(DICT *dict, float r) { char buf[50]; int value; /* Current nibble value */ int last = 0; /* Last nibble value */ int odd = 0; /* Flags odd nibble */ long i = (long)r; if (i == r) { /* Value was integer */ cfwDictSaveInt(dict, i); return; } ctuDtostr(buf, r, 0, 8); /* 8 places is as good as it gets when converting ASCII real numbers->float-> ASCII real numbers, as happens to all the PrivateDict values.*/ *dnaNEXT(*dict) = cff_BCD; for (i = buf[0] == '0';; i++) { switch (buf[i]) { case '\0': /* Terminate number */ *dnaNEXT(*dict) = odd ? last << 4 | 0xf : 0xff; return; case '+': continue; case '-': value = 0xe; break; case '.': value = 0xa; break; case 'E': case 'e': value = (buf[++i] == '-') ? 0xc : 0xb; break; default: value = buf[i] - '0'; break; } if (odd) { *dnaNEXT(*dict) = last << 4 | value; } else { last = value; } odd = !odd; } }
unsigned short addGlyphMarkClassGDEF(hotCtx g, GNode *markClassNode) { int i; unsigned char classIndex = 0; GNode *markNode; GDEFCtx h = g->ctx.GDEF; for (i = 0; i < h->markAttachClasses.cnt; i++) { markNode = *((GNode**) dnaINDEX( h->markAttachClasses, i)); if (markClassNode == markNode) { classIndex = i+1; /* GDEF MarkAttachment class index starts at 1, not 0. */ break; } } if (classIndex == 0) { GNode **nextMarkClass; if ( h->markAttachClasses.cnt > kMaxMarkAttachClasses) return kMaxMarkAttachClasses + 1; /* trigger error msg in caller of this function */ nextMarkClass = dnaNEXT(h->markAttachClasses); *nextMarkClass = markClassNode; classIndex = (unsigned char) h->markAttachClasses.cnt; } return classIndex; }
static LOffset createMarkSetClassDef(GDEFCtx h, hotCtx g) { int i; Offset size = (Offset)MARK_SET_TABLE_SIZE(h->markSetClasses.cnt); h->markSetClassTable.MarkSetTableFormat = 1; h->markSetClassTable.MarkSetCount = (unsigned short)h->markSetClasses.cnt; dnaINIT(g->dnaCtx, h->markSetClassTable.markSetEntries, h->markSetClasses.cnt, 10); for (i = 0; i < h->markSetClasses.cnt; i++) { GNode * p; otlTbl otl; MarkSetEntry* markSetEntry; GNode* srcNode = h->markSetClasses.array[i]; GNode* headNode; markSetEntry = dnaNEXT(h->markSetClassTable.markSetEntries); otl = otlTableNew(g); markSetEntry->otl = otl; featGlyphClassCopy(g, &headNode, srcNode); featGlyphClassSort(g, &headNode, 1, 1); otlCoverageBegin(g, otl); for (p = headNode; p != NULL; p = p->nextCl) otlCoverageAddGlyph(g, otl, p->gid); otlCoverageEnd(g, otl); markSetEntry->MarkSetCoverage = size; size += (Offset)otlGetCoverageSize(otl); featRecycleNodes(g, headNode); /* Don't need this class any more*/ h->markSetClasses.array[i] = NULL; } return size; }
/* Add curve to path. */ static void glyphCurve(abfGlyphCallbacks *cb, float x1, float y1, float x2, float y2, float x3, float y3) { OpRec *opRec; ufwCtx h = cb->direct_ctx; h->path.x = x3; h->path.y = y3; if (h->err.code != 0) return; /* Pending error */ else if (h->path.state != 3) { /* Call sequence error */ h->err.code = ufwErrBadCall; return; } opRec = dnaNEXT(h->path.opList); opRec->opType = curvetoType; opRec->coords[0] = x1; opRec->coords[1] = y1; opRec->coords[2] = x2; opRec->coords[3] = y2; opRec->coords[4] = x3; opRec->coords[5] = y3; }
unsigned short addMarkSetClassGDEF(hotCtx g, GNode *markClassNode) { int i; unsigned char classIndex = 0; GNode *markNode; GDEFCtx h = g->ctx.GDEF; for (i = 0; i < h->markSetClasses.cnt; i++) { markNode = *((GNode**) dnaINDEX( h->markSetClasses, i)); if (markClassNode == markNode) { classIndex = i+1; /* so that 0 means no value was assigned. */ break; } } if (classIndex == 0) { GNode **nextMarkClass = dnaNEXT(h->markSetClasses); *nextMarkClass = markClassNode; classIndex = (unsigned char)h->markSetClasses.cnt; } return classIndex - 1; }
/* Add move to path. */ static void glyphMove(abfGlyphCallbacks *cb, float x0, float y0) { OpRec *opRec; ufwCtx h = cb->direct_ctx; h->path.x = x0; h->path.y = y0; if (h->err.code != 0) return; /* Pending error */ else if (h->path.state < 2) { /* Call sequence error */ h->err.code = ufwErrBadCall; return; } if (h->path.state == 3) { /* Write previous path. */ writeContour(h); } else if (h->path.state < 3) { /* First path data seen in glyph */ writeLine(h, "\t<outline>"); } else if (h->path.state > 3) { /* Call sequence error */ h->err.code = ufwErrBadCall; return; } opRec = dnaNEXT(h->path.opList); opRec->opType = movetoType; opRec->coords[0] = x0; opRec->coords[1] = y0; h->path.state = 3; }
int addLigCaretEntryGDEF(hotCtx g, GNode* glyphNode, unsigned short caretValue, unsigned short format) { int i; LigGlyphEntry *lge = NULL; GID gid = glyphNode->gid; GDEFCtx h = g->ctx.GDEF; int seenCaretValue = 0; /* See if we can find matching GID entry in the attach point list.*/ i = 0; while (i < h->ligCaretEntries.cnt) { if (h->ligCaretEntries.array[i].gid == gid) { unsigned short j; CaretTable *ct; lge = &h->ligCaretEntries.array[i]; /* make sure the contour isn't already in the list. */ for (j = 0; j < lge->caretTables.cnt; j++) if (lge->caretTables.array[j].CaretValue == caretValue) { seenCaretValue = 1; break; } if (!seenCaretValue) { ct = dnaNEXT(lge->caretTables); ct->format = format; ct->CaretValue = caretValue; } break; } i++; } if (lge == NULL) { CaretTable *ct; lge = dnaNEXT(h->ligCaretEntries); lge->gid = gid; dnaINIT(g->dnaCtx, lge->caretTables, 10, 10); ct = dnaNEXT(lge->caretTables); ct->format = format; ct->CaretValue = caretValue; } return seenCaretValue; }
int addAttachEntryGDEF(hotCtx g, GNode* glyphNode, unsigned short contour) { int i; AttachEntry *attachEntry = NULL; GID gid = glyphNode->gid; GDEFCtx h = g->ctx.GDEF; int seenContour = 0; /* See if we can find matching GID entry in the attach point list.*/ i = 0; while (i < h->attachEntries.cnt) { if (h->attachEntries.array[i].gid == gid) { unsigned short j, *indexEntry; attachEntry = &h->attachEntries.array[i]; /* make sure the contour isn't already in the list. */ for (j = 0; j < attachEntry->contourIndices.cnt; j++) if (attachEntry->contourIndices.array[j] == contour) { seenContour = 1; break; } if (!seenContour) { indexEntry = dnaNEXT(attachEntry->contourIndices); *indexEntry = contour; } break; } i++; } if (attachEntry == NULL) { unsigned short *indexEntry; attachEntry = dnaNEXT(h->attachEntries); attachEntry->gid = gid; dnaINIT(g->dnaCtx, attachEntry->contourIndices, 10, 10); indexEntry = dnaNEXT(attachEntry->contourIndices); *indexEntry = contour; } return seenContour; }
/* Add font to set */ void tcAddFont(tcCtx g, long flags) { tcprivCtx h = g->ctx.tcpriv; Font *font = dnaNEXT(h->set); if (flags & TC_SMALLMEMORY && g->cb.tmpOpen == NULL) { tcFatal(g, "callbacks not supplied for SMALLMEMORY mode"); } g->flags = flags; font->filename = (g->cb.psId == NULL) ? "?" : g->cb.psId(g->cb.ctx); parseFont(g, font); }
/* Add line to path. */ static void glyphLine(abfGlyphCallbacks *cb, float x1, float y1) { OpRec *opRec; ufwCtx h = cb->direct_ctx; float dx1 = x1 - h->path.x; float dy1 = y1 - h->path.y; h->path.x = x1; h->path.y = y1; if (h->err.code != 0) return; /* Pending error */ else if (h->path.state != 3) { /* Call sequence error */ h->err.code = ufwErrBadCall; return; } opRec = dnaNEXT(h->path.opList); opRec->opType = linetoType; opRec->coords[0] = x1; opRec->coords[1] = y1; }
/* Add encoding to accumulator if unique and return index */ int encodingAdd(tcCtx g, int nCodes, unsigned char *code, int nSups, CodeMap *supplement) { encodingCtx h = g->ctx.encoding; int i; Encoding *encoding; for (i = 0; i < h->encodings.cnt; i++) { encoding = &h->encodings.array[i]; if (nCodes == encoding->nCodes && nSups == encoding->nSups) { int j; for (j = 0; j < nCodes; j++) if (code[j] != encoding->code[j]) goto mismatch; for (j = 0; j < nSups; j++) if (supplement[j].code != encoding->supplement[j].code || supplement[j].sid != encoding->supplement[j].sid) goto mismatch; return PREDEF_CNT + i; /* Found match */ mismatch: ; } } /* No match found; add encoding */ encoding = dnaNEXT(h->encodings); encoding->nCodes = nCodes; encoding->code = MEM_NEW(g, nCodes); COPY(encoding->code, code, nCodes); encoding->nSups = nSups; if (nSups > 0) { encoding->supplement = MEM_NEW(g, nSups * sizeof(CodeMap)); COPY(encoding->supplement, supplement, nSups); } return PREDEF_CNT + h->encodings.cnt - 1; }
/* Add supplementary code point to encoding. */ void cfwEncodingAddSupCode(cfwCtx g, unsigned char code, SID sid) { encodingCtx h = g->ctx.encoding; SupCode *sup = dnaNEXT(h->_new->supcodes); sup->code = code; sup->sid = sid; }
/* Add code point to encoding. */ void cfwEncodingAddCode(cfwCtx g, unsigned char code) { encodingCtx h = g->ctx.encoding; *dnaNEXT(h->_new->codes) = code; }
/* Begin new encoding. */ void cfwEncodingBeg(cfwCtx g) { encodingCtx h = g->ctx.encoding; h->_new = dnaNEXT(h->encodings); h->_new->codes.cnt = 0; h->_new->supcodes.cnt = 0; }
/* Save dict operator. */ void cfwDictSaveOp(DICT *dict, int op) { if (op & 0xff00) { *dnaNEXT(*dict) = cff_escape; } *dnaNEXT(*dict) = (unsigned char)op; }
/* Begin new glyph definition. */ static int glyphBeg(abfGlyphCallbacks *cb, abfGlyphInfo *info) { ufwCtx h = cb->direct_ctx; char buf[9]; char glyphName[MAX_UFO_GLYPH_NAME]; char glifName[MAX_UFO_GLYPH_NAME]; char glifRelPath[FILENAME_MAX]; Glyph *glyphRec; cb->info = info; if (h->err.code != 0) return ABF_FAIL_RET; /* Pending error */ else if (h->path.state != 0) { /* Call sequence error */ h->err.code = ufwErrBadCall; return ABF_FAIL_RET; } else if (info->flags & ABF_GLYPH_SEEN) return ABF_SKIP_RET; /* Ignore duplicate glyph */ if (info->flags & ABF_GLYPH_CID) { h->lastiFD = info->iFD; sprintf(glyphName, "cid%05hu", info->cid); } else { sprintf(glyphName, "%s", info->gname.ptr); sprintf(glifName, "%s", info->gname.ptr); } mapGlyphToGLIFName(glyphName, glifName); /* Initialize */ h->path.x = 0; h->path.y = 0; h->path.state = 1; DURING_EX(h->err.env) /* Open GLIF file as dst stream */ sprintf(glifRelPath, "%s/%s", h->arg.glyphLayer, glifName); h->cb.stm.clientFileName = glifRelPath; h->stm.dst = h->cb.stm.open(&h->cb.stm, UFW_DST_STREAM_ID, 0); if (h->stm.dst == NULL) fatal(h, ufwErrDstStream); // write start of GL:IF file and open glyph element. writeLine(h, XML_HEADER); writeStr(h, "<glyph"); // write glyph name writeStr(h, " name=\""); writeStr(h, glyphName); writeStr(h, "\""); // close glyph element writeLine(h, " format=\"1\" >"); // write encoding, if present. if (info->flags & ABF_GLYPH_UNICODE) { writeStr(h, "\t<unicode hex=\""); sprintf(buf, "%06lX", info->encoding.code); writeStr(h, buf); writeLine(h, "\"/>"); } glyphRec = dnaNEXT(h->glyphs); strcpy(glyphRec->glyphName, glyphName); strcpy(glyphRec->glifFileName, glifName); HANDLER return Exception.Code; END_HANDLER return ABF_CONT_RET; }
/* Add anonymous table to list */ void anonAddTable(hotCtx g, unsigned long tag, hotAnonRefill refill) { anonCtx h = g->ctx.anon; AnonTbl *tbl = dnaNEXT(h->tbls); tbl->tag = tag; tbl->refill = refill; }
/* Split font set file into arg list */ static void makeArgs(char *filename) { int state; long i; long length; File file; char *start = NULL; /* Suppress optimizer warning */ /* Read whole file into buffer */ fileOpen(&file, cbctx, filename, "r"); fileSeek(&file, 0, SEEK_END); length = fileTell(&file); script.buf = cbMemNew(cbctx, length + 1); fileSeek(&file, 0, SEEK_SET); fileReadN(&file, length, script.buf); fileClose(&file); script.buf[length] = '\n'; /* Ensure termination */ /* Parse buffer into args */ state = 0; for (i = 0; i < length + 1; i++) { int c = script.buf[i]; switch (state) { case 0: switch (c) { case ' ': case '\n': case '\t': case '\r': case '\f': break; case '#': state = 1; break; case '"': start = &script.buf[i + 1]; state = 2; break; default: start = &script.buf[i]; state = 3; break; } break; case 1: /* Comment */ if (c == '\n' || c == '\r') { state = 0; } break; case 2: /* Quoted string */ if (c == '"') { script.buf[i] = '\0'; /* Terminate string */ *dnaNEXT(script.args) = start; state = 0; } break; case 3: /* Space-delimited string */ if (isspace(c)) { script.buf[i] = '\0'; /* Terminate string */ *dnaNEXT(script.args) = start; state = 0; } break; } } }
void setGlyphClassGDef(hotCtx g, GNode *simple, GNode *ligature, GNode *mark, GNode *component) { GDEFCtx h = g->ctx.GDEF; GNode **simpleClass = dnaNEXT(h->glyphClasess); GNode **ligClass = dnaNEXT(h->glyphClasess); GNode **markClass = dnaNEXT(h->glyphClasess); GNode **compClass = dnaNEXT(h->glyphClasess); int hadConflictingClassDef = 0; char* glyphClassNames[] = {"Base", "Ligature", "Mark","Component"}; long i,j; if (simple == NULL) *simpleClass = NULL; else *simpleClass = simple; if (ligature == NULL) *ligClass = NULL; else *ligClass = ligature; if (mark == NULL) *markClass = NULL; else *markClass = mark; if (component == NULL) *compClass = NULL; else *compClass = component; /* Check and warn if the same glyph has ended up in more than one class */ for (i = 0; i < h->glyphClasess.cnt; i++) { GNode *p1; GNode *prev1 = NULL; GNode *headNode1 = h->glyphClasess.array[i]; if (headNode1 == NULL) continue; for (j = i+1; j < h->glyphClasess.cnt; j++) { GNode *p2; GNode *headNode2 = h->glyphClasess.array[j]; if (headNode2 == NULL) continue; for (p1 = headNode1; p1 != NULL;) { GNode *prev2 = NULL; unsigned int removedP1 = 0; for (p2 = headNode2; p2 != NULL;) { if (p1->gid == p2->gid) { if (j != 2) { // remove glyph from current class. if (i != 2) /* If the gid in class j is being overridden by the mark class definition, then we do not complain */ { hadConflictingClassDef = 1; featGlyphDump(g, p1->gid, 0, 0); hotMsg(g, hotWARNING, "GDEF GlyphClass. Glyph '%s' gid '%d'. previous glyph class '%s' overrides new class '%s'.", g->note.array, p1->gid, glyphClassNames[i], glyphClassNames[j]); } removeNodeFromClass(h, &(h->glyphClasess.array[j]), &headNode2, &prev2, &p2); } else { // class j is the mark class; we need to remove p1 from the glyph class i. We do this silently, as the mark class always supersedes other classes. removeNodeFromClass(h, &(h->glyphClasess.array[i]), &headNode1, &prev1, &p1); removedP1 = 1; } } else { prev2 = p2; p2 = p2->nextCl; } if (p1 == NULL) break; /* This can happen because all teh p1's get removed by mark class overrides above */ } if (!removedP1) { prev1 = p1; if (p1 != NULL) p1 = p1->nextCl; } } } } if (hadConflictingClassDef) { hotMsg(g, hotWARNING, "GDEF Glyph Class. Since there were conflicting GlyphClass assignments, you should examine this auto-built GDEF table, and make sure that the glyph class assignments are as needed. If not, you should specify the GDEF table explicitly, in the features file.\n"); } }