fonteditor-core
Version:
fonts (ttf, woff, woff2, eot, svg, otf) parse, write, transform, glyph adjust.
138 lines (128 loc) • 3.92 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = sizeof;
/**
* @file 获取cmap表的大小
* @author mengke01(kekee000@gmail.com)
*/
/**
* 获取format4 delta值
* Delta is saved in signed int in cmap format 4 subtable,
* but can be in -0xFFFF..0 interval.
* -0x10000..-0x7FFF values are stored with offset.
*
* @param {number} delta delta值
* @return {number} delta值
*/
function encodeDelta(delta) {
return delta > 0x7FFF ? delta - 0x10000 : delta < -0x7FFF ? delta + 0x10000 : delta;
}
/**
* 根据bound获取glyf segment
*
* @param {Array} glyfUnicodes glyf编码集合
* @param {number} bound 编码范围
* @return {Array} 码表
*/
function getSegments(glyfUnicodes, bound) {
var prevGlyph = null;
var result = [];
var segment = {};
glyfUnicodes.forEach(function (glyph) {
if (bound === undefined || glyph.unicode <= bound) {
// 初始化编码头部,这里unicode和graph id 都必须连续
if (prevGlyph === null || glyph.unicode !== prevGlyph.unicode + 1 || glyph.id !== prevGlyph.id + 1) {
if (prevGlyph !== null) {
segment.end = prevGlyph.unicode;
result.push(segment);
segment = {
start: glyph.unicode,
startId: glyph.id,
delta: encodeDelta(glyph.id - glyph.unicode)
};
} else {
segment.start = glyph.unicode;
segment.startId = glyph.id;
segment.delta = encodeDelta(glyph.id - glyph.unicode);
}
}
prevGlyph = glyph;
}
});
// need to finish the last segment
if (prevGlyph !== null) {
segment.end = prevGlyph.unicode;
result.push(segment);
}
// 返回编码范围
return result;
}
/**
* 获取format0编码集合
*
* @param {Array} glyfUnicodes glyf编码集合
* @return {Array} 码表
*/
function getFormat0Segment(glyfUnicodes) {
var unicodes = [];
glyfUnicodes.forEach(function (u) {
if (u.unicode !== undefined && u.unicode < 256) {
unicodes.push([u.unicode, u.id]);
}
});
// 按编码排序
unicodes.sort(function (a, b) {
return a[0] - b[0];
});
return unicodes;
}
/**
* 对cmap数据进行预处理,获取大小
*
* @param {Object} ttf ttf对象
* @return {number} 大小
*/
function sizeof(ttf) {
ttf.support.cmap = {};
var glyfUnicodes = [];
ttf.glyf.forEach(function (glyph, index) {
var unicodes = glyph.unicode;
if (typeof glyph.unicode === 'number') {
unicodes = [glyph.unicode];
}
if (unicodes && unicodes.length) {
unicodes.forEach(function (unicode) {
glyfUnicodes.push({
unicode: unicode,
id: unicode !== 0xFFFF ? index : 0
});
});
}
});
glyfUnicodes = glyfUnicodes.sort(function (a, b) {
return a.unicode - b.unicode;
});
ttf.support.cmap.unicodes = glyfUnicodes;
var unicodes2Bytes = glyfUnicodes;
ttf.support.cmap.format4Segments = getSegments(unicodes2Bytes, 0xFFFF);
ttf.support.cmap.format4Size = 24 + ttf.support.cmap.format4Segments.length * 8;
ttf.support.cmap.format0Segments = getFormat0Segment(glyfUnicodes);
ttf.support.cmap.format0Size = 262;
// we need subtable 12 only if found unicodes with > 2 bytes.
var hasGLyphsOver2Bytes = unicodes2Bytes.some(function (glyph) {
return glyph.unicode > 0xFFFF;
});
if (hasGLyphsOver2Bytes) {
ttf.support.cmap.hasGLyphsOver2Bytes = hasGLyphsOver2Bytes;
var unicodes4Bytes = glyfUnicodes;
ttf.support.cmap.format12Segments = getSegments(unicodes4Bytes);
ttf.support.cmap.format12Size = 16 + ttf.support.cmap.format12Segments.length * 12;
}
var size = 4 + (hasGLyphsOver2Bytes ? 32 : 24) // cmap header
+ ttf.support.cmap.format0Size // format 0
+ ttf.support.cmap.format4Size // format 4
+ (hasGLyphsOver2Bytes ? ttf.support.cmap.format12Size : 0); // format 12
return size;
}