summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/mfluadir/otfcc/lib/libcff/charstring-il.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/mfluadir/otfcc/lib/libcff/charstring-il.c')
-rw-r--r--Build/source/texk/web2c/mfluadir/otfcc/lib/libcff/charstring-il.c518
1 files changed, 0 insertions, 518 deletions
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/lib/libcff/charstring-il.c b/Build/source/texk/web2c/mfluadir/otfcc/lib/libcff/charstring-il.c
deleted file mode 100644
index d73f4dd57b5..00000000000
--- a/Build/source/texk/web2c/mfluadir/otfcc/lib/libcff/charstring-il.c
+++ /dev/null
@@ -1,518 +0,0 @@
-#include "charstring-il.h"
-#include "table/glyf.h"
-
-// Glyph building
-static void ensureThereIsSpace(cff_CharstringIL *il) {
- if (il->free) return;
- il->free = 0x100;
- RESIZE(il->instr, il->length + il->free);
-}
-
-void il_push_operand(cff_CharstringIL *il, double x) {
- ensureThereIsSpace(il);
- il->instr[il->length].type = IL_ITEM_OPERAND;
- il->instr[il->length].d = x;
- il->instr[il->length].arity = 0;
- il->length++;
- il->free--;
-}
-static void il_push_VQ(cff_CharstringIL *il, VQ x) {
- il_push_operand(il, iVQ.getStill(x));
-}
-void il_push_special(cff_CharstringIL *il, int32_t s) {
- ensureThereIsSpace(il);
- il->instr[il->length].type = IL_ITEM_SPECIAL;
- il->instr[il->length].i = s;
- il->instr[il->length].arity = 0;
- il->length++;
- il->free--;
-}
-void il_push_op(cff_CharstringIL *il, int32_t op) {
- ensureThereIsSpace(il);
- il->instr[il->length].type = IL_ITEM_OPERATOR;
- il->instr[il->length].i = op;
- il->instr[il->length].arity = cff_getStandardArity(op);
- il->length++;
- il->free--;
-}
-static void il_moveto(cff_CharstringIL *il, VQ dx, VQ dy) {
- il_push_VQ(il, dx);
- il_push_VQ(il, dy);
- il_push_op(il, op_rmoveto);
-}
-static void il_lineto(cff_CharstringIL *il, VQ dx, VQ dy) {
- il_push_VQ(il, dx);
- il_push_VQ(il, dy);
- il_push_op(il, op_rlineto);
-}
-static void il_curveto(cff_CharstringIL *il, VQ dx1, VQ dy1, VQ dx2, VQ dy2, VQ dx3, VQ dy3) {
- il_push_VQ(il, dx1);
- il_push_VQ(il, dy1);
- il_push_VQ(il, dx2);
- il_push_VQ(il, dy2);
- il_push_VQ(il, dx3);
- il_push_VQ(il, dy3);
- il_push_op(il, op_rrcurveto);
-}
-
-static void _il_push_maskgroup(cff_CharstringIL *il, // il seq
- glyf_MaskList *masks, // masks array
- uint16_t contours, // contous drawn
- uint16_t points, // points drawn
- uint16_t nh, uint16_t nv, // quantity of stems
- uint16_t *jm, // index of cur mask
- int32_t op) { // mask operator
- shapeid_t n = masks->length;
- while (*jm < n && (masks->items[*jm].contoursBefore < contours ||
- (masks->items[*jm].contoursBefore == contours &&
- masks->items[*jm].pointsBefore <= points))) {
- il_push_op(il, op);
- uint8_t maskByte = 0;
- uint8_t bits = 0;
- for (uint16_t j = 0; j < nh; j++) {
- maskByte = maskByte << 1 | (masks->items[*jm].maskH[j] & 1);
- bits += 1;
- if (bits == 8) {
- il_push_special(il, maskByte);
- bits = 0;
- }
- }
- for (uint16_t j = 0; j < nv; j++) {
- maskByte = maskByte << 1 | (masks->items[*jm].maskV[j] & 1);
- bits += 1;
- if (bits == 8) {
- il_push_special(il, maskByte);
- bits = 0;
- }
- }
- if (bits) {
- maskByte = maskByte << (8 - bits);
- il_push_special(il, maskByte);
- }
- *jm += 1;
- }
-}
-static void il_push_masks(cff_CharstringIL *il, glyf_Glyph *g, // meta
- uint16_t contours, // contours sofar
- uint16_t points, // points sofar
- uint16_t *jh, // index of pushed cmasks
- uint16_t *jm // index of pushed hmasks
-) {
- if (!g->stemH.length && !g->stemV.length) return;
- _il_push_maskgroup(il, &g->contourMasks, contours, points, //
- g->stemH.length, g->stemV.length, jh, op_cntrmask);
- _il_push_maskgroup(il, &g->hintMasks, contours, points, //
- g->stemH.length, g->stemV.length, jm, op_hintmask);
-}
-
-static void _il_push_stemgroup(cff_CharstringIL *il, // il seq
- glyf_StemDefList *stems, // stem array
- bool hasmask, bool haswidth, int32_t ophm, int32_t oph) {
- if (!stems || !stems->length) return;
- pos_t ref = 0;
- uint16_t nn = haswidth ? 1 : 0;
- for (uint16_t j = 0; j < stems->length; j++) {
- il_push_operand(il, stems->items[j].position - ref);
- il_push_operand(il, stems->items[j].width);
- ref = stems->items[j].position + stems->items[j].width;
- nn++;
- if (nn >= type2_argument_stack) {
- if (hasmask) {
- il_push_op(il, op_hstemhm);
- } else {
- il_push_op(il, op_hstem);
- }
- il->instr[il->length - 1].arity = nn;
- nn = 0;
- }
- }
- if (hasmask) {
- il_push_op(il, ophm);
- } else {
- il_push_op(il, oph);
- }
- il->instr[il->length - 1].arity = nn;
-}
-static void il_push_stems(cff_CharstringIL *il, glyf_Glyph *g, bool hasmask, bool haswidth) {
- _il_push_stemgroup(il, &g->stemH, hasmask, haswidth, op_hstemhm, op_hstem);
- _il_push_stemgroup(il, &g->stemV, hasmask, haswidth, op_vstemhm, op_vstem);
-}
-cff_CharstringIL *cff_compileGlyphToIL(glyf_Glyph *g, uint16_t defaultWidth,
- uint16_t nominalWidth) {
- cff_CharstringIL *il;
- NEW(il);
- // Convert absolute positions to deltas
- glyf_Contour *tempContours = NULL;
- {
- VQ x = iVQ.neutral();
- VQ y = iVQ.neutral();
- NEW(tempContours, g->contours.length);
- for (uint16_t c = 0; c < g->contours.length; c++) {
- glyf_Contour *contour = &(g->contours.items[c]);
- glyf_Contour *newcontour = &(tempContours[c]);
- glyf_iContour.init(newcontour);
- for (shapeid_t j = 0; j < contour->length; j++) {
- glyf_iContour.push(newcontour, glyf_iPoint.dup(contour->items[j]));
- }
-
- if (newcontour->length > 2 && !newcontour->items[newcontour->length - 1].onCurve) {
- // Duplicate first point for proper CurveTo generation
- glyf_iContour.push(newcontour, glyf_iPoint.dup(newcontour->items[0]));
- }
-
- for (shapeid_t j = 0; j < newcontour->length; j++) {
- VQ dx = iVQ.minus(newcontour->items[j].x, x);
- VQ dy = iVQ.minus(newcontour->items[j].y, y);
- iVQ.copyReplace(&x, newcontour->items[j].x);
- iVQ.copyReplace(&y, newcontour->items[j].y);
- iVQ.replace(&newcontour->items[j].x, dx);
- iVQ.replace(&newcontour->items[j].y, dy);
- }
- }
- iVQ.dispose(&x);
- iVQ.dispose(&y);
- }
-
- bool hasmask =
- g->hintMasks.length || g->contourMasks.length; // we have hint masks or contour masks
- const pos_t glyphADWConst = iVQ.getStill(g->advanceWidth);
- bool haswidth = glyphADWConst != defaultWidth; // we have width operand here
- // Write IL
- if (haswidth) { il_push_operand(il, (int)(glyphADWConst) - (int)(nominalWidth)); }
- il_push_stems(il, g, hasmask, haswidth);
- // Write contour
- shapeid_t contoursSofar = 0;
- shapeid_t pointsSofar = 0;
- shapeid_t jh = 0;
- shapeid_t jm = 0;
- if (hasmask) il_push_masks(il, g, contoursSofar, pointsSofar, &jh, &jm);
- for (shapeid_t c = 0; c < g->contours.length; c++) {
- glyf_Contour *contour = &(tempContours[c]);
- shapeid_t n = contour->length;
- if (n == 0) continue;
- il_moveto(il, contour->items[0].x, contour->items[0].y);
- pointsSofar++;
- if (hasmask) il_push_masks(il, g, contoursSofar, pointsSofar, &jh, &jm);
- // TODO: Generate BLENDs
- for (shapeid_t j = 1; j < n; j++) {
- if (contour->items[j].onCurve) { // A line-to
- il_lineto(il, contour->items[j].x, contour->items[j].y);
- pointsSofar += 1;
- } else if (j < n - 2 // have enough points
- && !contour->items[j + 1].onCurve // next is offcurve
- && contour->items[j + 2].onCurve // and next is oncurve
- ) { // means this is an bezier curve strand
- il_curveto(il, contour->items[j].x,
- contour->items[j].y, // dz1
- contour->items[j + 1].x,
- contour->items[j + 1].y, // dz2
- contour->items[j + 2].x,
- contour->items[j + 2].y); // dz3
- pointsSofar += 3;
- j += 2;
- } else { // invalid offcurve, treat as oncurve
- il_lineto(il, contour->items[j].x, contour->items[j].y);
- pointsSofar++;
- }
- if (hasmask) il_push_masks(il, g, contoursSofar, pointsSofar, &jh, &jm);
- }
- contoursSofar += 1;
- pointsSofar = 0;
- }
- il_push_op(il, op_endchar);
- // delete temp contour array
- for (shapeid_t c = 0; c < g->contours.length; c++) {
- glyf_iContour.dispose(&tempContours[c]);
- }
- FREE(tempContours);
- return il;
-}
-
-// Pattern-based peephole optimization
-static bool il_matchtype(cff_CharstringIL *il, uint32_t j, uint32_t k, cff_InstructionType t) {
- if (k >= il->length) return false;
- for (uint32_t m = j; m < k; m++) {
- if (il->instr[m].type != t) return false;
- }
- return true;
-}
-static bool il_matchop(cff_CharstringIL *il, uint32_t j, int32_t op) {
- if (il->instr[j].type != IL_ITEM_OPERATOR) return false;
- if (il->instr[j].i != op) return false;
- return true;
-}
-static uint8_t zroll(cff_CharstringIL *il, uint32_t j, int32_t op, int32_t op2, ...) {
- uint8_t arity = cff_getStandardArity(op);
- if (arity > 16 || j + arity >= il->length) return 0;
- if ((j == 0 || // We are at the beginning of charstring
- !il_matchtype(il, j - 1, j,
- IL_ITEM_PHANTOM_OPERATOR)) // .. or we are right after a solid operator
- && il_matchop(il, j + arity, op) // The next operator is <op>
- && il_matchtype(il, j, j + arity, IL_ITEM_OPERAND) // And we have correct number of operands
- ) {
- va_list ap;
- uint8_t check = true;
- uint8_t resultArity = arity;
- bool mask[16];
- va_start(ap, op2);
- for (uint32_t m = 0; m < arity; m++) {
- int checkzero = va_arg(ap, int);
- mask[m] = checkzero;
- if (checkzero) {
- resultArity -= 1;
- check = check && il->instr[j + m].d == 0;
- }
- }
- va_end(ap);
- if (check) {
- for (uint32_t m = 0; m < arity; m++) {
- if (mask[m]) { il->instr[j + m].type = IL_ITEM_PHANTOM_OPERAND; }
- }
- il->instr[j + arity].i = op2;
- il->instr[j + arity].arity = resultArity;
- return arity;
- } else {
- return 0;
- }
- } else {
- return 0;
- }
-}
-static uint8_t opop_roll(cff_CharstringIL *il, uint32_t j, int32_t op1, int32_t arity, int32_t op2,
- int32_t resultop) {
- if (j + 1 + arity >= il->length) return 0;
- cff_CharstringInstruction *current = &(il->instr[j]);
- cff_CharstringInstruction *nextop = &(il->instr[j + 1 + arity]);
- if (il_matchop(il, j, op1) // match this operator
- && il_matchtype(il, j + 1, j + 1 + arity, IL_ITEM_OPERAND) // match operands
- && il_matchop(il, j + 1 + arity, op2) // match next operator
- && current->arity + nextop->arity <= type2_argument_stack // stack is not full
- ) {
- current->type = IL_ITEM_PHANTOM_OPERATOR;
- nextop->i = resultop;
- nextop->arity += current->arity;
- return arity + 1;
- } else {
- return 0;
- }
-}
-static uint8_t hvlineto_roll(cff_CharstringIL *il, uint32_t j) {
- if (j + 3 >= il->length) return 0;
- cff_CharstringInstruction *current = &(il->instr[j]);
- // We will check whether operand <checkdelta> is zero
- // ODD EVEN -- current arity
- // hlineto X Y
- // vlineto Y X
- uint32_t checkdelta = ((bool)(current->arity & 1) ^ (bool)(current->i == op_vlineto) ? 1 : 2);
- if ((il_matchop(il, j, op_hlineto) || il_matchop(il, j, op_vlineto)) // a hlineto/vlineto
- && il_matchop(il, j + 3, op_rlineto) // followed by a lineto
- && il_matchtype(il, j + 1, j + 3, IL_ITEM_OPERAND) // have enough operands
- && il->instr[j + checkdelta].d == 0 // and it is a h/v
- && current->arity + 1 <= type2_argument_stack // we have enough stack space
- ) {
- il->instr[j + checkdelta].type = IL_ITEM_PHANTOM_OPERAND;
- il->instr[j].type = IL_ITEM_PHANTOM_OPERATOR;
- il->instr[j + 3].i = current->i;
- il->instr[j + 3].arity = current->arity + 1;
- return 3;
- } else {
- return 0;
- }
-}
-static uint8_t hvvhcurve_roll(cff_CharstringIL *il, uint32_t j) {
- if (!il_matchop(il, j, op_hvcurveto) && !il_matchop(il, j, op_vhcurveto)) return 0;
- cff_CharstringInstruction *current = &(il->instr[j]);
- // Exit in case of array not long enough or we have already ended
- if (j + 7 >= il->length || current->arity & 1) return 0;
- bool hvcase = (bool)((current->arity >> 2) & 1) ^ (bool)(current->i == op_hvcurveto);
- // We will check whether operand <checkdelta> is zero
- // ODD EVEN -- current arity divided by 4
- // hvcurveto X Y
- // vhcurveto Y X
- uint32_t checkdelta1 = hvcase ? 2 : 1;
- uint32_t checkdelta2 = hvcase ? 5 : 6;
- if (il_matchop(il, j + 7, op_rrcurveto) // followed by a curveto
- && il_matchtype(il, j + 1, j + 7, IL_ITEM_OPERAND) // have enough operands
- && il->instr[j + checkdelta1].d == 0 // and it is a h/v
- ) {
- if (il->instr[j + checkdelta2].d == 0 && current->arity + 4 <= type2_argument_stack) {
- // The Standard case
- il->instr[j + checkdelta1].type = IL_ITEM_PHANTOM_OPERAND;
- il->instr[j + checkdelta2].type = IL_ITEM_PHANTOM_OPERAND;
- il->instr[j].type = IL_ITEM_PHANTOM_OPERATOR;
- il->instr[j + 7].i = current->i;
- il->instr[j + 7].arity = current->arity + 4;
- return 7;
- } else if (current->arity + 5 <= type2_argument_stack) {
- // The trailing case
- il->instr[j + checkdelta1].type = IL_ITEM_PHANTOM_OPERAND;
- il->instr[j].type = IL_ITEM_PHANTOM_OPERATOR;
- il->instr[j + 7].i = current->i;
- il->instr[j + 7].arity = current->arity + 5;
- if (hvcase) {
- // Swap the last two operands because hvcurveto's trailing operand is in y-x order
- double t = il->instr[j + 5].d;
- il->instr[j + 5].d = il->instr[j + 6].d;
- il->instr[j + 6].d = t;
- }
- return 7;
- } else {
- return 0;
- }
- } else {
- return 0;
- }
-}
-static uint8_t hhvvcurve_roll(cff_CharstringIL *il, uint32_t j) {
- if (!il_matchop(il, j, op_hhcurveto) && !il_matchop(il, j, op_vvcurveto)) return 0;
- cff_CharstringInstruction *current = &(il->instr[j]);
- // Exit in case of array not long enough or we have already ended
- if (j + 7 >= il->length) return 0;
- bool hh = current->i == op_hhcurveto;
- uint32_t checkdelta1 = hh ? 2 : 1;
- uint32_t checkdelta2 = hh ? 6 : 5;
- if (il_matchop(il, j + 7, op_rrcurveto) // followed by a curveto
- && il_matchtype(il, j + 1, j + 7, IL_ITEM_OPERAND) // have enough operands
- && il->instr[j + checkdelta1].d == 0 // and it is a h/v
- && il->instr[j + checkdelta2].d == 0 // and it is a h/v
- && current->arity + 4 <= type2_argument_stack) {
- il->instr[j + checkdelta1].type = IL_ITEM_PHANTOM_OPERAND;
- il->instr[j + checkdelta2].type = IL_ITEM_PHANTOM_OPERAND;
- il->instr[j].type = IL_ITEM_PHANTOM_OPERATOR;
- il->instr[j + 7].i = current->i;
- il->instr[j + 7].arity = current->arity + 4;
- return 7;
- } else {
- return 0;
- }
-}
-static uint32_t nextstop(cff_CharstringIL *il, uint32_t j) {
- uint32_t delta = 0;
- for (; j + delta < il->length && il->instr[j + delta].type == IL_ITEM_OPERAND; delta++)
- ;
- return delta;
-}
-#define ROLL_FALL(x) \
- if ((r = (x))) return r;
-static uint8_t decideAdvance(cff_CharstringIL *il, uint32_t j, uint8_t optimizeLevel) {
- uint8_t r = 0;
- ROLL_FALL(zroll(il, j, op_rlineto, op_hlineto, 0, 1)); // rlineto -> hlineto
- ROLL_FALL(zroll(il, j, op_rlineto, op_vlineto, 1, 0)); // rlineto -> vlineto
- ROLL_FALL(zroll(il, j, op_rmoveto, op_hmoveto, 0, 1)); // rmoveto -> hmoveto
- ROLL_FALL(zroll(il, j, op_rmoveto, op_vmoveto, 1, 0)); // rmoveto -> vmoveto
- ROLL_FALL(zroll(il, j, op_rrcurveto, op_hvcurveto, 0, 1, 0, 0, 1, 0)); // rrcurveto->hvcurveto
- ROLL_FALL(zroll(il, j, op_rrcurveto, op_vhcurveto, 1, 0, 0, 0, 0, 1)); // rrcurveto->vhcurveto
- ROLL_FALL(zroll(il, j, op_rrcurveto, op_hhcurveto, 0, 1, 0, 0, 0, 1)); // rrcurveto->hhcurveto
- ROLL_FALL(zroll(il, j, op_rrcurveto, op_vvcurveto, 1, 0, 0, 0, 1, 0)); // rrcurveto->vvcurveto
- ROLL_FALL(opop_roll(il, j, op_rrcurveto, 6, op_rrcurveto, op_rrcurveto)); // rrcurveto roll
- ROLL_FALL(opop_roll(il, j, op_rrcurveto, 2, op_rlineto, op_rcurveline)); // rcurveline roll
- ROLL_FALL(opop_roll(il, j, op_rlineto, 6, op_rrcurveto, op_rlinecurve)); // rlinecurve roll
- ROLL_FALL(opop_roll(il, j, op_rlineto, 2, op_rlineto, op_rlineto)); // rlineto roll
- ROLL_FALL(opop_roll(il, j, op_hstemhm, 0, op_hintmask, op_hintmask)); // hintmask roll
- ROLL_FALL(opop_roll(il, j, op_vstemhm, 0, op_hintmask, op_hintmask)); // hintmask roll
- ROLL_FALL(opop_roll(il, j, op_hstemhm, 0, op_cntrmask, op_cntrmask)); // cntrmask roll
- ROLL_FALL(opop_roll(il, j, op_vstemhm, 0, op_cntrmask, op_cntrmask)); // cntrmask roll
- ROLL_FALL(hvlineto_roll(il, j)); // hlineto-vlineto roll
- ROLL_FALL(hhvvcurve_roll(il, j)); // hhcurveto-vvcurveto roll
- ROLL_FALL(hvvhcurve_roll(il, j)); // hvcurveto-vhcurveto roll
- ROLL_FALL(nextstop(il, j)); // move to next stop for operand match
- return 1; // nothing match
-}
-
-void cff_optimizeIL(cff_CharstringIL *il, const otfcc_Options *options) {
- if (!options->cff_rollCharString) return;
- uint32_t j = 0;
- while (j < il->length) {
- j += decideAdvance(il, j, options->cff_rollCharString);
- }
-}
-
-// IL to buffer conversion
-caryll_Buffer *cff_build_IL(cff_CharstringIL *il) {
- caryll_Buffer *blob = bufnew();
-
- for (uint16_t j = 0; j < il->length; j++) {
- switch (il->instr[j].type) {
- case IL_ITEM_OPERAND: {
- cff_mergeCS2Operand(blob, il->instr[j].d);
- break;
- }
- case IL_ITEM_OPERATOR: {
- cff_mergeCS2Operator(blob, il->instr[j].i);
- break;
- }
- case IL_ITEM_SPECIAL: {
- cff_mergeCS2Special(blob, il->instr[j].i);
- break;
- }
- default:
- break;
- }
- }
- return blob;
-}
-
-cff_CharstringIL *cff_shrinkIL(cff_CharstringIL *il) {
- cff_CharstringIL *out;
- NEW(out);
- for (uint16_t j = 0; j < il->length; j++) {
- switch (il->instr[j].type) {
- case IL_ITEM_OPERAND: {
- il_push_operand(out, il->instr[j].d);
- break;
- }
- case IL_ITEM_OPERATOR: {
- il_push_op(out, il->instr[j].i);
- break;
- }
- case IL_ITEM_SPECIAL: {
- il_push_special(out, il->instr[j].i);
- break;
- }
- default:
- break;
- }
- }
- return out;
-}
-
-void cff_ILmergeIL(cff_CharstringIL *self, cff_CharstringIL *il) {
- for (uint16_t j = 0; j < il->length; j++) {
- switch (il->instr[j].type) {
- case IL_ITEM_OPERAND: {
- il_push_operand(self, il->instr[j].d);
- break;
- }
- case IL_ITEM_OPERATOR: {
- il_push_op(self, il->instr[j].i);
- break;
- }
- case IL_ITEM_SPECIAL: {
- il_push_special(self, il->instr[j].i);
- break;
- }
- default:
- break;
- }
- }
-}
-
-bool instruction_eq(cff_CharstringInstruction *z1, cff_CharstringInstruction *z2) {
- if (z1->type == z2->type) {
- if (z1->type == IL_ITEM_OPERAND || z1->type == IL_ITEM_PHANTOM_OPERAND) {
- return z1->d == z2->d;
- } else {
- return z1->i == z2->i;
- }
- } else {
- return false;
- }
-}
-
-bool cff_ilEqual(cff_CharstringIL *a, cff_CharstringIL *b) {
- if (!a || !b) return false;
- if (a->length != b->length) return false;
- for (uint32_t j = 0; j < a->length; j++)
- if (!instruction_eq(a->instr + j, b->instr + j)) { return false; }
- return true;
-}