Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 104 additions & 36 deletions lib/loadFonts.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,74 @@ define([
opentype
) {
"use strict";
/*globals FileReader, XMLHttpRequest, console*/
/*globals setTimeout, FileReader, XMLHttpRequest, console*/

/**
* Callback for when a fontfile has been loaded
*
* @param i: index of the font loaded
* @param fontFileName
* @param err: null, error-object or string with error message
* @param fontArraybuffer
*/
function onLoadFont(i, fontFileName, err, fontArraybuffer) {
/* jshint validthis: true */
var font;
function _publishLoaded(task, data) {
var state = task.state
, index = task.index
, fontFileName = task.name
, err = data.error
, font = data.font
, fontArraybuffer = data.arraybuffer
;

if(err) {
console.warn('Can\'t load font', fontFileName, ' with error:', err);
state.countAll--;
}
else {
state.pubsub.publish('loadFont', index, fontFileName, font, fontArraybuffer);
state.countLoaded += 1;
}

if(state.countLoaded === state.countAll)
state.pubsub.publish('allFontsLoaded', state.countAll);
}

function _getLoadedFontData(err, fontArraybuffer) {
var err_ = err || null
, font = null
;
if(!err) {
try {
font = opentype.parse(fontArraybuffer);
font = opentype.parse(fontArraybuffer);
}
catch (parseError) {
err = parseError;
err_ = parseError;
}
}

if(err) {
console.warn('Can\'t load font', fontFileName, ' with error:', err);
this.countAll--;
}
else {
this.pubsub.publish('loadFont', i, fontFileName, font, fontArraybuffer);
this.countLoaded += 1;
}
return {
error:err_
, font: font
, arraybuffer:fontArraybuffer
};
}

function _onLoadQueued(cache, key, err, fontArraybuffer) {
var data, queue, i, l, task;

if(this.countLoaded === this.countAll)
this.pubsub.publish('allFontsLoaded', this.countAll);
cache.loaded[key] = data = _getLoadedFontData(err, fontArraybuffer);
queue = cache.queues[key];
delete cache.queues[key];

for(i=0,l=queue.length;i<l;i++) {
task = queue[i];
_publishLoaded(task, data);
}
}

/**
* Callback for when a fontfile has been loaded
*
* @param i: index of the font loaded
* @param fontFileName
* @param err: null, error-object or string with error message
* @param fontArraybuffer
*/
function _onLoadFont(task, err, fontArraybuffer) {
var data = _getLoadedFontData(err, fontArraybuffer);
_publishLoaded(task, data);
}

function loadFromUrl(fontInfo, callback) {
Expand Down Expand Up @@ -75,40 +109,74 @@ define([
}
loadFontsFromFileInput.needsPubSub = true;


function loadFontsFromUrl(pubsub, fontFiles) {
function loadFontsFromUrl(pubsub, fontFiles, cache) {
var i, l
, fontInfo = []
;
for(i=0,l=fontFiles.length;i<l;i++) {
if (!fontFiles[i])
throw new Error('The url at index '+i+' appears to be invalid.');
fontInfo.push({
name: fontFiles[i]
name: fontFiles[i]
, url: fontFiles[i]
// this is for the cache and must be the same as url in this case,
// to ensure we request a file only once
, key: fontFiles[i]
});
}
_loadFonts(pubsub, fontInfo, loadFromUrl);
_loadFonts(pubsub, fontInfo, loadFromUrl, cache);
}

function _initCache(cache) {
if(!('loaded' in cache))
cache.loaded = Object.create(null);
if(!('queues' in cache))
cache.queues = Object.create(null);
}

function _loadFonts(pubsub, fontFiles, loadFont) {
var i, l, fontInfo, onload
function _loadFonts(pubsub, fontFiles, loadFont, cache) {
var i, l, fontInfo, key, onload, task, data
, loaderState = {
countLoaded: 0
, countAll: fontFiles.length
, pubsub: pubsub
}
;
if(cache)
_initCache(cache);

filesLoop:
for(i=0,l=fontFiles.length;i<l;i++) {
fontInfo = fontFiles[i];
pubsub.publish('prepareFont', i, fontInfo.name, l);
onload = onLoadFont.bind(loaderState, i, fontInfo.name);
// The timeout thing is handy to slow down the load progress,
// if development is done on that part.
// setTimeout(function(fontInfo, onload) {
loadFont(fontInfo, onload);
// }.bind(null, fontInfo, onload), Math.random() * 5000);
task = {
state: loaderState
, index: i
, name: fontInfo.name
};
onload = null;
if(cache) {
key = fontInfo.key;
if(key in cache.loaded) {
data = cache.loaded[key];
// execute async
setTimeout(_publishLoaded.bind(null, task, data), 0);
continue filesLoop;
}
// put into queue
if(!(key in cache.queues)) {
// initiate queue
cache.queues[key] = [];
onload = _onLoadQueued.bind(null, cache, key);
}
cache.queues[key].push(task);
}
else // no cache
onload = _onLoadFont.bind(null, task);

// if no cache or of queue was just initiated
if(onload)
loadFont(fontInfo, onload);
}
}

Expand Down