// In the event that index chunks aren't available from an external source, it // winds up saving time to do a fast pass over the data to compute them. This // allows us to parse a single contig at a time using jBinary. function computeIndexChunks(buffer) { var BLOCK_SIZE = 65536; var view = new jDataView(buffer, 0, buffer.byteLength, true /* little endian */); var minBlockIndex = Infinity; var contigStartOffsets = []; view.getInt32(); // magic var n_ref = view.getInt32(); for (var j = 0; j < n_ref; j++) { contigStartOffsets.push(view.tell()); var n_bin = view.getInt32(); for (var i = 0; i < n_bin; i++) { view.getUint32(); // bin ID var n_chunk = view.getInt32(); view.skip(n_chunk * 16); } var n_intv = view.getInt32(); if (n_intv) { var offset = VirtualOffset.fromBlob(view.getBytes(8), 0), coffset = offset.coffset + (offset.uoffset ? BLOCK_SIZE : 0); minBlockIndex = coffset ? Math.min(coffset, minBlockIndex) : BLOCK_SIZE; view.skip((n_intv - 1) * 8); } } contigStartOffsets.push(view.tell()); // At this point, `minBlockIndex` should be non-Infinity (see #405 & #406) return { chunks: _.zip(_.initial(contigStartOffsets), _.rest(contigStartOffsets)), minBlockIndex }; }
function createNameTable(font) { var names = getNames(font); var buf = new jDataView(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; }
TTF.prototype._readTables = function() { // view作成 var view = new jDataView(this.ttf, 0, this.ttf.byteLength, false); // bigEndian this.view = view; // version this.version = view.getFixed(0, false); // num tables this.numTables = view.getUint16(4, false); // searchRenge this.searchRenge = view.getUint16(6, false); // entrySelector this.entrySelector = view.getUint16(8, false); // rengeShift this.rengeShift = view.getUint16(10, false); // tableDirectoryの取得と各テーブルの初期化 this.tableDirectory = new TTFTableDirecotry(view, view.tell(), this.numTables); //各種テーブルの初期化 for (var tag in this.tableDirectory) { this[tag] = {}; } // head var headOffset = this.tableDirectory.head.offset; this.head.version = view.getFixed(headOffset); this.head.fontRevision = view.getFixed(headOffset + 4); this.head.checkSumAdjustment = view.getUint32(headOffset + 8, false) .toString(16); this.head.magickNumber = view.getUint32(headOffset + 12, false) .toString(16); this.head.flags = padZero(view.getUint16(headOffset + 16, false) .toString(2), 16); this.head.unitsPerEm = view.getUint16(headOffset + 18, false); this.head.created = view.getLongDateTime(headOffset + 20, false); this.head.modified = view.getLongDateTime(headOffset + 28, false); this.head.xMin = view.getInt16(headOffset + 36, false); this.head.yMin = view.getInt16(headOffset + 38, false); this.head.xMax = view.getInt16(headOffset + 40, false); this.head.yMax = view.getInt16(headOffset + 42, false); this.head.macStyle = padZero(view.getUint16(headOffset + 44, false) .toString(2), 16); this.head.lowestRecPPEM = view.getUint16(headOffset + 46, false); this.head.fontDirectionHint = view.getInt16(headOffset + 48, false); this.head.indexToLocFormat = view.getInt16(headOffset + 50, false); this.head.glyphDataFormat = view.getInt16(headOffset + 52, false); // maxp var maxpOffset = this.tableDirectory.maxp.offset; this.maxp.version = view.getFixed(maxpOffset); this.maxp.numGlyphs = view.getUint16(maxpOffset + 4, false); this.maxp.maxPoints = view.getUint16(maxpOffset + 6, false); this.maxp.maxCompositePoints = view.getUint16(maxpOffset + 8, false); this.maxp.maxCompositeContours = view.getUint16(maxpOffset + 10, false); this.maxp.maxZones = view.getUint16(maxpOffset + 12, false); this.maxp.maxTwilightPoints = view.getUint16(maxpOffset + 14, false); this.maxp.maxStorage = view.getUint16(maxpOffset + 16, false); this.maxp.maxFunctionDefs = view.getUint16(maxpOffset + 18, false); this.maxp.maxInstructionDefs = view.getUint16(maxpOffset + 20, false); this.maxp.maxStackElements = view.getUint16(maxpOffset + 22, false); this.maxp.maxSizeOfInstructions = view .getUint16(maxpOffset + 26, false); this.maxp.maxComponentElements = view.getUint16(maxpOffset + 28, false); this.maxp.maxComponentDepth = view.getUint16(maxpOffset + 30, false); // loca var locaOffset = this.tableDirectory.loca.offset; this.loca = []; this.locaOffsetSize = []; var locaType = (this.head.indexToLocFormat === 0) ? "Uint16" : "Uint32"; var locaSize = (this.head.indexToLocFormat === 0) ? 2 : 4; var locaRatio = (this.head.indexToLocFormat === 0) ? 2 : 1; for ( var i = 0; i < this.maxp.numGlyphs; i++) { this.loca.push(view["get" + locaType](locaOffset, false) * locaRatio); // locaのタイプがshortだった場合、2で割った値が記録されている為2をかけて値を戻す this.locaOffsetSize.push(locaOffset); locaOffset += locaSize; } // glyf var glyfOffset = this.tableDirectory.glyf.offset; this._glyfDataList = {}; this.glyf = []; // グリフデータリストを作成 for ( var i = 0, l = this.loca.length; i < l; i++) { var offset = this.tableDirectory.glyf.offset + this.loca[i]; if (typeof this._glyfDataList[offset] == "undefined") { // 次のグリフと同じオフセット値だった場合は空のグリフとして処理 var isNull = (i + 1 < l && this.loca[i] === this.loca[i + 1]); this._glyfDataList[offset] = new TTFGlyf(view, offset, isNull); } this.glyf[i] = this._glyfDataList[offset]; } // cmap var cmapOffset = this.tableDirectory.cmap.offset; this.cmap.version = view.getUint16( cmapOffset , false ); this.cmap.numberSubtables = view.getUint16(cmapOffset + 2 , false ); this.cmap.tables = []; for( var i =0 ; i < this.cmap.numberSubtables; i++){ var table = {}; table.platformID = view.getUint16( cmapOffset + 8*i + 4 , false ); table.platformSpecificID = view.getUint16( cmapOffset + 8*i + 6, false ); table.offset = view.getUint32( cmapOffset + 8*i + 8, false ); //table.format = view.getUint16( cmapOffset + table.offset, false ); table.data = new TTFCmap( view, cmapOffset + table.offset ); this.cmap.tables.push( table ); } var self = this; this.cmap.getGlyphIndex = function ( c ) { return self.cmap.tables.map( function ( item ) { return item.data._getGlyphIndex( c ); }); } };