forked from enviPath/enviPy
Current Dev State
This commit is contained in:
54
static/js/ketcher2/node_modules/svg2ttf/lib/math.js
generated
vendored
Normal file
54
static/js/ketcher2/node_modules/svg2ttf/lib/math.js
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
'use strict';
|
||||
|
||||
function Point(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
Point.prototype.add = function (point) {
|
||||
return new Point(this.x + point.x, this.y + point.y);
|
||||
};
|
||||
|
||||
Point.prototype.sub = function (point) {
|
||||
return new Point(this.x - point.x, this.y - point.y);
|
||||
};
|
||||
|
||||
Point.prototype.mul = function (value) {
|
||||
return new Point(this.x * value, this.y * value);
|
||||
};
|
||||
|
||||
Point.prototype.div = function (value) {
|
||||
return new Point(this.x / value, this.y / value);
|
||||
};
|
||||
|
||||
Point.prototype.dist = function () {
|
||||
return Math.sqrt(this.x * this.x + this.y * this.y);
|
||||
};
|
||||
|
||||
Point.prototype.sqr = function () {
|
||||
return this.x * this.x + this.y * this.y;
|
||||
};
|
||||
|
||||
/*
|
||||
* Check if 3 points are in line, and second in the midle.
|
||||
* Used to replace quad curves with lines or join lines
|
||||
*
|
||||
*/
|
||||
function isInLine(p1, m, p2, accuracy) {
|
||||
var a = p1.sub(m).sqr();
|
||||
var b = p2.sub(m).sqr();
|
||||
var c = p1.sub(p2).sqr();
|
||||
|
||||
// control point not between anchors
|
||||
if ((a > (b + c)) || (b > (a + c))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// count distance via scalar multiplication
|
||||
var distance = Math.sqrt(Math.pow((p1.x - m.x) * (p2.y - m.y) - (p2.x - m.x) * (p1.y - m.y), 2) / c);
|
||||
|
||||
return distance < accuracy ? true : false;
|
||||
}
|
||||
|
||||
module.exports.Point = Point;
|
||||
module.exports.isInLine = isInLine;
|
||||
348
static/js/ketcher2/node_modules/svg2ttf/lib/sfnt.js
generated
vendored
Normal file
348
static/js/ketcher2/node_modules/svg2ttf/lib/sfnt.js
generated
vendored
Normal file
@ -0,0 +1,348 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
|
||||
function Font() {
|
||||
this.ascent = 850;
|
||||
this.copyright = '';
|
||||
this.createdDate = new Date();
|
||||
this.glyphs = [];
|
||||
this.ligatures = [];
|
||||
// Maping of code points to glyphs.
|
||||
// Keys are actually numeric, thus should be `parseInt`ed.
|
||||
this.codePoints = {};
|
||||
this.isFixedPitch = 0;
|
||||
this.italicAngle = 0;
|
||||
this.familyClass = 0; // No Classification
|
||||
this.familyName = '';
|
||||
this.fsSelection = 0x40; // Characters are in the standard weight/style for the font.
|
||||
// Non zero value can cause issues in IE, https://github.com/fontello/svg2ttf/issues/45
|
||||
this.fsType = 0;
|
||||
this.lowestRecPPEM = 8;
|
||||
this.macStyle = 0;
|
||||
this.modifiedDate = new Date();
|
||||
this.panose = {
|
||||
familyType: 2, // Latin Text
|
||||
serifStyle: 0, // any
|
||||
weight: 5, // book
|
||||
proportion: 3, //modern
|
||||
contrast: 0, //any
|
||||
strokeVariation: 0, //any,
|
||||
armStyle: 0, //any,
|
||||
letterform: 0, //any,
|
||||
midline: 0, //any,
|
||||
xHeight: 0 //any,
|
||||
};
|
||||
this.revision = 1;
|
||||
this.sfntNames = [];
|
||||
this.underlineThickness = 0;
|
||||
this.unitsPerEm = 1000;
|
||||
this.weightClass = 400; // normal
|
||||
this.width = 1000;
|
||||
this.widthClass = 5; // Medium (normal)
|
||||
this.ySubscriptXOffset = 0;
|
||||
this.ySuperscriptXOffset = 0;
|
||||
this.int_descent = -150;
|
||||
|
||||
//getters and setters
|
||||
|
||||
Object.defineProperty(this, 'descent', {
|
||||
get: function () {
|
||||
return this.int_descent;
|
||||
},
|
||||
set: function (value) {
|
||||
this.int_descent = parseInt(Math.round(-Math.abs(value)), 10);
|
||||
}
|
||||
});
|
||||
|
||||
this.__defineGetter__('avgCharWidth', function () {
|
||||
if (this.glyphs.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
var widths = _.map(this.glyphs, 'width');
|
||||
|
||||
return parseInt(widths.reduce(function (prev, cur) {
|
||||
return prev + cur;
|
||||
}) / widths.length, 10);
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'ySubscriptXSize', {
|
||||
get: function () {
|
||||
return parseInt(!_.isUndefined(this.int_ySubscriptXSize) ? this.int_ySubscriptXSize : (this.width * 0.6347), 10);
|
||||
},
|
||||
set: function (value) {
|
||||
this.int_ySubscriptXSize = value;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'ySubscriptYSize', {
|
||||
get: function () {
|
||||
return parseInt(!_.isUndefined(this.int_ySubscriptYSize) ? this.int_ySubscriptYSize : ((this.ascent - this.descent) * 0.7), 10);
|
||||
},
|
||||
set: function (value) {
|
||||
this.int_ySubscriptYSize = value;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'ySubscriptYOffset', {
|
||||
get: function () {
|
||||
return parseInt(!_.isUndefined(this.int_ySubscriptYOffset) ? this.int_ySubscriptYOffset : ((this.ascent - this.descent) * 0.14), 10);
|
||||
},
|
||||
set: function (value) {
|
||||
this.int_ySubscriptYOffset = value;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'ySuperscriptXSize', {
|
||||
get: function () {
|
||||
return parseInt(!_.isUndefined(this.int_ySuperscriptXSize) ? this.int_ySuperscriptXSize : (this.width * 0.6347), 10);
|
||||
},
|
||||
set: function (value) {
|
||||
this.int_ySuperscriptXSize = value;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'ySuperscriptYSize', {
|
||||
get: function () {
|
||||
return parseInt(!_.isUndefined(this.int_ySuperscriptYSize) ? this.int_ySuperscriptYSize : ((this.ascent - this.descent) * 0.7), 10);
|
||||
},
|
||||
set: function (value) {
|
||||
this.int_ySuperscriptYSize = value;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'ySuperscriptYOffset', {
|
||||
get: function () {
|
||||
return parseInt(!_.isUndefined(this.int_ySuperscriptYOffset) ? this.int_ySuperscriptYOffset : ((this.ascent - this.descent) * 0.48), 10);
|
||||
},
|
||||
set: function (value) {
|
||||
this.int_ySuperscriptYOffset = value;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'yStrikeoutSize', {
|
||||
get: function () {
|
||||
return parseInt(!_.isUndefined(this.int_yStrikeoutSize) ? this.int_yStrikeoutSize : ((this.ascent - this.descent) * 0.049), 10);
|
||||
},
|
||||
set: function (value) {
|
||||
this.int_yStrikeoutSize = value;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'yStrikeoutPosition', {
|
||||
get: function () {
|
||||
return parseInt(!_.isUndefined(this.int_yStrikeoutPosition) ? this.int_yStrikeoutPosition : ((this.ascent - this.descent) * 0.258), 10);
|
||||
},
|
||||
set: function (value) {
|
||||
this.int_yStrikeoutPosition = value;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'minLsb', {
|
||||
get: function () {
|
||||
return parseInt(_.min(_.map(this.glyphs, 'xMin')), 10);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'minRsb', {
|
||||
get: function () {
|
||||
if (!this.glyphs.length) return parseInt(this.width, 10);
|
||||
|
||||
return parseInt(_.reduce(this.glyphs, function (minRsb, glyph) {
|
||||
return Math.min(minRsb, glyph.width - glyph.xMax);
|
||||
}, 0), 10);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'xMin', {
|
||||
get: function () {
|
||||
if (!this.glyphs.length) return this.width;
|
||||
|
||||
return _.reduce(this.glyphs, function (xMin, glyph) {
|
||||
return Math.min(xMin, glyph.xMin);
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'yMin', {
|
||||
get: function () {
|
||||
if (!this.glyphs.length) return this.width;
|
||||
|
||||
return _.reduce(this.glyphs, function (yMin, glyph) {
|
||||
return Math.min(yMin, glyph.yMin);
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'xMax', {
|
||||
get: function () {
|
||||
if (!this.glyphs.length) return this.width;
|
||||
|
||||
return _.reduce(this.glyphs, function (xMax, glyph) {
|
||||
return Math.max(xMax, glyph.xMax);
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'yMax', {
|
||||
get: function () {
|
||||
if (!this.glyphs.length) return this.width;
|
||||
|
||||
return _.reduce(this.glyphs, function (yMax, glyph) {
|
||||
return Math.max(yMax, glyph.yMax);
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'avgWidth', {
|
||||
get: function () {
|
||||
var len = this.glyphs.length;
|
||||
|
||||
if (len === 0) {
|
||||
return this.width;
|
||||
}
|
||||
|
||||
var sumWidth = _.reduce(this.glyphs, function (sumWidth, glyph) {
|
||||
return sumWidth + glyph.width;
|
||||
}, 0);
|
||||
|
||||
return Math.round(sumWidth / len);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'maxWidth', {
|
||||
get: function () {
|
||||
if (!this.glyphs.length) return this.width;
|
||||
|
||||
return _.reduce(this.glyphs, function (maxWidth, glyph) {
|
||||
return Math.max(maxWidth, glyph.width);
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'maxExtent', {
|
||||
get: function () {
|
||||
if (!this.glyphs.length) return this.width;
|
||||
|
||||
return _.reduce(this.glyphs, function (maxExtent, glyph) {
|
||||
return Math.max(maxExtent, glyph.xMax /*- glyph.xMin*/);
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
// Property used for `sTypoLineGap` in OS/2 and not used for `lineGap` in HHEA, because
|
||||
// non zero lineGap causes bad offset in IE, https://github.com/fontello/svg2ttf/issues/37
|
||||
Object.defineProperty(this, 'lineGap', {
|
||||
get: function () {
|
||||
return parseInt(!_.isUndefined(this.int_lineGap) ? this.int_lineGap : ((this.ascent - this.descent) * 0.09), 10);
|
||||
},
|
||||
set: function (value) {
|
||||
this.int_lineGap = value;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'underlinePosition', {
|
||||
get: function () {
|
||||
return parseInt(!_.isUndefined(this.int_underlinePosition) ? this.int_underlinePosition : ((this.ascent - this.descent) * 0.01), 10);
|
||||
},
|
||||
set: function (value) {
|
||||
this.int_underlinePosition = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function Glyph() {
|
||||
this.contours = [];
|
||||
this.d = '';
|
||||
this.id = '';
|
||||
this.height = 0;
|
||||
this.name = '';
|
||||
this.width = 0;
|
||||
}
|
||||
|
||||
Object.defineProperty(Glyph.prototype, 'xMin', {
|
||||
get: function () {
|
||||
var xMin = 0;
|
||||
var hasPoints = false;
|
||||
|
||||
_.forEach(this.contours, function (contour) {
|
||||
_.forEach(contour.points, function (point) {
|
||||
xMin = Math.min(xMin, Math.floor(point.x));
|
||||
hasPoints = true;
|
||||
});
|
||||
|
||||
});
|
||||
return hasPoints ? xMin : 0;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Glyph.prototype, 'xMax', {
|
||||
get: function () {
|
||||
var xMax = 0;
|
||||
var hasPoints = false;
|
||||
|
||||
_.forEach(this.contours, function (contour) {
|
||||
_.forEach(contour.points, function (point) {
|
||||
xMax = Math.max(xMax, -Math.floor(-point.x));
|
||||
hasPoints = true;
|
||||
});
|
||||
|
||||
});
|
||||
return hasPoints ? xMax : this.width;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Glyph.prototype, 'yMin', {
|
||||
get: function () {
|
||||
var yMin = 0;
|
||||
var hasPoints = false;
|
||||
|
||||
_.forEach(this.contours, function (contour) {
|
||||
_.forEach(contour.points, function (point) {
|
||||
yMin = Math.min(yMin, Math.floor(point.y));
|
||||
hasPoints = true;
|
||||
});
|
||||
|
||||
});
|
||||
return hasPoints ? yMin : 0;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Glyph.prototype, 'yMax', {
|
||||
get: function () {
|
||||
var yMax = 0;
|
||||
var hasPoints = false;
|
||||
|
||||
_.forEach(this.contours, function (contour) {
|
||||
_.forEach(contour.points, function (point) {
|
||||
yMax = Math.max(yMax, -Math.floor(-point.y));
|
||||
hasPoints = true;
|
||||
});
|
||||
|
||||
});
|
||||
return hasPoints ? yMax : 0;
|
||||
}
|
||||
});
|
||||
|
||||
function Contour() {
|
||||
this.points = [];
|
||||
}
|
||||
|
||||
function Point() {
|
||||
this.onCurve = true;
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
}
|
||||
|
||||
function SfntName() {
|
||||
this.id = 0;
|
||||
this.value = '';
|
||||
}
|
||||
|
||||
module.exports.Font = Font;
|
||||
module.exports.Glyph = Glyph;
|
||||
module.exports.Contour = Contour;
|
||||
module.exports.Point = Point;
|
||||
module.exports.SfntName = SfntName;
|
||||
module.exports.toTTF = require('./ttf');
|
||||
43
static/js/ketcher2/node_modules/svg2ttf/lib/str.js
generated
vendored
Normal file
43
static/js/ketcher2/node_modules/svg2ttf/lib/str.js
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
'use strict';
|
||||
|
||||
function Str(str) {
|
||||
if (!(this instanceof Str)) {
|
||||
return new Str(str);
|
||||
}
|
||||
|
||||
this.str = str;
|
||||
|
||||
this.toUTF8Bytes = function () {
|
||||
|
||||
var byteArray = [];
|
||||
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
if (str.charCodeAt(i) <= 0x7F) {
|
||||
byteArray.push(str.charCodeAt(i));
|
||||
} else {
|
||||
var h = encodeURIComponent(str.charAt(i)).substr(1).split('%');
|
||||
|
||||
for (var j = 0; j < h.length; j++) {
|
||||
byteArray.push(parseInt(h[j], 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
return byteArray;
|
||||
};
|
||||
|
||||
this.toUCS2Bytes = function () {
|
||||
// Code is taken here:
|
||||
// http://stackoverflow.com/questions/6226189/how-to-convert-a-string-to-bytearray
|
||||
var byteArray = [];
|
||||
var ch;
|
||||
|
||||
for (var i = 0; i < str.length; ++i) {
|
||||
ch = str.charCodeAt(i); // get char
|
||||
byteArray.push(ch >> 8);
|
||||
byteArray.push(ch & 0xFF);
|
||||
}
|
||||
return byteArray;
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = Str;
|
||||
223
static/js/ketcher2/node_modules/svg2ttf/lib/svg.js
generated
vendored
Normal file
223
static/js/ketcher2/node_modules/svg2ttf/lib/svg.js
generated
vendored
Normal file
@ -0,0 +1,223 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var cubic2quad = require('cubic2quad');
|
||||
var DOMParser = require('xmldom').DOMParser;
|
||||
var ucs2 = require('./ucs2');
|
||||
|
||||
function getGlyph(glyphElem) {
|
||||
var glyph = {};
|
||||
|
||||
glyph.d = glyphElem.getAttribute('d').trim();
|
||||
glyph.unicode = [];
|
||||
|
||||
if (glyphElem.getAttribute('unicode')) {
|
||||
glyph.character = glyphElem.getAttribute('unicode');
|
||||
var unicode = ucs2.decode(glyph.character);
|
||||
|
||||
// If more than one code point is involved, the glyph is a ligature glyph
|
||||
if (unicode.length > 1) {
|
||||
glyph.ligature = glyph.character;
|
||||
glyph.ligatureCodes = unicode;
|
||||
} else {
|
||||
glyph.unicode.push(unicode[0]);
|
||||
}
|
||||
}
|
||||
|
||||
glyph.name = glyphElem.getAttribute('glyph-name');
|
||||
|
||||
if (glyphElem.getAttribute('horiz-adv-x')) {
|
||||
glyph.width = parseInt(glyphElem.getAttribute('horiz-adv-x'), 10);
|
||||
}
|
||||
|
||||
return glyph;
|
||||
}
|
||||
|
||||
function deduplicateGlyps(glyphs, ligatures) {
|
||||
// Result (the list of unique glyphs)
|
||||
var result = [];
|
||||
|
||||
_.forEach(glyphs, function (glyph) {
|
||||
// Search for glyphs with the same properties (width and d)
|
||||
var canonical = _.find(result, { width: glyph.width, d: glyph.d });
|
||||
|
||||
if (canonical) {
|
||||
// Add the code points to the unicode array.
|
||||
// The fields “name” and “character” are not that important so we leave them how we first enounter them and throw the rest away
|
||||
canonical.unicode = canonical.unicode.concat(glyph.unicode);
|
||||
glyph.canonical = canonical;
|
||||
} else {
|
||||
result.push(glyph);
|
||||
}
|
||||
});
|
||||
|
||||
// Update ligatures to point to the canonical version
|
||||
_.forEach(ligatures, function (ligature) {
|
||||
while (_.has(ligature.glyph, 'canonical')) {
|
||||
ligature.glyph = ligature.glyph.canonical;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function load(str) {
|
||||
var attrs;
|
||||
|
||||
var doc = (new DOMParser()).parseFromString(str, 'application/xml');
|
||||
|
||||
var metadata, fontElem, fontFaceElem;
|
||||
|
||||
metadata = doc.getElementsByTagName('metadata')[0];
|
||||
fontElem = doc.getElementsByTagName('font')[0];
|
||||
|
||||
if (!fontElem) {
|
||||
throw new Error("Can't find <font> tag. Make sure you SVG file is font, not image.");
|
||||
}
|
||||
|
||||
fontFaceElem = fontElem.getElementsByTagName('font-face')[0];
|
||||
|
||||
var familyName = fontFaceElem.getAttribute('font-family') || 'fontello';
|
||||
var subfamilyName = fontFaceElem.getAttribute('font-style') || 'Regular';
|
||||
var id = fontElem.getAttribute('id') || (familyName + '-' + subfamilyName).replace(/[\s\(\)\[\]<>%\/]/g, '').substr(0, 62);
|
||||
|
||||
var font = {
|
||||
id: id,
|
||||
familyName: familyName,
|
||||
subfamilyName: subfamilyName,
|
||||
stretch: fontFaceElem.getAttribute('font-stretch') || 'normal'
|
||||
};
|
||||
|
||||
// Doesn't work with complex content like <strong>Copyright:></strong><em>Fontello</em>
|
||||
if (metadata && metadata.textContent) {
|
||||
font.metadata = metadata.textContent;
|
||||
}
|
||||
|
||||
// Get <font> numeric attributes
|
||||
attrs = {
|
||||
width: 'horiz-adv-x',
|
||||
//height: 'vert-adv-y',
|
||||
horizOriginX: 'horiz-origin-x',
|
||||
horizOriginY: 'horiz-origin-y',
|
||||
vertOriginX: 'vert-origin-x',
|
||||
vertOriginY: 'vert-origin-y'
|
||||
};
|
||||
_.forEach(attrs, function (val, key) {
|
||||
if (fontElem.hasAttribute(val)) { font[key] = parseInt(fontElem.getAttribute(val), 10); }
|
||||
});
|
||||
|
||||
// Get <font-face> numeric attributes
|
||||
attrs = {
|
||||
ascent: 'ascent',
|
||||
descent: 'descent',
|
||||
unitsPerEm: 'units-per-em'
|
||||
};
|
||||
_.forEach(attrs, function (val, key) {
|
||||
if (fontFaceElem.hasAttribute(val)) { font[key] = parseInt(fontFaceElem.getAttribute(val), 10); }
|
||||
});
|
||||
|
||||
if (fontFaceElem.hasAttribute('font-weight')) {
|
||||
font.weightClass = fontFaceElem.getAttribute('font-weight');
|
||||
}
|
||||
|
||||
var missingGlyphElem = fontElem.getElementsByTagName('missing-glyph')[0];
|
||||
|
||||
if (missingGlyphElem) {
|
||||
|
||||
font.missingGlyph = {};
|
||||
font.missingGlyph.d = missingGlyphElem.getAttribute('d') || '';
|
||||
|
||||
if (missingGlyphElem.getAttribute('horiz-adv-x')) {
|
||||
font.missingGlyph.width = parseInt(missingGlyphElem.getAttribute('horiz-adv-x'), 10);
|
||||
}
|
||||
}
|
||||
|
||||
var glyphs = [];
|
||||
var ligatures = [];
|
||||
|
||||
_.forEach(fontElem.getElementsByTagName('glyph'), function (glyphElem) {
|
||||
var glyph = getGlyph(glyphElem);
|
||||
|
||||
if (_.has(glyph, 'ligature')) {
|
||||
ligatures.push({
|
||||
ligature: glyph.ligature,
|
||||
unicode: glyph.ligatureCodes,
|
||||
glyph: glyph
|
||||
});
|
||||
}
|
||||
|
||||
glyphs.push(glyph);
|
||||
});
|
||||
|
||||
glyphs = deduplicateGlyps(glyphs, ligatures);
|
||||
|
||||
font.glyphs = glyphs;
|
||||
font.ligatures = ligatures;
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
|
||||
function cubicToQuad(segment, index, x, y, accuracy) {
|
||||
if (segment[0] === 'C') {
|
||||
var quadCurves = cubic2quad(
|
||||
x, y,
|
||||
segment[1], segment[2],
|
||||
segment[3], segment[4],
|
||||
segment[5], segment[6],
|
||||
accuracy
|
||||
);
|
||||
|
||||
var res = [];
|
||||
|
||||
for (var i = 2; i < quadCurves.length; i += 4) {
|
||||
res.push([ 'Q', quadCurves[i], quadCurves[i + 1], quadCurves[i + 2], quadCurves[i + 3] ]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Converts svg points to contours. All points must be converted
|
||||
// to relative ones, smooth curves must be converted to generic ones
|
||||
// before this conversion.
|
||||
//
|
||||
function toSfntCoutours(svgPath) {
|
||||
var resContours = [];
|
||||
var resContour = [];
|
||||
|
||||
svgPath.iterate(function (segment, index, x, y) {
|
||||
|
||||
//start new contour
|
||||
if (index === 0 || segment[0] === 'M') {
|
||||
resContour = [];
|
||||
resContours.push(resContour);
|
||||
}
|
||||
|
||||
var name = segment[0];
|
||||
|
||||
if (name === 'Q') {
|
||||
//add control point of quad spline, it is not on curve
|
||||
resContour.push({ x: segment[1], y: segment[2], onCurve: false });
|
||||
}
|
||||
|
||||
// add on-curve point
|
||||
if (name === 'H') {
|
||||
// vertical line has Y coordinate only, X remains the same
|
||||
resContour.push({ x: segment[1], y: y, onCurve: true });
|
||||
} else if (name === 'V') {
|
||||
// horizontal line has X coordinate only, Y remains the same
|
||||
resContour.push({ x: x, y: segment[1], onCurve: true });
|
||||
} else if (name !== 'Z') {
|
||||
// for all commands (except H and V) X and Y are placed in the end of the segment
|
||||
resContour.push({ x: segment[segment.length - 2], y: segment[segment.length - 1], onCurve: true });
|
||||
}
|
||||
|
||||
});
|
||||
return resContours;
|
||||
}
|
||||
|
||||
|
||||
module.exports.load = load;
|
||||
module.exports.cubicToQuad = cubicToQuad;
|
||||
module.exports.toSfntCoutours = toSfntCoutours;
|
||||
161
static/js/ketcher2/node_modules/svg2ttf/lib/ttf.js
generated
vendored
Normal file
161
static/js/ketcher2/node_modules/svg2ttf/lib/ttf.js
generated
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var ByteBuffer = require('microbuffer');
|
||||
|
||||
var createGSUBTable = require('./ttf/tables/gsub');
|
||||
var createOS2Table = require('./ttf/tables/os2');
|
||||
var createCMapTable = require('./ttf/tables/cmap');
|
||||
var createGlyfTable = require('./ttf/tables/glyf');
|
||||
var createHeadTable = require('./ttf/tables/head');
|
||||
var createHHeadTable = require('./ttf/tables/hhea');
|
||||
var createHtmxTable = require('./ttf/tables/hmtx');
|
||||
var createLocaTable = require('./ttf/tables/loca');
|
||||
var createMaxpTable = require('./ttf/tables/maxp');
|
||||
var createNameTable = require('./ttf/tables/name');
|
||||
var createPostTable = require('./ttf/tables/post');
|
||||
|
||||
var utils = require('./ttf/utils');
|
||||
|
||||
// Tables
|
||||
var TABLES = [
|
||||
{ innerName: 'GSUB', order: 4, create: createGSUBTable }, // GSUB
|
||||
{ innerName: 'OS/2', order: 4, create: createOS2Table }, // OS/2
|
||||
{ innerName: 'cmap', order: 6, create: createCMapTable }, // cmap
|
||||
{ innerName: 'glyf', order: 8, create: createGlyfTable }, // glyf
|
||||
{ innerName: 'head', order: 2, create: createHeadTable }, // head
|
||||
{ innerName: 'hhea', order: 1, create: createHHeadTable }, // hhea
|
||||
{ innerName: 'hmtx', order: 5, create: createHtmxTable }, // hmtx
|
||||
{ innerName: 'loca', order: 7, create: createLocaTable }, // loca
|
||||
{ innerName: 'maxp', order: 3, create: createMaxpTable }, // maxp
|
||||
{ innerName: 'name', order: 9, create: createNameTable }, // name
|
||||
{ innerName: 'post', order: 10, create: createPostTable } // post
|
||||
];
|
||||
|
||||
// Various constants
|
||||
var CONST = {
|
||||
VERSION: 0x10000,
|
||||
CHECKSUM_ADJUSTMENT: 0xB1B0AFBA
|
||||
};
|
||||
|
||||
function ulong(t) {
|
||||
t &= 0xffffffff;
|
||||
if (t < 0) {
|
||||
t += 0x100000000;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
function calc_checksum(buf) {
|
||||
var sum = 0;
|
||||
var nlongs = Math.floor(buf.length / 4);
|
||||
var i;
|
||||
|
||||
for (i = 0; i < nlongs; ++i) {
|
||||
var t = buf.getUint32(i * 4);
|
||||
|
||||
sum = ulong(sum + t);
|
||||
}
|
||||
|
||||
var leftBytes = buf.length - nlongs * 4; //extra 1..3 bytes found, because table is not aligned. Need to include them in checksum too.
|
||||
|
||||
if (leftBytes > 0) {
|
||||
var leftRes = 0;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
leftRes = (leftRes << 8) + ((i < leftBytes) ? buf.getUint8(nlongs * 4 + i) : 0);
|
||||
}
|
||||
sum = ulong(sum + leftRes);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
function generateTTF(font) {
|
||||
|
||||
// Prepare TTF contours objects. Note, that while sfnt countours are classes,
|
||||
// ttf contours are just plain arrays of points
|
||||
_.forEach(font.glyphs, function (glyph) {
|
||||
glyph.ttfContours = _.map(glyph.contours, function (contour) {
|
||||
return contour.points;
|
||||
});
|
||||
});
|
||||
|
||||
// Process ttf contours data
|
||||
_.forEach(font.glyphs, function (glyph) {
|
||||
|
||||
// 0.3px accuracy is ok. fo 1000x1000.
|
||||
glyph.ttfContours = utils.simplify(glyph.ttfContours, 0.3);
|
||||
glyph.ttfContours = utils.simplify(glyph.ttfContours, 0.3); // one pass is not enougth
|
||||
|
||||
// Interpolated points can be removed. 1.1px is acceptable
|
||||
// measure - it will give us 1px error after coordinates rounding.
|
||||
glyph.ttfContours = utils.interpolate(glyph.ttfContours, 1.1);
|
||||
|
||||
glyph.ttfContours = utils.roundPoints(glyph.ttfContours);
|
||||
glyph.ttfContours = utils.removeClosingReturnPoints(glyph.ttfContours);
|
||||
glyph.ttfContours = utils.toRelative(glyph.ttfContours);
|
||||
});
|
||||
|
||||
// Add tables
|
||||
var headerSize = 12 + 16 * TABLES.length; // TTF header plus table headers
|
||||
var bufSize = headerSize;
|
||||
|
||||
_.forEach(TABLES, function (table) {
|
||||
//store each table in its own buffer
|
||||
table.buffer = table.create(font);
|
||||
table.length = table.buffer.length;
|
||||
table.corLength = table.length + (4 - table.length % 4) % 4; // table size should be divisible to 4
|
||||
table.checkSum = calc_checksum(table.buffer);
|
||||
bufSize += table.corLength;
|
||||
});
|
||||
|
||||
//calculate offsets
|
||||
var offset = headerSize;
|
||||
|
||||
_.forEach(_.sortBy(TABLES, 'order'), function (table) {
|
||||
table.offset = offset;
|
||||
offset += table.corLength;
|
||||
});
|
||||
|
||||
//create TTF buffer
|
||||
|
||||
var buf = new ByteBuffer(bufSize);
|
||||
|
||||
//special constants
|
||||
var entrySelector = Math.floor(Math.log(TABLES.length) / Math.LN2);
|
||||
var searchRange = Math.pow(2, entrySelector) * 16;
|
||||
var rangeShift = TABLES.length * 16 - searchRange;
|
||||
|
||||
// Add TTF header
|
||||
buf.writeUint32(CONST.VERSION);
|
||||
buf.writeUint16(TABLES.length);
|
||||
buf.writeUint16(searchRange);
|
||||
buf.writeUint16(entrySelector);
|
||||
buf.writeUint16(rangeShift);
|
||||
|
||||
_.forEach(TABLES, function (table) {
|
||||
buf.writeUint32(utils.identifier(table.innerName)); //inner name
|
||||
buf.writeUint32(table.checkSum); //checksum
|
||||
buf.writeUint32(table.offset); //offset
|
||||
buf.writeUint32(table.length); //length
|
||||
});
|
||||
|
||||
var headOffset = 0;
|
||||
|
||||
_.forEach(_.sortBy(TABLES, 'order'), function (table) {
|
||||
if (table.innerName === 'head') { //we must store head offset to write font checksum
|
||||
headOffset = buf.tell();
|
||||
}
|
||||
buf.writeBytes(table.buffer.buffer);
|
||||
for (var i = table.length; i < table.corLength; i++) { //align table to be divisible to 4
|
||||
buf.writeUint8(0);
|
||||
}
|
||||
});
|
||||
|
||||
// Write font checksum (corrected by magic value) into HEAD table
|
||||
buf.setUint32(headOffset + 8, ulong(CONST.CHECKSUM_ADJUSTMENT - calc_checksum(buf)));
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
module.exports = generateTTF;
|
||||
304
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/cmap.js
generated
vendored
Normal file
304
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/cmap.js
generated
vendored
Normal file
@ -0,0 +1,304 @@
|
||||
'use strict';
|
||||
|
||||
// See documentation here: http://www.microsoft.com/typography/otspec/cmap.htm
|
||||
|
||||
var _ = require('lodash');
|
||||
var ByteBuffer = require('microbuffer');
|
||||
|
||||
function getIDByUnicode(font, unicode) {
|
||||
return font.codePoints[unicode] ? font.codePoints[unicode].id : 0;
|
||||
}
|
||||
|
||||
// Calculate character segments with non-interruptable chains of unicodes
|
||||
function getSegments(font, bounds) {
|
||||
bounds = bounds || Number.MAX_VALUE;
|
||||
|
||||
var result = [];
|
||||
var segment;
|
||||
|
||||
// prevEndCode only changes when a segment closes
|
||||
_.forEach(font.codePoints, function (glyph, unicode) {
|
||||
unicode = parseInt(unicode, 10);
|
||||
if (unicode >= bounds) {
|
||||
return false;
|
||||
}
|
||||
// Initialize first segment or add new segment if code "hole" is found
|
||||
if (!segment || unicode !== (segment.end + 1)) {
|
||||
if (segment) {
|
||||
result.push(segment);
|
||||
}
|
||||
segment = {
|
||||
start: unicode
|
||||
};
|
||||
}
|
||||
segment.end = unicode;
|
||||
});
|
||||
|
||||
// Need to finish the last segment
|
||||
if (segment) {
|
||||
result.push(segment);
|
||||
}
|
||||
|
||||
_.forEach(result, function (segment) {
|
||||
segment.length = segment.end - segment.start + 1;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns an array of {unicode, glyph} sets for all valid code points up to bounds
|
||||
function getCodePoints(codePoints, bounds) {
|
||||
bounds = bounds || Number.MAX_VALUE;
|
||||
|
||||
var result = [];
|
||||
|
||||
_.forEach(codePoints, function (glyph, unicode) {
|
||||
unicode = parseInt(unicode, 10);
|
||||
// Since this is a sparse array, iterating will only yield the valid code points
|
||||
if (unicode > bounds) {
|
||||
return false;
|
||||
}
|
||||
result.push({
|
||||
unicode: unicode,
|
||||
glyph: glyph
|
||||
});
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function bufferForTable(format, length) {
|
||||
var fieldWidth = format === 8 || format === 10 || format === 12 || format === 13 ? 4 : 2;
|
||||
|
||||
length += (0
|
||||
+ fieldWidth // Format
|
||||
+ fieldWidth // Length
|
||||
+ fieldWidth // Language
|
||||
);
|
||||
|
||||
var LANGUAGE = 0;
|
||||
var buffer = new ByteBuffer(length);
|
||||
|
||||
var writer = fieldWidth === 4 ? buffer.writeUint32 : buffer.writeUint16;
|
||||
|
||||
// Format specifier
|
||||
buffer.writeUint16(format);
|
||||
if (fieldWidth === 4) {
|
||||
// In case of formats 8.…, 10.…, 12.… and 13.…, this is the decimal part of the format number
|
||||
// But since have not been any point releases, this can be zero in that case as well
|
||||
buffer.writeUint16(0);
|
||||
}
|
||||
// Length
|
||||
writer.call(buffer, length);
|
||||
// Language code (0, only used for legacy quickdraw tables)
|
||||
writer.call(buffer, LANGUAGE);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function createFormat0Table(font) {
|
||||
var FORMAT = 0;
|
||||
|
||||
var i;
|
||||
|
||||
var length = 0xff + 1; //Format 0 maps only single-byte code points
|
||||
|
||||
var buffer = bufferForTable(FORMAT, length);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
buffer.writeUint8(getIDByUnicode(font, i)); // existing char in table 0..255
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function createFormat4Table(font) {
|
||||
var FORMAT = 4;
|
||||
|
||||
var i;
|
||||
|
||||
var segments = getSegments(font, 0xFFFF);
|
||||
var glyphIndexArrays = [];
|
||||
|
||||
_.forEach(segments, function (segment) {
|
||||
var glyphIndexArray = [];
|
||||
|
||||
for (var unicode = segment.start; unicode <= segment.end; unicode++) {
|
||||
glyphIndexArray.push(getIDByUnicode(font, unicode));
|
||||
}
|
||||
glyphIndexArrays.push(glyphIndexArray);
|
||||
});
|
||||
|
||||
var segCount = segments.length + 1; // + 1 for the 0xFFFF section
|
||||
var glyphIndexArrayLength = _.reduce(_.map(glyphIndexArrays, 'length'), function (result, count) { return result + count; }, 0);
|
||||
|
||||
var length = (0
|
||||
+ 2 // segCountX2
|
||||
+ 2 // searchRange
|
||||
+ 2 // entrySelector
|
||||
+ 2 // rangeShift
|
||||
+ 2 * segCount // endCodes
|
||||
+ 2 // Padding
|
||||
+ 2 * segCount //startCodes
|
||||
+ 2 * segCount //idDeltas
|
||||
+ 2 * segCount //idRangeOffsets
|
||||
+ 2 * glyphIndexArrayLength
|
||||
);
|
||||
|
||||
var buffer = bufferForTable(FORMAT, length);
|
||||
|
||||
buffer.writeUint16(segCount * 2); // segCountX2
|
||||
var maxExponent = Math.floor(Math.log(segCount) / Math.LN2);
|
||||
var searchRange = 2 * Math.pow(2, maxExponent);
|
||||
|
||||
buffer.writeUint16(searchRange); // searchRange
|
||||
buffer.writeUint16(maxExponent); // entrySelector
|
||||
buffer.writeUint16(2 * segCount - searchRange); // rangeShift
|
||||
|
||||
// Array of end counts
|
||||
_.forEach(segments, function (segment) {
|
||||
buffer.writeUint16(segment.end);
|
||||
});
|
||||
buffer.writeUint16(0xFFFF); // endCountArray should be finished with 0xFFFF
|
||||
|
||||
buffer.writeUint16(0); // reservedPad
|
||||
|
||||
// Array of start counts
|
||||
_.forEach(segments, function (segment) {
|
||||
buffer.writeUint16(segment.start); //startCountArray
|
||||
});
|
||||
buffer.writeUint16(0xFFFF); // startCountArray should be finished with 0xFFFF
|
||||
|
||||
// Array of deltas. Leave it zero to not complicate things when using the glyph index array
|
||||
for (i = 0; i < segments.length; i++) {
|
||||
buffer.writeUint16(0); // delta is always zero because we use the glyph array
|
||||
}
|
||||
buffer.writeUint16(1); // idDeltaArray should be finished with 1
|
||||
|
||||
// Array of range offsets
|
||||
var offset = 0;
|
||||
|
||||
for (i = 0; i < segments.length; i++) {
|
||||
buffer.writeUint16(2 * ((segments.length - i + 1) + offset));
|
||||
offset += glyphIndexArrays[i].length;
|
||||
}
|
||||
buffer.writeUint16(0); // rangeOffsetArray should be finished with 0
|
||||
|
||||
_.forEach(glyphIndexArrays, function (glyphIndexArray) {
|
||||
_.forEach(glyphIndexArray, function (glyphId) {
|
||||
buffer.writeUint16(glyphId);
|
||||
});
|
||||
});
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function createFormat12Table(font) {
|
||||
var FORMAT = 12;
|
||||
|
||||
var codePoints = getCodePoints(font.codePoints);
|
||||
|
||||
var length = (0
|
||||
+ 4 // nGroups
|
||||
+ 4 * codePoints.length // startCharCode
|
||||
+ 4 * codePoints.length // endCharCode
|
||||
+ 4 * codePoints.length // startGlyphCode
|
||||
);
|
||||
|
||||
var buffer = bufferForTable(FORMAT, length);
|
||||
|
||||
buffer.writeUint32(codePoints.length); // nGroups
|
||||
_.forEach(codePoints, function (codePoint) {
|
||||
buffer.writeUint32(codePoint.unicode); // startCharCode
|
||||
buffer.writeUint32(codePoint.unicode); // endCharCode
|
||||
buffer.writeUint32(codePoint.glyph.id); // startGlyphCode
|
||||
});
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function createCMapTable(font) {
|
||||
var TABLE_HEAD = (0
|
||||
+ 2 // platform
|
||||
+ 2 // encoding
|
||||
+ 4 // offset
|
||||
);
|
||||
|
||||
var singleByteTable = createFormat0Table(font);
|
||||
var twoByteTable = createFormat4Table(font);
|
||||
var fourByteTable = createFormat12Table(font);
|
||||
|
||||
// Subtable headers must be sorted by platformID, encodingID
|
||||
var tableHeaders = [
|
||||
// subtable 4, unicode
|
||||
{
|
||||
platformID: 0,
|
||||
encodingID: 3,
|
||||
table: twoByteTable
|
||||
},
|
||||
// subtable 12, unicode
|
||||
{
|
||||
platformID: 0,
|
||||
encodingID: 4,
|
||||
table: fourByteTable
|
||||
},
|
||||
// subtable 0, mac standard
|
||||
{
|
||||
platformID: 1,
|
||||
encodingID: 0,
|
||||
table: singleByteTable
|
||||
},
|
||||
// subtable 4, windows standard, identical to the unicode table
|
||||
{
|
||||
platformID: 3,
|
||||
encodingID: 1,
|
||||
table: twoByteTable
|
||||
},
|
||||
// subtable 12, windows ucs4
|
||||
{
|
||||
platformID: 3,
|
||||
encodingID: 10,
|
||||
table: fourByteTable
|
||||
}
|
||||
];
|
||||
|
||||
var tables = [
|
||||
twoByteTable,
|
||||
singleByteTable,
|
||||
fourByteTable
|
||||
];
|
||||
|
||||
var tableOffset = (0
|
||||
+ 2 // version
|
||||
+ 2 // number of subtable headers
|
||||
+ tableHeaders.length * TABLE_HEAD
|
||||
);
|
||||
|
||||
// Calculate offsets for each table
|
||||
_.forEach(tables, function (table) {
|
||||
table._tableOffset = tableOffset;
|
||||
tableOffset += table.length;
|
||||
});
|
||||
|
||||
var length = tableOffset;
|
||||
|
||||
var buffer = new ByteBuffer(length);
|
||||
|
||||
// Write table header.
|
||||
buffer.writeUint16(0); // version
|
||||
buffer.writeUint16(tableHeaders.length); // count
|
||||
|
||||
// Write subtable headers
|
||||
_.forEach(tableHeaders, function (header) {
|
||||
buffer.writeUint16(header.platformID); // platform
|
||||
buffer.writeUint16(header.encodingID); // encoding
|
||||
buffer.writeUint32(header.table._tableOffset); // offset
|
||||
});
|
||||
|
||||
// Write subtables
|
||||
_.forEach(tables, function (table) {
|
||||
buffer.writeBytes(table.buffer);
|
||||
});
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
module.exports = createCMapTable;
|
||||
195
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/glyf.js
generated
vendored
Normal file
195
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/glyf.js
generated
vendored
Normal file
@ -0,0 +1,195 @@
|
||||
'use strict';
|
||||
|
||||
// See documentation here: http://www.microsoft.com/typography/otspec/glyf.htm
|
||||
|
||||
var _ = require('lodash');
|
||||
var ByteBuffer = require('microbuffer');
|
||||
|
||||
function getFlags(glyph) {
|
||||
var result = [];
|
||||
|
||||
_.forEach(glyph.ttfContours, function (contour) {
|
||||
_.forEach(contour, function (point) {
|
||||
var flag = point.onCurve ? 1 : 0;
|
||||
|
||||
if (point.x === 0) {
|
||||
flag += 16;
|
||||
} else {
|
||||
if (-0xFF <= point.x && point.x <= 0xFF) {
|
||||
flag += 2; // the corresponding x-coordinate is 1 byte long
|
||||
}
|
||||
if (point.x > 0 && point.x <= 0xFF) {
|
||||
flag += 16; // If x-Short Vector is set, this bit describes the sign of the value, with 1 equalling positive and 0 negative
|
||||
}
|
||||
}
|
||||
if (point.y === 0) {
|
||||
flag += 32;
|
||||
} else {
|
||||
if (-0xFF <= point.y && point.y <= 0xFF) {
|
||||
flag += 4; // the corresponding y-coordinate is 1 byte long
|
||||
}
|
||||
if (point.y > 0 && point.y <= 0xFF) {
|
||||
flag += 32; // If y-Short Vector is set, this bit describes the sign of the value, with 1 equalling positive and 0 negative.
|
||||
}
|
||||
}
|
||||
result.push(flag);
|
||||
});
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
//repeating flags can be packed
|
||||
function compactFlags(flags) {
|
||||
var result = [];
|
||||
var prevFlag = -1;
|
||||
var firstRepeat = false;
|
||||
|
||||
_.forEach(flags, function (flag) {
|
||||
if (prevFlag === flag) {
|
||||
if (firstRepeat) {
|
||||
result[result.length - 1] += 8; //current flag repeats previous one, need to set 3rd bit of previous flag and set 1 to the current one
|
||||
result.push(1);
|
||||
firstRepeat = false;
|
||||
} else {
|
||||
result[result.length - 1]++; //when flag is repeating second or more times, we need to increase the last flag value
|
||||
}
|
||||
} else {
|
||||
firstRepeat = true;
|
||||
prevFlag = flag;
|
||||
result.push(flag);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function getCoords(glyph, coordName) {
|
||||
var result = [];
|
||||
|
||||
_.forEach(glyph.ttfContours, function (contour) {
|
||||
result.push.apply(result, _.map(contour, coordName));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function compactCoords(coords) {
|
||||
return _.filter(coords, function (coord) {
|
||||
return coord !== 0;
|
||||
});
|
||||
}
|
||||
|
||||
//calculates length of glyph data in GLYF table
|
||||
function glyphDataSize(glyph) {
|
||||
// Ignore glyphs without outlines. These will get a length of zero in the “loca” table
|
||||
if (!glyph.contours.length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var result = 12; //glyph fixed properties
|
||||
|
||||
result += glyph.contours.length * 2; //add contours
|
||||
|
||||
_.forEach(glyph.ttf_x, function (x) {
|
||||
//add 1 or 2 bytes for each coordinate depending of its size
|
||||
result += ((-0xFF <= x && x <= 0xFF)) ? 1 : 2;
|
||||
});
|
||||
|
||||
_.forEach(glyph.ttf_y, function (y) {
|
||||
//add 1 or 2 bytes for each coordinate depending of its size
|
||||
result += ((-0xFF <= y && y <= 0xFF)) ? 1 : 2;
|
||||
});
|
||||
|
||||
// Add flags length to glyph size.
|
||||
result += glyph.ttf_flags.length;
|
||||
|
||||
if (result % 4 !== 0) { // glyph size must be divisible by 4.
|
||||
result += 4 - result % 4;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function tableSize(font) {
|
||||
var result = 0;
|
||||
|
||||
_.forEach(font.glyphs, function (glyph) {
|
||||
glyph.ttf_size = glyphDataSize(glyph);
|
||||
result += glyph.ttf_size;
|
||||
});
|
||||
font.ttf_glyph_size = result; //sum of all glyph lengths
|
||||
return result;
|
||||
}
|
||||
|
||||
function createGlyfTable(font) {
|
||||
|
||||
_.forEach(font.glyphs, function (glyph) {
|
||||
glyph.ttf_flags = getFlags(glyph);
|
||||
glyph.ttf_flags = compactFlags(glyph.ttf_flags);
|
||||
glyph.ttf_x = getCoords(glyph, 'x');
|
||||
glyph.ttf_x = compactCoords(glyph.ttf_x);
|
||||
glyph.ttf_y = getCoords(glyph, 'y');
|
||||
glyph.ttf_y = compactCoords(glyph.ttf_y);
|
||||
});
|
||||
|
||||
var buf = new ByteBuffer(tableSize(font));
|
||||
|
||||
_.forEach(font.glyphs, function (glyph) {
|
||||
|
||||
// Ignore glyphs without outlines. These will get a length of zero in the “loca” table
|
||||
if (!glyph.contours.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var offset = buf.tell();
|
||||
|
||||
buf.writeInt16(glyph.contours.length); // numberOfContours
|
||||
buf.writeInt16(glyph.xMin); // xMin
|
||||
buf.writeInt16(glyph.yMin); // yMin
|
||||
buf.writeInt16(glyph.xMax); // xMax
|
||||
buf.writeInt16(glyph.yMax); // yMax
|
||||
|
||||
// Array of end points
|
||||
var endPtsOfContours = -1;
|
||||
|
||||
var ttfContours = glyph.ttfContours;
|
||||
|
||||
_.forEach(ttfContours, function (contour) {
|
||||
endPtsOfContours += contour.length;
|
||||
buf.writeInt16(endPtsOfContours);
|
||||
});
|
||||
|
||||
buf.writeInt16(0); // instructionLength, is not used here
|
||||
|
||||
// Array of flags
|
||||
_.forEach(glyph.ttf_flags, function (flag) {
|
||||
buf.writeInt8(flag);
|
||||
});
|
||||
|
||||
// Array of X relative coordinates
|
||||
_.forEach(glyph.ttf_x, function (x) {
|
||||
if (-0xFF <= x && x <= 0xFF) {
|
||||
buf.writeUint8(Math.abs(x));
|
||||
} else {
|
||||
buf.writeInt16(x);
|
||||
}
|
||||
});
|
||||
|
||||
// Array of Y relative coordinates
|
||||
_.forEach(glyph.ttf_y, function (y) {
|
||||
if (-0xFF <= y && y <= 0xFF) {
|
||||
buf.writeUint8(Math.abs(y));
|
||||
} else {
|
||||
buf.writeInt16(y);
|
||||
}
|
||||
});
|
||||
|
||||
var tail = (buf.tell() - offset) % 4;
|
||||
|
||||
if (tail !== 0) { // glyph size must be divisible by 4.
|
||||
for (; tail < 4; tail++) {
|
||||
buf.writeUint8(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
return buf;
|
||||
}
|
||||
|
||||
module.exports = createGlyfTable;
|
||||
407
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/gsub.js
generated
vendored
Normal file
407
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/gsub.js
generated
vendored
Normal file
@ -0,0 +1,407 @@
|
||||
'use strict';
|
||||
|
||||
// See documentation here: http://www.microsoft.com/typography/otspec/GSUB.htm
|
||||
|
||||
var _ = require('lodash');
|
||||
var identifier = require('../utils.js').identifier;
|
||||
var ByteBuffer = require('microbuffer');
|
||||
|
||||
function createScript() {
|
||||
var scriptRecord = (0
|
||||
+ 2 // Script DefaultLangSys Offset
|
||||
+ 2 // Script[0] LangSysCount (0)
|
||||
);
|
||||
|
||||
var langSys = (0
|
||||
+ 2 // Script DefaultLangSys LookupOrder
|
||||
+ 2 // Script DefaultLangSys ReqFeatureIndex
|
||||
+ 2 // Script DefaultLangSys FeatureCount (0?)
|
||||
+ 2 // Script Optional Feature Index[0]
|
||||
);
|
||||
|
||||
var length = (0
|
||||
+ scriptRecord
|
||||
+ langSys
|
||||
);
|
||||
|
||||
var buffer = new ByteBuffer(length);
|
||||
|
||||
// Script Record
|
||||
// Offset to the start of langSys from the start of scriptRecord
|
||||
buffer.writeUint16(scriptRecord); // DefaultLangSys
|
||||
|
||||
// Number of LangSys entries other than the default (none)
|
||||
buffer.writeUint16(0);
|
||||
|
||||
// LangSys record (DefaultLangSys)
|
||||
// LookupOrder
|
||||
buffer.writeUint16(0);
|
||||
// ReqFeatureIndex -> only one required feature: all ligatures
|
||||
buffer.writeUint16(0);
|
||||
// Number of FeatureIndex values for this language system (excludes the required feature)
|
||||
buffer.writeUint16(1);
|
||||
// FeatureIndex for the first optional feature
|
||||
// Note: Adding the same feature to both the optional
|
||||
// and the required features is a clear violation of the spec
|
||||
// but it fixes IE not displaying the ligatures.
|
||||
// See http://partners.adobe.com/public/developer/opentype/index_table_formats.html, Section “Language System Table”
|
||||
// “FeatureCount: Number of FeatureIndex values for this language system-*excludes the required feature*” (emphasis added)
|
||||
buffer.writeUint16(0);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function createScriptList() {
|
||||
var scriptSize = (0
|
||||
+ 4 // Tag
|
||||
+ 2 // Offset
|
||||
);
|
||||
|
||||
// tags should be arranged alphabetically
|
||||
var scripts = [
|
||||
[ 'DFLT', createScript() ],
|
||||
[ 'latn', createScript() ]
|
||||
];
|
||||
|
||||
var header = (0
|
||||
+ 2 // Script count
|
||||
+ scripts.length * scriptSize
|
||||
);
|
||||
|
||||
var tableLengths = _.reduce(_.map(scripts, function (script) { return script[1].length; }), function (result, count) { return result + count; }, 0);
|
||||
|
||||
var length = (0
|
||||
+ header
|
||||
+ tableLengths
|
||||
);
|
||||
|
||||
var buffer = new ByteBuffer(length);
|
||||
|
||||
// Script count
|
||||
buffer.writeUint16(scripts.length);
|
||||
|
||||
// Write all ScriptRecords
|
||||
var offset = header;
|
||||
|
||||
_.forEach(scripts, function (script) {
|
||||
var name = script[0], table = script[1];
|
||||
|
||||
// Script identifier (DFLT/latn)
|
||||
buffer.writeUint32(identifier(name));
|
||||
// Offset to the ScriptRecord from start of the script list
|
||||
buffer.writeUint16(offset);
|
||||
// Increment offset by script table length
|
||||
offset += table.length;
|
||||
});
|
||||
|
||||
// Write all ScriptTables
|
||||
_.forEach(scripts, function (script) {
|
||||
var table = script[1];
|
||||
|
||||
buffer.writeBytes(table.buffer);
|
||||
});
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Write one feature containing all ligatures
|
||||
function createFeatureList() {
|
||||
var header = (0
|
||||
+ 2 // FeatureCount
|
||||
+ 4 // FeatureTag[0]
|
||||
+ 2 // Feature Offset[0]
|
||||
);
|
||||
|
||||
var length = (0
|
||||
+ header
|
||||
+ 2 // FeatureParams[0]
|
||||
+ 2 // LookupCount[0]
|
||||
+ 2 // Lookup[0] LookupListIndex[0]
|
||||
);
|
||||
|
||||
var buffer = new ByteBuffer(length);
|
||||
|
||||
// FeatureCount
|
||||
buffer.writeUint16(1);
|
||||
// FeatureTag[0]
|
||||
buffer.writeUint32(identifier('liga'));
|
||||
// Feature Offset[0]
|
||||
buffer.writeUint16(header);
|
||||
// FeatureParams[0]
|
||||
buffer.writeUint16(0);
|
||||
// LookupCount[0]
|
||||
buffer.writeUint16(1);
|
||||
// Index into lookup table. Since we only have ligatures, the index is always 0
|
||||
buffer.writeUint16(0);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function createLigatureCoverage(font, ligatureGroups) {
|
||||
var glyphCount = ligatureGroups.length;
|
||||
|
||||
var length = (0
|
||||
+ 2 // CoverageFormat
|
||||
+ 2 // GlyphCount
|
||||
+ 2 * glyphCount // GlyphID[i]
|
||||
);
|
||||
|
||||
var buffer = new ByteBuffer(length);
|
||||
|
||||
// CoverageFormat
|
||||
buffer.writeUint16(1);
|
||||
|
||||
// Length
|
||||
buffer.writeUint16(glyphCount);
|
||||
|
||||
|
||||
_.forEach(ligatureGroups, function (group) {
|
||||
buffer.writeUint16(group.startGlyph.id);
|
||||
});
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function createLigatureTable(font, ligature) {
|
||||
var allCodePoints = font.codePoints;
|
||||
|
||||
var unicode = ligature.unicode;
|
||||
|
||||
var length = (0
|
||||
+ 2 // LigGlyph
|
||||
+ 2 // CompCount
|
||||
+ 2 * (unicode.length - 1)
|
||||
);
|
||||
|
||||
var buffer = new ByteBuffer(length);
|
||||
|
||||
// LigGlyph
|
||||
var glyph = ligature.glyph;
|
||||
|
||||
buffer.writeUint16(glyph.id);
|
||||
|
||||
// CompCount
|
||||
buffer.writeUint16(unicode.length);
|
||||
|
||||
// Compound glyphs (excluding first as it’s already in the coverage table)
|
||||
for (var i = 1; i < unicode.length; i++) {
|
||||
glyph = allCodePoints[unicode[i]];
|
||||
buffer.writeUint16(glyph.id);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function createLigatureSet(font, codePoint, ligatures) {
|
||||
var ligatureTables = [];
|
||||
|
||||
_.forEach(ligatures, function (ligature) {
|
||||
ligatureTables.push(createLigatureTable(font, ligature));
|
||||
});
|
||||
|
||||
var tableLengths = _.reduce(_.map(ligatureTables, 'length'), function (result, count) { return result + count; }, 0);
|
||||
|
||||
var offset = (0
|
||||
+ 2 // LigatureCount
|
||||
+ 2 * ligatures.length
|
||||
);
|
||||
|
||||
var length = (0
|
||||
+ offset
|
||||
+ tableLengths
|
||||
);
|
||||
|
||||
var buffer = new ByteBuffer(length);
|
||||
|
||||
// LigatureCount
|
||||
buffer.writeUint16(ligatures.length);
|
||||
|
||||
// Ligature offsets
|
||||
_.forEach(ligatureTables, function (table) {
|
||||
// The offset to the current set, from SubstFormat
|
||||
buffer.writeUint16(offset);
|
||||
offset += table.length;
|
||||
});
|
||||
|
||||
// Ligatures
|
||||
_.forEach(ligatureTables, function (table) {
|
||||
buffer.writeBytes(table.buffer);
|
||||
});
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function createLigatureList(font, ligatureGroups) {
|
||||
var sets = [];
|
||||
|
||||
_.forEach(ligatureGroups, function (group) {
|
||||
var set = createLigatureSet(font, group.codePoint, group.ligatures);
|
||||
|
||||
sets.push(set);
|
||||
});
|
||||
|
||||
var setLengths = _.reduce(_.map(sets, 'length'), function (result, count) { return result + count; }, 0);
|
||||
|
||||
var coverage = createLigatureCoverage(font, ligatureGroups);
|
||||
|
||||
var tableOffset = (0
|
||||
+ 2 // Lookup type
|
||||
+ 2 // Lokup flag
|
||||
+ 2 // SubTableCount
|
||||
+ 2 // SubTable[0] Offset
|
||||
);
|
||||
|
||||
var setOffset = (0
|
||||
+ 2 // SubstFormat
|
||||
+ 2 // Coverage offset
|
||||
+ 2 // LigSetCount
|
||||
+ 2 * sets.length // LigSet Offsets
|
||||
);
|
||||
|
||||
var coverageOffset = setOffset + setLengths;
|
||||
|
||||
var length = (0
|
||||
+ tableOffset
|
||||
+ coverageOffset
|
||||
+ coverage.length
|
||||
);
|
||||
|
||||
var buffer = new ByteBuffer(length);
|
||||
|
||||
// Lookup type 4 – ligatures
|
||||
buffer.writeUint16(4);
|
||||
|
||||
// Lookup flag – empty
|
||||
buffer.writeUint16(0);
|
||||
|
||||
// Subtable count
|
||||
buffer.writeUint16(1);
|
||||
|
||||
// Subtable[0] offset
|
||||
buffer.writeUint16(tableOffset);
|
||||
|
||||
// SubstFormat
|
||||
buffer.writeUint16(1);
|
||||
|
||||
// Coverage
|
||||
buffer.writeUint16(coverageOffset);
|
||||
|
||||
// LigSetCount
|
||||
buffer.writeUint16(sets.length);
|
||||
|
||||
_.forEach(sets, function (set) {
|
||||
// The offset to the current set, from SubstFormat
|
||||
buffer.writeUint16(setOffset);
|
||||
setOffset += set.length;
|
||||
});
|
||||
|
||||
_.forEach(sets, function (set) {
|
||||
buffer.writeBytes(set.buffer);
|
||||
});
|
||||
|
||||
buffer.writeBytes(coverage.buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Add a lookup for each ligature
|
||||
function createLookupList(font) {
|
||||
var ligatures = font.ligatures;
|
||||
|
||||
var groupedLigatures = {};
|
||||
|
||||
// Group ligatures by first code point
|
||||
_.forEach(ligatures, function (ligature) {
|
||||
var first = ligature.unicode[0];
|
||||
|
||||
if (!_.has(groupedLigatures, first)) {
|
||||
groupedLigatures[first] = [];
|
||||
}
|
||||
groupedLigatures[first].push(ligature);
|
||||
});
|
||||
|
||||
var ligatureGroups = [];
|
||||
|
||||
_.forEach(groupedLigatures, function (ligatures, codePoint) {
|
||||
codePoint = parseInt(codePoint, 10);
|
||||
// Order ligatures by length, descending
|
||||
// “Ligatures with more components must be stored ahead of those with fewer components in order to be found”
|
||||
// From: http://partners.adobe.com/public/developer/opentype/index_tag7.html#liga
|
||||
ligatures.sort(function (ligA, ligB) {
|
||||
return ligB.unicode.length - ligA.unicode.length;
|
||||
});
|
||||
ligatureGroups.push({
|
||||
codePoint: codePoint,
|
||||
ligatures: ligatures,
|
||||
startGlyph: font.codePoints[codePoint]
|
||||
});
|
||||
});
|
||||
|
||||
ligatureGroups.sort(function (a, b) {
|
||||
return a.startGlyph.id - b.startGlyph.id;
|
||||
});
|
||||
|
||||
var offset = (0
|
||||
+ 2 // Lookup count
|
||||
+ 2 // Lookup[0] offset
|
||||
);
|
||||
|
||||
var set = createLigatureList(font, ligatureGroups);
|
||||
|
||||
var length = (0
|
||||
+ offset
|
||||
+ set.length
|
||||
);
|
||||
|
||||
var buffer = new ByteBuffer(length);
|
||||
|
||||
// Lookup count
|
||||
buffer.writeUint16(1);
|
||||
|
||||
// Lookup[0] offset
|
||||
buffer.writeUint16(offset);
|
||||
|
||||
// Lookup[0]
|
||||
buffer.writeBytes(set.buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function createGSUB(font) {
|
||||
var scriptList = createScriptList();
|
||||
var featureList = createFeatureList();
|
||||
var lookupList = createLookupList(font);
|
||||
|
||||
var lists = [ scriptList, featureList, lookupList ];
|
||||
|
||||
var offset = (0
|
||||
+ 4 // Version
|
||||
+ 2 * lists.length // List offsets
|
||||
);
|
||||
|
||||
// Calculate offsets
|
||||
_.forEach(lists, function (list) {
|
||||
list._listOffset = offset;
|
||||
offset += list.length;
|
||||
});
|
||||
|
||||
var length = offset;
|
||||
var buffer = new ByteBuffer(length);
|
||||
|
||||
// Version
|
||||
buffer.writeUint32(0x00010000);
|
||||
|
||||
// Offsets
|
||||
_.forEach(lists, function (list) {
|
||||
buffer.writeUint16(list._listOffset);
|
||||
});
|
||||
|
||||
// List contents
|
||||
_.forEach(lists, function (list) {
|
||||
buffer.writeBytes(list.buffer);
|
||||
});
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
module.exports = createGSUB;
|
||||
42
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/head.js
generated
vendored
Normal file
42
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/head.js
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
'use strict';
|
||||
|
||||
// See documentation here: http://www.microsoft.com/typography/otspec/head.htm
|
||||
|
||||
var ByteBuffer = require('microbuffer');
|
||||
|
||||
function dateToUInt64(date) {
|
||||
var startDate = new Date('1904-01-01T00:00:00.000Z');
|
||||
|
||||
return Math.floor((date - startDate) / 1000);
|
||||
}
|
||||
|
||||
function createHeadTable(font) {
|
||||
|
||||
var buf = new ByteBuffer(54); // fixed table length
|
||||
|
||||
buf.writeInt32(0x10000); // version
|
||||
buf.writeInt32(font.revision * 0x10000); // fontRevision
|
||||
buf.writeUint32(0); // checkSumAdjustment
|
||||
buf.writeUint32(0x5F0F3CF5); // magicNumber
|
||||
// FLag meanings:
|
||||
// Bit 0: Baseline for font at y=0;
|
||||
// Bit 1: Left sidebearing point at x=0;
|
||||
// Bit 3: Force ppem to integer values for all internal scaler math; may use fractional ppem sizes if this bit is clear;
|
||||
buf.writeUint16(0x000B); // flags
|
||||
buf.writeUint16(font.unitsPerEm); // unitsPerEm
|
||||
buf.writeUint64(dateToUInt64(font.createdDate)); // created
|
||||
buf.writeUint64(dateToUInt64(font.modifiedDate)); // modified
|
||||
buf.writeInt16(font.xMin); // xMin
|
||||
buf.writeInt16(font.yMin); // yMin
|
||||
buf.writeInt16(font.xMax); // xMax
|
||||
buf.writeInt16(font.yMax); // yMax
|
||||
buf.writeUint16(font.macStyle); //macStyle
|
||||
buf.writeUint16(font.lowestRecPPEM); // lowestRecPPEM
|
||||
buf.writeInt16(2); // fontDirectionHint
|
||||
buf.writeInt16(font.ttf_glyph_size < 0x20000 ? 0 : 1); // indexToLocFormat, 0 for short offsets, 1 for long offsets
|
||||
buf.writeInt16(0); // glyphDataFormat
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
module.exports = createHeadTable;
|
||||
31
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/hhea.js
generated
vendored
Normal file
31
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/hhea.js
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
// See documentation here: http://www.microsoft.com/typography/otspec/hhea.htm
|
||||
|
||||
var ByteBuffer = require('microbuffer');
|
||||
|
||||
function createHHeadTable(font) {
|
||||
|
||||
var buf = new ByteBuffer(36); // fixed table length
|
||||
|
||||
buf.writeInt32(0x10000); // version
|
||||
buf.writeInt16(font.ascent); // ascent
|
||||
buf.writeInt16(font.descent); // descend
|
||||
// Non zero lineGap causes offset in IE, https://github.com/fontello/svg2ttf/issues/37
|
||||
buf.writeInt16(0); // lineGap
|
||||
buf.writeUint16(font.maxWidth); // advanceWidthMax
|
||||
buf.writeInt16(font.minLsb); // minLeftSideBearing
|
||||
buf.writeInt16(font.minRsb); // minRightSideBearing
|
||||
buf.writeInt16(font.maxExtent); // xMaxExtent
|
||||
buf.writeInt16(1); // caretSlopeRise
|
||||
buf.writeInt16(0); // caretSlopeRun
|
||||
buf.writeUint32(0); // reserved1
|
||||
buf.writeUint32(0); // reserved2
|
||||
buf.writeUint16(0); // reserved3
|
||||
buf.writeInt16(0); // metricDataFormat
|
||||
buf.writeUint16(font.glyphs.length); // numberOfHMetrics
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
module.exports = createHHeadTable;
|
||||
19
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/hmtx.js
generated
vendored
Normal file
19
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/hmtx.js
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
// See documentation here: http://www.microsoft.com/typography/otspec/hmtx.htm
|
||||
|
||||
var _ = require('lodash');
|
||||
var ByteBuffer = require('microbuffer');
|
||||
|
||||
function createHtmxTable(font) {
|
||||
|
||||
var buf = new ByteBuffer(font.glyphs.length * 4);
|
||||
|
||||
_.forEach(font.glyphs, function (glyph) {
|
||||
buf.writeUint16(glyph.width); //advanceWidth
|
||||
buf.writeInt16(glyph.xMin); //lsb
|
||||
});
|
||||
return buf;
|
||||
}
|
||||
|
||||
module.exports = createHtmxTable;
|
||||
43
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/loca.js
generated
vendored
Normal file
43
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/loca.js
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
'use strict';
|
||||
|
||||
// See documentation here: http://www.microsoft.com/typography/otspec/loca.htm
|
||||
|
||||
var _ = require('lodash');
|
||||
var ByteBuffer = require('microbuffer');
|
||||
|
||||
function tableSize(font, isShortFormat) {
|
||||
var result = (font.glyphs.length + 1) * (isShortFormat ? 2 : 4); // by glyph count + tail
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function createLocaTable(font) {
|
||||
|
||||
var isShortFormat = font.ttf_glyph_size < 0x20000;
|
||||
|
||||
var buf = new ByteBuffer(tableSize(font, isShortFormat));
|
||||
|
||||
var location = 0;
|
||||
|
||||
// Array of offsets in GLYF table for each glyph
|
||||
_.forEach(font.glyphs, function (glyph) {
|
||||
if (isShortFormat) {
|
||||
buf.writeUint16(location);
|
||||
location += glyph.ttf_size / 2; // actual location must be divided to 2 in short format
|
||||
} else {
|
||||
buf.writeUint32(location);
|
||||
location += glyph.ttf_size; //actual location is stored as is in long format
|
||||
}
|
||||
});
|
||||
|
||||
// The last glyph location is stored to get last glyph length
|
||||
if (isShortFormat) {
|
||||
buf.writeUint16(location);
|
||||
} else {
|
||||
buf.writeUint32(location);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
module.exports = createLocaTable;
|
||||
46
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/maxp.js
generated
vendored
Normal file
46
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/maxp.js
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
'use strict';
|
||||
|
||||
// See documentation here: http://www.microsoft.com/typography/otspec/maxp.htm
|
||||
|
||||
var _ = require('lodash');
|
||||
var ByteBuffer = require('microbuffer');
|
||||
|
||||
// Find max points in glyph TTF contours.
|
||||
function getMaxPoints(font) {
|
||||
return _.max(_.map(font.glyphs, function (glyph) {
|
||||
return _.reduce(glyph.ttfContours, function (sum, ctr) { return sum + ctr.length; }, 0);
|
||||
}));
|
||||
}
|
||||
|
||||
function getMaxContours(font) {
|
||||
return _.max(_.map(font.glyphs, function (glyph) {
|
||||
return glyph.ttfContours.length;
|
||||
}));
|
||||
}
|
||||
|
||||
function createMaxpTable(font) {
|
||||
|
||||
var buf = new ByteBuffer(32);
|
||||
|
||||
buf.writeInt32(0x10000); // version
|
||||
buf.writeUint16(font.glyphs.length); // numGlyphs
|
||||
buf.writeUint16(getMaxPoints(font)); // maxPoints
|
||||
buf.writeUint16(getMaxContours(font)); // maxContours
|
||||
buf.writeUint16(0); // maxCompositePoints
|
||||
buf.writeUint16(0); // maxCompositeContours
|
||||
buf.writeUint16(2); // maxZones
|
||||
buf.writeUint16(0); // maxTwilightPoints
|
||||
// It is unclear how to calculate maxStorage, maxFunctionDefs and maxInstructionDefs.
|
||||
// These are magic constants now, with values exceeding values from FontForge
|
||||
buf.writeUint16(10); // maxStorage
|
||||
buf.writeUint16(10); // maxFunctionDefs
|
||||
buf.writeUint16(0); // maxInstructionDefs
|
||||
buf.writeUint16(255); // maxStackElements
|
||||
buf.writeUint16(0); // maxSizeOfInstructions
|
||||
buf.writeUint16(0); // maxComponentElements
|
||||
buf.writeUint16(0); // maxComponentDepth
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
module.exports = createMaxpTable;
|
||||
106
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/name.js
generated
vendored
Normal file
106
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/name.js
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
'use strict';
|
||||
|
||||
// See documentation here: http://www.microsoft.com/typography/otspec/name.htm
|
||||
|
||||
var _ = require('lodash');
|
||||
var ByteBuffer = require('microbuffer');
|
||||
var Str = require('../../str');
|
||||
|
||||
var TTF_NAMES = {
|
||||
COPYRIGHT: 0,
|
||||
FONT_FAMILY: 1,
|
||||
ID: 3,
|
||||
DESCRIPTION: 10,
|
||||
URL_VENDOR: 11
|
||||
};
|
||||
|
||||
function tableSize(names) {
|
||||
var result = 6; // table header
|
||||
|
||||
_.forEach(names, function (name) {
|
||||
result += 12 + name.data.length; //name header and data
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function getStrings(name, id) {
|
||||
var result = [];
|
||||
var str = new Str(name);
|
||||
|
||||
result.push({ data: str.toUTF8Bytes(), id: id, platformID : 1, encodingID : 0, languageID : 0 }); //mac standard
|
||||
result.push({ data: str.toUCS2Bytes(), id: id, platformID : 3, encodingID : 1, languageID : 0x409 }); //windows standard
|
||||
return result;
|
||||
}
|
||||
|
||||
// Collect font names
|
||||
function getNames(font) {
|
||||
var result = [];
|
||||
|
||||
if (font.copyright) {
|
||||
result.push.apply(result, getStrings(font.copyright, TTF_NAMES.COPYRIGHT));
|
||||
}
|
||||
if (font.familyName) {
|
||||
result.push.apply(result, getStrings(font.familyName, TTF_NAMES.FONT_FAMILY));
|
||||
}
|
||||
if (font.id) {
|
||||
result.push.apply(result, getStrings(font.id, TTF_NAMES.ID));
|
||||
}
|
||||
result.push.apply(result, getStrings('Generated by svg2ttf from Fontello project.', TTF_NAMES.DESCRIPTION));
|
||||
result.push.apply(result, getStrings('http://fontello.com', TTF_NAMES.URL_VENDOR));
|
||||
|
||||
_.forEach(font.sfntNames, function (sfntName) {
|
||||
result.push.apply(result, getStrings(sfntName.value, sfntName.id));
|
||||
});
|
||||
|
||||
result.sort(function (a, b) {
|
||||
var orderFields = [ 'platformID', 'encodingID', 'languageID', 'id' ];
|
||||
var i;
|
||||
|
||||
for (i = 0; i < orderFields.length; i++) {
|
||||
if (a[orderFields[i]] !== b[orderFields[i]]) {
|
||||
return a[orderFields[i]] < b[orderFields[i]] ? -1 : 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function createNameTable(font) {
|
||||
|
||||
var names = getNames(font);
|
||||
|
||||
var buf = new ByteBuffer(tableSize(names));
|
||||
|
||||
buf.writeUint16(0); // formatSelector
|
||||
buf.writeUint16(names.length); // nameRecordsCount
|
||||
var offsetPosition = buf.tell();
|
||||
|
||||
buf.writeUint16(0); // offset, will be filled later
|
||||
var nameOffset = 0;
|
||||
|
||||
_.forEach(names, function (name) {
|
||||
buf.writeUint16(name.platformID); // platformID
|
||||
buf.writeUint16(name.encodingID); // platEncID
|
||||
buf.writeUint16(name.languageID); // languageID, English (USA)
|
||||
buf.writeUint16(name.id); // nameID
|
||||
buf.writeUint16(name.data.length); // reclength
|
||||
buf.writeUint16(nameOffset); // offset
|
||||
nameOffset += name.data.length;
|
||||
});
|
||||
var actualStringDataOffset = buf.tell();
|
||||
|
||||
//Array of bytes with actual string data
|
||||
_.forEach(names, function (name) {
|
||||
buf.writeBytes(name.data);
|
||||
});
|
||||
|
||||
//write actual string data offset
|
||||
buf.seek(offsetPosition);
|
||||
buf.writeUint16(actualStringDataOffset); // offset
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
module.exports = createNameTable;
|
||||
74
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/os2.js
generated
vendored
Normal file
74
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/os2.js
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
'use strict';
|
||||
|
||||
// See documentation here: http://www.microsoft.com/typography/otspec/os2.htm
|
||||
|
||||
var _ = require('lodash');
|
||||
var identifier = require('../utils.js').identifier;
|
||||
var ByteBuffer = require('microbuffer');
|
||||
|
||||
//get first glyph unicode
|
||||
function getFirstCharIndex(font) {
|
||||
return Math.max(0, Math.min(0xffff, Math.abs(_.minBy(Object.keys(font.codePoints), function (point) {
|
||||
return parseInt(point, 10);
|
||||
}))));
|
||||
}
|
||||
|
||||
//get last glyph unicode
|
||||
function getLastCharIndex(font) {
|
||||
return Math.max(0, Math.min(0xffff, Math.abs(_.maxBy(Object.keys(font.codePoints), function (point) {
|
||||
return parseInt(point, 10);
|
||||
}))));
|
||||
}
|
||||
|
||||
function createOS2Table(font) {
|
||||
|
||||
var buf = new ByteBuffer(86);
|
||||
|
||||
buf.writeUint16(1); //version
|
||||
buf.writeInt16(font.avgWidth); // xAvgCharWidth
|
||||
buf.writeUint16(font.weightClass); // usWeightClass
|
||||
buf.writeUint16(font.widthClass); // usWidthClass
|
||||
buf.writeInt16(font.fsType); // fsType
|
||||
buf.writeInt16(font.ySubscriptXSize); // ySubscriptXSize
|
||||
buf.writeInt16(font.ySubscriptYSize); //ySubscriptYSize
|
||||
buf.writeInt16(font.ySubscriptXOffset); // ySubscriptXOffset
|
||||
buf.writeInt16(font.ySubscriptYOffset); // ySubscriptYOffset
|
||||
buf.writeInt16(font.ySuperscriptXSize); // ySuperscriptXSize
|
||||
buf.writeInt16(font.ySuperscriptYSize); // ySuperscriptYSize
|
||||
buf.writeInt16(font.ySuperscriptXOffset); // ySuperscriptXOffset
|
||||
buf.writeInt16(font.ySuperscriptYOffset); // ySuperscriptYOffset
|
||||
buf.writeInt16(font.yStrikeoutSize); // yStrikeoutSize
|
||||
buf.writeInt16(font.yStrikeoutPosition); // yStrikeoutPosition
|
||||
buf.writeInt16(font.familyClass); // sFamilyClass
|
||||
buf.writeUint8(font.panose.familyType); // panose.bFamilyType
|
||||
buf.writeUint8(font.panose.serifStyle); // panose.bSerifStyle
|
||||
buf.writeUint8(font.panose.weight); // panose.bWeight
|
||||
buf.writeUint8(font.panose.proportion); // panose.bProportion
|
||||
buf.writeUint8(font.panose.contrast); // panose.bContrast
|
||||
buf.writeUint8(font.panose.strokeVariation); // panose.bStrokeVariation
|
||||
buf.writeUint8(font.panose.armStyle); // panose.bArmStyle
|
||||
buf.writeUint8(font.panose.letterform); // panose.bLetterform
|
||||
buf.writeUint8(font.panose.midline); // panose.bMidline
|
||||
buf.writeUint8(font.panose.xHeight); // panose.bXHeight
|
||||
// TODO: This field is used to specify the Unicode blocks or ranges based on the 'cmap' table.
|
||||
buf.writeUint32(0); // ulUnicodeRange1
|
||||
buf.writeUint32(0); // ulUnicodeRange2
|
||||
buf.writeUint32(0); // ulUnicodeRange3
|
||||
buf.writeUint32(0); // ulUnicodeRange4
|
||||
buf.writeUint32(identifier('PfEd')); // achVendID, equal to PfEd
|
||||
buf.writeUint16(font.fsSelection); // fsSelection
|
||||
buf.writeUint16(getFirstCharIndex(font)); // usFirstCharIndex
|
||||
buf.writeUint16(getLastCharIndex(font)); // usLastCharIndex
|
||||
buf.writeInt16(font.ascent); // sTypoAscender
|
||||
buf.writeInt16(font.descent); // sTypoDescender
|
||||
buf.writeInt16(font.lineGap); // lineGap
|
||||
// Enlarge win acscent/descent to avoid clipping
|
||||
buf.writeInt16(Math.max(font.yMax, font.ascent)); // usWinAscent
|
||||
buf.writeInt16(-Math.min(font.yMin, font.descent)); // usWinDescent
|
||||
buf.writeInt32(1); // ulCodePageRange1, Latin 1
|
||||
buf.writeInt32(0); // ulCodePageRange2
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
module.exports = createOS2Table;
|
||||
73
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/post.js
generated
vendored
Normal file
73
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/tables/post.js
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
'use strict';
|
||||
|
||||
// See documentation here: http://www.microsoft.com/typography/otspec/post.htm
|
||||
|
||||
var _ = require('lodash');
|
||||
var ByteBuffer = require('microbuffer');
|
||||
|
||||
function tableSize(font, names) {
|
||||
var result = 36; // table header
|
||||
|
||||
result += font.glyphs.length * 2; // name declarations
|
||||
_.forEach(names, function (name) {
|
||||
result += name.length;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function pascalString(str) {
|
||||
var bytes = [];
|
||||
var len = str ? (str.length < 256 ? str.length : 255) : 0; //length in Pascal string is limited with 255
|
||||
|
||||
bytes.push(len);
|
||||
for (var i = 0; i < len; i++) {
|
||||
var char = str.charCodeAt(i);
|
||||
|
||||
bytes.push(char < 128 ? char : 95); //non-ASCII characters are substituted with '_'
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
function createPostTable(font) {
|
||||
|
||||
var names = [];
|
||||
|
||||
_.forEach(font.glyphs, function (glyph) {
|
||||
if (glyph.unicode !== 0) {
|
||||
names.push(pascalString(glyph.name));
|
||||
}
|
||||
});
|
||||
|
||||
var buf = new ByteBuffer(tableSize(font, names));
|
||||
|
||||
buf.writeInt32(0x20000); // formatType, version 2.0
|
||||
buf.writeInt32(font.italicAngle); // italicAngle
|
||||
buf.writeInt16(font.underlinePosition); // underlinePosition
|
||||
buf.writeInt16(font.underlineThickness); // underlineThickness
|
||||
buf.writeUint32(font.isFixedPitch); // isFixedPitch
|
||||
buf.writeUint32(0); // minMemType42
|
||||
buf.writeUint32(0); // maxMemType42
|
||||
buf.writeUint32(0); // minMemType1
|
||||
buf.writeUint32(0); // maxMemType1
|
||||
buf.writeUint16(font.glyphs.length); // numberOfGlyphs
|
||||
|
||||
// Array of glyph name indexes
|
||||
var index = 258; // first index of custom glyph name, it is calculated as glyph name index + 258
|
||||
|
||||
_.forEach(font.glyphs, function (glyph) {
|
||||
if (glyph.unicode === 0) {
|
||||
buf.writeUint16(0);// missed element should have .notDef name in the Macintosh standard order.
|
||||
} else {
|
||||
buf.writeUint16(index++);
|
||||
}
|
||||
});
|
||||
|
||||
// Array of glyph name indexes
|
||||
_.forEach(names, function (name) {
|
||||
buf.writeBytes(name);
|
||||
});
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
module.exports = createPostTable;
|
||||
129
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/utils.js
generated
vendored
Normal file
129
static/js/ketcher2/node_modules/svg2ttf/lib/ttf/utils.js
generated
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var math = require('../math');
|
||||
|
||||
// Remove points, that looks like straight line
|
||||
function simplify(contours, accuracy) {
|
||||
return _.map(contours, function (contour) {
|
||||
var i, curr, prev, next;
|
||||
var p, pPrev, pNext;
|
||||
|
||||
// run from the end, to simplify array elements removal
|
||||
for (i = contour.length - 2; i > 1; i--) {
|
||||
prev = contour[i - 1];
|
||||
next = contour[i + 1];
|
||||
curr = contour[i];
|
||||
|
||||
// skip point (both oncurve & offcurve),
|
||||
// if [prev,next] is straight line
|
||||
if (prev.onCurve && next.onCurve) {
|
||||
p = new math.Point(curr.x, curr.y);
|
||||
pPrev = new math.Point(prev.x, prev.y);
|
||||
pNext = new math.Point(next.x, next.y);
|
||||
if (math.isInLine(pPrev, p, pNext, accuracy)) {
|
||||
contour.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return contour;
|
||||
});
|
||||
}
|
||||
|
||||
// Remove interpolateable oncurve points
|
||||
// Those should be in the middle of nebor offcurve points
|
||||
function interpolate(contours, accuracy) {
|
||||
return _.map(contours, function (contour) {
|
||||
var resContour = [];
|
||||
|
||||
_.forEach(contour, function (point, idx) {
|
||||
// Never skip first and last points
|
||||
if (idx === 0 || idx === (contour.length - 1)) {
|
||||
resContour.push(point);
|
||||
return;
|
||||
}
|
||||
|
||||
var prev = contour[idx - 1];
|
||||
var next = contour[idx + 1];
|
||||
|
||||
var p, pPrev, pNext;
|
||||
|
||||
// skip interpolateable oncurve points (if exactly between previous and next offcurves)
|
||||
if (!prev.onCurve && point.onCurve && !next.onCurve) {
|
||||
p = new math.Point(point.x, point.y);
|
||||
pPrev = new math.Point(prev.x, prev.y);
|
||||
pNext = new math.Point(next.x, next.y);
|
||||
if (pPrev.add(pNext).div(2).sub(p).dist() < accuracy) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// keep the rest
|
||||
resContour.push(point);
|
||||
});
|
||||
return resContour;
|
||||
});
|
||||
}
|
||||
|
||||
function roundPoints(contours) {
|
||||
return _.map(contours, function (contour) {
|
||||
return _.map(contour, function (point) {
|
||||
return { x: Math.round(point.x), y: Math.round(point.y), onCurve: point.onCurve };
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Remove closing point if it is the same as first point of contour.
|
||||
// TTF doesn't need this point when drawing contours.
|
||||
function removeClosingReturnPoints(contours) {
|
||||
return _.map(contours, function (contour) {
|
||||
var length = contour.length;
|
||||
|
||||
if (length > 1 &&
|
||||
contour[0].x === contour[length - 1].x &&
|
||||
contour[0].y === contour[length - 1].y) {
|
||||
contour.splice(length - 1);
|
||||
}
|
||||
return contour;
|
||||
});
|
||||
}
|
||||
|
||||
function toRelative(contours) {
|
||||
var prevPoint = { x: 0, y: 0 };
|
||||
var resContours = [];
|
||||
var resContour;
|
||||
|
||||
_.forEach(contours, function (contour) {
|
||||
resContour = [];
|
||||
resContours.push(resContour);
|
||||
_.forEach(contour, function (point) {
|
||||
resContour.push({
|
||||
x: point.x - prevPoint.x,
|
||||
y: point.y - prevPoint.y,
|
||||
onCurve: point.onCurve
|
||||
});
|
||||
prevPoint = point;
|
||||
});
|
||||
});
|
||||
return resContours;
|
||||
}
|
||||
|
||||
function identifier(string, littleEndian) {
|
||||
var result = 0;
|
||||
|
||||
for (var i = 0; i < string.length; i++) {
|
||||
result = result << 8;
|
||||
var index = littleEndian ? string.length - i - 1 : i;
|
||||
|
||||
result += string.charCodeAt(index);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
module.exports.interpolate = interpolate;
|
||||
module.exports.simplify = simplify;
|
||||
module.exports.roundPoints = roundPoints;
|
||||
module.exports.removeClosingReturnPoints = removeClosingReturnPoints;
|
||||
module.exports.toRelative = toRelative;
|
||||
module.exports.identifier = identifier;
|
||||
|
||||
50
static/js/ketcher2/node_modules/svg2ttf/lib/ucs2.js
generated
vendored
Normal file
50
static/js/ketcher2/node_modules/svg2ttf/lib/ucs2.js
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
|
||||
// Taken from the punycode library
|
||||
function ucs2encode(array) {
|
||||
return _.map(array, function (value) {
|
||||
var output = '';
|
||||
|
||||
if (value > 0xFFFF) {
|
||||
value -= 0x10000;
|
||||
output += String.fromCharCode(value >>> 10 & 0x3FF | 0xD800);
|
||||
value = 0xDC00 | value & 0x3FF;
|
||||
}
|
||||
output += String.fromCharCode(value);
|
||||
return output;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function ucs2decode(string) {
|
||||
var output = [],
|
||||
counter = 0,
|
||||
length = string.length,
|
||||
value,
|
||||
extra;
|
||||
|
||||
while (counter < length) {
|
||||
value = string.charCodeAt(counter++);
|
||||
if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
|
||||
// high surrogate, and there is a next character
|
||||
extra = string.charCodeAt(counter++);
|
||||
if ((extra & 0xFC00) === 0xDC00) { // low surrogate
|
||||
output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
|
||||
} else {
|
||||
// unmatched surrogate; only append this code unit, in case the next
|
||||
// code unit is the high surrogate of a surrogate pair
|
||||
output.push(value);
|
||||
counter--;
|
||||
}
|
||||
} else {
|
||||
output.push(value);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
encode: ucs2encode,
|
||||
decode: ucs2decode
|
||||
};
|
||||
Reference in New Issue
Block a user