154 lines
4.1 KiB
Plaintext
154 lines
4.1 KiB
Plaintext
/**
|
|
* @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) {
|
|
|
|
let prevGlyph = null;
|
|
const result = [];
|
|
let segment = {};
|
|
|
|
glyfUnicodes.forEach((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) {
|
|
const unicodes = [];
|
|
glyfUnicodes.forEach((u) => {
|
|
if (u.unicode !== undefined && u.unicode < 256) {
|
|
unicodes.push([u.unicode, u.id]);
|
|
}
|
|
});
|
|
|
|
// 按编码排序
|
|
unicodes.sort((a, b) => a[0] - b[0]);
|
|
|
|
return unicodes;
|
|
}
|
|
|
|
/**
|
|
* 对cmap数据进行预处理,获取大小
|
|
*
|
|
* @param {Object} ttf ttf对象
|
|
* @return {number} 大小
|
|
*/
|
|
export default function sizeof(ttf) {
|
|
ttf.support.cmap = {};
|
|
let glyfUnicodes = [];
|
|
ttf.glyf.forEach((glyph, index) => {
|
|
|
|
let unicodes = glyph.unicode;
|
|
|
|
if (typeof glyph.unicode === 'number') {
|
|
unicodes = [glyph.unicode];
|
|
}
|
|
|
|
if (unicodes && unicodes.length) {
|
|
unicodes.forEach((unicode) => {
|
|
glyfUnicodes.push({
|
|
unicode,
|
|
id: unicode !== 0xFFFF ? index : 0
|
|
});
|
|
});
|
|
}
|
|
|
|
});
|
|
|
|
glyfUnicodes = glyfUnicodes.sort((a, b) => a.unicode - b.unicode);
|
|
|
|
ttf.support.cmap.unicodes = glyfUnicodes;
|
|
|
|
const 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.
|
|
const hasGLyphsOver2Bytes = unicodes2Bytes.some((glyph) => glyph.unicode > 0xFFFF);
|
|
|
|
if (hasGLyphsOver2Bytes) {
|
|
ttf.support.cmap.hasGLyphsOver2Bytes = hasGLyphsOver2Bytes;
|
|
|
|
const unicodes4Bytes = glyfUnicodes;
|
|
|
|
ttf.support.cmap.format12Segments = getSegments(unicodes4Bytes);
|
|
ttf.support.cmap.format12Size = 16
|
|
+ ttf.support.cmap.format12Segments.length * 12;
|
|
}
|
|
|
|
const 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;
|
|
}
|
|
|