/*!
 * @pixi/text-bitmap - v6.3.0
 * Compiled Wed, 23 Mar 2022 18:58:56 UTC
 *
 * @pixi/text-bitmap is licensed under the MIT License.
 * http://www.opensource.org/licenses/mit-license
 */
'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var math = require('@pixi/math');
var settings = require('@pixi/settings');
var mesh = require('@pixi/mesh');
var utils = require('@pixi/utils');
var core = require('@pixi/core');
var text = require('@pixi/text');
var constants = require('@pixi/constants');
var display = require('@pixi/display');
var loaders = require('@pixi/loaders');

/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
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

THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.

See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/* global Reflect, Promise */

var extendStatics = function(d, b) {
    extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) { if (b.hasOwnProperty(p)) { d[p] = b[p]; } } };
    return extendStatics(d, b);
};

function __extends(d, b) {
    extendStatics(d, b);
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}

/* eslint-disable max-len */
/**
 * Normalized parsed data from .fnt files.
 *
 * @memberof PIXI
 */
var BitmapFontData = /** @class */ (function () {
    function BitmapFontData() {
        this.info = [];
        this.common = [];
        this.page = [];
        this.char = [];
        this.kerning = [];
        this.distanceField = [];
    }
    return BitmapFontData;
}());

/**
 * BitmapFont format that's Text-based.
 *
 * @private
 */
