Best JavaScript code snippet using wpt
fonts.js
Source:fonts.js
...1741 );1742 }1743 }1744 }1745 function sanitizeGlyphLocations(1746 loca,1747 glyf,1748 numGlyphs,1749 isGlyphLocationsLong,1750 hintsValid,1751 dupFirstEntry,1752 maxSizeOfInstructions1753 ) {1754 let itemSize, itemDecode, itemEncode;1755 if (isGlyphLocationsLong) {1756 itemSize = 4;1757 itemDecode = function fontItemDecodeLong(data, offset) {1758 return (1759 (data[offset] << 24) |1760 (data[offset + 1] << 16) |1761 (data[offset + 2] << 8) |1762 data[offset + 3]1763 );1764 };1765 itemEncode = function fontItemEncodeLong(data, offset, value) {1766 data[offset] = (value >>> 24) & 0xff;1767 data[offset + 1] = (value >> 16) & 0xff;1768 data[offset + 2] = (value >> 8) & 0xff;1769 data[offset + 3] = value & 0xff;1770 };1771 } else {1772 itemSize = 2;1773 itemDecode = function fontItemDecode(data, offset) {1774 return (data[offset] << 9) | (data[offset + 1] << 1);1775 };1776 itemEncode = function fontItemEncode(data, offset, value) {1777 data[offset] = (value >> 9) & 0xff;1778 data[offset + 1] = (value >> 1) & 0xff;1779 };1780 }1781 // The first glyph is duplicated.1782 const numGlyphsOut = dupFirstEntry ? numGlyphs + 1 : numGlyphs;1783 const locaDataSize = itemSize * (1 + numGlyphsOut);1784 // Resize loca table to account for duplicated glyph.1785 const locaData = new Uint8Array(locaDataSize);1786 locaData.set(loca.data.subarray(0, locaDataSize));1787 loca.data = locaData;1788 // removing the invalid glyphs1789 const oldGlyfData = glyf.data;1790 const oldGlyfDataLength = oldGlyfData.length;1791 const newGlyfData = new Uint8Array(oldGlyfDataLength);1792 // The spec says the offsets should be in ascending order, however1793 // this is not true for some fonts or they use the offset of 0 to mark a1794 // glyph as missing. OTS requires the offsets to be in order and not to1795 // be zero, so we must sort and rebuild the loca table and potentially1796 // re-arrange the glyf data.1797 let i, j;1798 const locaEntries = [];1799 // There are numGlyphs + 1 loca table entries.1800 for (i = 0, j = 0; i < numGlyphs + 1; i++, j += itemSize) {1801 let offset = itemDecode(locaData, j);1802 if (offset > oldGlyfDataLength) {1803 offset = oldGlyfDataLength;1804 }1805 locaEntries.push({1806 index: i,1807 offset,1808 endOffset: 0,1809 });1810 }1811 locaEntries.sort((a, b) => {1812 return a.offset - b.offset;1813 });1814 // Now the offsets are sorted, calculate the end offset of each glyph.1815 // The last loca entry's endOffset is not calculated since it's the end1816 // of the data and will be stored on the previous entry's endOffset.1817 for (i = 0; i < numGlyphs; i++) {1818 locaEntries[i].endOffset = locaEntries[i + 1].offset;1819 }1820 // Re-sort so glyphs aren't out of order.1821 locaEntries.sort((a, b) => {1822 return a.index - b.index;1823 });1824 // Calculate the endOffset of the "first" glyph correctly when there are1825 // *multiple* empty ones at the start of the data (fixes issue14618.pdf).1826 for (i = 0; i < numGlyphs; i++) {1827 const { offset, endOffset } = locaEntries[i];1828 if (offset !== 0 || endOffset !== 0) {1829 break;1830 }1831 const nextOffset = locaEntries[i + 1].offset;1832 if (nextOffset === 0) {1833 continue;1834 }1835 locaEntries[i].endOffset = nextOffset;1836 break;1837 }1838 const missingGlyphs = Object.create(null);1839 let writeOffset = 0;1840 itemEncode(locaData, 0, writeOffset);1841 for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {1842 const glyphProfile = sanitizeGlyph(1843 oldGlyfData,1844 locaEntries[i].offset,1845 locaEntries[i].endOffset,1846 newGlyfData,1847 writeOffset,1848 hintsValid1849 );1850 const newLength = glyphProfile.length;1851 if (newLength === 0) {1852 missingGlyphs[i] = true;1853 }1854 if (glyphProfile.sizeOfInstructions > maxSizeOfInstructions) {1855 maxSizeOfInstructions = glyphProfile.sizeOfInstructions;1856 }1857 writeOffset += newLength;1858 itemEncode(locaData, j, writeOffset);1859 }1860 if (writeOffset === 0) {1861 // glyf table cannot be empty -- redoing the glyf and loca tables1862 // to have single glyph with one point1863 const simpleGlyph = new Uint8Array([1864 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0,1865 ]);1866 for (i = 0, j = itemSize; i < numGlyphsOut; i++, j += itemSize) {1867 itemEncode(locaData, j, simpleGlyph.length);1868 }1869 glyf.data = simpleGlyph;1870 } else if (dupFirstEntry) {1871 // Browsers will not display a glyph at position 0. Typically glyph 01872 // is notdef, but a number of fonts put a valid glyph there so it must1873 // be duplicated and appended.1874 const firstEntryLength = itemDecode(locaData, itemSize);1875 if (newGlyfData.length > firstEntryLength + writeOffset) {1876 glyf.data = newGlyfData.subarray(0, firstEntryLength + writeOffset);1877 } else {1878 glyf.data = new Uint8Array(firstEntryLength + writeOffset);1879 glyf.data.set(newGlyfData.subarray(0, writeOffset));1880 }1881 glyf.data.set(newGlyfData.subarray(0, firstEntryLength), writeOffset);1882 itemEncode(1883 loca.data,1884 locaData.length - itemSize,1885 writeOffset + firstEntryLength1886 );1887 } else {1888 glyf.data = newGlyfData.subarray(0, writeOffset);1889 }1890 return {1891 missingGlyphs,1892 maxSizeOfInstructions,1893 };1894 }1895 function readPostScriptTable(post, propertiesObj, maxpNumGlyphs) {1896 const start = (font.start ? font.start : 0) + post.offset;1897 font.pos = start;1898 const length = post.length,1899 end = start + length;1900 const version = font.getInt32();1901 // skip rest to the tables1902 font.skip(28);1903 let glyphNames;1904 let valid = true;1905 let i;1906 switch (version) {1907 case 0x00010000:1908 glyphNames = MacStandardGlyphOrdering;1909 break;1910 case 0x00020000:1911 const numGlyphs = font.getUint16();1912 if (numGlyphs !== maxpNumGlyphs) {1913 valid = false;1914 break;1915 }1916 const glyphNameIndexes = [];1917 for (i = 0; i < numGlyphs; ++i) {1918 const index = font.getUint16();1919 if (index >= 32768) {1920 valid = false;1921 break;1922 }1923 glyphNameIndexes.push(index);1924 }1925 if (!valid) {1926 break;1927 }1928 const customNames = [],1929 strBuf = [];1930 while (font.pos < end) {1931 const stringLength = font.getByte();1932 strBuf.length = stringLength;1933 for (i = 0; i < stringLength; ++i) {1934 strBuf[i] = String.fromCharCode(font.getByte());1935 }1936 customNames.push(strBuf.join(""));1937 }1938 glyphNames = [];1939 for (i = 0; i < numGlyphs; ++i) {1940 const j = glyphNameIndexes[i];1941 if (j < 258) {1942 glyphNames.push(MacStandardGlyphOrdering[j]);1943 continue;1944 }1945 glyphNames.push(customNames[j - 258]);1946 }1947 break;1948 case 0x00030000:1949 break;1950 default:1951 warn("Unknown/unsupported post table version " + version);1952 valid = false;1953 if (propertiesObj.defaultEncoding) {1954 glyphNames = propertiesObj.defaultEncoding;1955 }1956 break;1957 }1958 propertiesObj.glyphNames = glyphNames;1959 return valid;1960 }1961 function readNameTable(nameTable) {1962 const start = (font.start ? font.start : 0) + nameTable.offset;1963 font.pos = start;1964 const names = [[], []];1965 const length = nameTable.length,1966 end = start + length;1967 const format = font.getUint16();1968 const FORMAT_0_HEADER_LENGTH = 6;1969 if (format !== 0 || length < FORMAT_0_HEADER_LENGTH) {1970 // unsupported name table format or table "too" small1971 return names;1972 }1973 const numRecords = font.getUint16();1974 const stringsStart = font.getUint16();1975 const records = [];1976 const NAME_RECORD_LENGTH = 12;1977 let i, ii;1978 for (i = 0; i < numRecords && font.pos + NAME_RECORD_LENGTH <= end; i++) {1979 const r = {1980 platform: font.getUint16(),1981 encoding: font.getUint16(),1982 language: font.getUint16(),1983 name: font.getUint16(),1984 length: font.getUint16(),1985 offset: font.getUint16(),1986 };1987 // using only Macintosh and Windows platform/encoding names1988 if (1989 (r.platform === 1 && r.encoding === 0 && r.language === 0) ||1990 (r.platform === 3 && r.encoding === 1 && r.language === 0x409)1991 ) {1992 records.push(r);1993 }1994 }1995 for (i = 0, ii = records.length; i < ii; i++) {1996 const record = records[i];1997 if (record.length <= 0) {1998 continue; // Nothing to process, ignoring.1999 }2000 const pos = start + stringsStart + record.offset;2001 if (pos + record.length > end) {2002 continue; // outside of name table, ignoring2003 }2004 font.pos = pos;2005 const nameIndex = record.name;2006 if (record.encoding) {2007 // unicode2008 let str = "";2009 for (let j = 0, jj = record.length; j < jj; j += 2) {2010 str += String.fromCharCode(font.getUint16());2011 }2012 names[1][nameIndex] = str;2013 } else {2014 names[0][nameIndex] = font.getString(record.length);2015 }2016 }2017 return names;2018 }2019 // prettier-ignore2020 const TTOpsStackDeltas = [2021 0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, -2, -5,2022 -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, -1, -1,2023 1, -1, -999, 0, 1, 0, -1, -2, 0, -1, -2, -1, -1, 0, -1, -1,2024 0, 0, -999, -999, -1, -1, -1, -1, -2, -999, -2, -2, -999, 0, -2, -2,2025 0, 0, -2, 0, -2, 0, 0, 0, -2, -1, -1, 1, 1, 0, 0, -1,2026 -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, 0, -999, -1, -1,2027 -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,2028 -2, -999, -999, -999, -999, -999, -1, -1, -2, -2, 0, 0, 0, 0, -1, -1,2029 -999, -2, -2, 0, 0, -1, -2, -2, 0, 0, 0, -1, -1, -1, -2];2030 // 0xC0-DF == -1 and 0xE0-FF == -22031 function sanitizeTTProgram(table, ttContext) {2032 let data = table.data;2033 let i = 0,2034 j,2035 n,2036 b,2037 funcId,2038 pc,2039 lastEndf = 0,2040 lastDeff = 0;2041 const stack = [];2042 const callstack = [];2043 const functionsCalled = [];2044 let tooComplexToFollowFunctions = ttContext.tooComplexToFollowFunctions;2045 let inFDEF = false,2046 ifLevel = 0,2047 inELSE = 0;2048 for (let ii = data.length; i < ii; ) {2049 const op = data[i++];2050 // The TrueType instruction set docs can be found at2051 // https://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html2052 if (op === 0x40) {2053 // NPUSHB - pushes n bytes2054 n = data[i++];2055 if (inFDEF || inELSE) {2056 i += n;2057 } else {2058 for (j = 0; j < n; j++) {2059 stack.push(data[i++]);2060 }2061 }2062 } else if (op === 0x41) {2063 // NPUSHW - pushes n words2064 n = data[i++];2065 if (inFDEF || inELSE) {2066 i += n * 2;2067 } else {2068 for (j = 0; j < n; j++) {2069 b = data[i++];2070 stack.push((b << 8) | data[i++]);2071 }2072 }2073 } else if ((op & 0xf8) === 0xb0) {2074 // PUSHB - pushes bytes2075 n = op - 0xb0 + 1;2076 if (inFDEF || inELSE) {2077 i += n;2078 } else {2079 for (j = 0; j < n; j++) {2080 stack.push(data[i++]);2081 }2082 }2083 } else if ((op & 0xf8) === 0xb8) {2084 // PUSHW - pushes words2085 n = op - 0xb8 + 1;2086 if (inFDEF || inELSE) {2087 i += n * 2;2088 } else {2089 for (j = 0; j < n; j++) {2090 b = data[i++];2091 stack.push((b << 8) | data[i++]);2092 }2093 }2094 } else if (op === 0x2b && !tooComplexToFollowFunctions) {2095 // CALL2096 if (!inFDEF && !inELSE) {2097 // collecting information about which functions are used2098 funcId = stack[stack.length - 1];2099 if (isNaN(funcId)) {2100 info("TT: CALL empty stack (or invalid entry).");2101 } else {2102 ttContext.functionsUsed[funcId] = true;2103 if (funcId in ttContext.functionsStackDeltas) {2104 const newStackLength =2105 stack.length + ttContext.functionsStackDeltas[funcId];2106 if (newStackLength < 0) {2107 warn("TT: CALL invalid functions stack delta.");2108 ttContext.hintsValid = false;2109 return;2110 }2111 stack.length = newStackLength;2112 } else if (2113 funcId in ttContext.functionsDefined &&2114 !functionsCalled.includes(funcId)2115 ) {2116 callstack.push({ data, i, stackTop: stack.length - 1 });2117 functionsCalled.push(funcId);2118 pc = ttContext.functionsDefined[funcId];2119 if (!pc) {2120 warn("TT: CALL non-existent function");2121 ttContext.hintsValid = false;2122 return;2123 }2124 data = pc.data;2125 i = pc.i;2126 }2127 }2128 }2129 } else if (op === 0x2c && !tooComplexToFollowFunctions) {2130 // FDEF2131 if (inFDEF || inELSE) {2132 warn("TT: nested FDEFs not allowed");2133 tooComplexToFollowFunctions = true;2134 }2135 inFDEF = true;2136 // collecting information about which functions are defined2137 lastDeff = i;2138 funcId = stack.pop();2139 ttContext.functionsDefined[funcId] = { data, i };2140 } else if (op === 0x2d) {2141 // ENDF - end of function2142 if (inFDEF) {2143 inFDEF = false;2144 lastEndf = i;2145 } else {2146 pc = callstack.pop();2147 if (!pc) {2148 warn("TT: ENDF bad stack");2149 ttContext.hintsValid = false;2150 return;2151 }2152 funcId = functionsCalled.pop();2153 data = pc.data;2154 i = pc.i;2155 ttContext.functionsStackDeltas[funcId] = stack.length - pc.stackTop;2156 }2157 } else if (op === 0x89) {2158 // IDEF - instruction definition2159 if (inFDEF || inELSE) {2160 warn("TT: nested IDEFs not allowed");2161 tooComplexToFollowFunctions = true;2162 }2163 inFDEF = true;2164 // recording it as a function to track ENDF2165 lastDeff = i;2166 } else if (op === 0x58) {2167 // IF2168 ++ifLevel;2169 } else if (op === 0x1b) {2170 // ELSE2171 inELSE = ifLevel;2172 } else if (op === 0x59) {2173 // EIF2174 if (inELSE === ifLevel) {2175 inELSE = 0;2176 }2177 --ifLevel;2178 } else if (op === 0x1c) {2179 // JMPR2180 if (!inFDEF && !inELSE) {2181 const offset = stack[stack.length - 1];2182 // only jumping forward to prevent infinite loop2183 if (offset > 0) {2184 i += offset - 1;2185 }2186 }2187 }2188 // Adjusting stack not extactly, but just enough to get function id2189 if (!inFDEF && !inELSE) {2190 let stackDelta = 0;2191 if (op <= 0x8e) {2192 stackDelta = TTOpsStackDeltas[op];2193 } else if (op >= 0xc0 && op <= 0xdf) {2194 stackDelta = -1;2195 } else if (op >= 0xe0) {2196 stackDelta = -2;2197 }2198 if (op >= 0x71 && op <= 0x75) {2199 n = stack.pop();2200 if (!isNaN(n)) {2201 stackDelta = -n * 2;2202 }2203 }2204 while (stackDelta < 0 && stack.length > 0) {2205 stack.pop();2206 stackDelta++;2207 }2208 while (stackDelta > 0) {2209 stack.push(NaN); // pushing any number into stack2210 stackDelta--;2211 }2212 }2213 }2214 ttContext.tooComplexToFollowFunctions = tooComplexToFollowFunctions;2215 const content = [data];2216 if (i > data.length) {2217 content.push(new Uint8Array(i - data.length));2218 }2219 if (lastDeff > lastEndf) {2220 warn("TT: complementing a missing function tail");2221 // new function definition started, but not finished2222 // complete function by [CLEAR, ENDF]2223 content.push(new Uint8Array([0x22, 0x2d]));2224 }2225 foldTTTable(table, content);2226 }2227 function checkInvalidFunctions(ttContext, maxFunctionDefs) {2228 if (ttContext.tooComplexToFollowFunctions) {2229 return;2230 }2231 if (ttContext.functionsDefined.length > maxFunctionDefs) {2232 warn("TT: more functions defined than expected");2233 ttContext.hintsValid = false;2234 return;2235 }2236 for (let j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) {2237 if (j > maxFunctionDefs) {2238 warn("TT: invalid function id: " + j);2239 ttContext.hintsValid = false;2240 return;2241 }2242 if (ttContext.functionsUsed[j] && !ttContext.functionsDefined[j]) {2243 warn("TT: undefined function: " + j);2244 ttContext.hintsValid = false;2245 return;2246 }2247 }2248 }2249 function foldTTTable(table, content) {2250 if (content.length > 1) {2251 // concatenating the content items2252 let newLength = 0;2253 let j, jj;2254 for (j = 0, jj = content.length; j < jj; j++) {2255 newLength += content[j].length;2256 }2257 newLength = (newLength + 3) & ~3;2258 const result = new Uint8Array(newLength);2259 let pos = 0;2260 for (j = 0, jj = content.length; j < jj; j++) {2261 result.set(content[j], pos);2262 pos += content[j].length;2263 }2264 table.data = result;2265 table.length = newLength;2266 }2267 }2268 function sanitizeTTPrograms(fpgm, prep, cvt, maxFunctionDefs) {2269 const ttContext = {2270 functionsDefined: [],2271 functionsUsed: [],2272 functionsStackDeltas: [],2273 tooComplexToFollowFunctions: false,2274 hintsValid: true,2275 };2276 if (fpgm) {2277 sanitizeTTProgram(fpgm, ttContext);2278 }2279 if (prep) {2280 sanitizeTTProgram(prep, ttContext);2281 }2282 if (fpgm) {2283 checkInvalidFunctions(ttContext, maxFunctionDefs);2284 }2285 if (cvt && cvt.length & 1) {2286 const cvtData = new Uint8Array(cvt.length + 1);2287 cvtData.set(cvt.data);2288 cvt.data = cvtData;2289 }2290 return ttContext.hintsValid;2291 }2292 // The following steps modify the original font data, making copy2293 font = new Stream(new Uint8Array(font.getBytes()));2294 let header, tables;2295 if (isTrueTypeCollectionFile(font)) {2296 const ttcData = readTrueTypeCollectionData(font, this.name);2297 header = ttcData.header;2298 tables = ttcData.tables;2299 } else {2300 header = readOpenTypeHeader(font);2301 tables = readTables(font, header.numTables);2302 }2303 let cff, cffFile;2304 const isTrueType = !tables["CFF "];2305 if (!isTrueType) {2306 const isComposite =2307 properties.composite &&2308 ((properties.cidToGidMap || []).length > 0 ||2309 !(properties.cMap instanceof IdentityCMap));2310 // OpenType font (skip composite fonts with non-default glyph mapping).2311 if (2312 (header.version === "OTTO" && !isComposite) ||2313 !tables.head ||2314 !tables.hhea ||2315 !tables.maxp ||2316 !tables.post2317 ) {2318 // No major tables: throwing everything at `CFFFont`.2319 cffFile = new Stream(tables["CFF "].data);2320 cff = new CFFFont(cffFile, properties);2321 adjustWidths(properties);2322 return this.convert(name, cff, properties);2323 }2324 delete tables.glyf;2325 delete tables.loca;2326 delete tables.fpgm;2327 delete tables.prep;2328 delete tables["cvt "];2329 this.isOpenType = true;2330 } else {2331 if (!tables.loca) {2332 throw new FormatError('Required "loca" table is not found');2333 }2334 if (!tables.glyf) {2335 warn('Required "glyf" table is not found -- trying to recover.');2336 // Note: We use `sanitizeGlyphLocations` to add dummy glyf data below.2337 tables.glyf = {2338 tag: "glyf",2339 data: new Uint8Array(0),2340 };2341 }2342 this.isOpenType = false;2343 }2344 if (!tables.maxp) {2345 throw new FormatError('Required "maxp" table is not found');2346 }2347 font.pos = (font.start || 0) + tables.maxp.offset;2348 const version = font.getInt32();2349 const numGlyphs = font.getUint16();2350 if (2351 properties.scaleFactors &&2352 properties.scaleFactors.length === numGlyphs &&2353 isTrueType2354 ) {2355 const { scaleFactors } = properties;2356 const isGlyphLocationsLong = int16(2357 tables.head.data[50],2358 tables.head.data[51]2359 );2360 const glyphs = new GlyfTable({2361 glyfTable: tables.glyf.data,2362 isGlyphLocationsLong,2363 locaTable: tables.loca.data,2364 numGlyphs,2365 });2366 glyphs.scale(scaleFactors);2367 const { glyf, loca, isLocationLong } = glyphs.write();2368 tables.glyf.data = glyf;2369 tables.loca.data = loca;2370 if (isLocationLong !== !!isGlyphLocationsLong) {2371 tables.head.data[50] = 0;2372 tables.head.data[51] = isLocationLong ? 1 : 0;2373 }2374 const metrics = tables.hmtx.data;2375 for (let i = 0; i < numGlyphs; i++) {2376 const j = 4 * i;2377 const advanceWidth = Math.round(2378 scaleFactors[i] * int16(metrics[j], metrics[j + 1])2379 );2380 metrics[j] = (advanceWidth >> 8) & 0xff;2381 metrics[j + 1] = advanceWidth & 0xff;2382 const lsb = Math.round(2383 scaleFactors[i] * signedInt16(metrics[j + 2], metrics[j + 3])2384 );2385 writeSignedInt16(metrics, j + 2, lsb);2386 }2387 }2388 // Glyph 0 is duplicated and appended.2389 let numGlyphsOut = numGlyphs + 1;2390 let dupFirstEntry = true;2391 if (numGlyphsOut > 0xffff) {2392 dupFirstEntry = false;2393 numGlyphsOut = numGlyphs;2394 warn("Not enough space in glyfs to duplicate first glyph.");2395 }2396 let maxFunctionDefs = 0;2397 let maxSizeOfInstructions = 0;2398 if (version >= 0x00010000 && tables.maxp.length >= 22) {2399 // maxZones can be invalid2400 font.pos += 8;2401 const maxZones = font.getUint16();2402 if (maxZones > 2) {2403 // reset to 2 if font has invalid maxZones2404 tables.maxp.data[14] = 0;2405 tables.maxp.data[15] = 2;2406 }2407 font.pos += 4;2408 maxFunctionDefs = font.getUint16();2409 font.pos += 4;2410 maxSizeOfInstructions = font.getUint16();2411 }2412 tables.maxp.data[4] = numGlyphsOut >> 8;2413 tables.maxp.data[5] = numGlyphsOut & 255;2414 const hintsValid = sanitizeTTPrograms(2415 tables.fpgm,2416 tables.prep,2417 tables["cvt "],2418 maxFunctionDefs2419 );2420 if (!hintsValid) {2421 delete tables.fpgm;2422 delete tables.prep;2423 delete tables["cvt "];2424 }2425 // Ensure the hmtx table contains the advance width and2426 // sidebearings information for numGlyphs in the maxp table2427 sanitizeMetrics(2428 font,2429 tables.hhea,2430 tables.hmtx,2431 tables.head,2432 numGlyphsOut,2433 dupFirstEntry2434 );2435 if (!tables.head) {2436 throw new FormatError('Required "head" table is not found');2437 }2438 sanitizeHead(tables.head, numGlyphs, isTrueType ? tables.loca.length : 0);2439 let missingGlyphs = Object.create(null);2440 if (isTrueType) {2441 const isGlyphLocationsLong = int16(2442 tables.head.data[50],2443 tables.head.data[51]2444 );2445 const glyphsInfo = sanitizeGlyphLocations(2446 tables.loca,2447 tables.glyf,2448 numGlyphs,2449 isGlyphLocationsLong,2450 hintsValid,2451 dupFirstEntry,2452 maxSizeOfInstructions2453 );2454 missingGlyphs = glyphsInfo.missingGlyphs;2455 // Some fonts have incorrect maxSizeOfInstructions values, so we use2456 // the computed value instead.2457 if (version >= 0x00010000 && tables.maxp.length >= 22) {2458 tables.maxp.data[26] = glyphsInfo.maxSizeOfInstructions >> 8;2459 tables.maxp.data[27] = glyphsInfo.maxSizeOfInstructions & 255;...
Using AI Code Generation
1var wptools = require('wptools');2 {x: 10, y: 20},3 {x: 30, y: 40},4 {x: 50, y: 60},5 {x: 70, y: 80},6 {x: 90, y: 100}7];8var sanitizedGlyphLocations = wptools.sanitizeGlyphLocations(glyphLocations);9console.log(sanitizedGlyphLocations);10 {x: 10, y: 20},11 {x: 30, y: 40},12 {x: 50, y: 60},13 {x: 70, y: 80},14 {x: 90, y: 100}15var wptools = require('wptools');16 {x: 10, y: 20},17 {x: 30, y: 40},18 {x: 50, y: 60},19 {x: 70, y: 80},20 {x: 90, y: 100}21];22var sanitizedGlyphLocations = wptools.sanitizeGlyphLocations(glyphLocations, {x: 10, y: 20});23console.log(sanitizedGlyphLocations);24 {x: 0, y: 0},25 {x: 20, y: 20},26 {x: 40, y: 40},27 {x: 60, y: 60},28 {x: 80, y: 80}29var wptools = require('wptools');30 {x: 10, y: 20},31 {x: 30, y: 40},32 {x: 50, y: 60},33 {x: 70, y: 80},34 {x: 90, y: 100}35];36var sanitizedGlyphLocations = wptools.sanitizeGlyphLocations(glyphLocations, {x: 10, y: 20}, {x: 10, y: 20});
Using AI Code Generation
1var wptools = require('wptools');2var path = require('path');3var fs = require('fs');4var fontPath = path.join(__dirname, 'fonts', 'Roboto-Regular.ttf');5var font = fs.readFileSync(fontPath);6wptools.sanitizeGlyphLocations(font, function(err, result) {7 if (err) {8 console.log(err);9 } else {10 console.log(result);11 }12});
Using AI Code Generation
1var wptools = require('wptools');2var fs = require('fs');3var font = fs.readFileSync('test.ttf');4var newFont = wptools.sanitizeGlyphLocations(font);5fs.writeFileSync('test2.ttf', newFont);6var wptools = require('wptools');7var fs = require('fs');8var font = fs.readFileSync('test.ttf');9var newFont = wptools.sanitizeGlyphLocations(font);10fs.writeFileSync('test2.ttf', newFont);11var wptools = require('wptools');12var fs = require('fs');13var font = fs.readFileSync('test.ttf');14var newFont = wptools.sanitizeGlyphLocations(font);15fs.writeFileSync('test2.ttf', newFont);16var wptools = require('wptools');17var fs = require('fs');18var font = fs.readFileSync('test.ttf');19var newFont = wptools.sanitizeGlyphLocations(font);20fs.writeFileSync('test2.ttf', newFont);21var wptools = require('wptools');22var fs = require('fs');23var font = fs.readFileSync('test.ttf');24var newFont = wptools.sanitizeGlyphLocations(font);25fs.writeFileSync('test2.ttf', newFont);26var wptools = require('wptools');27var fs = require('fs');28var font = fs.readFileSync('test.ttf');29var newFont = wptools.sanitizeGlyphLocations(font);30fs.writeFileSync('test2.ttf', newFont);31var wptools = require('wptools');32var fs = require('fs');33var font = fs.readFileSync('test.ttf');34var newFont = wptools.sanitizeGlyphLocations(font);35fs.writeFileSync('test2.ttf', newFont);36var wptools = require('
Using AI Code Generation
1var wptools = require('wptools');2var fs = require('fs');3var path = require('path');4var font = new wptools.Font();5font.loadFromFile(path.join(__dirname, 'font.ttf'));6font.sanitizeGlyphLocations();7font.saveToFile(path.join(__dirname, 'font-sanitized.ttf'));
Using AI Code Generation
1var wptools = require('wp-tools');2var fs = require('fs');3var path = require('path');4var font = fs.readFileSync(path.resolve(__dirname, './fonts/Roboto-Regular.ttf'));5var sanitizedFont = wptools.sanitizeGlyphLocations(font);6fs.writeFileSync(path.resolve(__dirname, './fonts/Roboto-Regular-sanitized.ttf'), sanitizedFont);7Apache-2.0 © [Bhuvanesh Hingal](
Using AI Code Generation
1var wptools = require('wptools');2wptools.sanitizeGlyphLocations('path/to/font.ttf', 'path/to/output.ttf', function(err) {3 console.log('done');4});5var wptools = require('wptools');6wptools.sanitizeGlyphLocations('path/to/font.ttf', 'path/to/output.ttf', function(err) {7 console.log('done');8});9var wptools = require('wptools');10wptools.sanitizeGlyphLocations('path/to/font.ttf', 'path/to/output.ttf', function(err) {11 console.log('done');12});13var wptools = require('wptools');14wptools.sanitizeGlyphLocations('path/to/font.ttf', 'path/to/output.ttf', function(err) {15 console.log('done');16});17var wptools = require('wptools');18wptools.sanitizeGlyphLocations('path/to/font.ttf', 'path/to/output.ttf', function(err) {19 console.log('done');20});21var wptools = require('wptools');22wptools.sanitizeGlyphLocations('path/to/font.ttf', 'path/to/output.ttf', function(err) {23 console.log('done');24});25var wptools = require('wptools');26wptools.sanitizeGlyphLocations('path/to/font.ttf', 'path/to/output.ttf', function(err) {27 console.log('done');28});29var wptools = require('wptools');30wptools.sanitizeGlyphLocations('path/to/font.ttf', 'path/to/output.ttf', function(err) {31 console.log('done');32});33var wptools = require('wptools');
Using AI Code Generation
1var wptools = require('./wptools');2var fs = require('fs');3var font = wptools.loadFont('./fonts/Roboto-Regular.ttf');4var svg = wptools.getSVG(font, 'A', 100, 100, 100, 100);5fs.writeFile('test.svg', svg, function (err) {6 if (err) {7 return console.log(err);8 }9 console.log('The file was saved!');10});11var wptools = (function () {12 function wptools() {13 }14 wptools.loadFont = function (path) {15 return opentype.loadSync(path);16 };17 wptools.getSVG = function (font, text, x, y, size, lineHeight) {18 var path = font.getPath(text, x, y, size, { kerning: true });19 var svg = path.toSVG();20 var glyphLocations = path.commands.map(function (command) { return command.x; });21 var sanitizedGlyphLocations = wptools.sanitizeGlyphLocations(glyphLocations);22 return svg;23 };24 wptools.sanitizeGlyphLocations = function (glyphLocations) {25 var sanitizedGlyphLocations = [];26 var lastX = 0;27 for (var i = 0; i < glyphLocations.length; i++) {28 var x = glyphLocations[i];29 if (x != lastX) {30 sanitizedGlyphLocations.push(x);31 lastX = x;32 }33 }34 return sanitizedGlyphLocations;35 };36 return wptools;37})();38module.exports = wptools;39var path = font.getPath(text, x, y, size, { kerning: true });40var svg = path.toSVG();
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!