Repository

js/Mobilizing/text/Font.js

// Warning: 'opentype.js' is the package name, which differs from 'opentype'
import * as opentype from 'opentype.js';
import { Base64Binary } from '../core/util/Misc';

/**
To be able to use both bitmap rendered font and 3D vector rendering, we use openType.js (https://nodebox.github.io/opentype.js/ big thanks to Frederik!) to load any web compilant font and the use it in other classes.
*/
export default class Font {


    /**
    @param {Object} params Parameters object, given by the constructor.
    @param {Mixed} params.fontFile the font file already loaded, must be loaded with response type setted to arraybuffer
    */
    constructor({
        fontFile = undefined,
        base64String = undefined,
    } = {}) {
        this.fontFile = fontFile;
        this.base64String = base64String;

        //@TODO préparer des setters getters pour ce qui doit être accessible depuis l'extérieur, mais garder la syntaxe this._params.xxx dans les classes

        if (this.fontFile) {
            this.font = opentype.parse(this.fontFile);
        }
        else if (this.base64String) {
            const binary = new Base64Binary();
            const fontArrayBuffer = binary.decodeArrayBuffer(this.base64String);

            this.font = opentype.parse(fontArrayBuffer);
        }
    }

    /**
    * Return the underlying Font.js object to work with it outside of Mobilizing.Font ()
    * @method getFont
    * @return {Object} Font.js object
    */
    getFont() {
        return this.font;
    }

    /**
    * Calculates the size (in pixels) that should take the string with this font at the given fontSize. Handy for Label creation.
    * @method getTextSize
    * @param {String} text the string to use for the size computing
    * @param {Number} fontSize the text font size to use
    * @return {Object.width, Object.height} width and height
    */
    getTextSize(text, fontSize) {
        if (!this.font.supported) {
            return null;
        }

        let kerning, fontScale, glyphs, i, glyph, options, kerningValue;
        const ymax = [];
        let x = 0;

        fontSize = (fontSize !== undefined) ? fontSize : 72;
        options = options || {};
        kerning = options.kerning === undefined ? true : options.kerning;
        fontScale = 1 / this.font.unitsPerEm * fontSize;
        glyphs = this.font.stringToGlyphs(text);

        for (i = 0; i < glyphs.length; i += 1) {
            glyph = glyphs[i];

            ymax.push((glyph.getMetrics().yMax - glyph.getMetrics().yMin) * fontScale);

            if (glyph.advanceWidth) {
                x += glyph.advanceWidth * fontScale;
            }

            if (kerning && i < glyphs.length - 1) {
                kerningValue = this.font.getKerningValue(glyph, glyphs[i + 1]);
                x += kerningValue * fontScale;
            }
        }

        return {
            "width": x,
            "height": Math.max.apply(0, ymax)
        };
    }
}