var TextFormat = /** @class */ (function () {
    function TextFormat() {
    }
    /**
     * Check if resource refers to txt font data.
     *
     * @param data
     * @return - True if resource could be treated as font data, false otherwise.
     */
    TextFormat.test = function (data) {
        return typeof data === 'string' && data.indexOf('info face=') === 0;
    };
    /**
     * Convert text font data to a javascript object.
     *
     * @param txt - Raw string data to be converted
     * @return - Parsed font data
     */
    TextFormat.parse = function (txt) {
        // Retrieve data item
        var items = txt.match(/^[a-z]+\s+.+$/gm);
        var rawData = {
            info: [],
            common: [],
            page: [],
            char: [],
            chars: [],
            kerning: [],
            kernings: [],
            distanceField: [],
        };
        for (var i in items) {
            // Extract item name
            var name = items[i].match(/^[a-z]+/gm)[0];
            // Extract item attribute list as string ex.: "width=10"
            var attributeList = items[i].match(/[a-zA-Z]+=([^\s"']+|"([^"]*)")/gm);
            // Convert attribute list into an object
            var itemData = {};
            for (var i_1 in attributeList) {
                // Split key-value pairs
                var split = attributeList[i_1].split('=');
                var key = split[0];
                // Remove eventual quotes from value
                var strValue = split[1].replace(/"/gm, '');
                // Try to convert value into float
                var floatValue = parseFloat(strValue);
                // Use string value case float value is NaN
                var value = isNaN(floatValue) ? strValue : floatValue;
                itemData[key] = value;
            }
            // Push current item to the resulting data
            rawData[name].push(itemData);
        }
        var font = new BitmapFontData();
        rawData.info.forEach(function (info) { return font.info.push({
            face: info.face,
            size: parseInt(info.size, 10),
        }); });
        rawData.common.forEach(function (common) { return font.common.push({
            lineHeight: parseInt(common.lineHeight, 10),
        }); });
        rawData.page.forEach(function (page) { return font.page.push({
            id: parseInt(page.id, 10),
            file: page.file,
        }); });
        rawData.char.forEach(function (char) { return font.char.push({
            id: parseInt(char.id, 10),
            page: parseInt(char.page, 10),
            x: parseInt(char.x, 10),
            y: parseInt(char.y, 10),
            width: parseInt(char.width, 10),
            height: parseInt(char.height, 10),
            xoffset: parseInt(char.xoffset, 10),
            yoffset: parseInt(char.yoffset, 10),
            xadvance: parseInt(char.xadvance, 10),
        }); });
        rawData.kerning.forEach(function (kerning) { return font.kerning.push({
            first: parseInt(kerning.first, 10),
            second: parseInt(kerning.second, 10),
            amount: parseInt(kerning.amount, 10),
        }); });
        rawData.distanceField.forEach(function (df) { return font.distanceField.push({
            distanceRange: parseInt(df.distanceRange, 10),
            fieldType: df.fieldType,
        }); });
        return font;
    };
    return TextFormat;
}());

/**
 * BitmapFont format that's XML-based.
 *
 * @private
 */
var XMLFormat = /** @class */ (function () {
    function XMLFormat() {
    }
    /**
     * Check if resource refers to xml font data.
     *
     * @param data
     * @return - True if resource could be treated as font data, false otherwise.
     */
    XMLFormat.test = function (data) {
        return data instanceof XMLDocument
            && data.getElementsByTagName('page').length
            && data.getElementsByTagName('info')[0].getAttribute('face') !== null;
    };
    /**
     * Convert the XML into BitmapFontData that we can use.
     *
     * @param xml
     * @return - Data to use for BitmapFont
     */
    XMLFormat.parse = function (xml) {
        var data = new BitmapFontData();
        var info = xml.getElementsByTagName('info');
        var common = xml.getElementsByTagName('common');
        var page = xml.getElementsByTagName('page');
        var char = xml.getElementsByTagName('char');
        var kerning = xml.getElementsByTagName('kerning');
        var distanceField = xml.getElementsByTagName('distanceField');
        for (var i = 0; i < info.length; i++) {
            data.info.push({
                face: info[i].getAttribute('face'),
                size: parseInt(info[i].getAttribute('size'), 10),
            });
        }
        for (var i = 0; i < common.length; i++) {
            data.common.push({
                lineHeight: parseInt(common[i].getAttribute('lineHeight'), 10),
            });
        }
        for (var i = 0; i < page.length; i++) {
            data.page.push({
                id: parseInt(page[i].getAttribute('id'), 10) || 0,
                file: page[i].getAttribute('file'),
            });
        }
        for (var i = 0; i < char.length; i++) {
            var letter = char[i];
            data.char.push({
                id: parseInt(letter.getAttribute('id'), 10),
                page: parseInt(letter.getAttribute('page'), 10) || 0,
                x: parseInt(letter.getAttribute('x'), 10),
                y: parseInt(letter.getAttribute('y'), 10),
                width: parseInt(letter.getAttribute('width'), 10),
                height: parseInt(letter.getAttribute('height'), 10),
                xoffset: parseInt(letter.getAttribute('xoffset'), 10),
                yoffset: parseInt(letter.getAttribute('yoffset'), 10),
                xadvance: parseInt(letter.getAttribute('xadvance'), 10),
            });
        }
        for (var i = 0; i < kerning.length; i++) {
            data.kerning.push({
                first: parseInt(kerning[i].getAttribute('first'), 10),
                second: parseInt(kerning[i].getAttribute('second'), 10),
                amount: parseInt(kerning[i].getAttribute('amount'), 10),
            });
        }
        for (var i = 0; i < distanceField.length; i++) {
            data.distanceField.push({
                fieldType: distanceField[i].getAttribute('fieldType'),
                distanceRange: parseInt(distanceField[i].getAttribute('distanceRange'), 10),
            });
        }
        return data;
    };
    return XMLFormat;
}());

/**
 * BitmapFont format that's XML-based.
 *
 * @private
 */
var XMLStringFormat = /** @class */ (function () {
    function XMLStringFormat() {
    }
    /**
     * Check if resource refers to text xml font data.
     *
     * @param data
     * @return - True if resource could be treated as font data, false otherwise.
     */
    XMLStringFormat.test = function (data) {
        if (typeof data === 'string' && data.indexOf('<font>') > -1) {
            var xml = new globalThis.DOMParser().parseFromString(data, 'text/xml');
            return XMLFormat.test(xml);
        }
        return false;
    };
    /**
     * Convert the text XML into BitmapFontData that we can use.
     *
     * @param xmlTxt
     * @return - Data to use for BitmapFont
     */
    XMLStringFormat.parse = function (xmlTxt) {
        var xml = new globalThis.DOMParser().parseFromString(xmlTxt, 'text/xml');
        return XMLFormat.parse(xml);
    };
    return XMLStringFormat;
}());

// Registered formats, maybe make this extensible in the future?
var formats = [
    TextFormat,
    XMLFormat,
    XMLStringFormat ];
/**
 * Auto-detect BitmapFont parsing format based on data.
 * @private
 * @param {any} data - Data to detect format
 * @return {any} Format or null
 */
function autoDetectFormat(data) {
    for (var i = 0; i < formats.length; i++) {
        if (formats[i].test(data)) {
            return formats[i];
        }
    }
    return null;
}

// TODO: Prevent code duplication b/w generateFillStyle & Text#generateFillStyle
/**
 * Generates the fill style. Can automatically generate a gradient based on the fill style being an array
 *
 * @private
 * @param {object} style - The style.
 * @param {string[]} lines - The lines of text.
 * @return {string|number|CanvasGradient} The fill style
 */
function generateFillStyle(canvas, context, style, resolution, lines, metrics) {
    // TODO: Can't have different types for getter and setter. The getter shouldn't have the number type as
    //       the setter converts to string. See this thread for more details:
    //       https://github.com/microsoft/TypeScript/issues/2521
    var fillStyle = style.fill;
    if (!Array.isArray(fillStyle)) {
        return fillStyle;
    }
    else if (fillStyle.length === 1) {
        return fillStyle[0];
    }
    // the gradient will be evenly spaced out according to how large the array is.
    // ['#FF0000', '#00FF00', '#0000FF'] would created stops at 0.25, 0.5 and 0.75
    var gradient;
    // a dropshadow will enlarge the canvas and result in the gradient being
    // generated with the incorrect dimensions
    var dropShadowCorrection = (style.dropShadow) ? style.dropShadowDistance : 0;
    // should also take padding into account, padding can offset the gradient
    var padding = style.padding || 0;
    var width = (canvas.width / resolution) - dropShadowCorrection - (padding * 2);
    var height = (canvas.height / resolution) - dropShadowCorrection - (padding * 2);
    // make a copy of the style settings, so we can manipulate them later
    var fill = fillStyle.slice();
    var fillGradientStops = style.fillGradientStops.slice();
    // wanting to evenly distribute the fills. So an array of 4 colours should give fills of 0.25, 0.5 and 0.75
    if (!fillGradientStops.length) {
        var lengthPlus1 = fill.length + 1;
        for (var i = 1; i < lengthPlus1; ++i) {
            fillGradientStops.push(i / lengthPlus1);
        }
    }
    // stop the bleeding of the last gradient on the line above to the top gradient of the this line
    // by hard defining the first gradient colour at point 0, and last gradient colour at point 1
    fill.unshift(fillStyle[0]);
    fillGradientStops.unshift(0);
    fill.push(fillStyle[fillStyle.length - 1]);
    fillGradientStops.push(1);
    if (style.fillGradientType === text.TEXT_GRADIENT.LINEAR_VERTICAL) {
        // start the gradient at the top center of the canvas, and end at the bottom middle of the canvas
        gradient = context.createLinearGradient(width / 2, padding, width / 2, height + padding);
        // we need to repeat the gradient so that each individual line of text has the same vertical gradient effect
        // ['#FF0000', '#00FF00', '#0000FF'] over 2 lines would create stops at 0.125, 0.25, 0.375, 0.625, 0.75, 0.875
        // There's potential for floating point precision issues at the seams between gradient repeats.
        // The loop below generates the stops in order, so track the last generated one to prevent
        // floating point precision from making us go the teeniest bit backwards, resulting in
        // the first and last colors getting swapped.
        var lastIterationStop = 0;
        // Actual height of the text itself, not counting spacing for lineHeight/leading/dropShadow etc
        var textHeight = metrics.fontProperties.fontSize + style.strokeThickness;
        // textHeight, but as a 0-1 size in global gradient stop space
        var gradStopLineHeight = textHeight / height;
        for (var i = 0; i < lines.length; i++) {
            var thisLineTop = metrics.lineHeight * i;
            for (var j = 0; j < fill.length; j++) {
                // 0-1 stop point for the current line, multiplied to global space afterwards
                var lineStop = 0;
                if (typeof fillGradientStops[j] === 'number') {
                    lineStop = fillGradientStops[j];
                }
                else {
                    lineStop = j / fill.length;
                }
                var globalStop = (thisLineTop / height) + (lineStop * gradStopLineHeight);
                // Prevent color stop generation going backwards from floating point imprecision
                var clampedStop = Math.max(lastIterationStop, globalStop);
                clampedStop = Math.min(clampedStop, 1); // Cap at 1 as well for safety's sake to avoid a possible throw.
                gradient.addColorStop(clampedStop, fill[j]);
                lastIterationStop = clampedStop;
            }
        }
    }
    else {
        // start the gradient at the center left of the canvas, and end at the center right of the canvas
        gradient = context.createLinearGradient(padding, height / 2, width + padding, height / 2);
        // can just evenly space out the gradients in this case, as multiple lines makes no difference
        // to an even left to right gradient
        var totalIterations = fill.length + 1;
        var currentIteration = 1;
        for (var i = 0; i < fill.length; i++) {
            var stop = void 0;
            if (typeof fillGradientStops[i] === 'number') {
                stop = fillGradientStops[i];
            }
            else {
                stop = currentIteration / totalIterations;
            }
            gradient.addColorStop(stop, fill[i]);
            currentIteration++;
        }
    }
    return gradient;
}

// TODO: Prevent code duplication b/w drawGlyph & Text#updateText
/**
 * Draws the glyph `metrics.text` on the given canvas.
 *
 * Ignored because not directly exposed.
 *
 * @ignore
 * @param {HTMLCanvasElement} canvas
 * @param {CanvasRenderingContext2D} context
 * @param {TextMetrics} metrics
 * @param {number} x
 * @param {number} y
 * @param {number} resolution
 * @param {TextStyle} style
 */
function drawGlyph(canvas, context, metrics, x, y, resolution, style) {
    var char = metrics.text;
    var fontProperties = metrics.fontProperties;
    context.translate(x, y);
    context.scale(resolution, resolution);
    var tx = style.strokeThickness / 2;
    var ty = -(style.strokeThickness / 2);
    context.font = style.toFontString();
    context.lineWidth = style.strokeThickness;
    context.textBaseline = style.textBaseline;
    context.lineJoin = style.lineJoin;
    context.miterLimit = style.miterLimit;
    // set canvas text styles
    context.fillStyle = generateFillStyle(canvas, context, style, resolution, [char], metrics);
    context.strokeStyle = style.stroke;
    if (style.dropShadow) {
        var dropShadowColor = style.dropShadowColor;
        var rgb = utils.hex2rgb(typeof dropShadowColor === 'number' ? dropShadowColor : utils.string2hex(dropShadowColor));
        var dropShadowBlur = style.dropShadowBlur * resolution;
        var dropShadowDistance = style.dropShadowDistance * resolution;
        context.shadowColor = "rgba(" + rgb[0] * 255 + "," + rgb[1] * 255 + "," + rgb[2] * 255 + "," + style.dropShadowAlpha + ")";
        context.shadowBlur = dropShadowBlur;
        context.shadowOffsetX = Math.cos(style.dropShadowAngle) * dropShadowDistance;
        context.shadowOffsetY = Math.sin(style.dropShadowAngle) * dropShadowDistance;
    }
    else {
        context.shadowColor = 'black';
        context.shadowBlur = 0;
        context.shadowOffsetX = 0;
        context.shadowOffsetY = 0;
    }
    if (style.stroke && style.strokeThickness) {
        context.strokeText(char, tx, ty + metrics.lineHeight - fontProperties.descent);
    }
    if (style.fill) {
        context.fillText(char, tx, ty + metrics.lineHeight - fontProperties.descent);
    }
    context.setTransform(1, 0, 0, 1, 0, 0); // defaults needed for older browsers (e.g. Opera 29)
    context.fillStyle = 'rgba(0, 0, 0, 0)';
}

/**
 * Ponyfill for IE because it doesn't support `Array.from`
 * @private
 */
function splitTextToCharacters(text) {
    return Array.from ? Array.from(text) : text.split('');
}

/**
 * Processes the passed character set data and returns a flattened array of all the characters.
 *
 * Ignored because not directly exposed.
 *
 * @ignore
 * @param {string | string[] | string[][] } chars
 * @returns {string[]}
 */
function resolveCharacters(chars) {
    // Split the chars string into individual characters
    if (typeof chars === 'string') {
        chars = [chars];
    }
    // Handle an array of characters+ranges
    var result = [];
    for (var i = 0, j = chars.length; i < j; i++) {
        var item = chars[i];
        // Handle range delimited by start/end chars
        if (Array.isArray(item)) {
            if (item.length !== 2) {
                throw new Error("[BitmapFont]: Invalid character range length, expecting 2 got " + item.length + ".");
            }
            var startCode = item[0].charCodeAt(0);
            var endCode = item[1].charCodeAt(0);
            if (endCode < startCode) {
                throw new Error('[BitmapFont]: Invalid character range.');
            }
            for (var i_1 = startCode, j_1 = endCode; i_1 <= j_1; i_1++) {
                result.push(String.fromCharCode(i_1));
            }
        }
        // Handle a character set string
        else {
            result.push.apply(result, splitTextToCharacters(item));
        }
    }
    if (result.length === 0) {
        throw new Error('[BitmapFont]: Empty set when resolving characters.');
    }
    return result;
}

/**
 * Ponyfill for IE because it doesn't support `codePointAt`
 * @private
 */
function extractCharCode(str) {
    return str.codePointAt ? str.codePointAt(0) : str.charCodeAt(0);
}

/**
 * BitmapFont represents a typeface available for use with the BitmapText class. Use the `install`
 * method for adding a font to be used.
 *
 * @memberof PIXI
 */
var BitmapFont = /** @class */ (function () {
    /**
     * @param data
     * @param textures
     * @param ownsTextures - Setting to `true` will destroy page textures
     *        when the font is uninstalled.
     */
    function BitmapFont(data, textures, ownsTextures) {
        var _a, _b;
        var info = data.info[0];
        var common = data.common[0];
        var page = data.page[0];
        var distanceField = data.distanceField[0];
        var res = utils.getResolutionOfUrl(page.file);
        var pageTextures = {};
        this._ownsTextures = ownsTextures;
        this.font = info.face;
        this.size = info.size;
        this.lineHeight = common.lineHeight / res;
        this.chars = {};
        this.pageTextures = pageTextures;
        // Convert the input Texture, Textures or object
        // into a page Texture lookup by "id"
        for (var i = 0; i < data.page.length; i++) {
            var _c = data.page[i], id = _c.id, file = _c.file;
            pageTextures[id] = textures instanceof Array
                ? textures[i] : textures[file];
            // only MSDF and SDF fonts need no-premultiplied-alpha
            if ((distanceField === null || distanceField === void 0 ? void 0 : distanceField.fieldType) && distanceField.fieldType !== 'none') {
                pageTextures[id].baseTexture.alphaMode = constants.ALPHA_MODES.NO_PREMULTIPLIED_ALPHA;
            }
        }
        // parse letters
        for (var i = 0; i < data.char.length; i++) {
            var _d = data.char[i], id = _d.id, page_1 = _d.page;
            var _e = data.char[i], x = _e.x, y = _e.y, width = _e.width, height = _e.height, xoffset = _e.xoffset, yoffset = _e.yoffset, xadvance = _e.xadvance;
            x /= res;
            y /= res;
            width /= res;
            height /= res;
            xoffset /= res;
            yoffset /= res;
            xadvance /= res;
            var rect = new math.Rectangle(x + (pageTextures[page_1].frame.x / res), y + (pageTextures[page_1].frame.y / res), width, height);
            this.chars[id] = {
                xOffset: xoffset,
                yOffset: yoffset,
                xAdvance: xadvance,
                kerning: {},
                texture: new core.Texture(pageTextures[page_1].baseTexture, rect),
                page: page_1,
            };
        }
        // parse kernings
        for (var i = 0; i < data.kerning.length; i++) {
            var _f = data.kerning[i], first = _f.first, second = _f.second, amount = _f.amount;
            first /= res;
            second /= res;
            amount /= res;
            if (this.chars[second]) {
                this.chars[second].kerning[first] = amount;
            }
        }
        // Store distance field information
        this.distanceFieldRange = distanceField === null || distanceField === void 0 ? void 0 : distanceField.distanceRange;
        this.distanceFieldType = (_b = (_a = distanceField === null || distanceField === void 0 ? void 0 : distanceField.fieldType) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : 'none';
    }
    /** Remove references to created glyph textures. */
    BitmapFont.prototype.destroy = function () {
        for (var id in this.chars) {
            this.chars[id].texture.destroy();
            this.chars[id].texture = null;
        }
        for (var id in this.pageTextures) {
            if (this._ownsTextures) {
                this.pageTextures[id].destroy(true);
            }
            this.pageTextures[id] = null;
        }
        // Set readonly null.
        this.chars = null;
        this.pageTextures = null;
    };
    /**
     * Register a new bitmap font.
     *
     * @param data - The
     *        characters map that could be provided as xml or raw string.
     * @param textures - List of textures for each page.
     * @param ownsTextures - Set to `true` to destroy page textures
     *        when the font is uninstalled. By default fonts created with
     *        `BitmapFont.from` or from the `BitmapFontLoader` are `true`.
     * @return {PIXI.BitmapFont} Result font object with font, size, lineHeight
     *         and char fields.
     */
    BitmapFont.install = function (data, textures, ownsTextures) {
        var fontData;
        if (data instanceof BitmapFontData) {
            fontData = data;
        }
        else {
            var format = autoDetectFormat(data);
            if (!format) {
                throw new Error('Unrecognized data format for font.');
            }
            fontData = format.parse(data);
        }
        // Single texture, convert to list
        if (textures instanceof core.Texture) {
            textures = [textures];
        }
        var font = new BitmapFont(fontData, textures, ownsTextures);
        BitmapFont.available[font.font] = font;
        return font;
    };
    /**
     * Remove bitmap font by name.
     *
     * @param name - Name of the font to uninstall.
     */
    BitmapFont.uninstall = function (name) {
        var font = BitmapFont.available[name];
        if (!font) {
            throw new Error("No font found named '" + name + "'");
        }
        font.destroy();
        delete BitmapFont.available[name];
    };
    /**
     * Generates a bitmap-font for the given style and character set. This does not support
     * kernings yet. With `style` properties, only the following non-layout properties are used:
     *
     * - {@link PIXI.TextStyle#dropShadow|dropShadow}
     * - {@link PIXI.TextStyle#dropShadowDistance|dropShadowDistance}
     * - {@link PIXI.TextStyle#dropShadowColor|dropShadowColor}
     * - {@link PIXI.TextStyle#dropShadowBlur|dropShadowBlur}
     * - {@link PIXI.TextStyle#dropShadowAngle|dropShadowAngle}
     * - {@link PIXI.TextStyle#fill|fill}
     * - {@link PIXI.TextStyle#fillGradientStops|fillGradientStops}
     * - {@link PIXI.TextStyle#fillGradientType|fillGradientType}
     * - {@link PIXI.TextStyle#fontFamily|fontFamily}
     * - {@link PIXI.TextStyle#fontSize|fontSize}
     * - {@link PIXI.TextStyle#fontVariant|fontVariant}
     * - {@link PIXI.TextStyle#fontWeight|fontWeight}
     * - {@link PIXI.TextStyle#lineJoin|lineJoin}
     * - {@link PIXI.TextStyle#miterLimit|miterLimit}
     * - {@link PIXI.TextStyle#stroke|stroke}
     * - {@link PIXI.TextStyle#strokeThickness|strokeThickness}
     * - {@link PIXI.TextStyle#textBaseline|textBaseline}
     *
     * @param name - The name of the custom font to use with BitmapText.
     * @param style - Style options to render with BitmapFont.
     * @param options - Setup options for font or name of the font.
     * @param {string|string[]|string[][]} [options.chars=PIXI.BitmapFont.ALPHANUMERIC] - characters included
     *      in the font set. You can also use ranges. For example, `[['a', 'z'], ['A', 'Z'], "!@#$%^&*()~{}[] "]`.
     *      Don't forget to include spaces ' ' in your character set!
     * @param {number} [options.resolution=1] - Render resolution for glyphs.
     * @param {number} [options.textureWidth=512] - Optional width of atlas, smaller values to reduce memory.
     * @param {number} [options.textureHeight=512] - Optional height of atlas, smaller values to reduce memory.
     * @param {number} [options.padding=4] - Padding between glyphs on texture atlas.
     * @return Font generated by style options.
     * @example
     * PIXI.BitmapFont.from("TitleFont", {
     *     fontFamily: "Arial",
     *     fontSize: 12,
     *     strokeThickness: 2,
     *     fill: "purple"
     * });
     *
     * const title = new PIXI.BitmapText("This is the title", { fontName: "TitleFont" });
     */
    BitmapFont.from = function (name, textStyle, options) {
        if (!name) {
            throw new Error('[BitmapFont] Property `name` is required.');
        }
        var _a = Object.assign({}, BitmapFont.defaultOptions, options), chars = _a.chars, padding = _a.padding, resolution = _a.resolution, textureWidth = _a.textureWidth, textureHeight = _a.textureHeight;
        var charsList = resolveCharacters(chars);
        var style = textStyle instanceof text.TextStyle ? textStyle : new text.TextStyle(textStyle);
        var lineWidth = textureWidth;
        var fontData = new BitmapFontData();
        fontData.info[0] = {
            face: style.fontFamily,
            size: style.fontSize,
        };
        fontData.common[0] = {
            lineHeight: style.fontSize,
        };
        var positionX = 0;
        var positionY = 0;
        var canvas;
        var context;
        var baseTexture;
        var maxCharHeight = 0;
        var textures = [];
        for (var i = 0; i < charsList.length; i++) {
            if (!canvas) {
                canvas = document.createElement('canvas');
                canvas.width = textureWidth;
                canvas.height = textureHeight;
                context = canvas.getContext('2d');
                baseTexture = new core.BaseTexture(canvas, { resolution: resolution });
                textures.push(new core.Texture(baseTexture));
                fontData.page.push({
                    id: textures.length - 1,
                    file: '',
                });
            }
            // Measure glyph dimensions
            var metrics = text.TextMetrics.measureText(charsList[i], style, false, canvas);
            var width = metrics.width;
            var height = Math.ceil(metrics.height);
            // This is ugly - but italics are given more space so they don't overlap
            var textureGlyphWidth = Math.ceil((style.fontStyle === 'italic' ? 2 : 1) * width);
            // Can't fit char anymore: next canvas please!
            if (positionY >= textureHeight - (height * resolution)) {
                if (positionY === 0) {
                    // We don't want user debugging an infinite loop (or do we? :)
                    throw new Error("[BitmapFont] textureHeight " + textureHeight + "px is "
                        + ("too small for " + style.fontSize + "px fonts"));
                }
                --i;
                // Create new atlas once current has filled up
                canvas = null;
                context = null;
                baseTexture = null;
                positionY = 0;
                positionX = 0;
                maxCharHeight = 0;
                continue;
            }
            maxCharHeight = Math.max(height + metrics.fontProperties.descent, maxCharHeight);
            // Wrap line once full row has been rendered
            if ((textureGlyphWidth * resolution) + positionX >= lineWidth) {
                --i;
                positionY += maxCharHeight * resolution;
                positionY = Math.ceil(positionY);
                positionX = 0;
                maxCharHeight = 0;
                continue;
            }
            drawGlyph(canvas, context, metrics, positionX, positionY, resolution, style);
            // Unique (numeric) ID mapping to this glyph
            var id = extractCharCode(metrics.text);
            // Create a texture holding just the glyph
            fontData.char.push({
                id: id,
                page: textures.length - 1,
                x: positionX / resolution,
                y: positionY / resolution,
                width: textureGlyphWidth,
                height: height,
                xoffset: 0,
                yoffset: 0,
                xadvance: Math.ceil(width
                    - (style.dropShadow ? style.dropShadowDistance : 0)
                    - (style.stroke ? style.strokeThickness : 0)),
            });
            positionX += (textureGlyphWidth + (2 * padding)) * resolution;
            positionX = Math.ceil(positionX);
        }
        // Brute-force kerning info, this can be expensive b/c it's an O(n²),
        // but we're using measureText which is native and fast.
        for (var i = 0, len = charsList.length; i < len; i++) {
            var first = charsList[i];
            for (var j = 0; j < len; j++) {
                var second = charsList[j];
                var c1 = context.measureText(first).width;
                var c2 = context.measureText(second).width;
                var total = context.measureText(first + second).width;
                var amount = total - (c1 + c2);
                if (amount) {
                    fontData.kerning.push({
                        first: extractCharCode(first),
                        second: extractCharCode(second),
                        amount: amount,
                    });
                }
            }
        }
        var font = new BitmapFont(fontData, textures, true);
        // Make it easier to replace a font
        if (BitmapFont.available[name] !== undefined) {
            BitmapFont.uninstall(name);
        }
        BitmapFont.available[name] = font;
        return font;
    };
    /**
     * This character set includes all the letters in the alphabet (both lower- and upper- case).
     *
     * @type {string[][]}
     * @example
     * BitmapFont.from("ExampleFont", style, { chars: BitmapFont.ALPHA })
     */
    BitmapFont.ALPHA = [['a', 'z'], ['A', 'Z'], ' '];
    /**
     * This character set includes all decimal digits (from 0 to 9).
     *
     * @type {string[][]}
     * @example
     * BitmapFont.from("ExampleFont", style, { chars: BitmapFont.NUMERIC })
     */
    BitmapFont.NUMERIC = [['0', '9']];
    /**
     * This character set is the union of `BitmapFont.ALPHA` and `BitmapFont.NUMERIC`.
     *
     * @type {string[][]}
     */
    BitmapFont.ALPHANUMERIC = [['a', 'z'], ['A', 'Z'], ['0', '9'], ' '];
    /**
     * This character set consists of all the ASCII table.
     *
     * @member {string[][]}
     * @see http://www.asciitable.com/
     */
    BitmapFont.ASCII = [[' ', '~']];
    /**
     * Collection of default options when using `BitmapFont.from`.
     *
     * @property {number} resolution=1
     * @property {number} textureWidth=512
     * @property {number} textureHeight=512
     * @property {number} padding=4
     * @property {string|string[]|string[][]} chars = PIXI.BitmapFont.ALPHANUMERIC
     */
    BitmapFont.defaultOptions = {
        resolution: 1,
        textureWidth: 512,
        textureHeight: 512,
        padding: 4,
        chars: BitmapFont.ALPHANUMERIC,
    };
    /** Collection of available/installed fonts. */
    BitmapFont.available = {};
    return BitmapFont;
}());

var msdfFrag = "// Pixi texture info\r\nvarying vec2 vTextureCoord;\r\nuniform sampler2D uSampler;\r\n\r\n// Tint\r\nuniform vec4 uColor;\r\n\r\n// on 2D applications fwidth is screenScale / glyphAtlasScale * distanceFieldRange\r\nuniform float uFWidth;\r\n\r\nvoid main(void) {\r\n\r\n  // To stack MSDF and SDF we need a non-pre-multiplied-alpha texture.\r\n  vec4 texColor = texture2D(uSampler, vTextureCoord);\r\n\r\n  // MSDF\r\n  float median = texColor.r + texColor.g + texColor.b -\r\n                  min(texColor.r, min(texColor.g, texColor.b)) -\r\n                  max(texColor.r, max(texColor.g, texColor.b));\r\n  // SDF\r\n  median = min(median, texColor.a);\r\n\r\n  float screenPxDistance = uFWidth * (median - 0.5);\r\n  float alpha = clamp(screenPxDistance + 0.5, 0.0, 1.0);\r\n\r\n  // NPM Textures, NPM outputs\r\n  gl_FragColor = vec4(uColor.rgb, uColor.a * alpha);\r\n\r\n}\r\n";

var msdfVert = "// Mesh material default fragment\r\nattribute vec2 aVertexPosition;\r\nattribute vec2 aTextureCoord;\r\n\r\nuniform mat3 projectionMatrix;\r\nuniform mat3 translationMatrix;\r\nuniform mat3 uTextureMatrix;\r\n\r\nvarying vec2 vTextureCoord;\r\n\r\nvoid main(void)\r\n{\r\n    gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\r\n\r\n    vTextureCoord = (uTextureMatrix * vec3(aTextureCoord, 1.0)).xy;\r\n}\r\n";

// If we ever need more than two pools, please make a Dict or something better.
var pageMeshDataDefaultPageMeshData = [];
var pageMeshDataMSDFPageMeshData = [];
var charRenderDataPool = [];
/**
 * A BitmapText object will create a line or multiple lines of text using bitmap font.
 *
 * The primary advantage of this class over Text is that all of your textures are pre-generated and loading,
 * meaning that rendering is fast, and changing text has no performance implications.
 *
 * Supporting character sets other than latin, such as CJK languages, may be impractical due to the number of characters.
 *
 * To split a line you can use '\n', '\r' or '\r\n' in your string.
 *
 * PixiJS can auto-generate fonts on-the-fly using BitmapFont or use fnt files provided by:
 * http://www.angelcode.com/products/bmfont/ for Windows or
 * http://www.bmglyph.com/ for Mac.
 *
 * You can also use SDF, MSDF and MTSDF BitmapFonts for vector-like scaling appearance provided by:
 * https://github.com/soimy/msdf-bmfont-xml for SDF and MSDF fnt files or
 * https://github.com/Chlumsky/msdf-atlas-gen for SDF, MSDF and MTSDF json files
 *
 * A BitmapText can only be created when the font is loaded.
 *
 * ```js
 * // in this case the font is in a file called 'desyrel.fnt'
 * let bitmapText = new PIXI.BitmapText("text using a fancy font!", {
 *   fontName: "Desyrel",
 *   fontSize: 35,
 *   align: "right"
 * });
 * ```
 *
 * @memberof PIXI
 */
var BitmapText = /** @class */ (function (_super) {
    __extends(BitmapText, _super);
    /**
     * @param text - A string that you would like the text to display.
     * @param style - The style parameters.
     * @param {string} style.fontName - The installed BitmapFont name.
     * @param {number} [style.fontSize] - The size of the font in pixels, e.g. 24. If undefined,
     *.     this will default to the BitmapFont size.
     * @param {string} [style.align='left'] - Alignment for multiline text ('left', 'center', 'right' or 'justify'),
     *      does not affect single line text.
     * @param {number} [style.tint=0xFFFFFF] - The tint color.
     * @param {number} [style.letterSpacing=0] - The amount of spacing between letters.
     * @param {number} [style.maxWidth=0] - The max width of the text before line wrapping.
     */
    function BitmapText(text, style) {
        if (style === void 0) { style = {}; }
        var _this = _super.call(this) || this;
        /**
         * Private tracker for the current tint.
         *
         * @private
         */
        _this._tint = 0xFFFFFF;
        // Apply the defaults
        var _a = Object.assign({}, BitmapText.styleDefaults, style), align = _a.align, tint = _a.tint, maxWidth = _a.maxWidth, letterSpacing = _a.letterSpacing, fontName = _a.fontName, fontSize = _a.fontSize;
        if (!BitmapFont.available[fontName]) {
            throw new Error("Missing BitmapFont \"" + fontName + "\"");
        }
        _this._activePagesMeshData = [];
        _this._textWidth = 0;
        _this._textHeight = 0;
        _this._align = align;
        _this._tint = tint;
        _this._fontName = fontName;
        _this._fontSize = fontSize || BitmapFont.available[fontName].size;
        _this._text = text;
        _this._maxWidth = maxWidth;
        _this._maxLineHeight = 0;
        _this._letterSpacing = letterSpacing;
        _this._anchor = new math.ObservablePoint(function () { _this.dirty = true; }, _this, 0, 0);
        _this._roundPixels = settings.settings.ROUND_PIXELS;
        _this.dirty = true;
        _this._textureCache = {};
        return _this;
    }
    /**
     * Renders text and updates it when needed. This should only be called
     * if the BitmapFont is regenerated.
     */
    BitmapText.prototype.updateText = function () {
        var _a;
        var data = BitmapFont.available[this._fontName];
        var scale = this._fontSize / data.size;
        var pos = new math.Point();
        var chars = [];
        var lineWidths = [];
        var lineSpaces = [];
        var text = this._text.replace(/(?:\r\n|\r)/g, '\n') || ' ';
        var charsInput = splitTextToCharacters(text);
        var maxWidth = this._maxWidth * data.size / this._fontSize;
        var pageMeshDataPool = data.distanceFieldType === 'none'
            ? pageMeshDataDefaultPageMeshData : pageMeshDataMSDFPageMeshData;
        var prevCharCode = null;
        var lastLineWidth = 0;
        var maxLineWidth = 0;
        var line = 0;
        var lastBreakPos = -1;
        var lastBreakWidth = 0;
        var spacesRemoved = 0;
        var maxLineHeight = 0;
        var spaceCount = 0;
        for (var i = 0; i < charsInput.length; i++) {
            var char = charsInput[i];
            var charCode = extractCharCode(char);
            if ((/(?:\s)/).test(char)) {
                lastBreakPos = i;
                lastBreakWidth = lastLineWidth;
                spaceCount++;
            }
            if (char === '\r' || char === '\n') {
                lineWidths.push(lastLineWidth);
                lineSpaces.push(-1);
                maxLineWidth = Math.max(maxLineWidth, lastLineWidth);
                ++line;
                ++spacesRemoved;
                pos.x = 0;
                pos.y += data.lineHeight;
                prevCharCode = null;
                spaceCount = 0;
                continue;
            }
            var charData = data.chars[charCode];
            if (!charData) {
                continue;
            }
            if (prevCharCode && charData.kerning[prevCharCode]) {
                pos.x += charData.kerning[prevCharCode];
            }
            var charRenderData = charRenderDataPool.pop() || {
                texture: core.Texture.EMPTY,
                line: 0,
                charCode: 0,
                prevSpaces: 0,
                position: new math.Point(),
            };
            charRenderData.texture = charData.texture;
            charRenderData.line = line;
            charRenderData.charCode = charCode;
            charRenderData.position.x = pos.x + charData.xOffset + (this._letterSpacing / 2);
            charRenderData.position.y = pos.y + charData.yOffset;
            charRenderData.prevSpaces = spaceCount;
            chars.push(charRenderData);
            lastLineWidth = charRenderData.position.x + Math.max(charData.xAdvance, charData.texture.orig.width);
            pos.x += charData.xAdvance + this._letterSpacing;
            maxLineHeight = Math.max(maxLineHeight, (charData.yOffset + charData.texture.height));
            prevCharCode = charCode;
            if (lastBreakPos !== -1 && maxWidth > 0 && pos.x > maxWidth) {
                ++spacesRemoved;
                utils.removeItems(chars, 1 + lastBreakPos - spacesRemoved, 1 + i - lastBreakPos);
                i = lastBreakPos;
                lastBreakPos = -1;
                lineWidths.push(lastBreakWidth);
                lineSpaces.push(chars.length > 0 ? chars[chars.length - 1].prevSpaces : 0);
                maxLineWidth = Math.max(maxLineWidth, lastBreakWidth);
                line++;
                pos.x = 0;
                pos.y += data.lineHeight;
                prevCharCode = null;
                spaceCount = 0;
            }
        }
        var lastChar = charsInput[charsInput.length - 1];
        if (lastChar !== '\r' && lastChar !== '\n') {
            if ((/(?:\s)/).test(lastChar)) {
                lastLineWidth = lastBreakWidth;
            }
            lineWidths.push(lastLineWidth);
            maxLineWidth = Math.max(maxLineWidth, lastLineWidth);
            lineSpaces.push(-1);
        }
        var lineAlignOffsets = [];
        for (var i = 0; i <= line; i++) {
            var alignOffset = 0;
            if (this._align === 'right') {
                alignOffset = maxLineWidth - lineWidths[i];
            }
            else if (this._align === 'center') {
                alignOffset = (maxLineWidth - lineWidths[i]) / 2;
            }
            else if (this._align === 'justify') {
                alignOffset = lineSpaces[i] < 0 ? 0 : (maxLineWidth - lineWidths[i]) / lineSpaces[i];
            }
            lineAlignOffsets.push(alignOffset);
        }
        var lenChars = chars.length;
        var pagesMeshData = {};
        var newPagesMeshData = [];
        var activePagesMeshData = this._activePagesMeshData;
        for (var i = 0; i < activePagesMeshData.length; i++) {
            pageMeshDataPool.push(activePagesMeshData[i]);
        }
        for (var i = 0; i < lenChars; i++) {
            var texture = chars[i].texture;
            var baseTextureUid = texture.baseTexture.uid;
            if (!pagesMeshData[baseTextureUid]) {
                var pageMeshData = pageMeshDataPool.pop();
                if (!pageMeshData) {
                    var geometry = new mesh.MeshGeometry();
                    var material = void 0;
                    var meshBlendMode = void 0;
                    if (data.distanceFieldType === 'none') {
                        material = new mesh.MeshMaterial(core.Texture.EMPTY);
                        meshBlendMode = constants.BLEND_MODES.NORMAL;
                    }
                    else {
                        material = new mesh.MeshMaterial(core.Texture.EMPTY, { program: core.Program.from(msdfVert, msdfFrag), uniforms: { uFWidth: 0 } });
                        meshBlendMode = constants.BLEND_MODES.NORMAL_NPM;
                    }
                    var mesh$1 = new mesh.Mesh(geometry, material);
                    mesh$1.blendMode = meshBlendMode;
                    pageMeshData = {
                        index: 0,
                        indexCount: 0,
                        vertexCount: 0,
                        uvsCount: 0,
                        total: 0,
                        mesh: mesh$1,
                        vertices: null,
                        uvs: null,
                        indices: null,
                    };
                }
                // reset data..
                pageMeshData.index = 0;
                pageMeshData.indexCount = 0;
                pageMeshData.vertexCount = 0;
                pageMeshData.uvsCount = 0;
                pageMeshData.total = 0;
                // TODO need to get page texture here somehow..
                var _textureCache = this._textureCache;
                _textureCache[baseTextureUid] = _textureCache[baseTextureUid] || new core.Texture(texture.baseTexture);
                pageMeshData.mesh.texture = _textureCache[baseTextureUid];
                pageMeshData.mesh.tint = this._tint;
                newPagesMeshData.push(pageMeshData);
                pagesMeshData[baseTextureUid] = pageMeshData;
            }
            pagesMeshData[baseTextureUid].total++;
        }
        // lets find any previously active pageMeshDatas that are no longer required for
        // the updated text (if any), removed and return them to the pool.
        for (var i = 0; i < activePagesMeshData.length; i++) {
            if (newPagesMeshData.indexOf(activePagesMeshData[i]) === -1) {
                this.removeChild(activePagesMeshData[i].mesh);
            }
        }
        // next lets add any new meshes, that have not yet been added to this BitmapText
        // we only add if its not already a child of this BitmapObject
        for (var i = 0; i < newPagesMeshData.length; i++) {
            if (newPagesMeshData[i].mesh.parent !== this) {
                this.addChild(newPagesMeshData[i].mesh);
            }
        }
        // active page mesh datas are set to be the new pages added.
        this._activePagesMeshData = newPagesMeshData;
        for (var i in pagesMeshData) {
            var pageMeshData = pagesMeshData[i];
            var total = pageMeshData.total;
            // lets only allocate new buffers if we can fit the new text in the current ones..
            // unless that is, we will be batching. Currently batching dose not respect the size property of mesh
            if (!(((_a = pageMeshData.indices) === null || _a === void 0 ? void 0 : _a.length) > 6 * total) || pageMeshData.vertices.length < mesh.Mesh.BATCHABLE_SIZE * 2) {
                pageMeshData.vertices = new Float32Array(4 * 2 * total);
                pageMeshData.uvs = new Float32Array(4 * 2 * total);
                pageMeshData.indices = new Uint16Array(6 * total);
            }
            else {
                var total_1 = pageMeshData.total;
                var vertices = pageMeshData.vertices;
                // Clear the garbage at the end of the vertices buffer. This will prevent the bounds miscalculation.
                for (var i_1 = total_1 * 4 * 2; i_1 < vertices.length; i_1++) {
                    vertices[i_1] = 0;
                }
            }
            // as a buffer maybe bigger than the current word, we set the size of the meshMaterial
            // to match the number of letters needed
            pageMeshData.mesh.size = 6 * total;
        }
        for (var i = 0; i < lenChars; i++) {
            var char = chars[i];
            var offset = char.position.x + (lineAlignOffsets[char.line] * (this._align === 'justify' ? char.prevSpaces : 1));
            if (this._roundPixels) {
                offset = Math.round(offset);
            }
            var xPos = offset * scale;
            var yPos = char.position.y * scale;
            var texture = char.texture;
            var pageMesh = pagesMeshData[texture.baseTexture.uid];
            var textureFrame = texture.frame;
            var textureUvs = texture._uvs;
            var index = pageMesh.index++;
            pageMesh.indices[(index * 6) + 0] = 0 + (index * 4);
            pageMesh.indices[(index * 6) + 1] = 1 + (index * 4);
            pageMesh.indices[(index * 6) + 2] = 2 + (index * 4);
            pageMesh.indices[(index * 6) + 3] = 0 + (index * 4);
            pageMesh.indices[(index * 6) + 4] = 2 + (index * 4);
            pageMesh.indices[(index * 6) + 5] = 3 + (index * 4);
            pageMesh.vertices[(index * 8) + 0] = xPos;
            pageMesh.vertices[(index * 8) + 1] = yPos;
            pageMesh.vertices[(index * 8) + 2] = xPos + (textureFrame.width * scale);
            pageMesh.vertices[(index * 8) + 3] = yPos;
            pageMesh.vertices[(index * 8) + 4] = xPos + (textureFrame.width * scale);
            pageMesh.vertices[(index * 8) + 5] = yPos + (textureFrame.height * scale);
            pageMesh.vertices[(index * 8) + 6] = xPos;
            pageMesh.vertices[(index * 8) + 7] = yPos + (textureFrame.height * scale);
            pageMesh.uvs[(index * 8) + 0] = textureUvs.x0;
            pageMesh.uvs[(index * 8) + 1] = textureUvs.y0;
            pageMesh.uvs[(index * 8) + 2] = textureUvs.x1;
            pageMesh.uvs[(index * 8) + 3] = textureUvs.y1;
            pageMesh.uvs[(index * 8) + 4] = textureUvs.x2;
            pageMesh.uvs[(index * 8) + 5] = textureUvs.y2;
            pageMesh.uvs[(index * 8) + 6] = textureUvs.x3;
            pageMesh.uvs[(index * 8) + 7] = textureUvs.y3;
        }
        this._textWidth = maxLineWidth * scale;
        this._textHeight = (pos.y + data.lineHeight) * scale;
        for (var i in pagesMeshData) {
            var pageMeshData = pagesMeshData[i];
            // apply anchor
            if (this.anchor.x !== 0 || this.anchor.y !== 0) {
                var vertexCount = 0;
                var anchorOffsetX = this._textWidth * this.anchor.x;
                var anchorOffsetY = this._textHeight * this.anchor.y;
                for (var i_2 = 0; i_2 < pageMeshData.total; i_2++) {
                    pageMeshData.vertices[vertexCount++] -= anchorOffsetX;
                    pageMeshData.vertices[vertexCount++] -= anchorOffsetY;
                    pageMeshData.vertices[vertexCount++] -= anchorOffsetX;
                    pageMeshData.vertices[vertexCount++] -= anchorOffsetY;
                    pageMeshData.vertices[vertexCount++] -= anchorOffsetX;
                    pageMeshData.vertices[vertexCount++] -= anchorOffsetY;
                    pageMeshData.vertices[vertexCount++] -= anchorOffsetX;
                    pageMeshData.vertices[vertexCount++] -= anchorOffsetY;
                }
            }
            this._maxLineHeight = maxLineHeight * scale;
            var vertexBuffer = pageMeshData.mesh.geometry.getBuffer('aVertexPosition');
            var textureBuffer = pageMeshData.mesh.geometry.getBuffer('aTextureCoord');
            var indexBuffer = pageMeshData.mesh.geometry.getIndex();
            vertexBuffer.data = pageMeshData.vertices;
            textureBuffer.data = pageMeshData.uvs;
            indexBuffer.data = pageMeshData.indices;
            vertexBuffer.update();
            textureBuffer.update();
            indexBuffer.update();
        }
        for (var i = 0; i < chars.length; i++) {
            charRenderDataPool.push(chars[i]);
        }
    };
    BitmapText.prototype.updateTransform = function () {
        this.validate();
        this.containerUpdateTransform();
    };
    BitmapText.prototype._render = function (renderer) {
        // Update the uniform
        var _a = BitmapFont.available[this._fontName], distanceFieldRange = _a.distanceFieldRange, distanceFieldType = _a.distanceFieldType, size = _a.size;
        if (distanceFieldType !== 'none') {
            // Inject the shader code with the correct value
            var _b = this.worldTransform, a = _b.a, b = _b.b, c = _b.c, d = _b.d;
            var dx = Math.sqrt((a * a) + (b * b));
            var dy = Math.sqrt((c * c) + (d * d));
            var worldScale = (Math.abs(dx) + Math.abs(dy)) / 2;
            var fontScale = this._fontSize / size;
            for (var _i = 0, _c = this._activePagesMeshData; _i < _c.length; _i++) {
                var mesh = _c[_i];
                mesh.mesh.shader.uniforms.uFWidth = worldScale * distanceFieldRange * fontScale * renderer.resolution;
            }
        }
        _super.prototype._render.call(this, renderer);
    };
    /**
     * Validates text before calling parent's getLocalBounds
     *
     * @return - The rectangular bounding area
     */
    BitmapText.prototype.getLocalBounds = function () {
        this.validate();
        return _super.prototype.getLocalBounds.call(this);
    };
    /**
     * Updates text when needed
     *
     * @private
     */
    BitmapText.prototype.validate = function () {
        if (this.dirty) {
            this.updateText();
            this.dirty = false;
        }
    };
    Object.defineProperty(BitmapText.prototype, "tint", {
        /**
         * The tint of the BitmapText object.
         *
         * @default 0xffffff
         */
        get: function () {
            return this._tint;
        },
        set: function (value) {
            if (this._tint === value)
                { return; }
            this._tint = value;
            for (var i = 0; i < this._activePagesMeshData.length; i++) {
                this._activePagesMeshData[i].mesh.tint = value;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BitmapText.prototype, "align", {
        /**
         * The alignment of the BitmapText object.
         *
         * @member {string}
         * @default 'left'
         */
        get: function () {
            return this._align;
        },
        set: function (value) {
            if (this._align !== value) {
                this._align = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BitmapText.prototype, "fontName", {
        /** The name of the BitmapFont. */
        get: function () {
            return this._fontName;
        },
        set: function (value) {
            if (!BitmapFont.available[value]) {
                throw new Error("Missing BitmapFont \"" + value + "\"");
            }
            if (this._fontName !== value) {
                this._fontName = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BitmapText.prototype, "fontSize", {
        /** The size of the font to display. */
        get: function () {
            return this._fontSize;
        },
        set: function (value) {
            if (this._fontSize !== value) {
                this._fontSize = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BitmapText.prototype, "anchor", {
        /**
         * The anchor sets the origin point of the text.
         *
         * The default is `(0,0)`, this means the text's origin is the top left.
         *
         * Setting the anchor to `(0.5,0.5)` means the text's origin is centered.
         *
         * Setting the anchor to `(1,1)` would mean the text's origin point will be the bottom right corner.
         */
        get: function () {
            return this._anchor;
        },
        set: function (value) {
            if (typeof value === 'number') {
                this._anchor.set(value);
            }
            else {
                this._anchor.copyFrom(value);
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BitmapText.prototype, "text", {
        /** The text of the BitmapText object. */
        get: function () {
            return this._text;
        },
        set: function (text) {
            text = String(text === null || text === undefined ? '' : text);
            if (this._text === text) {
                return;
            }
            this._text = text;
            this.dirty = true;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BitmapText.prototype, "maxWidth", {
        /**
         * The max width of this bitmap text in pixels. If the text provided is longer than the
         * value provided, line breaks will be automatically inserted in the last whitespace.
         * Disable by setting the value to 0.
         */
        get: function () {
            return this._maxWidth;
        },
        set: function (value) {
            if (this._maxWidth === value) {
                return;
            }
            this._maxWidth = value;
            this.dirty = true;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BitmapText.prototype, "maxLineHeight", {
        /**
         * The max line height. This is useful when trying to use the total height of the Text,
         * i.e. when trying to vertically align.
         *
         * @readonly
         */
        get: function () {
            this.validate();
            return this._maxLineHeight;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BitmapText.prototype, "textWidth", {
        /**
         * The width of the overall text, different from fontSize,
         * which is defined in the style object.
         *
         * @readonly
         */
        get: function () {
            this.validate();
            return this._textWidth;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BitmapText.prototype, "letterSpacing", {
        /** Additional space between characters. */
        get: function () {
            return this._letterSpacing;
        },
        set: function (value) {
            if (this._letterSpacing !== value) {
                this._letterSpacing = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BitmapText.prototype, "roundPixels", {
        /**
         * If true PixiJS will Math.floor() x/y values when rendering, stopping pixel interpolation.
         * Advantages can include sharper image quality (like text) and faster rendering on canvas.
         * The main disadvantage is movement of objects may appear less smooth.
         * To set the global default, change {@link PIXI.settings.ROUND_PIXELS}
         *
         * @default PIXI.settings.ROUND_PIXELS
         */
        get: function () {
            return this._roundPixels;
        },
        set: function (value) {
            if (value !== this._roundPixels) {
                this._roundPixels = value;
                this.dirty = true;
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BitmapText.prototype, "textHeight", {
        /**
         * The height of the overall text, different from fontSize,
         * which is defined in the style object.
         *
         * @readonly
         */
        get: function () {
            this.validate();
            return this._textHeight;
        },
        enumerable: false,
        configurable: true
    });
    BitmapText.prototype.destroy = function (options) {
        var _textureCache = this._textureCache;
        for (var id in _textureCache) {
            var texture = _textureCache[id];
            texture.destroy();
            delete _textureCache[id];
        }
        this._textureCache = null;
        _super.prototype.destroy.call(this, options);
    };
    BitmapText.styleDefaults = {
        align: 'left',
        tint: 0xFFFFFF,
        maxWidth: 0,
        letterSpacing: 0,
    };
    return BitmapText;
}(display.Container));

/**
 * {@link PIXI.Loader Loader} middleware for loading
 * bitmap-based fonts suitable for using with {@link PIXI.BitmapText}.
 *
 * @memberof PIXI
 */
var BitmapFontLoader = /** @class */ (function () {
    function BitmapFontLoader() {
    }
    /**
     * Called when the plugin is installed.
     *
     * @see PIXI.Loader.registerPlugin
     */
    BitmapFontLoader.add = function () {
        loaders.LoaderResource.setExtensionXhrType('fnt', loaders.LoaderResource.XHR_RESPONSE_TYPE.TEXT);
    };
    /**
     * Called after a resource is loaded.
     *
     * @see PIXI.Loader.loaderMiddleware
     * @param {PIXI.LoaderResource} resource
     * @param {function} next
     */
    BitmapFontLoader.use = function (resource, next) {
        var format = autoDetectFormat(resource.data);
        // Resource was not recognised as any of the expected font data format
        if (!format) {
            next();
            return;
        }
        var baseUrl = BitmapFontLoader.getBaseUrl(this, resource);
        var data = format.parse(resource.data);
        var textures = {};
        // Handle completed, when the number of textures
        // load is the same number as references in the fnt file
        var completed = function (page) {
            textures[page.metadata.pageFile] = page.texture;
            if (Object.keys(textures).length === data.page.length) {
                resource.bitmapFont = BitmapFont.install(data, textures, true);
                next();
            }
        };
        for (var i = 0; i < data.page.length; ++i) {
            var pageFile = data.page[i].file;
            var url = baseUrl + pageFile;
            var exists = false;
            // incase the image is loaded outside
            // using the same loader, resource will be available
            for (var name in this.resources) {
                var bitmapResource = this.resources[name];
                if (bitmapResource.url === url) {
                    bitmapResource.metadata.pageFile = pageFile;
                    if (bitmapResource.texture) {
                        completed(bitmapResource);
                    }
                    else {
                        bitmapResource.onAfterMiddleware.add(completed);
                    }
                    exists = true;
                    break;
                }
            }
            // texture is not loaded, we'll attempt to add
            // it to the load and add the texture to the list
            if (!exists) {
                // Standard loading options for images
                var options = {
                    crossOrigin: resource.crossOrigin,
                    loadType: loaders.LoaderResource.LOAD_TYPE.IMAGE,
                    metadata: Object.assign({ pageFile: pageFile }, resource.metadata.imageMetadata),
                    parentResource: resource,
                };
                this.add(url, options, completed);
            }
        }
    };
    /** Get folder path from a resource. */
    BitmapFontLoader.getBaseUrl = function (loader, resource) {
        var resUrl = !resource.isDataUrl ? BitmapFontLoader.dirname(resource.url) : '';
        if (resource.isDataUrl) {
            if (resUrl === '.') {
                resUrl = '';
            }
            if (loader.baseUrl && resUrl) {
                // if baseurl has a trailing slash then add one to resUrl so the replace works below
                if (loader.baseUrl.charAt(loader.baseUrl.length - 1) === '/') {
                    resUrl += '/';
                }
            }
        }
        // remove baseUrl from resUrl
        resUrl = resUrl.replace(loader.baseUrl, '');
        // if there is an resUrl now, it needs a trailing slash. Ensure that it does if the string isn't empty.
        if (resUrl && resUrl.charAt(resUrl.length - 1) !== '/') {
            resUrl += '/';
        }
        return resUrl;
    };
    /**
     * Replacement for NodeJS's path.dirname
     *
     * @param {string} url - Path to get directory for
     */
    BitmapFontLoader.dirname = function (url) {
        var dir = url
            .replace(/\\/g, '/') // convert windows notation to UNIX notation, URL-safe because it's a forbidden character
            .replace(/\/$/, '') // replace trailing slash
            .replace(/\/[^\/]*$/, ''); // remove everything after the last
        // File request is relative, use current directory
        if (dir === url) {
            return '.';
        }
        // Started with a slash
        else if (dir === '') {
            return '/';
        }
        return dir;
    };
    return BitmapFontLoader;
}());

exports.BitmapFont = BitmapFont;
exports.BitmapFontData = BitmapFontData;
exports.BitmapFontLoader = BitmapFontLoader;
exports.BitmapText = BitmapText;
//# sourceMappingURL=text-bitmap.js.map
