Exemplo n.º 1
0
// 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
  };
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
	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 );
            });
        }

	};