diff --git a/src/components/text.js b/src/components/text.js index 68f850caa13..bbf82611572 100644 --- a/src/components/text.js +++ b/src/components/text.js @@ -36,6 +36,9 @@ var cache = new PromiseCache(); var fontWidthFactors = {}; var textures = {}; +// Regular expression for detecting a URLs with a protocol prefix. +var protocolRe = /^\w+:/; + /** * SDF-based text component. * Based on https://github.com/Jam3/three-bmfont-text. @@ -95,13 +98,12 @@ module.exports.Component = registerComponent('text', { update: function (oldData) { var data = coerceData(this.data); var font = this.currentFont; - var fontImage = this.getFontImageSrc(); - if (textures[fontImage]) { - this.texture = textures[fontImage]; + if (textures[data.font]) { + this.texture = textures[data.font]; } else { // Create texture per font. - this.texture = textures[fontImage] = new THREE.Texture(); + this.texture = textures[data.font] = new THREE.Texture(); this.texture.anisotropy = MAX_ANISOTROPY; } @@ -234,7 +236,7 @@ module.exports.Component = registerComponent('text', { var texture = self.texture; texture.image = image; texture.needsUpdate = true; - textures[fontImgSrc] = texture; + textures[data.font] = texture; self.texture = texture; self.mesh.visible = true; el.emit('textfontset', {font: data.font, fontObj: font}); @@ -249,8 +251,15 @@ module.exports.Component = registerComponent('text', { }, getFontImageSrc: function () { + if (this.data.fontImage) { return this.data.fontImage; } var fontSrc = this.lookupFont(this.data.font || DEFAULT_FONT) || this.data.font; - return this.data.fontImage || fontSrc.replace(/(\.fnt)|(\.json)/, '.png'); + var imageSrc = this.currentFont.pages[0]; + // If the image URL contains a non-HTTP(S) protocol, assume it's an absolute + // path on disk and try to infer the path from the font source instead. + if (imageSrc.match(protocolRe) && imageSrc.indexOf('http') !== 0) { + return fontSrc.replace(/(\.fnt)|(\.json)/, '.png'); + } + return THREE.LoaderUtils.extractUrlBase(fontSrc) + imageSrc; }, /** diff --git a/tests/components/text.test.js b/tests/components/text.test.js index de91c009f9f..5c98a137354 100644 --- a/tests/components/text.test.js +++ b/tests/components/text.test.js @@ -11,7 +11,8 @@ suite('text', function () { return { default: '/base/tests/assets/test.fnt?foo', mozillavr: '/base/tests/assets/test.fnt?bar', - roboto: '/base/tests/assets/test.fnt?baz' + roboto: '/base/tests/assets/test.fnt?baz', + msdf: '/base/tests/assets/test.fnt?msdf' }[key]; }); @@ -232,6 +233,28 @@ suite('text', function () { el.setAttribute('text', {font: 'mozillavr', fontImage: '/base/tests/assets/test2.png'}); }); + test('loads font with inferred font image', function (done) { + // `test.fnt` contains an absolute filepath, which should be ignored + // in favor of a page-relative texture URL. + el.addEventListener('textfontset', evt => { + component.currentFont.pages[0] = 'C:\\Windows\\Documents\\custom-texture.png'; + assert.equal(component.getFontImageSrc(), '/base/tests/assets/test.png'); + done(); + }); + el.setAttribute('text', 'font', '/base/tests/assets/test.fnt'); + }); + + test('loads font with referenced font image', function (done) { + // `test.fnt` contains a local reference to the page texture, which + // should be loaded relative to the font's base path. + el.addEventListener('textfontset', evt => { + component.currentFont.pages[0] = 'custom-texture.png'; + assert.equal(component.getFontImageSrc(), '/base/tests/assets/custom-texture.png'); + done(); + }); + el.setAttribute('text', {font: 'msdf'}); + }); + test('uses up-to-date data once loaded', function (done) { var updateSpy = this.sinon.spy(component, 'updateGeometry'); el.addEventListener('textfontset', evt => {