text-bitmap.mjs 68 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637
  1. /*!
  2. * @pixi/text-bitmap - v6.5.10
  3. * Compiled Thu, 06 Jul 2023 15:25:11 UTC
  4. *
  5. * @pixi/text-bitmap is licensed under the MIT License.
  6. * http://www.opensource.org/licenses/mit-license
  7. */
  8. import { Rectangle, Point, ObservablePoint } from '@pixi/math';
  9. import { settings } from '@pixi/settings';
  10. import { MeshGeometry, MeshMaterial, Mesh } from '@pixi/mesh';
  11. import { hex2rgb, string2hex, getResolutionOfUrl, removeItems } from '@pixi/utils';
  12. import { BaseTexture, Texture, Program, ExtensionType } from '@pixi/core';
  13. import { TEXT_GRADIENT, TextStyle, TextMetrics } from '@pixi/text';
  14. import { ALPHA_MODES, MIPMAP_MODES, BLEND_MODES } from '@pixi/constants';
  15. import { Container } from '@pixi/display';
  16. import { LoaderResource } from '@pixi/loaders';
  17. /*! *****************************************************************************
  18. Copyright (c) Microsoft Corporation.
  19. Permission to use, copy, modify, and/or distribute this software for any
  20. purpose with or without fee is hereby granted.
  21. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  22. REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  23. AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  24. INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  25. LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  26. OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  27. PERFORMANCE OF THIS SOFTWARE.
  28. ***************************************************************************** */
  29. /* global Reflect, Promise */
  30. var extendStatics = function(d, b) {
  31. extendStatics = Object.setPrototypeOf ||
  32. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  33. function (d, b) { for (var p in b) { if (b.hasOwnProperty(p)) { d[p] = b[p]; } } };
  34. return extendStatics(d, b);
  35. };
  36. function __extends(d, b) {
  37. extendStatics(d, b);
  38. function __() { this.constructor = d; }
  39. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  40. }
  41. /* eslint-disable max-len */
  42. /**
  43. * Normalized parsed data from .fnt files.
  44. * @memberof PIXI
  45. */
  46. var BitmapFontData = /** @class */ (function () {
  47. function BitmapFontData() {
  48. this.info = [];
  49. this.common = [];
  50. this.page = [];
  51. this.char = [];
  52. this.kerning = [];
  53. this.distanceField = [];
  54. }
  55. return BitmapFontData;
  56. }());
  57. /**
  58. * BitmapFont format that's Text-based.
  59. * @private
  60. */
  61. var TextFormat = /** @class */ (function () {
  62. function TextFormat() {
  63. }
  64. /**
  65. * Check if resource refers to txt font data.
  66. * @param data
  67. * @returns - True if resource could be treated as font data, false otherwise.
  68. */
  69. TextFormat.test = function (data) {
  70. return typeof data === 'string' && data.indexOf('info face=') === 0;
  71. };
  72. /**
  73. * Convert text font data to a javascript object.
  74. * @param txt - Raw string data to be converted
  75. * @returns - Parsed font data
  76. */
  77. TextFormat.parse = function (txt) {
  78. // Retrieve data item
  79. var items = txt.match(/^[a-z]+\s+.+$/gm);
  80. var rawData = {
  81. info: [],
  82. common: [],
  83. page: [],
  84. char: [],
  85. chars: [],
  86. kerning: [],
  87. kernings: [],
  88. distanceField: [],
  89. };
  90. for (var i in items) {
  91. // Extract item name
  92. var name = items[i].match(/^[a-z]+/gm)[0];
  93. // Extract item attribute list as string ex.: "width=10"
  94. var attributeList = items[i].match(/[a-zA-Z]+=([^\s"']+|"([^"]*)")/gm);
  95. // Convert attribute list into an object
  96. var itemData = {};
  97. for (var i_1 in attributeList) {
  98. // Split key-value pairs
  99. var split = attributeList[i_1].split('=');
  100. var key = split[0];
  101. // Remove eventual quotes from value
  102. var strValue = split[1].replace(/"/gm, '');
  103. // Try to convert value into float
  104. var floatValue = parseFloat(strValue);
  105. // Use string value case float value is NaN
  106. var value = isNaN(floatValue) ? strValue : floatValue;
  107. itemData[key] = value;
  108. }
  109. // Push current item to the resulting data
  110. rawData[name].push(itemData);
  111. }
  112. var font = new BitmapFontData();
  113. rawData.info.forEach(function (info) { return font.info.push({
  114. face: info.face,
  115. size: parseInt(info.size, 10),
  116. }); });
  117. rawData.common.forEach(function (common) { return font.common.push({
  118. lineHeight: parseInt(common.lineHeight, 10),
  119. }); });
  120. rawData.page.forEach(function (page) { return font.page.push({
  121. id: parseInt(page.id, 10),
  122. file: page.file,
  123. }); });
  124. rawData.char.forEach(function (char) { return font.char.push({
  125. id: parseInt(char.id, 10),
  126. page: parseInt(char.page, 10),
  127. x: parseInt(char.x, 10),
  128. y: parseInt(char.y, 10),
  129. width: parseInt(char.width, 10),
  130. height: parseInt(char.height, 10),
  131. xoffset: parseInt(char.xoffset, 10),
  132. yoffset: parseInt(char.yoffset, 10),
  133. xadvance: parseInt(char.xadvance, 10),
  134. }); });
  135. rawData.kerning.forEach(function (kerning) { return font.kerning.push({
  136. first: parseInt(kerning.first, 10),
  137. second: parseInt(kerning.second, 10),
  138. amount: parseInt(kerning.amount, 10),
  139. }); });
  140. rawData.distanceField.forEach(function (df) { return font.distanceField.push({
  141. distanceRange: parseInt(df.distanceRange, 10),
  142. fieldType: df.fieldType,
  143. }); });
  144. return font;
  145. };
  146. return TextFormat;
  147. }());
  148. /**
  149. * BitmapFont format that's XML-based.
  150. * @private
  151. */
  152. var XMLFormat = /** @class */ (function () {
  153. function XMLFormat() {
  154. }
  155. /**
  156. * Check if resource refers to xml font data.
  157. * @param data
  158. * @returns - True if resource could be treated as font data, false otherwise.
  159. */
  160. XMLFormat.test = function (data) {
  161. return data instanceof XMLDocument
  162. && data.getElementsByTagName('page').length
  163. && data.getElementsByTagName('info')[0].getAttribute('face') !== null;
  164. };
  165. /**
  166. * Convert the XML into BitmapFontData that we can use.
  167. * @param xml
  168. * @returns - Data to use for BitmapFont
  169. */
  170. XMLFormat.parse = function (xml) {
  171. var data = new BitmapFontData();
  172. var info = xml.getElementsByTagName('info');
  173. var common = xml.getElementsByTagName('common');
  174. var page = xml.getElementsByTagName('page');
  175. var char = xml.getElementsByTagName('char');
  176. var kerning = xml.getElementsByTagName('kerning');
  177. var distanceField = xml.getElementsByTagName('distanceField');
  178. for (var i = 0; i < info.length; i++) {
  179. data.info.push({
  180. face: info[i].getAttribute('face'),
  181. size: parseInt(info[i].getAttribute('size'), 10),
  182. });
  183. }
  184. for (var i = 0; i < common.length; i++) {
  185. data.common.push({
  186. lineHeight: parseInt(common[i].getAttribute('lineHeight'), 10),
  187. });
  188. }
  189. for (var i = 0; i < page.length; i++) {
  190. data.page.push({
  191. id: parseInt(page[i].getAttribute('id'), 10) || 0,
  192. file: page[i].getAttribute('file'),
  193. });
  194. }
  195. for (var i = 0; i < char.length; i++) {
  196. var letter = char[i];
  197. data.char.push({
  198. id: parseInt(letter.getAttribute('id'), 10),
  199. page: parseInt(letter.getAttribute('page'), 10) || 0,
  200. x: parseInt(letter.getAttribute('x'), 10),
  201. y: parseInt(letter.getAttribute('y'), 10),
  202. width: parseInt(letter.getAttribute('width'), 10),
  203. height: parseInt(letter.getAttribute('height'), 10),
  204. xoffset: parseInt(letter.getAttribute('xoffset'), 10),
  205. yoffset: parseInt(letter.getAttribute('yoffset'), 10),
  206. xadvance: parseInt(letter.getAttribute('xadvance'), 10),
  207. });
  208. }
  209. for (var i = 0; i < kerning.length; i++) {
  210. data.kerning.push({
  211. first: parseInt(kerning[i].getAttribute('first'), 10),
  212. second: parseInt(kerning[i].getAttribute('second'), 10),
  213. amount: parseInt(kerning[i].getAttribute('amount'), 10),
  214. });
  215. }
  216. for (var i = 0; i < distanceField.length; i++) {
  217. data.distanceField.push({
  218. fieldType: distanceField[i].getAttribute('fieldType'),
  219. distanceRange: parseInt(distanceField[i].getAttribute('distanceRange'), 10),
  220. });
  221. }
  222. return data;
  223. };
  224. return XMLFormat;
  225. }());
  226. /**
  227. * BitmapFont format that's XML-based.
  228. * @private
  229. */
  230. var XMLStringFormat = /** @class */ (function () {
  231. function XMLStringFormat() {
  232. }
  233. /**
  234. * Check if resource refers to text xml font data.
  235. * @param data
  236. * @returns - True if resource could be treated as font data, false otherwise.
  237. */
  238. XMLStringFormat.test = function (data) {
  239. if (typeof data === 'string' && data.indexOf('<font>') > -1) {
  240. var xml = new globalThis.DOMParser().parseFromString(data, 'text/xml');
  241. return XMLFormat.test(xml);
  242. }
  243. return false;
  244. };
  245. /**
  246. * Convert the text XML into BitmapFontData that we can use.
  247. * @param xmlTxt
  248. * @returns - Data to use for BitmapFont
  249. */
  250. XMLStringFormat.parse = function (xmlTxt) {
  251. var xml = new globalThis.DOMParser().parseFromString(xmlTxt, 'text/xml');
  252. return XMLFormat.parse(xml);
  253. };
  254. return XMLStringFormat;
  255. }());
  256. // Registered formats, maybe make this extensible in the future?
  257. var formats = [
  258. TextFormat,
  259. XMLFormat,
  260. XMLStringFormat ];
  261. /**
  262. * Auto-detect BitmapFont parsing format based on data.
  263. * @private
  264. * @param {any} data - Data to detect format
  265. * @returns {any} Format or null
  266. */
  267. function autoDetectFormat(data) {
  268. for (var i = 0; i < formats.length; i++) {
  269. if (formats[i].test(data)) {
  270. return formats[i];
  271. }
  272. }
  273. return null;
  274. }
  275. // TODO: Prevent code duplication b/w generateFillStyle & Text#generateFillStyle
  276. /**
  277. * Generates the fill style. Can automatically generate a gradient based on the fill style being an array
  278. * @private
  279. * @param canvas
  280. * @param context
  281. * @param {object} style - The style.
  282. * @param resolution
  283. * @param {string[]} lines - The lines of text.
  284. * @param metrics
  285. * @returns {string|number|CanvasGradient} The fill style
  286. */
  287. function generateFillStyle(canvas, context, style, resolution, lines, metrics) {
  288. // TODO: Can't have different types for getter and setter. The getter shouldn't have the number type as
  289. // the setter converts to string. See this thread for more details:
  290. // https://github.com/microsoft/TypeScript/issues/2521
  291. var fillStyle = style.fill;
  292. if (!Array.isArray(fillStyle)) {
  293. return fillStyle;
  294. }
  295. else if (fillStyle.length === 1) {
  296. return fillStyle[0];
  297. }
  298. // the gradient will be evenly spaced out according to how large the array is.
  299. // ['#FF0000', '#00FF00', '#0000FF'] would created stops at 0.25, 0.5 and 0.75
  300. var gradient;
  301. // a dropshadow will enlarge the canvas and result in the gradient being
  302. // generated with the incorrect dimensions
  303. var dropShadowCorrection = (style.dropShadow) ? style.dropShadowDistance : 0;
  304. // should also take padding into account, padding can offset the gradient
  305. var padding = style.padding || 0;
  306. var width = (canvas.width / resolution) - dropShadowCorrection - (padding * 2);
  307. var height = (canvas.height / resolution) - dropShadowCorrection - (padding * 2);
  308. // make a copy of the style settings, so we can manipulate them later
  309. var fill = fillStyle.slice();
  310. var fillGradientStops = style.fillGradientStops.slice();
  311. // wanting to evenly distribute the fills. So an array of 4 colours should give fills of 0.25, 0.5 and 0.75
  312. if (!fillGradientStops.length) {
  313. var lengthPlus1 = fill.length + 1;
  314. for (var i = 1; i < lengthPlus1; ++i) {
  315. fillGradientStops.push(i / lengthPlus1);
  316. }
  317. }
  318. // stop the bleeding of the last gradient on the line above to the top gradient of the this line
  319. // by hard defining the first gradient colour at point 0, and last gradient colour at point 1
  320. fill.unshift(fillStyle[0]);
  321. fillGradientStops.unshift(0);
  322. fill.push(fillStyle[fillStyle.length - 1]);
  323. fillGradientStops.push(1);
  324. if (style.fillGradientType === TEXT_GRADIENT.LINEAR_VERTICAL) {
  325. // start the gradient at the top center of the canvas, and end at the bottom middle of the canvas
  326. gradient = context.createLinearGradient(width / 2, padding, width / 2, height + padding);
  327. // we need to repeat the gradient so that each individual line of text has the same vertical gradient effect
  328. // ['#FF0000', '#00FF00', '#0000FF'] over 2 lines would create stops at 0.125, 0.25, 0.375, 0.625, 0.75, 0.875
  329. // There's potential for floating point precision issues at the seams between gradient repeats.
  330. // The loop below generates the stops in order, so track the last generated one to prevent
  331. // floating point precision from making us go the teeniest bit backwards, resulting in
  332. // the first and last colors getting swapped.
  333. var lastIterationStop = 0;
  334. // Actual height of the text itself, not counting spacing for lineHeight/leading/dropShadow etc
  335. var textHeight = metrics.fontProperties.fontSize + style.strokeThickness;
  336. // textHeight, but as a 0-1 size in global gradient stop space
  337. var gradStopLineHeight = textHeight / height;
  338. for (var i = 0; i < lines.length; i++) {
  339. var thisLineTop = metrics.lineHeight * i;
  340. for (var j = 0; j < fill.length; j++) {
  341. // 0-1 stop point for the current line, multiplied to global space afterwards
  342. var lineStop = 0;
  343. if (typeof fillGradientStops[j] === 'number') {
  344. lineStop = fillGradientStops[j];
  345. }
  346. else {
  347. lineStop = j / fill.length;
  348. }
  349. var globalStop = (thisLineTop / height) + (lineStop * gradStopLineHeight);
  350. // Prevent color stop generation going backwards from floating point imprecision
  351. var clampedStop = Math.max(lastIterationStop, globalStop);
  352. clampedStop = Math.min(clampedStop, 1); // Cap at 1 as well for safety's sake to avoid a possible throw.
  353. gradient.addColorStop(clampedStop, fill[j]);
  354. lastIterationStop = clampedStop;
  355. }
  356. }
  357. }
  358. else {
  359. // start the gradient at the center left of the canvas, and end at the center right of the canvas
  360. gradient = context.createLinearGradient(padding, height / 2, width + padding, height / 2);
  361. // can just evenly space out the gradients in this case, as multiple lines makes no difference
  362. // to an even left to right gradient
  363. var totalIterations = fill.length + 1;
  364. var currentIteration = 1;
  365. for (var i = 0; i < fill.length; i++) {
  366. var stop = void 0;
  367. if (typeof fillGradientStops[i] === 'number') {
  368. stop = fillGradientStops[i];
  369. }
  370. else {
  371. stop = currentIteration / totalIterations;
  372. }
  373. gradient.addColorStop(stop, fill[i]);
  374. currentIteration++;
  375. }
  376. }
  377. return gradient;
  378. }
  379. // TODO: Prevent code duplication b/w drawGlyph & Text#updateText
  380. /**
  381. * Draws the glyph `metrics.text` on the given canvas.
  382. *
  383. * Ignored because not directly exposed.
  384. * @ignore
  385. * @param {HTMLCanvasElement} canvas
  386. * @param {CanvasRenderingContext2D} context
  387. * @param {TextMetrics} metrics
  388. * @param {number} x
  389. * @param {number} y
  390. * @param {number} resolution
  391. * @param {TextStyle} style
  392. */
  393. function drawGlyph(canvas, context, metrics, x, y, resolution, style) {
  394. var char = metrics.text;
  395. var fontProperties = metrics.fontProperties;
  396. context.translate(x, y);
  397. context.scale(resolution, resolution);
  398. var tx = style.strokeThickness / 2;
  399. var ty = -(style.strokeThickness / 2);
  400. context.font = style.toFontString();
  401. context.lineWidth = style.strokeThickness;
  402. context.textBaseline = style.textBaseline;
  403. context.lineJoin = style.lineJoin;
  404. context.miterLimit = style.miterLimit;
  405. // set canvas text styles
  406. context.fillStyle = generateFillStyle(canvas, context, style, resolution, [char], metrics);
  407. context.strokeStyle = style.stroke;
  408. if (style.dropShadow) {
  409. var dropShadowColor = style.dropShadowColor;
  410. var rgb = hex2rgb(typeof dropShadowColor === 'number' ? dropShadowColor : string2hex(dropShadowColor));
  411. var dropShadowBlur = style.dropShadowBlur * resolution;
  412. var dropShadowDistance = style.dropShadowDistance * resolution;
  413. context.shadowColor = "rgba(" + rgb[0] * 255 + "," + rgb[1] * 255 + "," + rgb[2] * 255 + "," + style.dropShadowAlpha + ")";
  414. context.shadowBlur = dropShadowBlur;
  415. context.shadowOffsetX = Math.cos(style.dropShadowAngle) * dropShadowDistance;
  416. context.shadowOffsetY = Math.sin(style.dropShadowAngle) * dropShadowDistance;
  417. }
  418. else {
  419. context.shadowColor = 'black';
  420. context.shadowBlur = 0;
  421. context.shadowOffsetX = 0;
  422. context.shadowOffsetY = 0;
  423. }
  424. if (style.stroke && style.strokeThickness) {
  425. context.strokeText(char, tx, ty + metrics.lineHeight - fontProperties.descent);
  426. }
  427. if (style.fill) {
  428. context.fillText(char, tx, ty + metrics.lineHeight - fontProperties.descent);
  429. }
  430. context.setTransform(1, 0, 0, 1, 0, 0); // defaults needed for older browsers (e.g. Opera 29)
  431. context.fillStyle = 'rgba(0, 0, 0, 0)';
  432. }
  433. /**
  434. * Ponyfill for IE because it doesn't support `Array.from`
  435. * @param text
  436. * @private
  437. */
  438. function splitTextToCharacters(text) {
  439. return Array.from ? Array.from(text) : text.split('');
  440. }
  441. /**
  442. * Processes the passed character set data and returns a flattened array of all the characters.
  443. *
  444. * Ignored because not directly exposed.
  445. * @ignore
  446. * @param {string | string[] | string[][] } chars
  447. * @returns {string[]} the flattened array of characters
  448. */
  449. function resolveCharacters(chars) {
  450. // Split the chars string into individual characters
  451. if (typeof chars === 'string') {
  452. chars = [chars];
  453. }
  454. // Handle an array of characters+ranges
  455. var result = [];
  456. for (var i = 0, j = chars.length; i < j; i++) {
  457. var item = chars[i];
  458. // Handle range delimited by start/end chars
  459. if (Array.isArray(item)) {
  460. if (item.length !== 2) {
  461. throw new Error("[BitmapFont]: Invalid character range length, expecting 2 got " + item.length + ".");
  462. }
  463. var startCode = item[0].charCodeAt(0);
  464. var endCode = item[1].charCodeAt(0);
  465. if (endCode < startCode) {
  466. throw new Error('[BitmapFont]: Invalid character range.');
  467. }
  468. for (var i_1 = startCode, j_1 = endCode; i_1 <= j_1; i_1++) {
  469. result.push(String.fromCharCode(i_1));
  470. }
  471. }
  472. // Handle a character set string
  473. else {
  474. result.push.apply(result, splitTextToCharacters(item));
  475. }
  476. }
  477. if (result.length === 0) {
  478. throw new Error('[BitmapFont]: Empty set when resolving characters.');
  479. }
  480. return result;
  481. }
  482. /**
  483. * Ponyfill for IE because it doesn't support `codePointAt`
  484. * @param str
  485. * @private
  486. */
  487. function extractCharCode(str) {
  488. return str.codePointAt ? str.codePointAt(0) : str.charCodeAt(0);
  489. }
  490. /**
  491. * BitmapFont represents a typeface available for use with the BitmapText class. Use the `install`
  492. * method for adding a font to be used.
  493. * @memberof PIXI
  494. */
  495. var BitmapFont = /** @class */ (function () {
  496. /**
  497. * @param data
  498. * @param textures
  499. * @param ownsTextures - Setting to `true` will destroy page textures
  500. * when the font is uninstalled.
  501. */
  502. function BitmapFont(data, textures, ownsTextures) {
  503. var _a, _b;
  504. var info = data.info[0];
  505. var common = data.common[0];
  506. var page = data.page[0];
  507. var distanceField = data.distanceField[0];
  508. var res = getResolutionOfUrl(page.file);
  509. var pageTextures = {};
  510. this._ownsTextures = ownsTextures;
  511. this.font = info.face;
  512. this.size = info.size;
  513. this.lineHeight = common.lineHeight / res;
  514. this.chars = {};
  515. this.pageTextures = pageTextures;
  516. // Convert the input Texture, Textures or object
  517. // into a page Texture lookup by "id"
  518. for (var i = 0; i < data.page.length; i++) {
  519. var _c = data.page[i], id = _c.id, file = _c.file;
  520. pageTextures[id] = textures instanceof Array
  521. ? textures[i] : textures[file];
  522. // only MSDF and SDF fonts need no-premultiplied-alpha
  523. if ((distanceField === null || distanceField === void 0 ? void 0 : distanceField.fieldType) && distanceField.fieldType !== 'none') {
  524. pageTextures[id].baseTexture.alphaMode = ALPHA_MODES.NO_PREMULTIPLIED_ALPHA;
  525. pageTextures[id].baseTexture.mipmap = MIPMAP_MODES.OFF;
  526. }
  527. }
  528. // parse letters
  529. for (var i = 0; i < data.char.length; i++) {
  530. var _d = data.char[i], id = _d.id, page_1 = _d.page;
  531. 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;
  532. x /= res;
  533. y /= res;
  534. width /= res;
  535. height /= res;
  536. xoffset /= res;
  537. yoffset /= res;
  538. xadvance /= res;
  539. var rect = new Rectangle(x + (pageTextures[page_1].frame.x / res), y + (pageTextures[page_1].frame.y / res), width, height);
  540. this.chars[id] = {
  541. xOffset: xoffset,
  542. yOffset: yoffset,
  543. xAdvance: xadvance,
  544. kerning: {},
  545. texture: new Texture(pageTextures[page_1].baseTexture, rect),
  546. page: page_1,
  547. };
  548. }
  549. // parse kernings
  550. for (var i = 0; i < data.kerning.length; i++) {
  551. var _f = data.kerning[i], first = _f.first, second = _f.second, amount = _f.amount;
  552. first /= res;
  553. second /= res;
  554. amount /= res;
  555. if (this.chars[second]) {
  556. this.chars[second].kerning[first] = amount;
  557. }
  558. }
  559. // Store distance field information
  560. this.distanceFieldRange = distanceField === null || distanceField === void 0 ? void 0 : distanceField.distanceRange;
  561. 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';
  562. }
  563. /** Remove references to created glyph textures. */
  564. BitmapFont.prototype.destroy = function () {
  565. for (var id in this.chars) {
  566. this.chars[id].texture.destroy();
  567. this.chars[id].texture = null;
  568. }
  569. for (var id in this.pageTextures) {
  570. if (this._ownsTextures) {
  571. this.pageTextures[id].destroy(true);
  572. }
  573. this.pageTextures[id] = null;
  574. }
  575. // Set readonly null.
  576. this.chars = null;
  577. this.pageTextures = null;
  578. };
  579. /**
  580. * Register a new bitmap font.
  581. * @param data - The
  582. * characters map that could be provided as xml or raw string.
  583. * @param textures - List of textures for each page.
  584. * @param ownsTextures - Set to `true` to destroy page textures
  585. * when the font is uninstalled. By default fonts created with
  586. * `BitmapFont.from` or from the `BitmapFontLoader` are `true`.
  587. * @returns {PIXI.BitmapFont} Result font object with font, size, lineHeight
  588. * and char fields.
  589. */
  590. BitmapFont.install = function (data, textures, ownsTextures) {
  591. var fontData;
  592. if (data instanceof BitmapFontData) {
  593. fontData = data;
  594. }
  595. else {
  596. var format = autoDetectFormat(data);
  597. if (!format) {
  598. throw new Error('Unrecognized data format for font.');
  599. }
  600. fontData = format.parse(data);
  601. }
  602. // Single texture, convert to list
  603. if (textures instanceof Texture) {
  604. textures = [textures];
  605. }
  606. var font = new BitmapFont(fontData, textures, ownsTextures);
  607. BitmapFont.available[font.font] = font;
  608. return font;
  609. };
  610. /**
  611. * Remove bitmap font by name.
  612. * @param name - Name of the font to uninstall.
  613. */
  614. BitmapFont.uninstall = function (name) {
  615. var font = BitmapFont.available[name];
  616. if (!font) {
  617. throw new Error("No font found named '" + name + "'");
  618. }
  619. font.destroy();
  620. delete BitmapFont.available[name];
  621. };
  622. /**
  623. * Generates a bitmap-font for the given style and character set. This does not support
  624. * kernings yet. With `style` properties, only the following non-layout properties are used:
  625. *
  626. * - {@link PIXI.TextStyle#dropShadow|dropShadow}
  627. * - {@link PIXI.TextStyle#dropShadowDistance|dropShadowDistance}
  628. * - {@link PIXI.TextStyle#dropShadowColor|dropShadowColor}
  629. * - {@link PIXI.TextStyle#dropShadowBlur|dropShadowBlur}
  630. * - {@link PIXI.TextStyle#dropShadowAngle|dropShadowAngle}
  631. * - {@link PIXI.TextStyle#fill|fill}
  632. * - {@link PIXI.TextStyle#fillGradientStops|fillGradientStops}
  633. * - {@link PIXI.TextStyle#fillGradientType|fillGradientType}
  634. * - {@link PIXI.TextStyle#fontFamily|fontFamily}
  635. * - {@link PIXI.TextStyle#fontSize|fontSize}
  636. * - {@link PIXI.TextStyle#fontVariant|fontVariant}
  637. * - {@link PIXI.TextStyle#fontWeight|fontWeight}
  638. * - {@link PIXI.TextStyle#lineJoin|lineJoin}
  639. * - {@link PIXI.TextStyle#miterLimit|miterLimit}
  640. * - {@link PIXI.TextStyle#stroke|stroke}
  641. * - {@link PIXI.TextStyle#strokeThickness|strokeThickness}
  642. * - {@link PIXI.TextStyle#textBaseline|textBaseline}
  643. * @param name - The name of the custom font to use with BitmapText.
  644. * @param textStyle - Style options to render with BitmapFont.
  645. * @param options - Setup options for font or name of the font.
  646. * @param {string|string[]|string[][]} [options.chars=PIXI.BitmapFont.ALPHANUMERIC] - characters included
  647. * in the font set. You can also use ranges. For example, `[['a', 'z'], ['A', 'Z'], "!@#$%^&*()~{}[] "]`.
  648. * Don't forget to include spaces ' ' in your character set!
  649. * @param {number} [options.resolution=1] - Render resolution for glyphs.
  650. * @param {number} [options.textureWidth=512] - Optional width of atlas, smaller values to reduce memory.
  651. * @param {number} [options.textureHeight=512] - Optional height of atlas, smaller values to reduce memory.
  652. * @param {number} [options.padding=4] - Padding between glyphs on texture atlas.
  653. * @returns Font generated by style options.
  654. * @example
  655. * PIXI.BitmapFont.from("TitleFont", {
  656. * fontFamily: "Arial",
  657. * fontSize: 12,
  658. * strokeThickness: 2,
  659. * fill: "purple"
  660. * });
  661. *
  662. * const title = new PIXI.BitmapText("This is the title", { fontName: "TitleFont" });
  663. */
  664. BitmapFont.from = function (name, textStyle, options) {
  665. if (!name) {
  666. throw new Error('[BitmapFont] Property `name` is required.');
  667. }
  668. var _a = Object.assign({}, BitmapFont.defaultOptions, options), chars = _a.chars, padding = _a.padding, resolution = _a.resolution, textureWidth = _a.textureWidth, textureHeight = _a.textureHeight;
  669. var charsList = resolveCharacters(chars);
  670. var style = textStyle instanceof TextStyle ? textStyle : new TextStyle(textStyle);
  671. var lineWidth = textureWidth;
  672. var fontData = new BitmapFontData();
  673. fontData.info[0] = {
  674. face: style.fontFamily,
  675. size: style.fontSize,
  676. };
  677. fontData.common[0] = {
  678. lineHeight: style.fontSize,
  679. };
  680. var positionX = 0;
  681. var positionY = 0;
  682. var canvas;
  683. var context;
  684. var baseTexture;
  685. var maxCharHeight = 0;
  686. var textures = [];
  687. for (var i = 0; i < charsList.length; i++) {
  688. if (!canvas) {
  689. canvas = settings.ADAPTER.createCanvas();
  690. canvas.width = textureWidth;
  691. canvas.height = textureHeight;
  692. context = canvas.getContext('2d');
  693. baseTexture = new BaseTexture(canvas, { resolution: resolution });
  694. textures.push(new Texture(baseTexture));
  695. fontData.page.push({
  696. id: textures.length - 1,
  697. file: '',
  698. });
  699. }
  700. // Measure glyph dimensions
  701. var character = charsList[i];
  702. var metrics = TextMetrics.measureText(character, style, false, canvas);
  703. var width = metrics.width;
  704. var height = Math.ceil(metrics.height);
  705. // This is ugly - but italics are given more space so they don't overlap
  706. var textureGlyphWidth = Math.ceil((style.fontStyle === 'italic' ? 2 : 1) * width);
  707. // Can't fit char anymore: next canvas please!
  708. if (positionY >= textureHeight - (height * resolution)) {
  709. if (positionY === 0) {
  710. // We don't want user debugging an infinite loop (or do we? :)
  711. throw new Error("[BitmapFont] textureHeight " + textureHeight + "px is too small "
  712. + ("(fontFamily: '" + style.fontFamily + "', fontSize: " + style.fontSize + "px, char: '" + character + "')"));
  713. }
  714. --i;
  715. // Create new atlas once current has filled up
  716. canvas = null;
  717. context = null;
  718. baseTexture = null;
  719. positionY = 0;
  720. positionX = 0;
  721. maxCharHeight = 0;
  722. continue;
  723. }
  724. maxCharHeight = Math.max(height + metrics.fontProperties.descent, maxCharHeight);
  725. // Wrap line once full row has been rendered
  726. if ((textureGlyphWidth * resolution) + positionX >= lineWidth) {
  727. if (positionX === 0) {
  728. // Avoid infinite loop (There can be some very wide char like '\uFDFD'!)
  729. throw new Error("[BitmapFont] textureWidth " + textureWidth + "px is too small "
  730. + ("(fontFamily: '" + style.fontFamily + "', fontSize: " + style.fontSize + "px, char: '" + character + "')"));
  731. }
  732. --i;
  733. positionY += maxCharHeight * resolution;
  734. positionY = Math.ceil(positionY);
  735. positionX = 0;
  736. maxCharHeight = 0;
  737. continue;
  738. }
  739. drawGlyph(canvas, context, metrics, positionX, positionY, resolution, style);
  740. // Unique (numeric) ID mapping to this glyph
  741. var id = extractCharCode(metrics.text);
  742. // Create a texture holding just the glyph
  743. fontData.char.push({
  744. id: id,
  745. page: textures.length - 1,
  746. x: positionX / resolution,
  747. y: positionY / resolution,
  748. width: textureGlyphWidth,
  749. height: height,
  750. xoffset: 0,
  751. yoffset: 0,
  752. xadvance: Math.ceil(width
  753. - (style.dropShadow ? style.dropShadowDistance : 0)
  754. - (style.stroke ? style.strokeThickness : 0)),
  755. });
  756. positionX += (textureGlyphWidth + (2 * padding)) * resolution;
  757. positionX = Math.ceil(positionX);
  758. }
  759. if (!(options === null || options === void 0 ? void 0 : options.skipKerning)) {
  760. // Brute-force kerning info, this can be expensive b/c it's an O(n²),
  761. // but we're using measureText which is native and fast.
  762. for (var i = 0, len = charsList.length; i < len; i++) {
  763. var first = charsList[i];
  764. for (var j = 0; j < len; j++) {
  765. var second = charsList[j];
  766. var c1 = context.measureText(first).width;
  767. var c2 = context.measureText(second).width;
  768. var total = context.measureText(first + second).width;
  769. var amount = total - (c1 + c2);
  770. if (amount) {
  771. fontData.kerning.push({
  772. first: extractCharCode(first),
  773. second: extractCharCode(second),
  774. amount: amount,
  775. });
  776. }
  777. }
  778. }
  779. }
  780. var font = new BitmapFont(fontData, textures, true);
  781. // Make it easier to replace a font
  782. if (BitmapFont.available[name] !== undefined) {
  783. BitmapFont.uninstall(name);
  784. }
  785. BitmapFont.available[name] = font;
  786. return font;
  787. };
  788. /**
  789. * This character set includes all the letters in the alphabet (both lower- and upper- case).
  790. * @type {string[][]}
  791. * @example
  792. * BitmapFont.from("ExampleFont", style, { chars: BitmapFont.ALPHA })
  793. */
  794. BitmapFont.ALPHA = [['a', 'z'], ['A', 'Z'], ' '];
  795. /**
  796. * This character set includes all decimal digits (from 0 to 9).
  797. * @type {string[][]}
  798. * @example
  799. * BitmapFont.from("ExampleFont", style, { chars: BitmapFont.NUMERIC })
  800. */
  801. BitmapFont.NUMERIC = [['0', '9']];
  802. /**
  803. * This character set is the union of `BitmapFont.ALPHA` and `BitmapFont.NUMERIC`.
  804. * @type {string[][]}
  805. */
  806. BitmapFont.ALPHANUMERIC = [['a', 'z'], ['A', 'Z'], ['0', '9'], ' '];
  807. /**
  808. * This character set consists of all the ASCII table.
  809. * @member {string[][]}
  810. * @see http://www.asciitable.com/
  811. */
  812. BitmapFont.ASCII = [[' ', '~']];
  813. /**
  814. * Collection of default options when using `BitmapFont.from`.
  815. * @property {number} [resolution=1] -
  816. * @property {number} [textureWidth=512] -
  817. * @property {number} [textureHeight=512] -
  818. * @property {number} [padding=4] -
  819. * @property {string|string[]|string[][]} chars = PIXI.BitmapFont.ALPHANUMERIC
  820. */
  821. BitmapFont.defaultOptions = {
  822. resolution: 1,
  823. textureWidth: 512,
  824. textureHeight: 512,
  825. padding: 4,
  826. chars: BitmapFont.ALPHANUMERIC,
  827. };
  828. /** Collection of available/installed fonts. */
  829. BitmapFont.available = {};
  830. return BitmapFont;
  831. }());
  832. 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 if (median < 0.01) {\r\n alpha = 0.0;\r\n } else if (median > 0.99) {\r\n alpha = 1.0;\r\n }\r\n\r\n // NPM Textures, NPM outputs\r\n gl_FragColor = vec4(uColor.rgb, uColor.a * alpha);\r\n\r\n}\r\n";
  833. 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";
  834. // If we ever need more than two pools, please make a Dict or something better.
  835. var pageMeshDataDefaultPageMeshData = [];
  836. var pageMeshDataMSDFPageMeshData = [];
  837. var charRenderDataPool = [];
  838. /**
  839. * A BitmapText object will create a line or multiple lines of text using bitmap font.
  840. *
  841. * The primary advantage of this class over Text is that all of your textures are pre-generated and loading,
  842. * meaning that rendering is fast, and changing text has no performance implications.
  843. *
  844. * Supporting character sets other than latin, such as CJK languages, may be impractical due to the number of characters.
  845. *
  846. * To split a line you can use '\n', '\r' or '\r\n' in your string.
  847. *
  848. * PixiJS can auto-generate fonts on-the-fly using BitmapFont or use fnt files provided by:
  849. * http://www.angelcode.com/products/bmfont/ for Windows or
  850. * http://www.bmglyph.com/ for Mac.
  851. *
  852. * You can also use SDF, MSDF and MTSDF BitmapFonts for vector-like scaling appearance provided by:
  853. * https://github.com/soimy/msdf-bmfont-xml for SDF and MSDF fnt files or
  854. * https://github.com/Chlumsky/msdf-atlas-gen for SDF, MSDF and MTSDF json files
  855. *
  856. * A BitmapText can only be created when the font is loaded.
  857. *
  858. * ```js
  859. * // in this case the font is in a file called 'desyrel.fnt'
  860. * let bitmapText = new PIXI.BitmapText("text using a fancy font!", {
  861. * fontName: "Desyrel",
  862. * fontSize: 35,
  863. * align: "right"
  864. * });
  865. * ```
  866. * @memberof PIXI
  867. */
  868. var BitmapText = /** @class */ (function (_super) {
  869. __extends(BitmapText, _super);
  870. /**
  871. * @param text - A string that you would like the text to display.
  872. * @param style - The style parameters.
  873. * @param {string} style.fontName - The installed BitmapFont name.
  874. * @param {number} [style.fontSize] - The size of the font in pixels, e.g. 24. If undefined,
  875. *. this will default to the BitmapFont size.
  876. * @param {string} [style.align='left'] - Alignment for multiline text ('left', 'center', 'right' or 'justify'),
  877. * does not affect single line text.
  878. * @param {number} [style.tint=0xFFFFFF] - The tint color.
  879. * @param {number} [style.letterSpacing=0] - The amount of spacing between letters.
  880. * @param {number} [style.maxWidth=0] - The max width of the text before line wrapping.
  881. */
  882. function BitmapText(text, style) {
  883. if (style === void 0) { style = {}; }
  884. var _this = _super.call(this) || this;
  885. /**
  886. * Private tracker for the current tint.
  887. * @private
  888. */
  889. _this._tint = 0xFFFFFF;
  890. // Apply the defaults
  891. 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;
  892. if (!BitmapFont.available[fontName]) {
  893. throw new Error("Missing BitmapFont \"" + fontName + "\"");
  894. }
  895. _this._activePagesMeshData = [];
  896. _this._textWidth = 0;
  897. _this._textHeight = 0;
  898. _this._align = align;
  899. _this._tint = tint;
  900. _this._font = undefined;
  901. _this._fontName = fontName;
  902. _this._fontSize = fontSize;
  903. _this.text = text;
  904. _this._maxWidth = maxWidth;
  905. _this._maxLineHeight = 0;
  906. _this._letterSpacing = letterSpacing;
  907. _this._anchor = new ObservablePoint(function () { _this.dirty = true; }, _this, 0, 0);
  908. _this._roundPixels = settings.ROUND_PIXELS;
  909. _this.dirty = true;
  910. _this._resolution = settings.RESOLUTION;
  911. _this._autoResolution = true;
  912. _this._textureCache = {};
  913. return _this;
  914. }
  915. /** Renders text and updates it when needed. This should only be called if the BitmapFont is regenerated. */
  916. BitmapText.prototype.updateText = function () {
  917. var _a;
  918. var data = BitmapFont.available[this._fontName];
  919. var fontSize = this.fontSize;
  920. var scale = fontSize / data.size;
  921. var pos = new Point();
  922. var chars = [];
  923. var lineWidths = [];
  924. var lineSpaces = [];
  925. var text = this._text.replace(/(?:\r\n|\r)/g, '\n') || ' ';
  926. var charsInput = splitTextToCharacters(text);
  927. var maxWidth = this._maxWidth * data.size / fontSize;
  928. var pageMeshDataPool = data.distanceFieldType === 'none'
  929. ? pageMeshDataDefaultPageMeshData : pageMeshDataMSDFPageMeshData;
  930. var prevCharCode = null;
  931. var lastLineWidth = 0;
  932. var maxLineWidth = 0;
  933. var line = 0;
  934. var lastBreakPos = -1;
  935. var lastBreakWidth = 0;
  936. var spacesRemoved = 0;
  937. var maxLineHeight = 0;
  938. var spaceCount = 0;
  939. for (var i = 0; i < charsInput.length; i++) {
  940. var char = charsInput[i];
  941. var charCode = extractCharCode(char);
  942. if ((/(?:\s)/).test(char)) {
  943. lastBreakPos = i;
  944. lastBreakWidth = lastLineWidth;
  945. spaceCount++;
  946. }
  947. if (char === '\r' || char === '\n') {
  948. lineWidths.push(lastLineWidth);
  949. lineSpaces.push(-1);
  950. maxLineWidth = Math.max(maxLineWidth, lastLineWidth);
  951. ++line;
  952. ++spacesRemoved;
  953. pos.x = 0;
  954. pos.y += data.lineHeight;
  955. prevCharCode = null;
  956. spaceCount = 0;
  957. continue;
  958. }
  959. var charData = data.chars[charCode];
  960. if (!charData) {
  961. continue;
  962. }
  963. if (prevCharCode && charData.kerning[prevCharCode]) {
  964. pos.x += charData.kerning[prevCharCode];
  965. }
  966. var charRenderData = charRenderDataPool.pop() || {
  967. texture: Texture.EMPTY,
  968. line: 0,
  969. charCode: 0,
  970. prevSpaces: 0,
  971. position: new Point(),
  972. };
  973. charRenderData.texture = charData.texture;
  974. charRenderData.line = line;
  975. charRenderData.charCode = charCode;
  976. charRenderData.position.x = pos.x + charData.xOffset + (this._letterSpacing / 2);
  977. charRenderData.position.y = pos.y + charData.yOffset;
  978. charRenderData.prevSpaces = spaceCount;
  979. chars.push(charRenderData);
  980. lastLineWidth = charRenderData.position.x
  981. + Math.max(charData.xAdvance - charData.xOffset, charData.texture.orig.width);
  982. pos.x += charData.xAdvance + this._letterSpacing;
  983. maxLineHeight = Math.max(maxLineHeight, (charData.yOffset + charData.texture.height));
  984. prevCharCode = charCode;
  985. if (lastBreakPos !== -1 && maxWidth > 0 && pos.x > maxWidth) {
  986. ++spacesRemoved;
  987. removeItems(chars, 1 + lastBreakPos - spacesRemoved, 1 + i - lastBreakPos);
  988. i = lastBreakPos;
  989. lastBreakPos = -1;
  990. lineWidths.push(lastBreakWidth);
  991. lineSpaces.push(chars.length > 0 ? chars[chars.length - 1].prevSpaces : 0);
  992. maxLineWidth = Math.max(maxLineWidth, lastBreakWidth);
  993. line++;
  994. pos.x = 0;
  995. pos.y += data.lineHeight;
  996. prevCharCode = null;
  997. spaceCount = 0;
  998. }
  999. }
  1000. var lastChar = charsInput[charsInput.length - 1];
  1001. if (lastChar !== '\r' && lastChar !== '\n') {
  1002. if ((/(?:\s)/).test(lastChar)) {
  1003. lastLineWidth = lastBreakWidth;
  1004. }
  1005. lineWidths.push(lastLineWidth);
  1006. maxLineWidth = Math.max(maxLineWidth, lastLineWidth);
  1007. lineSpaces.push(-1);
  1008. }
  1009. var lineAlignOffsets = [];
  1010. for (var i = 0; i <= line; i++) {
  1011. var alignOffset = 0;
  1012. if (this._align === 'right') {
  1013. alignOffset = maxLineWidth - lineWidths[i];
  1014. }
  1015. else if (this._align === 'center') {
  1016. alignOffset = (maxLineWidth - lineWidths[i]) / 2;
  1017. }
  1018. else if (this._align === 'justify') {
  1019. alignOffset = lineSpaces[i] < 0 ? 0 : (maxLineWidth - lineWidths[i]) / lineSpaces[i];
  1020. }
  1021. lineAlignOffsets.push(alignOffset);
  1022. }
  1023. var lenChars = chars.length;
  1024. var pagesMeshData = {};
  1025. var newPagesMeshData = [];
  1026. var activePagesMeshData = this._activePagesMeshData;
  1027. pageMeshDataPool.push.apply(pageMeshDataPool, activePagesMeshData);
  1028. for (var i = 0; i < lenChars; i++) {
  1029. var texture = chars[i].texture;
  1030. var baseTextureUid = texture.baseTexture.uid;
  1031. if (!pagesMeshData[baseTextureUid]) {
  1032. var pageMeshData = pageMeshDataPool.pop();
  1033. if (!pageMeshData) {
  1034. var geometry = new MeshGeometry();
  1035. var material = void 0;
  1036. var meshBlendMode = void 0;
  1037. if (data.distanceFieldType === 'none') {
  1038. material = new MeshMaterial(Texture.EMPTY);
  1039. meshBlendMode = BLEND_MODES.NORMAL;
  1040. }
  1041. else {
  1042. material = new MeshMaterial(Texture.EMPTY, { program: Program.from(msdfVert, msdfFrag), uniforms: { uFWidth: 0 } });
  1043. meshBlendMode = BLEND_MODES.NORMAL_NPM;
  1044. }
  1045. var mesh = new Mesh(geometry, material);
  1046. mesh.blendMode = meshBlendMode;
  1047. pageMeshData = {
  1048. index: 0,
  1049. indexCount: 0,
  1050. vertexCount: 0,
  1051. uvsCount: 0,
  1052. total: 0,
  1053. mesh: mesh,
  1054. vertices: null,
  1055. uvs: null,
  1056. indices: null,
  1057. };
  1058. }
  1059. // reset data..
  1060. pageMeshData.index = 0;
  1061. pageMeshData.indexCount = 0;
  1062. pageMeshData.vertexCount = 0;
  1063. pageMeshData.uvsCount = 0;
  1064. pageMeshData.total = 0;
  1065. // TODO need to get page texture here somehow..
  1066. var _textureCache = this._textureCache;
  1067. _textureCache[baseTextureUid] = _textureCache[baseTextureUid] || new Texture(texture.baseTexture);
  1068. pageMeshData.mesh.texture = _textureCache[baseTextureUid];
  1069. pageMeshData.mesh.tint = this._tint;
  1070. newPagesMeshData.push(pageMeshData);
  1071. pagesMeshData[baseTextureUid] = pageMeshData;
  1072. }
  1073. pagesMeshData[baseTextureUid].total++;
  1074. }
  1075. // lets find any previously active pageMeshDatas that are no longer required for
  1076. // the updated text (if any), removed and return them to the pool.
  1077. for (var i = 0; i < activePagesMeshData.length; i++) {
  1078. if (newPagesMeshData.indexOf(activePagesMeshData[i]) === -1) {
  1079. this.removeChild(activePagesMeshData[i].mesh);
  1080. }
  1081. }
  1082. // next lets add any new meshes, that have not yet been added to this BitmapText
  1083. // we only add if its not already a child of this BitmapObject
  1084. for (var i = 0; i < newPagesMeshData.length; i++) {
  1085. if (newPagesMeshData[i].mesh.parent !== this) {
  1086. this.addChild(newPagesMeshData[i].mesh);
  1087. }
  1088. }
  1089. // active page mesh datas are set to be the new pages added.
  1090. this._activePagesMeshData = newPagesMeshData;
  1091. for (var i in pagesMeshData) {
  1092. var pageMeshData = pagesMeshData[i];
  1093. var total = pageMeshData.total;
  1094. // lets only allocate new buffers if we can fit the new text in the current ones..
  1095. // unless that is, we will be batching. Currently batching dose not respect the size property of mesh
  1096. if (!(((_a = pageMeshData.indices) === null || _a === void 0 ? void 0 : _a.length) > 6 * total) || pageMeshData.vertices.length < Mesh.BATCHABLE_SIZE * 2) {
  1097. pageMeshData.vertices = new Float32Array(4 * 2 * total);
  1098. pageMeshData.uvs = new Float32Array(4 * 2 * total);
  1099. pageMeshData.indices = new Uint16Array(6 * total);
  1100. }
  1101. else {
  1102. var total_1 = pageMeshData.total;
  1103. var vertices = pageMeshData.vertices;
  1104. // Clear the garbage at the end of the vertices buffer. This will prevent the bounds miscalculation.
  1105. for (var i_1 = total_1 * 4 * 2; i_1 < vertices.length; i_1++) {
  1106. vertices[i_1] = 0;
  1107. }
  1108. }
  1109. // as a buffer maybe bigger than the current word, we set the size of the meshMaterial
  1110. // to match the number of letters needed
  1111. pageMeshData.mesh.size = 6 * total;
  1112. }
  1113. for (var i = 0; i < lenChars; i++) {
  1114. var char = chars[i];
  1115. var offset = char.position.x + (lineAlignOffsets[char.line] * (this._align === 'justify' ? char.prevSpaces : 1));
  1116. if (this._roundPixels) {
  1117. offset = Math.round(offset);
  1118. }
  1119. var xPos = offset * scale;
  1120. var yPos = char.position.y * scale;
  1121. var texture = char.texture;
  1122. var pageMesh = pagesMeshData[texture.baseTexture.uid];
  1123. var textureFrame = texture.frame;
  1124. var textureUvs = texture._uvs;
  1125. var index = pageMesh.index++;
  1126. pageMesh.indices[(index * 6) + 0] = 0 + (index * 4);
  1127. pageMesh.indices[(index * 6) + 1] = 1 + (index * 4);
  1128. pageMesh.indices[(index * 6) + 2] = 2 + (index * 4);
  1129. pageMesh.indices[(index * 6) + 3] = 0 + (index * 4);
  1130. pageMesh.indices[(index * 6) + 4] = 2 + (index * 4);
  1131. pageMesh.indices[(index * 6) + 5] = 3 + (index * 4);
  1132. pageMesh.vertices[(index * 8) + 0] = xPos;
  1133. pageMesh.vertices[(index * 8) + 1] = yPos;
  1134. pageMesh.vertices[(index * 8) + 2] = xPos + (textureFrame.width * scale);
  1135. pageMesh.vertices[(index * 8) + 3] = yPos;
  1136. pageMesh.vertices[(index * 8) + 4] = xPos + (textureFrame.width * scale);
  1137. pageMesh.vertices[(index * 8) + 5] = yPos + (textureFrame.height * scale);
  1138. pageMesh.vertices[(index * 8) + 6] = xPos;
  1139. pageMesh.vertices[(index * 8) + 7] = yPos + (textureFrame.height * scale);
  1140. pageMesh.uvs[(index * 8) + 0] = textureUvs.x0;
  1141. pageMesh.uvs[(index * 8) + 1] = textureUvs.y0;
  1142. pageMesh.uvs[(index * 8) + 2] = textureUvs.x1;
  1143. pageMesh.uvs[(index * 8) + 3] = textureUvs.y1;
  1144. pageMesh.uvs[(index * 8) + 4] = textureUvs.x2;
  1145. pageMesh.uvs[(index * 8) + 5] = textureUvs.y2;
  1146. pageMesh.uvs[(index * 8) + 6] = textureUvs.x3;
  1147. pageMesh.uvs[(index * 8) + 7] = textureUvs.y3;
  1148. }
  1149. this._textWidth = maxLineWidth * scale;
  1150. this._textHeight = (pos.y + data.lineHeight) * scale;
  1151. for (var i in pagesMeshData) {
  1152. var pageMeshData = pagesMeshData[i];
  1153. // apply anchor
  1154. if (this.anchor.x !== 0 || this.anchor.y !== 0) {
  1155. var vertexCount = 0;
  1156. var anchorOffsetX = this._textWidth * this.anchor.x;
  1157. var anchorOffsetY = this._textHeight * this.anchor.y;
  1158. for (var i_2 = 0; i_2 < pageMeshData.total; i_2++) {
  1159. pageMeshData.vertices[vertexCount++] -= anchorOffsetX;
  1160. pageMeshData.vertices[vertexCount++] -= anchorOffsetY;
  1161. pageMeshData.vertices[vertexCount++] -= anchorOffsetX;
  1162. pageMeshData.vertices[vertexCount++] -= anchorOffsetY;
  1163. pageMeshData.vertices[vertexCount++] -= anchorOffsetX;
  1164. pageMeshData.vertices[vertexCount++] -= anchorOffsetY;
  1165. pageMeshData.vertices[vertexCount++] -= anchorOffsetX;
  1166. pageMeshData.vertices[vertexCount++] -= anchorOffsetY;
  1167. }
  1168. }
  1169. this._maxLineHeight = maxLineHeight * scale;
  1170. var vertexBuffer = pageMeshData.mesh.geometry.getBuffer('aVertexPosition');
  1171. var textureBuffer = pageMeshData.mesh.geometry.getBuffer('aTextureCoord');
  1172. var indexBuffer = pageMeshData.mesh.geometry.getIndex();
  1173. vertexBuffer.data = pageMeshData.vertices;
  1174. textureBuffer.data = pageMeshData.uvs;
  1175. indexBuffer.data = pageMeshData.indices;
  1176. vertexBuffer.update();
  1177. textureBuffer.update();
  1178. indexBuffer.update();
  1179. }
  1180. for (var i = 0; i < chars.length; i++) {
  1181. charRenderDataPool.push(chars[i]);
  1182. }
  1183. this._font = data;
  1184. this.dirty = false;
  1185. };
  1186. BitmapText.prototype.updateTransform = function () {
  1187. this.validate();
  1188. this.containerUpdateTransform();
  1189. };
  1190. BitmapText.prototype._render = function (renderer) {
  1191. if (this._autoResolution && this._resolution !== renderer.resolution) {
  1192. this._resolution = renderer.resolution;
  1193. this.dirty = true;
  1194. }
  1195. // Update the uniform
  1196. var _a = BitmapFont.available[this._fontName], distanceFieldRange = _a.distanceFieldRange, distanceFieldType = _a.distanceFieldType, size = _a.size;
  1197. if (distanceFieldType !== 'none') {
  1198. // Inject the shader code with the correct value
  1199. var _b = this.worldTransform, a = _b.a, b = _b.b, c = _b.c, d = _b.d;
  1200. var dx = Math.sqrt((a * a) + (b * b));
  1201. var dy = Math.sqrt((c * c) + (d * d));
  1202. var worldScale = (Math.abs(dx) + Math.abs(dy)) / 2;
  1203. var fontScale = this.fontSize / size;
  1204. for (var _i = 0, _c = this._activePagesMeshData; _i < _c.length; _i++) {
  1205. var mesh = _c[_i];
  1206. mesh.mesh.shader.uniforms.uFWidth = worldScale * distanceFieldRange * fontScale * this._resolution;
  1207. }
  1208. }
  1209. _super.prototype._render.call(this, renderer);
  1210. };
  1211. /**
  1212. * Validates text before calling parent's getLocalBounds
  1213. * @returns - The rectangular bounding area
  1214. */
  1215. BitmapText.prototype.getLocalBounds = function () {
  1216. this.validate();
  1217. return _super.prototype.getLocalBounds.call(this);
  1218. };
  1219. /**
  1220. * Updates text when needed
  1221. * @private
  1222. */
  1223. BitmapText.prototype.validate = function () {
  1224. var font = BitmapFont.available[this._fontName];
  1225. if (!font) {
  1226. throw new Error("Missing BitmapFont \"" + this._fontName + "\"");
  1227. }
  1228. if (this._font !== font) {
  1229. this.dirty = true;
  1230. }
  1231. if (this.dirty) {
  1232. this.updateText();
  1233. }
  1234. };
  1235. Object.defineProperty(BitmapText.prototype, "tint", {
  1236. /**
  1237. * The tint of the BitmapText object.
  1238. * @default 0xffffff
  1239. */
  1240. get: function () {
  1241. return this._tint;
  1242. },
  1243. set: function (value) {
  1244. if (this._tint === value)
  1245. { return; }
  1246. this._tint = value;
  1247. for (var i = 0; i < this._activePagesMeshData.length; i++) {
  1248. this._activePagesMeshData[i].mesh.tint = value;
  1249. }
  1250. },
  1251. enumerable: false,
  1252. configurable: true
  1253. });
  1254. Object.defineProperty(BitmapText.prototype, "align", {
  1255. /**
  1256. * The alignment of the BitmapText object.
  1257. * @member {string}
  1258. * @default 'left'
  1259. */
  1260. get: function () {
  1261. return this._align;
  1262. },
  1263. set: function (value) {
  1264. if (this._align !== value) {
  1265. this._align = value;
  1266. this.dirty = true;
  1267. }
  1268. },
  1269. enumerable: false,
  1270. configurable: true
  1271. });
  1272. Object.defineProperty(BitmapText.prototype, "fontName", {
  1273. /** The name of the BitmapFont. */
  1274. get: function () {
  1275. return this._fontName;
  1276. },
  1277. set: function (value) {
  1278. if (!BitmapFont.available[value]) {
  1279. throw new Error("Missing BitmapFont \"" + value + "\"");
  1280. }
  1281. if (this._fontName !== value) {
  1282. this._fontName = value;
  1283. this.dirty = true;
  1284. }
  1285. },
  1286. enumerable: false,
  1287. configurable: true
  1288. });
  1289. Object.defineProperty(BitmapText.prototype, "fontSize", {
  1290. /** The size of the font to display. */
  1291. get: function () {
  1292. var _a;
  1293. return (_a = this._fontSize) !== null && _a !== void 0 ? _a : BitmapFont.available[this._fontName].size;
  1294. },
  1295. set: function (value) {
  1296. if (this._fontSize !== value) {
  1297. this._fontSize = value;
  1298. this.dirty = true;
  1299. }
  1300. },
  1301. enumerable: false,
  1302. configurable: true
  1303. });
  1304. Object.defineProperty(BitmapText.prototype, "anchor", {
  1305. /**
  1306. * The anchor sets the origin point of the text.
  1307. *
  1308. * The default is `(0,0)`, this means the text's origin is the top left.
  1309. *
  1310. * Setting the anchor to `(0.5,0.5)` means the text's origin is centered.
  1311. *
  1312. * Setting the anchor to `(1,1)` would mean the text's origin point will be the bottom right corner.
  1313. */
  1314. get: function () {
  1315. return this._anchor;
  1316. },
  1317. set: function (value) {
  1318. if (typeof value === 'number') {
  1319. this._anchor.set(value);
  1320. }
  1321. else {
  1322. this._anchor.copyFrom(value);
  1323. }
  1324. },
  1325. enumerable: false,
  1326. configurable: true
  1327. });
  1328. Object.defineProperty(BitmapText.prototype, "text", {
  1329. /** The text of the BitmapText object. */
  1330. get: function () {
  1331. return this._text;
  1332. },
  1333. set: function (text) {
  1334. text = String(text === null || text === undefined ? '' : text);
  1335. if (this._text === text) {
  1336. return;
  1337. }
  1338. this._text = text;
  1339. this.dirty = true;
  1340. },
  1341. enumerable: false,
  1342. configurable: true
  1343. });
  1344. Object.defineProperty(BitmapText.prototype, "maxWidth", {
  1345. /**
  1346. * The max width of this bitmap text in pixels. If the text provided is longer than the
  1347. * value provided, line breaks will be automatically inserted in the last whitespace.
  1348. * Disable by setting the value to 0.
  1349. */
  1350. get: function () {
  1351. return this._maxWidth;
  1352. },
  1353. set: function (value) {
  1354. if (this._maxWidth === value) {
  1355. return;
  1356. }
  1357. this._maxWidth = value;
  1358. this.dirty = true;
  1359. },
  1360. enumerable: false,
  1361. configurable: true
  1362. });
  1363. Object.defineProperty(BitmapText.prototype, "maxLineHeight", {
  1364. /**
  1365. * The max line height. This is useful when trying to use the total height of the Text,
  1366. * i.e. when trying to vertically align.
  1367. * @readonly
  1368. */
  1369. get: function () {
  1370. this.validate();
  1371. return this._maxLineHeight;
  1372. },
  1373. enumerable: false,
  1374. configurable: true
  1375. });
  1376. Object.defineProperty(BitmapText.prototype, "textWidth", {
  1377. /**
  1378. * The width of the overall text, different from fontSize,
  1379. * which is defined in the style object.
  1380. * @readonly
  1381. */
  1382. get: function () {
  1383. this.validate();
  1384. return this._textWidth;
  1385. },
  1386. enumerable: false,
  1387. configurable: true
  1388. });
  1389. Object.defineProperty(BitmapText.prototype, "letterSpacing", {
  1390. /** Additional space between characters. */
  1391. get: function () {
  1392. return this._letterSpacing;
  1393. },
  1394. set: function (value) {
  1395. if (this._letterSpacing !== value) {
  1396. this._letterSpacing = value;
  1397. this.dirty = true;
  1398. }
  1399. },
  1400. enumerable: false,
  1401. configurable: true
  1402. });
  1403. Object.defineProperty(BitmapText.prototype, "roundPixels", {
  1404. /**
  1405. * If true PixiJS will Math.floor() x/y values when rendering, stopping pixel interpolation.
  1406. * Advantages can include sharper image quality (like text) and faster rendering on canvas.
  1407. * The main disadvantage is movement of objects may appear less smooth.
  1408. * To set the global default, change {@link PIXI.settings.ROUND_PIXELS}
  1409. * @default PIXI.settings.ROUND_PIXELS
  1410. */
  1411. get: function () {
  1412. return this._roundPixels;
  1413. },
  1414. set: function (value) {
  1415. if (value !== this._roundPixels) {
  1416. this._roundPixels = value;
  1417. this.dirty = true;
  1418. }
  1419. },
  1420. enumerable: false,
  1421. configurable: true
  1422. });
  1423. Object.defineProperty(BitmapText.prototype, "textHeight", {
  1424. /**
  1425. * The height of the overall text, different from fontSize,
  1426. * which is defined in the style object.
  1427. * @readonly
  1428. */
  1429. get: function () {
  1430. this.validate();
  1431. return this._textHeight;
  1432. },
  1433. enumerable: false,
  1434. configurable: true
  1435. });
  1436. Object.defineProperty(BitmapText.prototype, "resolution", {
  1437. /**
  1438. * The resolution / device pixel ratio of the canvas.
  1439. *
  1440. * This is set to automatically match the renderer resolution by default, but can be overridden by setting manually.
  1441. * @default 1
  1442. */
  1443. get: function () {
  1444. return this._resolution;
  1445. },
  1446. set: function (value) {
  1447. this._autoResolution = false;
  1448. if (this._resolution === value) {
  1449. return;
  1450. }
  1451. this._resolution = value;
  1452. this.dirty = true;
  1453. },
  1454. enumerable: false,
  1455. configurable: true
  1456. });
  1457. BitmapText.prototype.destroy = function (options) {
  1458. var _textureCache = this._textureCache;
  1459. var data = BitmapFont.available[this._fontName];
  1460. var pageMeshDataPool = data.distanceFieldType === 'none'
  1461. ? pageMeshDataDefaultPageMeshData : pageMeshDataMSDFPageMeshData;
  1462. pageMeshDataPool.push.apply(pageMeshDataPool, this._activePagesMeshData);
  1463. for (var _i = 0, _a = this._activePagesMeshData; _i < _a.length; _i++) {
  1464. var pageMeshData = _a[_i];
  1465. this.removeChild(pageMeshData.mesh);
  1466. }
  1467. this._activePagesMeshData = [];
  1468. // Release references to any cached textures in page pool
  1469. pageMeshDataPool
  1470. .filter(function (page) { return _textureCache[page.mesh.texture.baseTexture.uid]; })
  1471. .forEach(function (page) {
  1472. page.mesh.texture = Texture.EMPTY;
  1473. });
  1474. for (var id in _textureCache) {
  1475. var texture = _textureCache[id];
  1476. texture.destroy();
  1477. delete _textureCache[id];
  1478. }
  1479. this._font = null;
  1480. this._textureCache = null;
  1481. _super.prototype.destroy.call(this, options);
  1482. };
  1483. BitmapText.styleDefaults = {
  1484. align: 'left',
  1485. tint: 0xFFFFFF,
  1486. maxWidth: 0,
  1487. letterSpacing: 0,
  1488. };
  1489. return BitmapText;
  1490. }(Container));
  1491. /**
  1492. * {@link PIXI.Loader Loader} middleware for loading
  1493. * bitmap-based fonts suitable for using with {@link PIXI.BitmapText}.
  1494. * @memberof PIXI
  1495. */
  1496. var BitmapFontLoader = /** @class */ (function () {
  1497. function BitmapFontLoader() {
  1498. }
  1499. /**
  1500. * Called when the plugin is installed.
  1501. * @see PIXI.extensions.add
  1502. */
  1503. BitmapFontLoader.add = function () {
  1504. LoaderResource.setExtensionXhrType('fnt', LoaderResource.XHR_RESPONSE_TYPE.TEXT);
  1505. };
  1506. /**
  1507. * Called after a resource is loaded.
  1508. * @see PIXI.Loader.loaderMiddleware
  1509. * @param this
  1510. * @param {PIXI.LoaderResource} resource
  1511. * @param {Function} next
  1512. */
  1513. BitmapFontLoader.use = function (resource, next) {
  1514. var format = autoDetectFormat(resource.data);
  1515. // Resource was not recognised as any of the expected font data format
  1516. if (!format) {
  1517. next();
  1518. return;
  1519. }
  1520. var baseUrl = BitmapFontLoader.getBaseUrl(this, resource);
  1521. var data = format.parse(resource.data);
  1522. var textures = {};
  1523. // Handle completed, when the number of textures
  1524. // load is the same number as references in the fnt file
  1525. var completed = function (page) {
  1526. textures[page.metadata.pageFile] = page.texture;
  1527. if (Object.keys(textures).length === data.page.length) {
  1528. resource.bitmapFont = BitmapFont.install(data, textures, true);
  1529. next();
  1530. }
  1531. };
  1532. for (var i = 0; i < data.page.length; ++i) {
  1533. var pageFile = data.page[i].file;
  1534. var url = baseUrl + pageFile;
  1535. var exists = false;
  1536. // incase the image is loaded outside
  1537. // using the same loader, resource will be available
  1538. for (var name in this.resources) {
  1539. var bitmapResource = this.resources[name];
  1540. if (bitmapResource.url === url) {
  1541. bitmapResource.metadata.pageFile = pageFile;
  1542. if (bitmapResource.texture) {
  1543. completed(bitmapResource);
  1544. }
  1545. else {
  1546. bitmapResource.onAfterMiddleware.add(completed);
  1547. }
  1548. exists = true;
  1549. break;
  1550. }
  1551. }
  1552. // texture is not loaded, we'll attempt to add
  1553. // it to the load and add the texture to the list
  1554. if (!exists) {
  1555. // Standard loading options for images
  1556. var options = {
  1557. crossOrigin: resource.crossOrigin,
  1558. loadType: LoaderResource.LOAD_TYPE.IMAGE,
  1559. metadata: Object.assign({ pageFile: pageFile }, resource.metadata.imageMetadata),
  1560. parentResource: resource,
  1561. };
  1562. this.add(url, options, completed);
  1563. }
  1564. }
  1565. };
  1566. /**
  1567. * Get folder path from a resource.
  1568. * @param loader
  1569. * @param resource
  1570. */
  1571. BitmapFontLoader.getBaseUrl = function (loader, resource) {
  1572. var resUrl = !resource.isDataUrl ? BitmapFontLoader.dirname(resource.url) : '';
  1573. if (resource.isDataUrl) {
  1574. if (resUrl === '.') {
  1575. resUrl = '';
  1576. }
  1577. if (loader.baseUrl && resUrl) {
  1578. // if baseurl has a trailing slash then add one to resUrl so the replace works below
  1579. if (loader.baseUrl.charAt(loader.baseUrl.length - 1) === '/') {
  1580. resUrl += '/';
  1581. }
  1582. }
  1583. }
  1584. // remove baseUrl from resUrl
  1585. resUrl = resUrl.replace(loader.baseUrl, '');
  1586. // if there is an resUrl now, it needs a trailing slash. Ensure that it does if the string isn't empty.
  1587. if (resUrl && resUrl.charAt(resUrl.length - 1) !== '/') {
  1588. resUrl += '/';
  1589. }
  1590. return resUrl;
  1591. };
  1592. /**
  1593. * Replacement for NodeJS's path.dirname
  1594. * @param {string} url - Path to get directory for
  1595. */
  1596. BitmapFontLoader.dirname = function (url) {
  1597. var dir = url
  1598. .replace(/\\/g, '/') // convert windows notation to UNIX notation, URL-safe because it's a forbidden character
  1599. .replace(/\/$/, '') // replace trailing slash
  1600. .replace(/\/[^\/]*$/, ''); // remove everything after the last
  1601. // File request is relative, use current directory
  1602. if (dir === url) {
  1603. return '.';
  1604. }
  1605. // Started with a slash
  1606. else if (dir === '') {
  1607. return '/';
  1608. }
  1609. return dir;
  1610. };
  1611. /** @ignore */
  1612. BitmapFontLoader.extension = ExtensionType.Loader;
  1613. return BitmapFontLoader;
  1614. }());
  1615. export { BitmapFont, BitmapFontData, BitmapFontLoader, BitmapText, TextFormat, XMLFormat, XMLStringFormat, autoDetectFormat };
  1616. //# sourceMappingURL=text-bitmap.mjs.map