| /** |
| * @licstart The following is the entire license notice for the |
| * Javascript code in this page |
| * |
| * Copyright 2020 Mozilla Foundation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * @licend The above is the entire license notice for the |
| * Javascript code in this page |
| */ |
| "use strict"; |
| |
| Object.defineProperty(exports, "__esModule", { |
| value: true |
| }); |
| exports.FontRendererFactory = void 0; |
| |
| var _util = require("../shared/util.js"); |
| |
| var _cff_parser = require("./cff_parser.js"); |
| |
| var _glyphlist = require("./glyphlist.js"); |
| |
| var _encodings = require("./encodings.js"); |
| |
| var _stream = require("./stream.js"); |
| |
| var FontRendererFactory = function FontRendererFactoryClosure() { |
| function getLong(data, offset) { |
| return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]; |
| } |
| |
| function getUshort(data, offset) { |
| return data[offset] << 8 | data[offset + 1]; |
| } |
| |
| function getSubroutineBias(subrs) { |
| const numSubrs = subrs.length; |
| let bias = 32768; |
| |
| if (numSubrs < 1240) { |
| bias = 107; |
| } else if (numSubrs < 33900) { |
| bias = 1131; |
| } |
| |
| return bias; |
| } |
| |
| function parseCmap(data, start, end) { |
| var offset = getUshort(data, start + 2) === 1 ? getLong(data, start + 8) : getLong(data, start + 16); |
| var format = getUshort(data, start + offset); |
| var ranges, p, i; |
| |
| if (format === 4) { |
| getUshort(data, start + offset + 2); |
| var segCount = getUshort(data, start + offset + 6) >> 1; |
| p = start + offset + 14; |
| ranges = []; |
| |
| for (i = 0; i < segCount; i++, p += 2) { |
| ranges[i] = { |
| end: getUshort(data, p) |
| }; |
| } |
| |
| p += 2; |
| |
| for (i = 0; i < segCount; i++, p += 2) { |
| ranges[i].start = getUshort(data, p); |
| } |
| |
| for (i = 0; i < segCount; i++, p += 2) { |
| ranges[i].idDelta = getUshort(data, p); |
| } |
| |
| for (i = 0; i < segCount; i++, p += 2) { |
| var idOffset = getUshort(data, p); |
| |
| if (idOffset === 0) { |
| continue; |
| } |
| |
| ranges[i].ids = []; |
| |
| for (var j = 0, jj = ranges[i].end - ranges[i].start + 1; j < jj; j++) { |
| ranges[i].ids[j] = getUshort(data, p + idOffset); |
| idOffset += 2; |
| } |
| } |
| |
| return ranges; |
| } else if (format === 12) { |
| getLong(data, start + offset + 4); |
| var groups = getLong(data, start + offset + 12); |
| p = start + offset + 16; |
| ranges = []; |
| |
| for (i = 0; i < groups; i++) { |
| ranges.push({ |
| start: getLong(data, p), |
| end: getLong(data, p + 4), |
| idDelta: getLong(data, p + 8) - getLong(data, p) |
| }); |
| p += 12; |
| } |
| |
| return ranges; |
| } |
| |
| throw new _util.FormatError(`unsupported cmap: ${format}`); |
| } |
| |
| function parseCff(data, start, end, seacAnalysisEnabled) { |
| var properties = {}; |
| var parser = new _cff_parser.CFFParser(new _stream.Stream(data, start, end - start), properties, seacAnalysisEnabled); |
| var cff = parser.parse(); |
| return { |
| glyphs: cff.charStrings.objects, |
| subrs: cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex && cff.topDict.privateDict.subrsIndex.objects, |
| gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects, |
| isCFFCIDFont: cff.isCIDFont, |
| fdSelect: cff.fdSelect, |
| fdArray: cff.fdArray |
| }; |
| } |
| |
| function parseGlyfTable(glyf, loca, isGlyphLocationsLong) { |
| var itemSize, itemDecode; |
| |
| if (isGlyphLocationsLong) { |
| itemSize = 4; |
| |
| itemDecode = function fontItemDecodeLong(data, offset) { |
| return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]; |
| }; |
| } else { |
| itemSize = 2; |
| |
| itemDecode = function fontItemDecode(data, offset) { |
| return data[offset] << 9 | data[offset + 1] << 1; |
| }; |
| } |
| |
| var glyphs = []; |
| var startOffset = itemDecode(loca, 0); |
| |
| for (var j = itemSize; j < loca.length; j += itemSize) { |
| var endOffset = itemDecode(loca, j); |
| glyphs.push(glyf.subarray(startOffset, endOffset)); |
| startOffset = endOffset; |
| } |
| |
| return glyphs; |
| } |
| |
| function lookupCmap(ranges, unicode) { |
| var code = unicode.codePointAt(0), |
| gid = 0; |
| var l = 0, |
| r = ranges.length - 1; |
| |
| while (l < r) { |
| var c = l + r + 1 >> 1; |
| |
| if (code < ranges[c].start) { |
| r = c - 1; |
| } else { |
| l = c; |
| } |
| } |
| |
| if (ranges[l].start <= code && code <= ranges[l].end) { |
| gid = ranges[l].idDelta + (ranges[l].ids ? ranges[l].ids[code - ranges[l].start] : code) & 0xffff; |
| } |
| |
| return { |
| charCode: code, |
| glyphId: gid |
| }; |
| } |
| |
| function compileGlyf(code, cmds, font) { |
| function moveTo(x, y) { |
| cmds.push({ |
| cmd: "moveTo", |
| args: [x, y] |
| }); |
| } |
| |
| function lineTo(x, y) { |
| cmds.push({ |
| cmd: "lineTo", |
| args: [x, y] |
| }); |
| } |
| |
| function quadraticCurveTo(xa, ya, x, y) { |
| cmds.push({ |
| cmd: "quadraticCurveTo", |
| args: [xa, ya, x, y] |
| }); |
| } |
| |
| var i = 0; |
| var numberOfContours = (code[i] << 24 | code[i + 1] << 16) >> 16; |
| var flags; |
| var x = 0, |
| y = 0; |
| i += 10; |
| |
| if (numberOfContours < 0) { |
| do { |
| flags = code[i] << 8 | code[i + 1]; |
| var glyphIndex = code[i + 2] << 8 | code[i + 3]; |
| i += 4; |
| var arg1, arg2; |
| |
| if (flags & 0x01) { |
| arg1 = (code[i] << 24 | code[i + 1] << 16) >> 16; |
| arg2 = (code[i + 2] << 24 | code[i + 3] << 16) >> 16; |
| i += 4; |
| } else { |
| arg1 = code[i++]; |
| arg2 = code[i++]; |
| } |
| |
| if (flags & 0x02) { |
| x = arg1; |
| y = arg2; |
| } else { |
| x = 0; |
| y = 0; |
| } |
| |
| var scaleX = 1, |
| scaleY = 1, |
| scale01 = 0, |
| scale10 = 0; |
| |
| if (flags & 0x08) { |
| scaleX = scaleY = (code[i] << 24 | code[i + 1] << 16) / 1073741824; |
| i += 2; |
| } else if (flags & 0x40) { |
| scaleX = (code[i] << 24 | code[i + 1] << 16) / 1073741824; |
| scaleY = (code[i + 2] << 24 | code[i + 3] << 16) / 1073741824; |
| i += 4; |
| } else if (flags & 0x80) { |
| scaleX = (code[i] << 24 | code[i + 1] << 16) / 1073741824; |
| scale01 = (code[i + 2] << 24 | code[i + 3] << 16) / 1073741824; |
| scale10 = (code[i + 4] << 24 | code[i + 5] << 16) / 1073741824; |
| scaleY = (code[i + 6] << 24 | code[i + 7] << 16) / 1073741824; |
| i += 8; |
| } |
| |
| var subglyph = font.glyphs[glyphIndex]; |
| |
| if (subglyph) { |
| cmds.push({ |
| cmd: "save" |
| }); |
| cmds.push({ |
| cmd: "transform", |
| args: [scaleX, scale01, scale10, scaleY, x, y] |
| }); |
| compileGlyf(subglyph, cmds, font); |
| cmds.push({ |
| cmd: "restore" |
| }); |
| } |
| } while (flags & 0x20); |
| } else { |
| var endPtsOfContours = []; |
| var j, jj; |
| |
| for (j = 0; j < numberOfContours; j++) { |
| endPtsOfContours.push(code[i] << 8 | code[i + 1]); |
| i += 2; |
| } |
| |
| var instructionLength = code[i] << 8 | code[i + 1]; |
| i += 2 + instructionLength; |
| var numberOfPoints = endPtsOfContours[endPtsOfContours.length - 1] + 1; |
| var points = []; |
| |
| while (points.length < numberOfPoints) { |
| flags = code[i++]; |
| var repeat = 1; |
| |
| if (flags & 0x08) { |
| repeat += code[i++]; |
| } |
| |
| while (repeat-- > 0) { |
| points.push({ |
| flags |
| }); |
| } |
| } |
| |
| for (j = 0; j < numberOfPoints; j++) { |
| switch (points[j].flags & 0x12) { |
| case 0x00: |
| x += (code[i] << 24 | code[i + 1] << 16) >> 16; |
| i += 2; |
| break; |
| |
| case 0x02: |
| x -= code[i++]; |
| break; |
| |
| case 0x12: |
| x += code[i++]; |
| break; |
| } |
| |
| points[j].x = x; |
| } |
| |
| for (j = 0; j < numberOfPoints; j++) { |
| switch (points[j].flags & 0x24) { |
| case 0x00: |
| y += (code[i] << 24 | code[i + 1] << 16) >> 16; |
| i += 2; |
| break; |
| |
| case 0x04: |
| y -= code[i++]; |
| break; |
| |
| case 0x24: |
| y += code[i++]; |
| break; |
| } |
| |
| points[j].y = y; |
| } |
| |
| var startPoint = 0; |
| |
| for (i = 0; i < numberOfContours; i++) { |
| var endPoint = endPtsOfContours[i]; |
| var contour = points.slice(startPoint, endPoint + 1); |
| |
| if (contour[0].flags & 1) { |
| contour.push(contour[0]); |
| } else if (contour[contour.length - 1].flags & 1) { |
| contour.unshift(contour[contour.length - 1]); |
| } else { |
| var p = { |
| flags: 1, |
| x: (contour[0].x + contour[contour.length - 1].x) / 2, |
| y: (contour[0].y + contour[contour.length - 1].y) / 2 |
| }; |
| contour.unshift(p); |
| contour.push(p); |
| } |
| |
| moveTo(contour[0].x, contour[0].y); |
| |
| for (j = 1, jj = contour.length; j < jj; j++) { |
| if (contour[j].flags & 1) { |
| lineTo(contour[j].x, contour[j].y); |
| } else if (contour[j + 1].flags & 1) { |
| quadraticCurveTo(contour[j].x, contour[j].y, contour[j + 1].x, contour[j + 1].y); |
| j++; |
| } else { |
| quadraticCurveTo(contour[j].x, contour[j].y, (contour[j].x + contour[j + 1].x) / 2, (contour[j].y + contour[j + 1].y) / 2); |
| } |
| } |
| |
| startPoint = endPoint + 1; |
| } |
| } |
| } |
| |
| function compileCharString(charStringCode, cmds, font, glyphId) { |
| function moveTo(x, y) { |
| cmds.push({ |
| cmd: "moveTo", |
| args: [x, y] |
| }); |
| } |
| |
| function lineTo(x, y) { |
| cmds.push({ |
| cmd: "lineTo", |
| args: [x, y] |
| }); |
| } |
| |
| function bezierCurveTo(x1, y1, x2, y2, x, y) { |
| cmds.push({ |
| cmd: "bezierCurveTo", |
| args: [x1, y1, x2, y2, x, y] |
| }); |
| } |
| |
| var stack = []; |
| var x = 0, |
| y = 0; |
| var stems = 0; |
| |
| function parse(code) { |
| var i = 0; |
| |
| while (i < code.length) { |
| var stackClean = false; |
| var v = code[i++]; |
| var xa, xb, ya, yb, y1, y2, y3, n, subrCode; |
| |
| switch (v) { |
| case 1: |
| stems += stack.length >> 1; |
| stackClean = true; |
| break; |
| |
| case 3: |
| stems += stack.length >> 1; |
| stackClean = true; |
| break; |
| |
| case 4: |
| y += stack.pop(); |
| moveTo(x, y); |
| stackClean = true; |
| break; |
| |
| case 5: |
| while (stack.length > 0) { |
| x += stack.shift(); |
| y += stack.shift(); |
| lineTo(x, y); |
| } |
| |
| break; |
| |
| case 6: |
| while (stack.length > 0) { |
| x += stack.shift(); |
| lineTo(x, y); |
| |
| if (stack.length === 0) { |
| break; |
| } |
| |
| y += stack.shift(); |
| lineTo(x, y); |
| } |
| |
| break; |
| |
| case 7: |
| while (stack.length > 0) { |
| y += stack.shift(); |
| lineTo(x, y); |
| |
| if (stack.length === 0) { |
| break; |
| } |
| |
| x += stack.shift(); |
| lineTo(x, y); |
| } |
| |
| break; |
| |
| case 8: |
| while (stack.length > 0) { |
| xa = x + stack.shift(); |
| ya = y + stack.shift(); |
| xb = xa + stack.shift(); |
| yb = ya + stack.shift(); |
| x = xb + stack.shift(); |
| y = yb + stack.shift(); |
| bezierCurveTo(xa, ya, xb, yb, x, y); |
| } |
| |
| break; |
| |
| case 10: |
| n = stack.pop(); |
| subrCode = null; |
| |
| if (font.isCFFCIDFont) { |
| const fdIndex = font.fdSelect.getFDIndex(glyphId); |
| |
| if (fdIndex >= 0 && fdIndex < font.fdArray.length) { |
| const fontDict = font.fdArray[fdIndex]; |
| let subrs; |
| |
| if (fontDict.privateDict && fontDict.privateDict.subrsIndex) { |
| subrs = fontDict.privateDict.subrsIndex.objects; |
| } |
| |
| if (subrs) { |
| n += getSubroutineBias(subrs); |
| subrCode = subrs[n]; |
| } |
| } else { |
| (0, _util.warn)("Invalid fd index for glyph index."); |
| } |
| } else { |
| subrCode = font.subrs[n + font.subrsBias]; |
| } |
| |
| if (subrCode) { |
| parse(subrCode); |
| } |
| |
| break; |
| |
| case 11: |
| return; |
| |
| case 12: |
| v = code[i++]; |
| |
| switch (v) { |
| case 34: |
| xa = x + stack.shift(); |
| xb = xa + stack.shift(); |
| y1 = y + stack.shift(); |
| x = xb + stack.shift(); |
| bezierCurveTo(xa, y, xb, y1, x, y1); |
| xa = x + stack.shift(); |
| xb = xa + stack.shift(); |
| x = xb + stack.shift(); |
| bezierCurveTo(xa, y1, xb, y, x, y); |
| break; |
| |
| case 35: |
| xa = x + stack.shift(); |
| ya = y + stack.shift(); |
| xb = xa + stack.shift(); |
| yb = ya + stack.shift(); |
| x = xb + stack.shift(); |
| y = yb + stack.shift(); |
| bezierCurveTo(xa, ya, xb, yb, x, y); |
| xa = x + stack.shift(); |
| ya = y + stack.shift(); |
| xb = xa + stack.shift(); |
| yb = ya + stack.shift(); |
| x = xb + stack.shift(); |
| y = yb + stack.shift(); |
| bezierCurveTo(xa, ya, xb, yb, x, y); |
| stack.pop(); |
| break; |
| |
| case 36: |
| xa = x + stack.shift(); |
| y1 = y + stack.shift(); |
| xb = xa + stack.shift(); |
| y2 = y1 + stack.shift(); |
| x = xb + stack.shift(); |
| bezierCurveTo(xa, y1, xb, y2, x, y2); |
| xa = x + stack.shift(); |
| xb = xa + stack.shift(); |
| y3 = y2 + stack.shift(); |
| x = xb + stack.shift(); |
| bezierCurveTo(xa, y2, xb, y3, x, y); |
| break; |
| |
| case 37: |
| var x0 = x, |
| y0 = y; |
| xa = x + stack.shift(); |
| ya = y + stack.shift(); |
| xb = xa + stack.shift(); |
| yb = ya + stack.shift(); |
| x = xb + stack.shift(); |
| y = yb + stack.shift(); |
| bezierCurveTo(xa, ya, xb, yb, x, y); |
| xa = x + stack.shift(); |
| ya = y + stack.shift(); |
| xb = xa + stack.shift(); |
| yb = ya + stack.shift(); |
| x = xb; |
| y = yb; |
| |
| if (Math.abs(x - x0) > Math.abs(y - y0)) { |
| x += stack.shift(); |
| } else { |
| y += stack.shift(); |
| } |
| |
| bezierCurveTo(xa, ya, xb, yb, x, y); |
| break; |
| |
| default: |
| throw new _util.FormatError(`unknown operator: 12 ${v}`); |
| } |
| |
| break; |
| |
| case 14: |
| if (stack.length >= 4) { |
| var achar = stack.pop(); |
| var bchar = stack.pop(); |
| y = stack.pop(); |
| x = stack.pop(); |
| cmds.push({ |
| cmd: "save" |
| }); |
| cmds.push({ |
| cmd: "translate", |
| args: [x, y] |
| }); |
| var cmap = lookupCmap(font.cmap, String.fromCharCode(font.glyphNameMap[_encodings.StandardEncoding[achar]])); |
| compileCharString(font.glyphs[cmap.glyphId], cmds, font, cmap.glyphId); |
| cmds.push({ |
| cmd: "restore" |
| }); |
| cmap = lookupCmap(font.cmap, String.fromCharCode(font.glyphNameMap[_encodings.StandardEncoding[bchar]])); |
| compileCharString(font.glyphs[cmap.glyphId], cmds, font, cmap.glyphId); |
| } |
| |
| return; |
| |
| case 18: |
| stems += stack.length >> 1; |
| stackClean = true; |
| break; |
| |
| case 19: |
| stems += stack.length >> 1; |
| i += stems + 7 >> 3; |
| stackClean = true; |
| break; |
| |
| case 20: |
| stems += stack.length >> 1; |
| i += stems + 7 >> 3; |
| stackClean = true; |
| break; |
| |
| case 21: |
| y += stack.pop(); |
| x += stack.pop(); |
| moveTo(x, y); |
| stackClean = true; |
| break; |
| |
| case 22: |
| x += stack.pop(); |
| moveTo(x, y); |
| stackClean = true; |
| break; |
| |
| case 23: |
| stems += stack.length >> 1; |
| stackClean = true; |
| break; |
| |
| case 24: |
| while (stack.length > 2) { |
| xa = x + stack.shift(); |
| ya = y + stack.shift(); |
| xb = xa + stack.shift(); |
| yb = ya + stack.shift(); |
| x = xb + stack.shift(); |
| y = yb + stack.shift(); |
| bezierCurveTo(xa, ya, xb, yb, x, y); |
| } |
| |
| x += stack.shift(); |
| y += stack.shift(); |
| lineTo(x, y); |
| break; |
| |
| case 25: |
| while (stack.length > 6) { |
| x += stack.shift(); |
| y += stack.shift(); |
| lineTo(x, y); |
| } |
| |
| xa = x + stack.shift(); |
| ya = y + stack.shift(); |
| xb = xa + stack.shift(); |
| yb = ya + stack.shift(); |
| x = xb + stack.shift(); |
| y = yb + stack.shift(); |
| bezierCurveTo(xa, ya, xb, yb, x, y); |
| break; |
| |
| case 26: |
| if (stack.length % 2) { |
| x += stack.shift(); |
| } |
| |
| while (stack.length > 0) { |
| xa = x; |
| ya = y + stack.shift(); |
| xb = xa + stack.shift(); |
| yb = ya + stack.shift(); |
| x = xb; |
| y = yb + stack.shift(); |
| bezierCurveTo(xa, ya, xb, yb, x, y); |
| } |
| |
| break; |
| |
| case 27: |
| if (stack.length % 2) { |
| y += stack.shift(); |
| } |
| |
| while (stack.length > 0) { |
| xa = x + stack.shift(); |
| ya = y; |
| xb = xa + stack.shift(); |
| yb = ya + stack.shift(); |
| x = xb + stack.shift(); |
| y = yb; |
| bezierCurveTo(xa, ya, xb, yb, x, y); |
| } |
| |
| break; |
| |
| case 28: |
| stack.push((code[i] << 24 | code[i + 1] << 16) >> 16); |
| i += 2; |
| break; |
| |
| case 29: |
| n = stack.pop() + font.gsubrsBias; |
| subrCode = font.gsubrs[n]; |
| |
| if (subrCode) { |
| parse(subrCode); |
| } |
| |
| break; |
| |
| case 30: |
| while (stack.length > 0) { |
| xa = x; |
| ya = y + stack.shift(); |
| xb = xa + stack.shift(); |
| yb = ya + stack.shift(); |
| x = xb + stack.shift(); |
| y = yb + (stack.length === 1 ? stack.shift() : 0); |
| bezierCurveTo(xa, ya, xb, yb, x, y); |
| |
| if (stack.length === 0) { |
| break; |
| } |
| |
| xa = x + stack.shift(); |
| ya = y; |
| xb = xa + stack.shift(); |
| yb = ya + stack.shift(); |
| y = yb + stack.shift(); |
| x = xb + (stack.length === 1 ? stack.shift() : 0); |
| bezierCurveTo(xa, ya, xb, yb, x, y); |
| } |
| |
| break; |
| |
| case 31: |
| while (stack.length > 0) { |
| xa = x + stack.shift(); |
| ya = y; |
| xb = xa + stack.shift(); |
| yb = ya + stack.shift(); |
| y = yb + stack.shift(); |
| x = xb + (stack.length === 1 ? stack.shift() : 0); |
| bezierCurveTo(xa, ya, xb, yb, x, y); |
| |
| if (stack.length === 0) { |
| break; |
| } |
| |
| xa = x; |
| ya = y + stack.shift(); |
| xb = xa + stack.shift(); |
| yb = ya + stack.shift(); |
| x = xb + stack.shift(); |
| y = yb + (stack.length === 1 ? stack.shift() : 0); |
| bezierCurveTo(xa, ya, xb, yb, x, y); |
| } |
| |
| break; |
| |
| default: |
| if (v < 32) { |
| throw new _util.FormatError(`unknown operator: ${v}`); |
| } |
| |
| if (v < 247) { |
| stack.push(v - 139); |
| } else if (v < 251) { |
| stack.push((v - 247) * 256 + code[i++] + 108); |
| } else if (v < 255) { |
| stack.push(-(v - 251) * 256 - code[i++] - 108); |
| } else { |
| stack.push((code[i] << 24 | code[i + 1] << 16 | code[i + 2] << 8 | code[i + 3]) / 65536); |
| i += 4; |
| } |
| |
| break; |
| } |
| |
| if (stackClean) { |
| stack.length = 0; |
| } |
| } |
| } |
| |
| parse(charStringCode); |
| } |
| |
| const NOOP = []; |
| |
| class CompiledFont { |
| constructor(fontMatrix) { |
| if (this.constructor === CompiledFont) { |
| (0, _util.unreachable)("Cannot initialize CompiledFont."); |
| } |
| |
| this.fontMatrix = fontMatrix; |
| this.compiledGlyphs = Object.create(null); |
| this.compiledCharCodeToGlyphId = Object.create(null); |
| } |
| |
| getPathJs(unicode) { |
| const cmap = lookupCmap(this.cmap, unicode); |
| let fn = this.compiledGlyphs[cmap.glyphId]; |
| |
| if (!fn) { |
| fn = this.compileGlyph(this.glyphs[cmap.glyphId], cmap.glyphId); |
| this.compiledGlyphs[cmap.glyphId] = fn; |
| } |
| |
| if (this.compiledCharCodeToGlyphId[cmap.charCode] === undefined) { |
| this.compiledCharCodeToGlyphId[cmap.charCode] = cmap.glyphId; |
| } |
| |
| return fn; |
| } |
| |
| compileGlyph(code, glyphId) { |
| if (!code || code.length === 0 || code[0] === 14) { |
| return NOOP; |
| } |
| |
| let fontMatrix = this.fontMatrix; |
| |
| if (this.isCFFCIDFont) { |
| const fdIndex = this.fdSelect.getFDIndex(glyphId); |
| |
| if (fdIndex >= 0 && fdIndex < this.fdArray.length) { |
| const fontDict = this.fdArray[fdIndex]; |
| fontMatrix = fontDict.getByName("FontMatrix") || _util.FONT_IDENTITY_MATRIX; |
| } else { |
| (0, _util.warn)("Invalid fd index for glyph index."); |
| } |
| } |
| |
| const cmds = []; |
| cmds.push({ |
| cmd: "save" |
| }); |
| cmds.push({ |
| cmd: "transform", |
| args: fontMatrix.slice() |
| }); |
| cmds.push({ |
| cmd: "scale", |
| args: ["size", "-size"] |
| }); |
| this.compileGlyphImpl(code, cmds, glyphId); |
| cmds.push({ |
| cmd: "restore" |
| }); |
| return cmds; |
| } |
| |
| compileGlyphImpl() { |
| (0, _util.unreachable)("Children classes should implement this."); |
| } |
| |
| hasBuiltPath(unicode) { |
| const cmap = lookupCmap(this.cmap, unicode); |
| return this.compiledGlyphs[cmap.glyphId] !== undefined && this.compiledCharCodeToGlyphId[cmap.charCode] !== undefined; |
| } |
| |
| } |
| |
| class TrueTypeCompiled extends CompiledFont { |
| constructor(glyphs, cmap, fontMatrix) { |
| super(fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0]); |
| this.glyphs = glyphs; |
| this.cmap = cmap; |
| } |
| |
| compileGlyphImpl(code, cmds) { |
| compileGlyf(code, cmds, this); |
| } |
| |
| } |
| |
| class Type2Compiled extends CompiledFont { |
| constructor(cffInfo, cmap, fontMatrix, glyphNameMap) { |
| super(fontMatrix || [0.001, 0, 0, 0.001, 0, 0]); |
| this.glyphs = cffInfo.glyphs; |
| this.gsubrs = cffInfo.gsubrs || []; |
| this.subrs = cffInfo.subrs || []; |
| this.cmap = cmap; |
| this.glyphNameMap = glyphNameMap || (0, _glyphlist.getGlyphsUnicode)(); |
| this.gsubrsBias = getSubroutineBias(this.gsubrs); |
| this.subrsBias = getSubroutineBias(this.subrs); |
| this.isCFFCIDFont = cffInfo.isCFFCIDFont; |
| this.fdSelect = cffInfo.fdSelect; |
| this.fdArray = cffInfo.fdArray; |
| } |
| |
| compileGlyphImpl(code, cmds, glyphId) { |
| compileCharString(code, cmds, this, glyphId); |
| } |
| |
| } |
| |
| return { |
| create: function FontRendererFactory_create(font, seacAnalysisEnabled) { |
| var data = new Uint8Array(font.data); |
| var cmap, glyf, loca, cff, indexToLocFormat, unitsPerEm; |
| var numTables = getUshort(data, 4); |
| |
| for (var i = 0, p = 12; i < numTables; i++, p += 16) { |
| var tag = (0, _util.bytesToString)(data.subarray(p, p + 4)); |
| var offset = getLong(data, p + 8); |
| var length = getLong(data, p + 12); |
| |
| switch (tag) { |
| case "cmap": |
| cmap = parseCmap(data, offset, offset + length); |
| break; |
| |
| case "glyf": |
| glyf = data.subarray(offset, offset + length); |
| break; |
| |
| case "loca": |
| loca = data.subarray(offset, offset + length); |
| break; |
| |
| case "head": |
| unitsPerEm = getUshort(data, offset + 18); |
| indexToLocFormat = getUshort(data, offset + 50); |
| break; |
| |
| case "CFF ": |
| cff = parseCff(data, offset, offset + length, seacAnalysisEnabled); |
| break; |
| } |
| } |
| |
| if (glyf) { |
| var fontMatrix = !unitsPerEm ? font.fontMatrix : [1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0]; |
| return new TrueTypeCompiled(parseGlyfTable(glyf, loca, indexToLocFormat), cmap, fontMatrix); |
| } |
| |
| return new Type2Compiled(cff, cmap, font.fontMatrix, font.glyphNameMap); |
| } |
| }; |
| }(); |
| |
| exports.FontRendererFactory = FontRendererFactory; |