diff --git a/src/engine/tw-font-manager.js b/src/engine/tw-font-manager.js index 1535aa04bf3..f617a67f95e 100644 --- a/src/engine/tw-font-manager.js +++ b/src/engine/tw-font-manager.js @@ -22,6 +22,22 @@ const log = require('../util/log'); */ const removeInvalidCharacters = font => font.replace(/[^-\w ]/g, ''); +/** + * @param {InternalFont[]} fonts Modified in-place + * @param {InternalFont} newFont + * @returns {InternalFont|null} + */ +const addOrUpdateFont = (fonts, newFont) => { + let oldFont; + const oldIndex = fonts.findIndex(i => i.family.toLowerCase() === newFont.family.toLowerCase()); + if (oldIndex !== -1) { + oldFont = fonts[oldIndex]; + fonts.splice(oldIndex, 1); + } + fonts.push(newFont); + return oldFont; +}; + class FontManager extends EventEmitter { /** * @param {Runtime} runtime @@ -129,11 +145,14 @@ class FontManager extends EventEmitter { if (!this.isValidSystemFont(family)) { throw new Error('Invalid system font family'); } - this.fonts.push({ + const oldFont = addOrUpdateFont(this.fonts, { system: true, family, fallback }); + if (oldFont && !oldFont.system) { + this.updateRenderer(); + } this.changed(); } @@ -146,14 +165,12 @@ class FontManager extends EventEmitter { if (!this.isValidCustomFont(family)) { throw new Error('Invalid custom font family'); } - - this.fonts.push({ + addOrUpdateFont(this.fonts, { system: false, family, fallback, asset }); - this.updateRenderer(); this.changed(); } diff --git a/test/integration/tw_font_manager.js b/test/integration/tw_font_manager.js index a9cc635b852..452fabc687a 100644 --- a/test/integration/tw_font_manager.js +++ b/test/integration/tw_font_manager.js @@ -714,3 +714,53 @@ test('restrict removes existing fonts', t => { t.end(); }); + +test('overriding existing fonts', t => { + let setCustomFontsCalls = 0; + const mockRenderer = { + setLayerGroupOrdering: () => {}, + setCustomFonts: () => { + setCustomFontsCalls++; + } + }; + + const rt = new Runtime(); + rt.attachRenderer(mockRenderer); + rt.attachStorage(makeTestStorage()); + const {fontManager, storage} = rt; + + let changeEvents = 0; + fontManager.on('change', () => { + changeEvents++; + }); + + const asset = storage.createAsset( + storage.AssetType.Font, + 'ttf', + new Uint8Array([11, 12, 13]), + null, + true + ); + + fontManager.addCustomFont('TestFont', 'sans-serif', asset); + t.equal(changeEvents, 1); + t.equal(setCustomFontsCalls, 1); + t.same(fontManager.getFonts().map(i => i.name), ['TestFont']); + + fontManager.addSystemFont('TestFonT', 'sans-serif'); + t.equal(changeEvents, 2); + t.equal(setCustomFontsCalls, 2); + t.same(fontManager.getFonts().map(i => i.name), ['TestFonT']); + + fontManager.addSystemFont('TestFONT', 'sans-serif'); + t.equal(changeEvents, 3); + t.equal(setCustomFontsCalls, 2); + t.same(fontManager.getFonts().map(i => i.name), ['TestFONT']); + + fontManager.addCustomFont('TESTFONT', 'sans-serif', asset); + t.equal(changeEvents, 4); + t.equal(setCustomFontsCalls, 3); + t.same(fontManager.getFonts().map(i => i.name), ['TESTFONT']); + + t.end(); +});