Build NapCat Artifacts / Windows Loader Test (push) Canceled after 0s
Build NapCat Artifacts / Type Check & Test (push) Canceled after 0s
Build NapCat Artifacts / Build NapCat.Framework (push) Canceled after 0s
Build NapCat Artifacts / Build NapCat.Shell (push) Canceled after 0s
508 lines
14 KiB
Plaintext
508 lines
14 KiB
Plaintext
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.default = parseCFFCharstring;
|
|
/**
|
|
* @file 解析cff字形
|
|
* @author mengke01(kekee000@gmail.com)
|
|
*/
|
|
|
|
/**
|
|
* 解析cff字形,返回直线和三次bezier曲线点数组
|
|
*
|
|
* @param {Array} code 操作码
|
|
* @param {Object} font 相关联的font对象
|
|
* @param {number} index glyf索引
|
|
* @return {Object} glyf对象
|
|
*/
|
|
function parseCFFCharstring(code, font, index) {
|
|
var c1x;
|
|
var c1y;
|
|
var c2x;
|
|
var c2y;
|
|
var contours = [];
|
|
var contour = [];
|
|
var stack = [];
|
|
var glyfs = [];
|
|
var nStems = 0;
|
|
var haveWidth = false;
|
|
var width = font.defaultWidthX;
|
|
var open = false;
|
|
var x = 0;
|
|
var y = 0;
|
|
function lineTo(x, y) {
|
|
contour.push({
|
|
onCurve: true,
|
|
x: x,
|
|
y: y
|
|
});
|
|
}
|
|
function curveTo(c1x, c1y, c2x, c2y, x, y) {
|
|
contour.push({
|
|
x: c1x,
|
|
y: c1y
|
|
});
|
|
contour.push({
|
|
x: c2x,
|
|
y: c2y
|
|
});
|
|
contour.push({
|
|
onCurve: true,
|
|
x: x,
|
|
y: y
|
|
});
|
|
}
|
|
function newContour(x, y) {
|
|
if (open) {
|
|
contours.push(contour);
|
|
}
|
|
contour = [];
|
|
lineTo(x, y);
|
|
open = true;
|
|
}
|
|
function parseStems() {
|
|
// The number of stem operators on the stack is always even.
|
|
// If the value is uneven, that means a width is specified.
|
|
var hasWidthArg = stack.length % 2 !== 0;
|
|
if (hasWidthArg && !haveWidth) {
|
|
width = stack.shift() + font.nominalWidthX;
|
|
}
|
|
nStems += stack.length >> 1;
|
|
stack.length = 0;
|
|
haveWidth = true;
|
|
}
|
|
function parse(code) {
|
|
var b1;
|
|
var b2;
|
|
var b3;
|
|
var b4;
|
|
var codeIndex;
|
|
var subrCode;
|
|
var jpx;
|
|
var jpy;
|
|
var c3x;
|
|
var c3y;
|
|
var c4x;
|
|
var c4y;
|
|
var i = 0;
|
|
while (i < code.length) {
|
|
var v = code[i];
|
|
i += 1;
|
|
switch (v) {
|
|
case 1:
|
|
// hstem
|
|
parseStems();
|
|
break;
|
|
case 3:
|
|
// vstem
|
|
parseStems();
|
|
break;
|
|
case 4:
|
|
// vmoveto
|
|
if (stack.length > 1 && !haveWidth) {
|
|
width = stack.shift() + font.nominalWidthX;
|
|
haveWidth = true;
|
|
}
|
|
y += stack.pop();
|
|
newContour(x, y);
|
|
break;
|
|
case 5:
|
|
// rlineto
|
|
while (stack.length > 0) {
|
|
x += stack.shift();
|
|
y += stack.shift();
|
|
lineTo(x, y);
|
|
}
|
|
break;
|
|
case 6:
|
|
// hlineto
|
|
while (stack.length > 0) {
|
|
x += stack.shift();
|
|
lineTo(x, y);
|
|
if (stack.length === 0) {
|
|
break;
|
|
}
|
|
y += stack.shift();
|
|
lineTo(x, y);
|
|
}
|
|
break;
|
|
case 7:
|
|
// vlineto
|
|
while (stack.length > 0) {
|
|
y += stack.shift();
|
|
lineTo(x, y);
|
|
if (stack.length === 0) {
|
|
break;
|
|
}
|
|
x += stack.shift();
|
|
lineTo(x, y);
|
|
}
|
|
break;
|
|
case 8:
|
|
// rrcurveto
|
|
while (stack.length > 0) {
|
|
c1x = x + stack.shift();
|
|
c1y = y + stack.shift();
|
|
c2x = c1x + stack.shift();
|
|
c2y = c1y + stack.shift();
|
|
x = c2x + stack.shift();
|
|
y = c2y + stack.shift();
|
|
curveTo(c1x, c1y, c2x, c2y, x, y);
|
|
}
|
|
break;
|
|
case 10:
|
|
// callsubr
|
|
codeIndex = stack.pop() + font.subrsBias;
|
|
subrCode = font.subrs[codeIndex];
|
|
if (subrCode) {
|
|
parse(subrCode);
|
|
}
|
|
break;
|
|
case 11:
|
|
// return
|
|
return;
|
|
case 12:
|
|
// flex operators
|
|
v = code[i];
|
|
i += 1;
|
|
switch (v) {
|
|
case 35:
|
|
// flex
|
|
// |- dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 dx6 dy6 fd flex (12 35) |-
|
|
c1x = x + stack.shift(); // dx1
|
|
c1y = y + stack.shift(); // dy1
|
|
c2x = c1x + stack.shift(); // dx2
|
|
c2y = c1y + stack.shift(); // dy2
|
|
jpx = c2x + stack.shift(); // dx3
|
|
jpy = c2y + stack.shift(); // dy3
|
|
c3x = jpx + stack.shift(); // dx4
|
|
c3y = jpy + stack.shift(); // dy4
|
|
c4x = c3x + stack.shift(); // dx5
|
|
c4y = c3y + stack.shift(); // dy5
|
|
x = c4x + stack.shift(); // dx6
|
|
y = c4y + stack.shift(); // dy6
|
|
stack.shift(); // flex depth
|
|
curveTo(c1x, c1y, c2x, c2y, jpx, jpy);
|
|
curveTo(c3x, c3y, c4x, c4y, x, y);
|
|
break;
|
|
case 34:
|
|
// hflex
|
|
// |- dx1 dx2 dy2 dx3 dx4 dx5 dx6 hflex (12 34) |-
|
|
c1x = x + stack.shift(); // dx1
|
|
c1y = y; // dy1
|
|
c2x = c1x + stack.shift(); // dx2
|
|
c2y = c1y + stack.shift(); // dy2
|
|
jpx = c2x + stack.shift(); // dx3
|
|
jpy = c2y; // dy3
|
|
c3x = jpx + stack.shift(); // dx4
|
|
c3y = c2y; // dy4
|
|
c4x = c3x + stack.shift(); // dx5
|
|
c4y = y; // dy5
|
|
x = c4x + stack.shift(); // dx6
|
|
curveTo(c1x, c1y, c2x, c2y, jpx, jpy);
|
|
curveTo(c3x, c3y, c4x, c4y, x, y);
|
|
break;
|
|
case 36:
|
|
// hflex1
|
|
// |- dx1 dy1 dx2 dy2 dx3 dx4 dx5 dy5 dx6 hflex1 (12 36) |-
|
|
c1x = x + stack.shift(); // dx1
|
|
c1y = y + stack.shift(); // dy1
|
|
c2x = c1x + stack.shift(); // dx2
|
|
c2y = c1y + stack.shift(); // dy2
|
|
jpx = c2x + stack.shift(); // dx3
|
|
jpy = c2y; // dy3
|
|
c3x = jpx + stack.shift(); // dx4
|
|
c3y = c2y; // dy4
|
|
c4x = c3x + stack.shift(); // dx5
|
|
c4y = c3y + stack.shift(); // dy5
|
|
x = c4x + stack.shift(); // dx6
|
|
curveTo(c1x, c1y, c2x, c2y, jpx, jpy);
|
|
curveTo(c3x, c3y, c4x, c4y, x, y);
|
|
break;
|
|
case 37:
|
|
// flex1
|
|
// |- dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 d6 flex1 (12 37) |-
|
|
c1x = x + stack.shift(); // dx1
|
|
c1y = y + stack.shift(); // dy1
|
|
c2x = c1x + stack.shift(); // dx2
|
|
c2y = c1y + stack.shift(); // dy2
|
|
jpx = c2x + stack.shift(); // dx3
|
|
jpy = c2y + stack.shift(); // dy3
|
|
c3x = jpx + stack.shift(); // dx4
|
|
c3y = jpy + stack.shift(); // dy4
|
|
c4x = c3x + stack.shift(); // dx5
|
|
c4y = c3y + stack.shift(); // dy5
|
|
if (Math.abs(c4x - x) > Math.abs(c4y - y)) {
|
|
x = c4x + stack.shift();
|
|
} else {
|
|
y = c4y + stack.shift();
|
|
}
|
|
curveTo(c1x, c1y, c2x, c2y, jpx, jpy);
|
|
curveTo(c3x, c3y, c4x, c4y, x, y);
|
|
break;
|
|
default:
|
|
console.warn('Glyph ' + index + ': unknown operator ' + (1200 + v));
|
|
stack.length = 0;
|
|
}
|
|
break;
|
|
case 14:
|
|
// endchar
|
|
if (stack.length === 1 && !haveWidth) {
|
|
width = stack.shift() + font.nominalWidthX;
|
|
haveWidth = true;
|
|
} else if (stack.length === 4) {
|
|
glyfs[1] = {
|
|
glyphIndex: font.charset.indexOf(font.encoding[stack.pop()]),
|
|
transform: {
|
|
a: 1,
|
|
b: 0,
|
|
c: 0,
|
|
d: 1,
|
|
e: 0,
|
|
f: 0
|
|
}
|
|
};
|
|
glyfs[0] = {
|
|
glyphIndex: font.charset.indexOf(font.encoding[stack.pop()]),
|
|
transform: {
|
|
a: 1,
|
|
b: 0,
|
|
c: 0,
|
|
d: 1,
|
|
e: 0,
|
|
f: 0
|
|
}
|
|
};
|
|
glyfs[1].transform.f = stack.pop();
|
|
glyfs[1].transform.e = stack.pop();
|
|
} else if (stack.length === 5) {
|
|
if (!haveWidth) {
|
|
width = stack.shift() + font.nominalWidthX;
|
|
}
|
|
haveWidth = true;
|
|
glyfs[1] = {
|
|
glyphIndex: font.charset.indexOf(font.encoding[stack.pop()]),
|
|
transform: {
|
|
a: 1,
|
|
b: 0,
|
|
c: 0,
|
|
d: 1,
|
|
e: 0,
|
|
f: 0
|
|
}
|
|
};
|
|
glyfs[0] = {
|
|
glyphIndex: font.charset.indexOf(font.encoding[stack.pop()]),
|
|
transform: {
|
|
a: 1,
|
|
b: 0,
|
|
c: 0,
|
|
d: 1,
|
|
e: 0,
|
|
f: 0
|
|
}
|
|
};
|
|
glyfs[1].transform.f = stack.pop();
|
|
glyfs[1].transform.e = stack.pop();
|
|
}
|
|
if (open) {
|
|
contours.push(contour);
|
|
open = false;
|
|
}
|
|
break;
|
|
case 18:
|
|
// hstemhm
|
|
parseStems();
|
|
break;
|
|
case 19: // hintmask
|
|
case 20:
|
|
// cntrmask
|
|
parseStems();
|
|
i += nStems + 7 >> 3;
|
|
break;
|
|
case 21:
|
|
// rmoveto
|
|
if (stack.length > 2 && !haveWidth) {
|
|
width = stack.shift() + font.nominalWidthX;
|
|
haveWidth = true;
|
|
}
|
|
y += stack.pop();
|
|
x += stack.pop();
|
|
newContour(x, y);
|
|
break;
|
|
case 22:
|
|
// hmoveto
|
|
if (stack.length > 1 && !haveWidth) {
|
|
width = stack.shift() + font.nominalWidthX;
|
|
haveWidth = true;
|
|
}
|
|
x += stack.pop();
|
|
newContour(x, y);
|
|
break;
|
|
case 23:
|
|
// vstemhm
|
|
parseStems();
|
|
break;
|
|
case 24:
|
|
// rcurveline
|
|
while (stack.length > 2) {
|
|
c1x = x + stack.shift();
|
|
c1y = y + stack.shift();
|
|
c2x = c1x + stack.shift();
|
|
c2y = c1y + stack.shift();
|
|
x = c2x + stack.shift();
|
|
y = c2y + stack.shift();
|
|
curveTo(c1x, c1y, c2x, c2y, x, y);
|
|
}
|
|
x += stack.shift();
|
|
y += stack.shift();
|
|
lineTo(x, y);
|
|
break;
|
|
case 25:
|
|
// rlinecurve
|
|
while (stack.length > 6) {
|
|
x += stack.shift();
|
|
y += stack.shift();
|
|
lineTo(x, y);
|
|
}
|
|
c1x = x + stack.shift();
|
|
c1y = y + stack.shift();
|
|
c2x = c1x + stack.shift();
|
|
c2y = c1y + stack.shift();
|
|
x = c2x + stack.shift();
|
|
y = c2y + stack.shift();
|
|
curveTo(c1x, c1y, c2x, c2y, x, y);
|
|
break;
|
|
case 26:
|
|
// vvcurveto
|
|
if (stack.length % 2) {
|
|
x += stack.shift();
|
|
}
|
|
while (stack.length > 0) {
|
|
c1x = x;
|
|
c1y = y + stack.shift();
|
|
c2x = c1x + stack.shift();
|
|
c2y = c1y + stack.shift();
|
|
x = c2x;
|
|
y = c2y + stack.shift();
|
|
curveTo(c1x, c1y, c2x, c2y, x, y);
|
|
}
|
|
break;
|
|
case 27:
|
|
// hhcurveto
|
|
if (stack.length % 2) {
|
|
y += stack.shift();
|
|
}
|
|
while (stack.length > 0) {
|
|
c1x = x + stack.shift();
|
|
c1y = y;
|
|
c2x = c1x + stack.shift();
|
|
c2y = c1y + stack.shift();
|
|
x = c2x + stack.shift();
|
|
y = c2y;
|
|
curveTo(c1x, c1y, c2x, c2y, x, y);
|
|
}
|
|
break;
|
|
case 28:
|
|
// shortint
|
|
b1 = code[i];
|
|
b2 = code[i + 1];
|
|
stack.push((b1 << 24 | b2 << 16) >> 16);
|
|
i += 2;
|
|
break;
|
|
case 29:
|
|
// callgsubr
|
|
codeIndex = stack.pop() + font.gsubrsBias;
|
|
subrCode = font.gsubrs[codeIndex];
|
|
if (subrCode) {
|
|
parse(subrCode);
|
|
}
|
|
break;
|
|
case 30:
|
|
// vhcurveto
|
|
while (stack.length > 0) {
|
|
c1x = x;
|
|
c1y = y + stack.shift();
|
|
c2x = c1x + stack.shift();
|
|
c2y = c1y + stack.shift();
|
|
x = c2x + stack.shift();
|
|
y = c2y + (stack.length === 1 ? stack.shift() : 0);
|
|
curveTo(c1x, c1y, c2x, c2y, x, y);
|
|
if (stack.length === 0) {
|
|
break;
|
|
}
|
|
c1x = x + stack.shift();
|
|
c1y = y;
|
|
c2x = c1x + stack.shift();
|
|
c2y = c1y + stack.shift();
|
|
y = c2y + stack.shift();
|
|
x = c2x + (stack.length === 1 ? stack.shift() : 0);
|
|
curveTo(c1x, c1y, c2x, c2y, x, y);
|
|
}
|
|
break;
|
|
case 31:
|
|
// hvcurveto
|
|
while (stack.length > 0) {
|
|
c1x = x + stack.shift();
|
|
c1y = y;
|
|
c2x = c1x + stack.shift();
|
|
c2y = c1y + stack.shift();
|
|
y = c2y + stack.shift();
|
|
x = c2x + (stack.length === 1 ? stack.shift() : 0);
|
|
curveTo(c1x, c1y, c2x, c2y, x, y);
|
|
if (stack.length === 0) {
|
|
break;
|
|
}
|
|
c1x = x;
|
|
c1y = y + stack.shift();
|
|
c2x = c1x + stack.shift();
|
|
c2y = c1y + stack.shift();
|
|
x = c2x + stack.shift();
|
|
y = c2y + (stack.length === 1 ? stack.shift() : 0);
|
|
curveTo(c1x, c1y, c2x, c2y, x, y);
|
|
}
|
|
break;
|
|
default:
|
|
if (v < 32) {
|
|
console.warn('Glyph ' + index + ': unknown operator ' + v);
|
|
} else if (v < 247) {
|
|
stack.push(v - 139);
|
|
} else if (v < 251) {
|
|
b1 = code[i];
|
|
i += 1;
|
|
stack.push((v - 247) * 256 + b1 + 108);
|
|
} else if (v < 255) {
|
|
b1 = code[i];
|
|
i += 1;
|
|
stack.push(-(v - 251) * 256 - b1 - 108);
|
|
} else {
|
|
b1 = code[i];
|
|
b2 = code[i + 1];
|
|
b3 = code[i + 2];
|
|
b4 = code[i + 3];
|
|
i += 4;
|
|
stack.push((b1 << 24 | b2 << 16 | b3 << 8 | b4) / 65536);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
parse(code);
|
|
var glyf = {
|
|
// 移除重复的起点和终点
|
|
contours: contours.map(function (contour) {
|
|
var last = contour.length - 1;
|
|
if (contour[0].x === contour[last].x && contour[0].y === contour[last].y) {
|
|
contour.splice(last, 1);
|
|
}
|
|
return contour;
|
|
}),
|
|
advanceWidth: width
|
|
};
|
|
if (glyfs.length) {
|
|
glyf.compound = true;
|
|
glyf.glyfs = glyfs;
|
|
}
|
|
return glyf;
|
|
} |