diff --git a/fonts.js b/fonts.js
index 728bc5c68..381d37c09 100644
--- a/fonts.js
+++ b/fonts.js
@@ -64,8 +64,15 @@ var Fonts = {
       var unicode = encoding[charcode];
 
       // Check if the glyph has already been converted
-      if (unicode instanceof Name)
-        unicode = encoding[unicode] = GlyphsUnicode[unicode.name];
+      // if (unicode instanceof Name)
+      try {
+        if (!IsNum(unicode))
+        // if ("name" in unicode)
+          unicode = encoding[unicode] = GlyphsUnicode[unicode.name];
+        
+      } catch(e) {
+        console.log("FAIL");
+      }
 
       // Handle surrogate pairs
       if (unicode > 0xFFFF) {
@@ -165,6 +172,7 @@ var Font = (function () {
         warn("Font " + properties.type + " is not supported");
         break;
     }
+    this.data = data;
 
     Fonts[name] = {
       data: data,
diff --git a/pdf.js b/pdf.js
index 3179f42ec..27ccc6c10 100644
--- a/pdf.js
+++ b/pdf.js
@@ -3819,6 +3819,9 @@ var CanvasGraphics = (function() {
 
             this.current.fontSize = size;
             this.ctx.font = this.current.fontSize +'px "' + fontName + '", Symbol';
+            if (this.ctx.$setFont) {
+              this.ctx.$setFont(fontName);
+            }
         },
         setTextRenderingMode: function(mode) {
             TODO("text rendering mode");
diff --git a/viewer_worker.html b/viewer_worker.html
index 6443b22c1..fe3319d62 100644
--- a/viewer_worker.html
+++ b/viewer_worker.html
@@ -1,6 +1,9 @@
 <html>
     <head>
         <title>Simple pdf.js page worker viewer</title>
+        <script type="text/javascript" src="fonts.js"></script>
+        <script type="text/javascript" src="glyphlist.js"></script>
+        <script type="text/javascript" src="pdf.js"></script>
         <script type="text/javascript" src="worker/client.js"></script>
 <script>
 
diff --git a/worker/canvas.js b/worker/canvas.js
index d6f5a0a25..bc96d8453 100644
--- a/worker/canvas.js
+++ b/worker/canvas.js
@@ -119,7 +119,8 @@ function CanvasProxy(width, height) {
   "$addCurrentX",
   "$saveCurrentX",
   "$restoreCurrentX",
-  "$showText"
+  "$showText",
+  "$setFont"
   ];
 
   function buildFuncCall(name) {
diff --git a/worker/client.js b/worker/client.js
index 5d0cae05a..78568252f 100644
--- a/worker/client.js
+++ b/worker/client.js
@@ -18,12 +18,115 @@ if (typeof console.time == "undefined") {
   };
 }
 
+function FontWorker() {
+  this.worker = new Worker("worker/font.js");
+  this.fontsWaiting = 0;
+  this.fontsWaitingCallbacks = [];
+
+  // Listen to the WebWorker for data and call actionHandler on it.
+  this.worker.onmessage = function(event) {
+    var data = event.data;
+    var actionHandler = this.actionHandler
+    if (data.action in actionHandler) {
+      actionHandler[data.action].call(this, data.data);
+    } else {
+      throw "Unkown action from worker: " + data.action;
+    }
+  }.bind(this);
+}
+
+FontWorker.prototype = {
+  actionHandler: {
+    "fonts": function(data) {
+      // console.log("got processed fonts from worker", Object.keys(data));
+      for (name in data) {
+        var base64 = window.btoa(data[name]);
+
+        // Add the @font-face rule to the document
+        var url = "url(data:font/opentype;base64," + base64 + ");";
+        var rule = "@font-face { font-family:'" + name + "';src:" + url + "}";
+        var styleSheet = document.styleSheets[0];
+        styleSheet.insertRule(rule, styleSheet.length);
+
+        // Just adding the font-face to the DOM doesn't make it load. It
+        // seems it's loaded once Gecko notices it's used. Therefore,
+        // add a div on the page using the loaded font.
+        var div = document.createElement("div");
+        var style = 'font-family:"' + name + 
+          '";position: absolute;top:-99999;left:-99999;z-index:-99999';
+        div.setAttribute("style", style);
+        document.body.appendChild(div);
+        this.fontsWaiting --;
+      }
+      
+      // This timeout is necessary right now to make sure the fonts are really
+      // loaded at the point the callbacks are called.
+      setTimeout(function() {
+        // If all fonts are available now, then call all the callbacks.
+        if (this.fontsWaiting == 0) {
+          var callbacks = this.fontsWaitingCallbacks;
+          for (var i = 0; i < callbacks.length; i++) {
+            callbacks[i]();
+          }
+        }        
+      }.bind(this), 100);
+    }
+  },
+
+  ensureFonts: function(data, callback) {
+    var font;
+    var notLoaded = [];
+    for (var i = 0; i < data.length; i++) {
+      font = data[i];
+      if (Fonts[font.name]) {
+        continue;
+      }
+    
+      // Store only the data on Fonts that is needed later on, such that we
+      // hold track on as lease memory as possible.
+      Fonts[font.name] = {
+        properties: {
+          charset:  font.properties.charset
+        },
+        cache:      Object.create(null)
+      };
+
+      // Mark this font to be handled later.
+      notLoaded.push(font);
+      // Increate the number of fonts to wait for.
+      this.fontsWaiting++;
+    }
+    
+    // If there are fonts, that need to get loaded, tell the FontWorker to get
+    // started and push the callback on the waiting-callback-stack.
+    if (notLoaded.length != 0) {
+      // Send the worker the fonts to work on.
+      this.worker.postMessage({
+        action: "fonts",
+        data:   notLoaded
+      });
+      if (callback) {
+        this.fontsWaitingCallbacks.push(callback);
+      }
+    }
+    // All fonts are present? Well, then just call the callback if there is one.
+    else {
+      if (callback) {
+        callback();
+      }
+    }
+  },
+}
+
 function WorkerPDFDoc(canvas) {
   var timer = null
 
   this.ctx = canvas.getContext("2d");
   this.canvas = canvas;
   this.worker = new Worker('worker/pdf.js');
+  this.fontWorker = new FontWorker();
+  this.waitingForFonts = false;
+  this.waitingForFontsCallback = [];
 
   this.numPage = 1;
   this.numPages = null;
@@ -56,6 +159,7 @@ function WorkerPDFDoc(canvas) {
     },
 
     "$showText": function(y, text) {
+      text = Fonts.charsToUnicode(text);
       this.translate(currentX, -1 * y);
       this.fillText(text, 0, 0);
       currentX += this.measureText(text).width;
@@ -136,6 +240,10 @@ function WorkerPDFDoc(canvas) {
         throw "Pattern not found";
       }
       this.strokeStyle = pattern;
+    },
+    
+    "$setFont": function(name) {
+      Fonts.active = name;
     }
   }
 
@@ -187,6 +295,17 @@ function WorkerPDFDoc(canvas) {
       div.setAttribute("style", style);
       document.body.appendChild(div);
     },
+    
+    "fonts": function(data) {
+      this.waitingForFonts = true;
+      this.fontWorker.ensureFonts(data, function() {
+        this.waitingForFonts = false;
+        var callbacks = this.waitingForFontsCallback;
+        for (var i = 0; i < callbacks.length; i++) {
+          callbacks[i]();
+        }
+      }.bind(this));
+    },
 
     "jpeg_stream": function(data) {
       var img = new Image();
@@ -207,9 +326,7 @@ function WorkerPDFDoc(canvas) {
           canvasList[id] = newCanvas;
         }
 
-        // There might be fonts that need to get loaded. Shedule the
-        // rendering at the end of the event queue ensures this.
-        setTimeout(function() {
+        var renderData = function() {
           if (id == 0) {
             console.time("canvas rendering");
             var ctx = this.ctx;
@@ -220,11 +337,18 @@ function WorkerPDFDoc(canvas) {
           }
           renderProxyCanvas(canvasList[id], cmdQueue);
           if (id == 0) console.timeEnd("canvas rendering")
-        }, 0, this);
+        }.bind(this);
+
+        if (this.waitingForFonts) {
+          console.log("want to render, but not all fonts are there", id);
+          this.waitingForFontsCallback.push(renderData);
+        } else {
+          renderData();
+        }
     }
   }
 
-  // List to the WebWorker for data and call actionHandler on it.
+  // Listen to the WebWorker for data and call actionHandler on it.
   this.worker.onmessage = function(event) {
     var data = event.data;
     if (data.action in actionHandler) {
@@ -232,7 +356,7 @@ function WorkerPDFDoc(canvas) {
     } else {
       throw "Unkown action from worker: " + data.action;
     }
-  }
+  }.bind(this)
 }
 
 WorkerPDFDoc.prototype.open = function(url, callback) {
diff --git a/worker/console.js b/worker/console.js
new file mode 100644
index 000000000..e544db7a2
--- /dev/null
+++ b/worker/console.js
@@ -0,0 +1,27 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+
+"use strict";
+
+var consoleTimer = {};
+var console = {
+  log: function log() {
+    var args = Array.prototype.slice.call(arguments);
+    postMessage({
+      action: "log",
+      data: args
+    });
+  },
+  
+  time: function(name) {
+    consoleTimer[name] = Date.now();
+  },
+  
+  timeEnd: function(name) {
+    var time = consoleTimer[name];
+    if (time == null) {
+      throw "Unkown timer name " + name;
+    }
+    this.log("Timer:", name, Date.now() - time);
+  }
+}
diff --git a/worker/font.js b/worker/font.js
new file mode 100644
index 000000000..a8ec5ebd4
--- /dev/null
+++ b/worker/font.js
@@ -0,0 +1,65 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+
+"use strict";
+
+importScripts("console.js");
+
+importScripts("../pdf.js");
+importScripts("../fonts.js");
+importScripts("../glyphlist.js")
+
+function fontDataToString(font) {
+  // Doing postMessage on objects make them lose their "shape". This adds the
+  // "shape" for all required objects agains, such that the encoding works as
+  // expected.
+  var fontFileDict = new Dict();
+  fontFileDict.map = font.file.dict.map;
+
+  var fontFile = new Stream(font.file.bytes, font.file.start, font.file.end - font.file.start, fontFileDict);
+  font.file = new FlateStream(fontFile);
+  
+  // This will encode the font.
+  var fontObj = new Font(font.name, font.file, font.properties);
+
+  // Create string that is used for css later.
+  var str = "";
+  var data = fontObj.data;
+  var length = data.length;
+  for (var j = 0; j < length; j++)
+    str += String.fromCharCode(data[j]);
+  
+  return {
+    str:      str,
+    encoding: font.properties.encoding
+  }
+}
+
+/**
+* Functions to handle data sent by the MainThread.
+*/
+var actionHandler = {
+  "fonts": function(data) {
+    var fontData;
+    var result = {};
+    for (var i = 0; i < data.length; i++) {
+      fontData = data[i];
+      result[fontData.name] = fontDataToString(fontData);
+    }
+    
+    postMessage({
+      action: "fonts",
+      data:   result
+    })
+  },
+}
+
+// Listen to the MainThread for data and call actionHandler on it.
+this.onmessage = function(event) {
+  var data = event.data;
+  if (data.action in actionHandler) {
+    actionHandler[data.action].call(this, data.data);
+  } else {
+    throw "Unkown action from worker: " + data.action;
+  }
+}
\ No newline at end of file
diff --git a/worker/pdf.js b/worker/pdf.js
index c4d16d8d0..d9a7b5319 100644
--- a/worker/pdf.js
+++ b/worker/pdf.js
@@ -27,6 +27,7 @@ var console = {
 }
 
 //
+importScripts("console.js")
 importScripts("canvas.js");
 importScripts("../pdf.js");
 importScripts("../fonts.js");
@@ -65,21 +66,14 @@ onmessage = function(event) {
     page.compile(gfx, fonts);
     console.timeEnd("compile");
 
+    // Send fonts to the main thread.
     console.time("fonts");
-    // Inspect fonts and translate the missing one.
-    var count = fonts.length;
-    for (var i = 0; i < count; i++) {
-      var font = fonts[i];
-      if (Fonts[font.name]) {
-        fontsReady = fontsReady && !Fonts[font.name].loading;
-        continue;
-      }
-
-      // This "builds" the font and sents it over to the main thread.
-      new Font(font.name, font.file, font.properties);
-    }
+    postMessage({
+      action: "fonts",
+      data:   fonts
+    });
     console.timeEnd("fonts");
-
+    
     console.time("display");
     page.display(gfx);
     canvas.flush();