forked from enviPath/enviPy
Current Dev State
This commit is contained in:
160
static/js/ketcher2/node_modules/svg2ttf/CHANGELOG.md
generated
vendored
Normal file
160
static/js/ketcher2/node_modules/svg2ttf/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,160 @@
|
||||
4.1.0 / 2017-06-24
|
||||
------------------
|
||||
|
||||
- Added font subfamily name support, #57.
|
||||
|
||||
|
||||
4.0.3 / 2017-05-27
|
||||
------------------
|
||||
|
||||
- Script tags should be arranged alpabetically, #55.
|
||||
|
||||
|
||||
4.0.2 / 2016-08-04
|
||||
------------------
|
||||
|
||||
- Added option to customize version string.
|
||||
|
||||
|
||||
4.0.1 / 2016-06-03
|
||||
------------------
|
||||
|
||||
- Fix IE ligatures by explicitly adding the latin script to the script list, #47.
|
||||
|
||||
|
||||
4.0.0 / 2016-03-08
|
||||
------------------
|
||||
|
||||
- Deps update (lodash -> 4.+).
|
||||
- Set HHEA lineGap to 0, #37 (second attempt :).
|
||||
- Cleanup, testing.
|
||||
|
||||
|
||||
3.0.0 / 2016-02-12
|
||||
------------------
|
||||
|
||||
- Changed defaults to workaround IE bugs.
|
||||
- Set HHEA lineGap to 0, #37.
|
||||
- Set OS/2 fsType to 0, #45.
|
||||
|
||||
|
||||
2.1.1 / 2015-12-22
|
||||
------------------
|
||||
|
||||
- Maintenance release: deps bump (svgpath with bugfixes).
|
||||
|
||||
|
||||
2.1.0 / 2015-10-28
|
||||
------------------
|
||||
|
||||
- Fixed smoothness at the ends of interpolated cubic beziers.
|
||||
|
||||
|
||||
2.0.2 / 2015-08-23
|
||||
------------------
|
||||
|
||||
- Fixed parse empty SVG glyphs without `d` attribute.
|
||||
|
||||
|
||||
2.0.1 / 2015-07-17
|
||||
------------------
|
||||
|
||||
- Fix: TTF creation timestamp should not depende on timezone, thanks to @nfroidure.
|
||||
|
||||
|
||||
2.0.0 / 2015-04-25
|
||||
------------------
|
||||
|
||||
- Added ligatures support, big thanks to @sabberworm.
|
||||
- Added arcs support in SVG paths.
|
||||
- Added `--ts` option to override default timestamp.
|
||||
- Fixed horisontal offset (`lsb`) when glyph exceed width.
|
||||
- Allow zero-width glyphs.
|
||||
- Better error message on attempt to convert SVG image instead of SVG font.
|
||||
|
||||
|
||||
1.2.0 / 2014-10-05
|
||||
------------------
|
||||
|
||||
- Fixed usWinAscent/usWinDescent - should not go below ascent/descent.
|
||||
- Upgraded ByteBuffer internal lib.
|
||||
- Code cleanup.
|
||||
|
||||
|
||||
1.1.2 / 2013-12-02
|
||||
------------------
|
||||
|
||||
- Fixed crash on SVG with empty <metadata> (#8)
|
||||
- Fixed descent when input font has descent = 0 (@nfroidure)
|
||||
|
||||
|
||||
1.1.1 / 2013-09-26
|
||||
------------------
|
||||
|
||||
- SVG parser moved to external package
|
||||
- Speed opts
|
||||
- Code refactoring/cleanup
|
||||
|
||||
|
||||
1.1.0 / 2013-09-25
|
||||
------------------
|
||||
|
||||
- Rewritten svg parser to improve speed
|
||||
- API changed, now returns buffer as array/Uint8Array
|
||||
|
||||
|
||||
1.0.7 / 2013-09-22
|
||||
------------------
|
||||
|
||||
- Improved speed x2.5 times
|
||||
|
||||
|
||||
1.0.6 / 2013-09-12
|
||||
------------------
|
||||
|
||||
- Improved handling glyphs without codes or names
|
||||
- Fixed crash on glyphs with `v`/`h` commands
|
||||
- Logic cleanup
|
||||
|
||||
|
||||
1.0.5 / 2013-08-27
|
||||
------------------
|
||||
|
||||
- Added CLI option `-c` to set copyright string
|
||||
- Fixed crash when some metrics missed in source SVG
|
||||
- Minor code cleanup
|
||||
|
||||
|
||||
1.0.4 / 2013-08-09
|
||||
------------------
|
||||
|
||||
- Fixed importing into OSX Font Book
|
||||
|
||||
|
||||
1.0.3 / 2013-08-02
|
||||
------------------
|
||||
|
||||
- Fixed maxp table max points count (solved chrome problems under windozze)
|
||||
|
||||
|
||||
1.0.2 / 2013-07-24
|
||||
------------------
|
||||
|
||||
- Fixed htmx table size
|
||||
- Fixed loca table size for long format
|
||||
- Fixed glyph bounding boxes writing
|
||||
|
||||
|
||||
1.0.1 / 2013-07-24
|
||||
------------------
|
||||
|
||||
- Added options support
|
||||
- Added `ttfinfo` utility
|
||||
- Multiple fixes
|
||||
|
||||
|
||||
1.0.0 / 2013-07-19
|
||||
------------------
|
||||
|
||||
- First release
|
||||
|
||||
21
static/js/ketcher2/node_modules/svg2ttf/LICENSE
generated
vendored
Normal file
21
static/js/ketcher2/node_modules/svg2ttf/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (C) 2013-2015 by Vitaly Puzrin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
70
static/js/ketcher2/node_modules/svg2ttf/README.md
generated
vendored
Normal file
70
static/js/ketcher2/node_modules/svg2ttf/README.md
generated
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
svg2ttf
|
||||
========
|
||||
|
||||
[](https://travis-ci.org/fontello/svg2ttf)
|
||||
[](https://www.npmjs.org/package/svg2ttf)
|
||||
|
||||
> Converts SVG fonts to TTF format. It was initially written for
|
||||
[Fontello](http://fontello.com), but you can find it useful for your projects.
|
||||
|
||||
__For developpers:__
|
||||
|
||||
Internal API is similar to FontForge's one. Since primary goal
|
||||
is generating iconic fonts, sources can lack some specific TTF/OTF features,
|
||||
like kerning and so on. Anyway, current code is a good base for development,
|
||||
because it will save you tons of hours to implement correct writing & optimizing
|
||||
TTF tables.
|
||||
|
||||
|
||||
Using from CLI
|
||||
----------------
|
||||
|
||||
Install:
|
||||
|
||||
``` bash
|
||||
npm install -g svg2ttf
|
||||
```
|
||||
|
||||
Usage example:
|
||||
|
||||
``` bash
|
||||
svg2ttf fontello.svg fontello.ttf
|
||||
```
|
||||
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
### svg2ttf(svgFontString, options) -> buf
|
||||
|
||||
- `svgFontString` - SVG font content
|
||||
- `options`
|
||||
- `copyright` - copyright string (optional)
|
||||
- `ts` - Unix timestamp (in seconds) to override creation time (optional)
|
||||
- `version` - font version string, can be `Version x.y` or `x.y`.
|
||||
- `buf` - internal [byte buffer](https://github.com/fontello/microbuffer)
|
||||
object, similar to DataView. It's `buffer` property is `Uin8Array` or `Array`
|
||||
with ttf content.
|
||||
|
||||
Example:
|
||||
|
||||
``` javascript
|
||||
var fs = require('fs');
|
||||
var svg2ttf = require('svg2ttf');
|
||||
|
||||
var ttf = svg2ttf(fs.readFileSync('myfont.svg', 'utf8'), {});
|
||||
fs.writeFileSync('myfont.ttf', new Buffer(ttf.buffer));
|
||||
```
|
||||
|
||||
|
||||
Authors
|
||||
-------
|
||||
|
||||
* Sergey Batishchev - [@snb2013](https://github.com/snb2013)
|
||||
* Vitaly Puzrin - [@puzrin](https://github.com/puzrin)
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
[MIT](https://github.com/nodeca/svg2ttf/blob/master/LICENSE).
|
||||
186
static/js/ketcher2/node_modules/svg2ttf/index.js
generated
vendored
Normal file
186
static/js/ketcher2/node_modules/svg2ttf/index.js
generated
vendored
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright: Vitaly Puzrin
|
||||
* Author: Sergey Batishchev <snb2003@rambler.ru>
|
||||
*
|
||||
* Written for fontello.com project.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var SvgPath = require('svgpath');
|
||||
var ucs2 = require('./lib/ucs2');
|
||||
var svg = require('./lib/svg');
|
||||
var sfnt = require('./lib/sfnt');
|
||||
|
||||
|
||||
var VERSION_RE = /^(Version )?(\d+[.]\d+)$/i;
|
||||
|
||||
|
||||
function svg2ttf(svgString, options) {
|
||||
var font = new sfnt.Font();
|
||||
var svgFont = svg.load(svgString);
|
||||
|
||||
options = options || {};
|
||||
|
||||
font.id = options.id || svgFont.id;
|
||||
font.familyName = options.familyname || svgFont.familyName || svgFont.id;
|
||||
font.copyright = options.copyright || svgFont.metadata;
|
||||
font.sfntNames.push({ id: 2, value: options.subfamilyname || svgFont.subfamilyName || 'Regular' }); // subfamily name
|
||||
font.sfntNames.push({ id: 4, value: options.fullname || svgFont.id }); // full name
|
||||
|
||||
var versionString = options.version || 'Version 1.0';
|
||||
|
||||
if (typeof versionString !== 'string') {
|
||||
throw new Error('svg2ttf: version option should be a string');
|
||||
}
|
||||
if (!VERSION_RE.test(versionString)) {
|
||||
throw new Error('svg2ttf: invalid option, version - "' + options.version + '"');
|
||||
}
|
||||
|
||||
versionString = 'Version ' + versionString.match(VERSION_RE)[2];
|
||||
font.sfntNames.push({ id: 5, value: versionString }); // version ID for TTF name table
|
||||
font.sfntNames.push({ id: 6, value: (options.fullname || svgFont.id).replace(/[\s\(\)\[\]<>%\/]/g, '').substr(0, 62) }); // Postscript name for the font, required for OSX Font Book
|
||||
|
||||
if (typeof options.ts !== 'undefined') {
|
||||
font.createdDate = font.modifiedDate = new Date(parseInt(options.ts, 10) * 1000);
|
||||
}
|
||||
|
||||
// Try to fill font metrics or guess defaults
|
||||
//
|
||||
font.unitsPerEm = svgFont.unitsPerEm || 1000;
|
||||
font.horizOriginX = svgFont.horizOriginX || 0;
|
||||
font.horizOriginY = svgFont.horizOriginY || 0;
|
||||
font.vertOriginX = svgFont.vertOriginX || 0;
|
||||
font.vertOriginY = svgFont.vertOriginY || 0;
|
||||
// need to correctly convert text values, use default (400) until compleete
|
||||
//font.weightClass = svgFont.weightClass;
|
||||
font.width = svgFont.width || svgFont.unitsPerEm;
|
||||
font.height = svgFont.height || svgFont.unitsPerEm;
|
||||
font.descent = !isNaN(svgFont.descent) ? svgFont.descent : -font.vertOriginY;
|
||||
font.ascent = svgFont.ascent || (font.unitsPerEm - font.vertOriginY);
|
||||
|
||||
var glyphs = font.glyphs;
|
||||
var codePoints = font.codePoints;
|
||||
var ligatures = font.ligatures;
|
||||
|
||||
function addCodePoint(codePoint, glyph) {
|
||||
if (codePoints[codePoint]) {
|
||||
// Ignore code points already defined
|
||||
return false;
|
||||
}
|
||||
codePoints[codePoint] = glyph;
|
||||
return true;
|
||||
}
|
||||
|
||||
// add SVG glyphs to SFNT font
|
||||
_.forEach(svgFont.glyphs, function (svgGlyph) {
|
||||
var glyph = new sfnt.Glyph();
|
||||
|
||||
glyph.name = svgGlyph.name;
|
||||
glyph.d = svgGlyph.d;
|
||||
glyph.height = !isNaN(svgGlyph.height) ? svgGlyph.height : font.height;
|
||||
glyph.width = !isNaN(svgGlyph.width) ? svgGlyph.width : font.width;
|
||||
glyphs.push(glyph);
|
||||
|
||||
svgGlyph.sfntGlyph = glyph;
|
||||
|
||||
_.forEach(svgGlyph.unicode, function (codePoint) {
|
||||
addCodePoint(codePoint, glyph);
|
||||
});
|
||||
});
|
||||
|
||||
var missingGlyph;
|
||||
|
||||
// add missing glyph to SFNT font
|
||||
// also, check missing glyph existance and single instance
|
||||
if (svgFont.missingGlyph) {
|
||||
missingGlyph = new sfnt.Glyph();
|
||||
missingGlyph.d = svgFont.missingGlyph.d;
|
||||
missingGlyph.height = !isNaN(svgFont.missingGlyph.height) ? svgFont.missingGlyph.height : font.height;
|
||||
missingGlyph.width = !isNaN(svgFont.missingGlyph.width) ? svgFont.missingGlyph.width : font.width;
|
||||
} else {
|
||||
missingGlyph = _.find(glyphs, function (glyph) {
|
||||
return glyph.name === '.notdef';
|
||||
});
|
||||
}
|
||||
if (!missingGlyph) { // no missing glyph and .notdef glyph, we need to create missing glyph
|
||||
missingGlyph = new sfnt.Glyph();
|
||||
}
|
||||
|
||||
// Create glyphs for all characters used in ligatures
|
||||
_.forEach(svgFont.ligatures, function (svgLigature) {
|
||||
var ligature = {
|
||||
ligature: svgLigature.ligature,
|
||||
unicode: svgLigature.unicode,
|
||||
glyph: svgLigature.glyph.sfntGlyph
|
||||
};
|
||||
|
||||
_.forEach(ligature.unicode, function (charPoint) {
|
||||
// We need to have a distinct glyph for each code point so we can reference it in GSUB
|
||||
var glyph = new sfnt.Glyph();
|
||||
var added = addCodePoint(charPoint, glyph);
|
||||
|
||||
if (added) {
|
||||
glyph.name = ucs2.encode([ charPoint ]);
|
||||
glyphs.push(glyph);
|
||||
}
|
||||
});
|
||||
ligatures.push(ligature);
|
||||
});
|
||||
|
||||
// Missing Glyph needs to have index 0
|
||||
if (glyphs.indexOf(missingGlyph) !== -1) {
|
||||
glyphs.splice(glyphs.indexOf(missingGlyph), 1);
|
||||
}
|
||||
glyphs.unshift(missingGlyph);
|
||||
|
||||
var nextID = 0;
|
||||
|
||||
//add IDs
|
||||
_.forEach(glyphs, function (glyph) {
|
||||
glyph.id = nextID;
|
||||
nextID++;
|
||||
});
|
||||
|
||||
_.forEach(glyphs, function (glyph) {
|
||||
|
||||
// Calculate accuracy for cubicToQuad transformation
|
||||
// For glyphs with height and width smaller than 500 use relative 0.06% accuracy,
|
||||
// for larger glyphs use fixed accuracy 0.3.
|
||||
var glyphSize = Math.max(glyph.width, glyph.height);
|
||||
var accuracy = (glyphSize > 500) ? 0.3 : glyphSize * 0.0006;
|
||||
|
||||
//SVG transformations
|
||||
var svgPath = new SvgPath(glyph.d)
|
||||
.abs()
|
||||
.unshort()
|
||||
.unarc()
|
||||
.iterate(function (segment, index, x, y) {
|
||||
return svg.cubicToQuad(segment, index, x, y, accuracy);
|
||||
});
|
||||
var sfntContours = svg.toSfntCoutours(svgPath);
|
||||
|
||||
// Add contours to SFNT font
|
||||
glyph.contours = _.map(sfntContours, function (sfntContour) {
|
||||
var contour = new sfnt.Contour();
|
||||
|
||||
contour.points = _.map(sfntContour, function (sfntPoint) {
|
||||
var point = new sfnt.Point();
|
||||
|
||||
point.x = sfntPoint.x;
|
||||
point.y = sfntPoint.y;
|
||||
point.onCurve = sfntPoint.onCurve;
|
||||
return point;
|
||||
});
|
||||
|
||||
return contour;
|
||||
});
|
||||
});
|
||||
|
||||
var ttf = sfnt.toTTF(font);
|
||||
|
||||
return ttf;
|
||||
}
|
||||
|
||||
module.exports = svg2ttf;
|
||||
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
|
||||
};
|
||||
74
static/js/ketcher2/node_modules/svg2ttf/package.json
generated
vendored
Normal file
74
static/js/ketcher2/node_modules/svg2ttf/package.json
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
{
|
||||
"_from": "svg2ttf@^4.1.0",
|
||||
"_id": "svg2ttf@4.1.0",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha1-ggIuVovQPBq7Zo/djRXwCJVqDhA=",
|
||||
"_location": "/svg2ttf",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "range",
|
||||
"registry": true,
|
||||
"raw": "svg2ttf@^4.1.0",
|
||||
"name": "svg2ttf",
|
||||
"escapedName": "svg2ttf",
|
||||
"rawSpec": "^4.1.0",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "^4.1.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/gulp-svg2ttf"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/svg2ttf/-/svg2ttf-4.1.0.tgz",
|
||||
"_shasum": "82022e568bd03c1abb668fdd8d15f008956a0e10",
|
||||
"_spec": "svg2ttf@^4.1.0",
|
||||
"_where": "/home/manfred/enviPath/ketcher2/ketcher/node_modules/gulp-svg2ttf",
|
||||
"author": {
|
||||
"name": "Sergey Batishchev",
|
||||
"email": "sergej.batishchev@gmail.com"
|
||||
},
|
||||
"bin": {
|
||||
"svg2ttf": "./svg2ttf.js"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/fontello/svg2ttf/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"dependencies": {
|
||||
"argparse": "^1.0.6",
|
||||
"cubic2quad": "^1.0.0",
|
||||
"lodash": "^4.6.1",
|
||||
"microbuffer": "^1.0.0",
|
||||
"svgpath": "^2.1.5",
|
||||
"xmldom": "~0.1.22"
|
||||
},
|
||||
"deprecated": false,
|
||||
"description": "Converts SVG font to TTF font",
|
||||
"devDependencies": {
|
||||
"eslint": "^4.1.0",
|
||||
"mocha": "^3.0.0"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"svg2ttf.js",
|
||||
"lib/"
|
||||
],
|
||||
"homepage": "https://github.com/fontello/svg2ttf#readme",
|
||||
"keywords": [
|
||||
"font",
|
||||
"ttf",
|
||||
"svg",
|
||||
"convertor"
|
||||
],
|
||||
"license": "MIT",
|
||||
"name": "svg2ttf",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/fontello/svg2ttf.git"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"test": "npm run lint && mocha",
|
||||
"update_fixture": "./svg2ttf.js --ts 1457357570703 test/fixtures/test.svg test/fixtures/test.ttf"
|
||||
},
|
||||
"version": "4.1.0"
|
||||
}
|
||||
85
static/js/ketcher2/node_modules/svg2ttf/svg2ttf.js
generated
vendored
Executable file
85
static/js/ketcher2/node_modules/svg2ttf/svg2ttf.js
generated
vendored
Executable file
@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env node
|
||||
/*
|
||||
Author: Sergey Batishchev <sergej.batishchev@gmail.com>
|
||||
|
||||
Written for fontello.com project.
|
||||
*/
|
||||
|
||||
/*eslint-disable no-console*/
|
||||
|
||||
'use strict';
|
||||
|
||||
|
||||
var fs = require('fs');
|
||||
var ArgumentParser = require('argparse').ArgumentParser;
|
||||
|
||||
var svg2ttf = require('./');
|
||||
|
||||
|
||||
var parser = new ArgumentParser({
|
||||
version: require('./package.json').version,
|
||||
addHelp: true,
|
||||
description: 'SVG to TTF font converter'
|
||||
});
|
||||
|
||||
parser.addArgument(
|
||||
[ '-c', '--copyright' ],
|
||||
{
|
||||
help: 'Copyright text',
|
||||
required: false
|
||||
}
|
||||
);
|
||||
|
||||
parser.addArgument(
|
||||
[ '--ts' ],
|
||||
{
|
||||
help: 'Override font creation time (Unix time stamp)',
|
||||
required: false,
|
||||
type: 'int'
|
||||
}
|
||||
);
|
||||
|
||||
parser.addArgument(
|
||||
[ '--vs' ],
|
||||
{
|
||||
help: 'Override default font version string (Version 1.0), can be "x.y" or "Version x.y"',
|
||||
required: false,
|
||||
type: 'string'
|
||||
}
|
||||
);
|
||||
|
||||
parser.addArgument(
|
||||
[ 'infile' ],
|
||||
{
|
||||
nargs: 1,
|
||||
help: 'Input file'
|
||||
}
|
||||
);
|
||||
|
||||
parser.addArgument(
|
||||
[ 'outfile' ],
|
||||
{
|
||||
nargs: 1,
|
||||
help: 'Output file'
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
var args = parser.parseArgs();
|
||||
var svg;
|
||||
var options = {};
|
||||
|
||||
try {
|
||||
svg = fs.readFileSync(args.infile[0], 'utf-8');
|
||||
} catch (e) {
|
||||
console.error("Can't open input file (%s)", args.infile[0]);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (args.copyright) options.copyright = args.copyright;
|
||||
|
||||
if (args.ts !== null) options.ts = args.ts;
|
||||
|
||||
if (args.vs) options.version = args.vs;
|
||||
|
||||
fs.writeFileSync(args.outfile[0], new Buffer(svg2ttf(svg, options).buffer));
|
||||
Reference in New Issue
Block a user