Re-pull m-c in preparation for pushing back.
authorBrendan Eich <brendan@mozilla.org>
Wed, 01 Oct 2008 00:24:49 -0400
changeset 20019 e3499376211cb88a6df6c62cfa9cb2d36aa8634f
parent 20018 2255cddff8effc470c66102a7d874503a20583dc (current diff)
parent 19968 a9838a973cdd044ae123f2ddfbed41d6a591120b (diff)
child 20020 a613924403d65648564e8bb6587d9c30000f2292
push id2577
push userbrendan@mozilla.com
push dateWed, 01 Oct 2008 04:35:27 +0000
treeherdermozilla-central@a613924403d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.1b1pre
Re-pull m-c in preparation for pushing back.
content/base/test/test_bug425201.html
content/media/video/test/sound.ogg
content/media/video/test/test_audio1.html
content/media/video/test/test_audio2.html
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -180,17 +180,16 @@ include $(topsrcdir)/config/rules.mk
 		file_XHR_pass2.txt \
 		file_XHR_pass3.txt \
 		file_XHR_pass3.txt^headers^ \
 		file_XHR_fail1.txt \
 		file_XHR_fail1.txt^headers^ \
 		test_bug428847.html \
 		file_bug428847-1.xhtml \
 		file_bug428847-2.xhtml \
-		test_bug425201.html \
 		test_bug431701.html \
 		test_bug431833.html \
 		test_bug435425.html \
 		bug435425.sjs \
 		bug435425_redirect.sjs \
 		test_bug438519.html \
 		test_bug444722.html \
 		test_bug451376.html \
deleted file mode 100644
--- a/content/base/test/test_bug425201.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=425201
--->
-<head>
-  <title>Test for Bug 425201</title>
-  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=425201">Mozilla Bug 425201</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-  
-</div>
-<pre id="test">
-<script class="testbody" type="text/javascript">
-
-/** Test for Bug 425201 **/
-
-var req = new XMLHttpRequest();
-
-var threw = false;
-try {
-  req.open("GET", "http://www.example.com/", false);
-}
-catch (e) {
-  threw = true;
-}
-
-ok(threw, "Open should have thrown");
-
-threw = false;
-try {
-  req.send(null);
-}
-catch (e) {
-  threw = true;
-}
-
-ok(threw, "Send should have thrown");
-
-</script>
-</pre>
-</body>
-</html>
--- a/content/base/test/test_bug428847.html
+++ b/content/base/test/test_bug428847.html
@@ -12,18 +12,18 @@ https://bugzilla.mozilla.org/show_bug.cg
 <body onload="runtests();">
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=428847">Mozilla Bug 428847</a>
 <script class="testbody" type="text/javascript">
 var iframe1Loaded = false;
 var iframe2Loaded = false;
 
 function runtests()
 {
-  is(iframe1Loaded, true,
-     "Iframe with cross-origin xslt stylesheet failed to load");
+  //is(iframe1Loaded, true,
+  //   "Iframe with cross-origin xslt stylesheet failed to load");
   is(iframe2Loaded, false,
      "Iframe with invalid xslt stylesheet URI didn't fail to load");
 
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 </script>
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -1970,17 +1970,17 @@ nsCanvasRenderingContext2D::SetFont(cons
     gfxFontStyle style(fontStyle->mFont.style,
                        fontStyle->mFont.weight,
                        NSAppUnitsToFloatPixels(fontSize, aupcp),
                        langGroup,
                        fontStyle->mFont.sizeAdjust,
                        fontStyle->mFont.systemFont,
                        fontStyle->mFont.familyNameQuirks);
 
-    CurrentState().fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(fontStyle->mFont.name, &style);
+    CurrentState().fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(fontStyle->mFont.name, &style, presShell->GetPresContext()->GetUserFontSet());
     NS_ASSERTION(CurrentState().fontGroup, "Could not get font group");
     CurrentState().font = font;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetFont(nsAString& font)
 {
--- a/content/html/content/public/nsHTMLAudioElement.h
+++ b/content/html/content/public/nsHTMLAudioElement.h
@@ -31,26 +31,24 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 #include "nsIDOMHTMLAudioElement.h"
-#include "nsIJSNativeInitializer.h"
 #include "nsHTMLMediaElement.h"
 #include "nsVideoDecoder.h"
 
 typedef PRUint16 nsMediaNetworkState;
 typedef PRUint16 nsMediaReadyState;
 
 class nsHTMLAudioElement : public nsHTMLMediaElement,
-                           public nsIDOMHTMLAudioElement,
-                           public nsIJSNativeInitializer
+                           public nsIDOMHTMLAudioElement
 {
 public:
   nsHTMLAudioElement(nsINodeInfo *aNodeInfo, PRBool aFromParser = PR_FALSE);
   virtual ~nsHTMLAudioElement();
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
@@ -64,20 +62,16 @@ public:
   NS_FORWARD_NSIDOMHTMLELEMENT(nsHTMLMediaElement::)
 
   // nsIDOMHTMLMediaElement
   NS_FORWARD_NSIDOMHTMLMEDIAELEMENT(nsHTMLMediaElement::)
 
   // nsIDOMHTMLAudioElement
   NS_DECL_NSIDOMHTMLAUDIOELEMENT
 
-  // nsIJSNativeInitializer
-  NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* aContext,
-                        JSObject* aObj, PRUint32 argc, jsval* argv);
-
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               PRBool aCompileEventHandlers);
   virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
                               PRBool aNullParent = PR_TRUE);
 protected:
   virtual nsresult InitializeDecoder(nsAString& aChosenMediaResource);
--- a/content/html/content/src/Makefile.in
+++ b/content/html/content/src/Makefile.in
@@ -150,13 +150,12 @@ FORCE_STATIC_LIB = 1
 include $(topsrcdir)/config/rules.mk
 
 INCLUDES	+= \
 		-I$(srcdir)/../../../base/src \
 		-I$(srcdir)/../../../events/src \
 		-I$(srcdir)/../../../xbl/src \
 		-I$(srcdir)/../../../../layout/style \
 		-I$(srcdir)/../../../../layout/tables \
-		-I$(srcdir)/../../../../dom/src/base \
 		-I$(srcdir) \
 		$(NULL)
 
 DEFINES += -D_IMPL_NS_LAYOUT
--- a/content/html/content/src/nsHTMLAudioElement.cpp
+++ b/content/html/content/src/nsHTMLAudioElement.cpp
@@ -50,57 +50,36 @@
 #include "nsNodeInfoManager.h"
 #include "plbase64.h"
 #include "nsNetUtil.h"
 #include "prmem.h"
 #include "nsNetUtil.h"
 #include "nsXPCOMStrings.h"
 #include "prlock.h"
 #include "nsThreadUtils.h"
-#include "nsJSUtils.h"
 
 #include "nsIScriptSecurityManager.h"
 #include "nsIXPConnect.h"
 #include "jsapi.h"
 
 #include "nsIRenderingContext.h"
 #include "nsITimer.h"
 
 #include "nsEventDispatcher.h"
 #include "nsIDOMDocumentEvent.h"
 #include "nsIDOMProgressEvent.h"
 #include "nsHTMLMediaError.h"
 
-nsGenericHTMLElement*
-NS_NewHTMLAudioElement(nsINodeInfo *aNodeInfo, PRBool aFromParser)
-{
-  /*
-   * nsHTMLAudioElement's will be created without a nsINodeInfo passed in
-   * if someone says "var audio = new Audio();" in JavaScript, in a case like
-   * that we request the nsINodeInfo from the document's nodeinfo list.
-   */
-  nsCOMPtr<nsINodeInfo> nodeInfo(aNodeInfo);
-  if (!nodeInfo) {
-    nsCOMPtr<nsIDocument> doc =
-      do_QueryInterface(nsContentUtils::GetDocumentFromCaller());
-    NS_ENSURE_TRUE(doc, nsnull);
-
-    nodeInfo = doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::audio, nsnull,
-                                                   kNameSpaceID_None);
-    NS_ENSURE_TRUE(nodeInfo, nsnull);
-  }
-
-  return new nsHTMLAudioElement(nodeInfo);
-}
+NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Audio)
 
 NS_IMPL_ADDREF_INHERITED(nsHTMLAudioElement, nsHTMLMediaElement)
 NS_IMPL_RELEASE_INHERITED(nsHTMLAudioElement, nsHTMLMediaElement)
 
 NS_HTML_CONTENT_INTERFACE_TABLE_HEAD(nsHTMLAudioElement, nsHTMLMediaElement)
-NS_INTERFACE_TABLE_INHERITED2(nsHTMLAudioElement, nsIDOMHTMLAudioElement, nsIJSNativeInitializer)
+  NS_INTERFACE_TABLE_INHERITED1(nsHTMLAudioElement, nsIDOMHTMLAudioElement)
 NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLAudioElement)
 
 NS_IMPL_ELEMENT_CLONE(nsHTMLAudioElement)
 
 
 nsHTMLAudioElement::nsHTMLAudioElement(nsINodeInfo *aNodeInfo, PRBool aFromParser)
   : nsHTMLMediaElement(aNodeInfo, aFromParser)
 {
@@ -134,26 +113,8 @@ void nsHTMLAudioElement::UnbindFromTree(
 
 nsresult nsHTMLAudioElement::InitializeDecoder(nsAString& aChosenMediaResource)
 {
   if (mDecoder) 
     mDecoder->ElementAvailable(this);
 
   return nsHTMLMediaElement::InitializeDecoder(aChosenMediaResource);
 }
-
-NS_IMETHODIMP
-nsHTMLAudioElement::Initialize(nsISupports* aOwner, JSContext* aContext,
-                               JSObject *aObj, PRUint32 argc, jsval *argv)
-{
-  if (argc <= 0) {
-    // Nothing to do here if we don't get any arguments.
-    return NS_OK;
-  }
-
-  // The only (optional) argument is the url of the audio
-  JSString* jsstr = JS_ValueToString(aContext, argv[0]);
-  if (!jsstr)
-    return NS_ERROR_FAILURE;
-
-  nsDependentJSString str(jsstr);
-  return SetAttr(kNameSpaceID_None, nsGkAtoms::src, str, PR_TRUE);
-}
--- a/content/media/video/test/Makefile.in
+++ b/content/media/video/test/Makefile.in
@@ -38,27 +38,24 @@ DEPTH		= ../../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = content/media/video/test
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
-_TEST_FILES = 	test_audio1.html \
-		test_audio2.html \
-                test_autoplay.html \
+_TEST_FILES = 	test_autoplay.html \
                 test_constants.html \
                 test_controls.html \
                 test_currentTime.html \
                 test_defaultPlaybackRate.html \
                 test_networkState.html \
                 test_paused.html \
                 test_playbackRate.html \
                 test_readyState.html \
                 test_start.html \
-                sound.ogg \
 #               test_bug448534.html \
                 320x240.ogg \
                 $(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
deleted file mode 100644
index edda4e9128435b0cc9ba500c9daca90e2be30acf..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/content/media/video/test/test_audio1.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Media test: Audio Constructor Test 1</title>
-  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<pre id="test">
-<script class="testbody" type="text/javascript">
-var timeout = setTimeout(function () {
-                          ok(false, "Test timed out");
-                          SimpleTest.finish();
-                          }, 30000); 
-var a1 = new Audio();
-a1.onload = function() {
-  ok(a1.networkState == a1.LOADED, "Audio onload");
-  clearTimeout(timeout);
-  SimpleTest.finish();
-}
-a1.src = 'sound.ogg';
-
-SimpleTest.waitForExplicitFinish();
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/content/media/video/test/test_audio2.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Media test: Audio Constructor Test 2</title>
-  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<pre id="test">
-<script class="testbody" type="text/javascript">
-var timeout = setTimeout(function () {
-                          ok(false, "Test timed out");
-                          SimpleTest.finish();
-                          }, 30000); 
-var a1 = new Audio('sound.ogg');
-a1.onload = function() {
-  ok(a1.networkState == a1.LOADED, "Audio onload");
-  clearTimeout(timeout);
-  SimpleTest.finish();
-}
-
-SimpleTest.waitForExplicitFinish();
-</script>
-</pre>
-</body>
-</html>
--- a/gfx/public/nsDeviceContext.h
+++ b/gfx/public/nsDeviceContext.h
@@ -56,17 +56,17 @@ class NS_GFX nsFontCache
 {
 public:
   nsFontCache();
   virtual ~nsFontCache();
 
   virtual nsresult Init(nsIDeviceContext* aContext);
   virtual nsresult GetDeviceContext(nsIDeviceContext *&aContext) const;
   virtual nsresult GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
-                                 nsIFontMetrics *&aMetrics);
+                                 nsIFontMetrics *&aMetrics, gfxUserFontSet *aUserFontSet = nsnull);
 
   nsresult   FontMetricsDeleted(const nsIFontMetrics* aFontMetrics);
   nsresult   Compact();
   nsresult   Flush();
   /* printer device context classes may create their own
    * subclasses of nsFontCache (and override this method) and override 
    * DeviceContextImpl::CreateFontCache (see bug 81311).
    */
@@ -95,18 +95,19 @@ public:
   NS_IMETHOD  Init(nsNativeWidget aWidget);
 
   NS_IMETHOD  CreateRenderingContext(nsIView *aView, nsIRenderingContext *&aContext);
   NS_IMETHOD  CreateRenderingContext(nsIWidget *aWidget, nsIRenderingContext *&aContext);
   NS_IMETHOD  CreateRenderingContext(nsIRenderingContext *&aContext){return NS_ERROR_NOT_IMPLEMENTED;}
   NS_IMETHOD  CreateRenderingContextInstance(nsIRenderingContext *&aContext);
 
   NS_IMETHOD  GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
-                            nsIFontMetrics*& aMetrics);
-  NS_IMETHOD  GetMetricsFor(const nsFont& aFont, nsIFontMetrics*& aMetrics);
+                            nsIFontMetrics*& aMetrics, gfxUserFontSet *aUserFontSet = nsnull);
+  NS_IMETHOD  GetMetricsFor(const nsFont& aFont, nsIFontMetrics*& aMetrics, 
+                            gfxUserFontSet *aUserFontSet = nsnull);
 
   NS_IMETHOD FirstExistingFont(const nsFont& aFont, nsString& aFaceName);
 
   NS_IMETHOD GetLocalFontName(const nsString& aFaceName, nsString& aLocalName,
                               PRBool& aAliased);
 
   NS_IMETHOD CreateFontCache();
   NS_IMETHOD FontMetricsDeleted(const nsIFontMetrics* aFontMetrics);
--- a/gfx/public/nsIDeviceContext.h
+++ b/gfx/public/nsIDeviceContext.h
@@ -47,16 +47,17 @@
 // XXX we need only gfxTypes.h, but we cannot include it directly.
 #include "gfxPoint.h"
 
 class nsIView;
 class nsIFontMetrics;
 class nsIWidget;
 class nsIDeviceContextSpec;
 class nsIAtom;
+class gfxUserFontSet;
 
 struct nsFont;
 
 //a cross platform way of specifying a native device context
 typedef void * nsNativeDeviceContext;
 
 /* error codes for printer device contexts */
 #define NS_ERROR_GFX_PRINTER_BASE (1) /* adjustable :-) */
@@ -325,29 +326,33 @@ public:
   NS_IMETHOD  GetSystemFont(nsSystemFontID aID, nsFont *aFont) const = 0;
 
   /**
    * Get the nsIFontMetrics that describe the properties of
    * an nsFont.
    * @param aFont font description to obtain metrics for
    * @param aLangGroup the language group of the document
    * @param aMetrics out parameter for font metrics
+   * @param aUserFontSet user font set
    * @return error status
    */
   NS_IMETHOD  GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
-                            nsIFontMetrics*& aMetrics) = 0;
+                            nsIFontMetrics*& aMetrics, 
+                            gfxUserFontSet *aUserFontSet = nsnull) = 0;
 
   /**
    * Get the nsIFontMetrics that describe the properties of
    * an nsFont.
    * @param aFont font description to obtain metrics for
    * @param aMetrics out parameter for font metrics
+   * @param aUserFontSet user font set
    * @return error status
    */
-  NS_IMETHOD  GetMetricsFor(const nsFont& aFont, nsIFontMetrics*& aMetrics) = 0;
+  NS_IMETHOD  GetMetricsFor(const nsFont& aFont, nsIFontMetrics*& aMetrics, 
+                            gfxUserFontSet *aUserFontSet = nsnull) = 0;
 
   /**
    * Check to see if a particular named font exists.
    * @param aFontName character string of font face name
    * @return NS_OK if font is available, else font is unavailable
    */
   NS_IMETHOD CheckFontExistence(const nsString& aFaceName) = 0;
   NS_IMETHOD FirstExistingFont(const nsFont& aFont, nsString& aFaceName) = 0;
--- a/gfx/public/nsIFontMetrics.h
+++ b/gfx/public/nsIFontMetrics.h
@@ -40,16 +40,17 @@
 
 #include "nsISupports.h"
 #include "nsCoord.h"
 #include "nsFont.h"
 
 class nsString;
 class nsIDeviceContext;
 class nsIAtom;
+class gfxUserFontSet;
 
 // IID for the nsIFontMetrics interface
 #define NS_IFONT_METRICS_IID   \
 { 0xc74cb770, 0xa33e, 0x11d1, \
 { 0xa8, 0x24, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9 } }
 
 //----------------------------------------------------------------------
 
@@ -82,17 +83,17 @@ public:
 
   /**
    * Initialize the font metrics. Call this after creating the font metrics.
    * Font metrics you get from the font cache do NOT need to be initialized
    *
    * @see nsIDeviceContext#GetMetricsFor()
    */
   NS_IMETHOD  Init(const nsFont& aFont, nsIAtom* aLangGroup,
-                   nsIDeviceContext *aContext) = 0;
+                   nsIDeviceContext *aContext, gfxUserFontSet *aUserFontSet = nsnull) = 0;
 
   /**
    * Destroy this font metrics. This breaks the association between
    * the font metrics and the device context.
    */
   NS_IMETHOD  Destroy() = 0;
 
   /**
--- a/gfx/src/nsDeviceContext.cpp
+++ b/gfx/src/nsDeviceContext.cpp
@@ -45,16 +45,17 @@
 #include "nsVoidArray.h"
 #include "nsIFontMetrics.h"
 #include "nsHashtable.h"
 #include "nsILanguageAtomService.h"
 #include "nsIServiceManager.h"
 #include "nsUnicharUtils.h"
 #include "nsCRT.h"
 #include "nsIRenderingContext.h"
+#include "gfxUserFontSet.h"
 
 NS_IMPL_ISUPPORTS3(DeviceContextImpl, nsIDeviceContext, nsIObserver, nsISupportsWeakReference)
 
 DeviceContextImpl::DeviceContextImpl()
 {
   mAppUnitsPerDevPixel = -1;
   mAppUnitsPerInch = -1;
   mAppUnitsPerDevNotScaledPixel = -1;
@@ -208,48 +209,51 @@ DeviceContextImpl::GetLocaleLangGroup(vo
     }
     if (!mLocaleLangGroup) {
       mLocaleLangGroup = do_GetAtom("x-western");
     }
   }
 }
 
 NS_IMETHODIMP DeviceContextImpl::GetMetricsFor(const nsFont& aFont,
-  nsIAtom* aLangGroup, nsIFontMetrics*& aMetrics)
+  nsIAtom* aLangGroup, nsIFontMetrics*& aMetrics, gfxUserFontSet *aUserFontSet)
 {
   if (nsnull == mFontCache) {
     nsresult  rv = CreateFontCache();
     if (NS_FAILED(rv)) {
       aMetrics = nsnull;
       return rv;
     }
     // XXX temporary fix for performance problem -- erik
     GetLocaleLangGroup();
   }
 
   // XXX figure out why aLangGroup is NULL sometimes
   if (!aLangGroup) {
     aLangGroup = mLocaleLangGroup;
   }
 
-  return mFontCache->GetMetricsFor(aFont, aLangGroup, aMetrics);
+  return mFontCache->GetMetricsFor(aFont, aLangGroup, aMetrics, aUserFontSet);
 }
 
-NS_IMETHODIMP DeviceContextImpl::GetMetricsFor(const nsFont& aFont, nsIFontMetrics*& aMetrics)
+NS_IMETHODIMP DeviceContextImpl::GetMetricsFor(const nsFont& aFont, 
+                                               nsIFontMetrics*& aMetrics, 
+                                               gfxUserFontSet *aUserFontSet)
 {
   if (nsnull == mFontCache) {
     nsresult  rv = CreateFontCache();
     if (NS_FAILED(rv)) {
       aMetrics = nsnull;
       return rv;
     }
     // XXX temporary fix for performance problem -- erik
     GetLocaleLangGroup();
   }
-  return mFontCache->GetMetricsFor(aFont, mLocaleLangGroup, aMetrics);
+  return mFontCache->GetMetricsFor(aFont, mLocaleLangGroup, 
+                                   aMetrics, aUserFontSet);
 }
 
 NS_IMETHODIMP DeviceContextImpl::GetDepth(PRUint32& aDepth)
 {
   aDepth = 24;
   return NS_OK;
 }
 
@@ -464,17 +468,17 @@ nsFontCache::GetDeviceContext(nsIDeviceC
 {
   aContext = mContext;
   NS_IF_ADDREF(aContext);
   return NS_OK;
 }
 
 nsresult
 nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
-  nsIFontMetrics *&aMetrics)
+  nsIFontMetrics *&aMetrics, gfxUserFontSet *aUserFontSet)
 {
   // First check our cache
   // start from the end, which is where we put the most-recent-used element
 
   nsIFontMetrics* fm;
   PRInt32 n = mFontMetrics.Count() - 1;
   for (PRInt32 i = n; i >= 0; --i) {
     fm = static_cast<nsIFontMetrics*>(mFontMetrics[i]);
@@ -492,17 +496,17 @@ nsFontCache::GetMetricsFor(const nsFont&
     }
   }
 
   // It's not in the cache. Get font metrics and then cache them.
 
   aMetrics = nsnull;
   nsresult rv = CreateFontMetricsInstance(&fm);
   if (NS_FAILED(rv)) return rv;
-  rv = fm->Init(aFont, aLangGroup, mContext);
+  rv = fm->Init(aFont, aLangGroup, mContext, aUserFontSet);
   if (NS_SUCCEEDED(rv)) {
     // the mFontMetrics list has the "head" at the end, because append is
     // cheaper than insert
     mFontMetrics.AppendElement(fm);
     aMetrics = fm;
     NS_ADDREF(aMetrics);
     return NS_OK;
   }
@@ -511,17 +515,17 @@ nsFontCache::GetMetricsFor(const nsFont&
 
   // One reason why Init() fails is because the system is running out of resources. 
   // e.g., on Win95/98 only a very limited number of GDI objects are available.
   // Compact the cache and try again.
 
   Compact();
   rv = CreateFontMetricsInstance(&fm);
   if (NS_FAILED(rv)) return rv;
-  rv = fm->Init(aFont, aLangGroup, mContext);
+  rv = fm->Init(aFont, aLangGroup, mContext, aUserFontSet);
   if (NS_SUCCEEDED(rv)) {
     mFontMetrics.AppendElement(fm);
     aMetrics = fm;
     NS_ADDREF(aMetrics);
     return NS_OK;
   }
   fm->Destroy();
   NS_RELEASE(fm);
--- a/gfx/src/thebes/nsThebesFontMetrics.cpp
+++ b/gfx/src/thebes/nsThebesFontMetrics.cpp
@@ -39,16 +39,17 @@
 #include "nsThebesFontMetrics.h"    
 #include "nsFont.h"
 
 #include "nsString.h"
 #include <stdio.h>
 
 #include "gfxTextRunCache.h"
 #include "gfxPlatform.h"
+#include "gfxUserFontSet.h"
 
 NS_IMPL_ISUPPORTS1(nsThebesFontMetrics, nsIFontMetrics)
 
 #include <stdlib.h>
 
 nsThebesFontMetrics::nsThebesFontMetrics()
 {
     mFontStyle = nsnull;
@@ -58,17 +59,18 @@ nsThebesFontMetrics::nsThebesFontMetrics
 nsThebesFontMetrics::~nsThebesFontMetrics()
 {
     delete mFontStyle;
     //delete mFontGroup;
 }
 
 NS_IMETHODIMP
 nsThebesFontMetrics::Init(const nsFont& aFont, nsIAtom* aLangGroup,
-                          nsIDeviceContext *aContext)
+                          nsIDeviceContext *aContext, 
+                          gfxUserFontSet *aUserFontSet)
 {
     mFont = aFont;
     mLangGroup = aLangGroup;
     mDeviceContext = (nsThebesDeviceContext*)aContext;
     mP2A = mDeviceContext->AppUnitsPerDevPixel();
     mIsRightToLeft = PR_FALSE;
     mTextRunRTL = PR_FALSE;
 
@@ -81,17 +83,18 @@ nsThebesFontMetrics::Init(const nsFont& 
         langGroup.Assign(lg);
     }
 
     mFontStyle = new gfxFontStyle(aFont.style, aFont.weight, size, langGroup,
                                   aFont.sizeAdjust, aFont.systemFont,
                                   aFont.familyNameQuirks);
 
     mFontGroup =
-        gfxPlatform::GetPlatform()->CreateFontGroup(aFont.name, mFontStyle);
+        gfxPlatform::GetPlatform()->CreateFontGroup(aFont.name, mFontStyle, 
+                                                    aUserFontSet);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsThebesFontMetrics::Destroy()
 {
     return NS_OK;
--- a/gfx/src/thebes/nsThebesFontMetrics.h
+++ b/gfx/src/thebes/nsThebesFontMetrics.h
@@ -52,17 +52,18 @@ class nsThebesFontMetrics : public nsITh
 {
 public:
     nsThebesFontMetrics();
     virtual ~nsThebesFontMetrics();
 
     NS_DECL_ISUPPORTS
 
     NS_IMETHOD  Init(const nsFont& aFont, nsIAtom* aLangGroup,
-                     nsIDeviceContext *aContext);
+                     nsIDeviceContext *aContext, 
+                     gfxUserFontSet *aUserFontSet = nsnull);
     NS_IMETHOD  Destroy();
     NS_IMETHOD  GetXHeight(nscoord& aResult);
     NS_IMETHOD  GetSuperscriptOffset(nscoord& aResult);
     NS_IMETHOD  GetSubscriptOffset(nscoord& aResult);
     NS_IMETHOD  GetStrikeout(nscoord& aOffset, nscoord& aSize);
     NS_IMETHOD  GetUnderline(nscoord& aOffset, nscoord& aSize);
     NS_IMETHOD  GetHeight(nscoord &aHeight);
     NS_IMETHOD  GetInternalLeading(nscoord &aLeading);
--- a/gfx/thebes/public/Makefile.in
+++ b/gfx/thebes/public/Makefile.in
@@ -26,16 +26,17 @@ EXPORTS		= 	gfxASurface.h \
 			gfxPlatform.h \
 			gfxPoint.h \
 			gfxRect.h \
 			gfxSkipChars.h \
 			gfxTypes.h \
 			gfxTextRunCache.h \
 			gfxTextRunWordCache.h \
 			gfxUtils.h \
+			gfxUserFontSet.h \
 			$(NULL)
 
 EXPORTS += gfxFontTest.h
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 EXPORTS	+=	gfxWindowsFonts.h \
 		gfxWindowsPlatform.h \
 		gfxWindowsSurface.h \
--- a/gfx/thebes/public/gfxAtsuiFonts.h
+++ b/gfx/thebes/public/gfxAtsuiFonts.h
@@ -108,17 +108,18 @@ protected:
     void InitMetrics(ATSUFontID aFontID, ATSFontRef aFontRef);
 
     virtual PRBool SetupCairoFont(gfxContext *aContext);
 };
 
 class THEBES_API gfxAtsuiFontGroup : public gfxFontGroup {
 public:
     gfxAtsuiFontGroup(const nsAString& families,
-                      const gfxFontStyle *aStyle);
+                      const gfxFontStyle *aStyle,
+                      gfxUserFontSet *aUserFontSet);
     virtual ~gfxAtsuiFontGroup() {};
 
     virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
 
     virtual gfxTextRun *MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
                                     const Parameters* aParams, PRUint32 aFlags);
     virtual gfxTextRun *MakeTextRun(const PRUint8* aString, PRUint32 aLength,
                                     const Parameters* aParams, PRUint32 aFlags);
@@ -132,30 +133,34 @@ public:
                              PRBool aWrapped, gfxTextRun *aTextRun);
 
     gfxAtsuiFont* GetFontAt(PRInt32 aFontIndex) {
         return static_cast<gfxAtsuiFont*>(static_cast<gfxFont*>(mFonts[aFontIndex]));
     }
 
     PRBool HasFont(ATSUFontID fid);
 
-    inline gfxAtsuiFont* WhichFontSupportsChar(nsTArray< nsRefPtr<gfxFont> >& aFontList, PRUint32 aCh) {
+    inline gfxAtsuiFont* WhichFontSupportsChar(nsTArray< nsRefPtr<gfxFont> >& aFontList, 
+                                               PRUint32 aCh)
+    {
         PRUint32 len = aFontList.Length();
         for (PRUint32 i = 0; i < len; i++) {
             gfxAtsuiFont* font = static_cast<gfxAtsuiFont*>(aFontList.ElementAt(i).get());
             if (font->TestCharacterMap(aCh))
                 return font;
         }
         return nsnull;
     }
 
-   // search through pref fonts for a character, return nsnull if no matching pref font
-   already_AddRefed<gfxFont> WhichPrefFontSupportsChar(PRUint32 aCh);
-   
-   already_AddRefed<gfxFont> WhichSystemFontSupportsChar(PRUint32 aCh);
+    // search through pref fonts for a character, return nsnull if no matching pref font
+    already_AddRefed<gfxFont> WhichPrefFontSupportsChar(PRUint32 aCh);
+
+    already_AddRefed<gfxFont> WhichSystemFontSupportsChar(PRUint32 aCh);
+
+    void UpdateFontList();
 
 protected:
     static PRBool FindATSUFont(const nsAString& aName,
                                const nsACString& aGenericName,
                                void *closure);
 
     PRUint32 GuessMaximumStringLength();
 
--- a/gfx/thebes/public/gfxFont.h
+++ b/gfx/thebes/public/gfxFont.h
@@ -46,28 +46,28 @@
 #include "gfxPoint.h"
 #include "gfxFontUtils.h"
 #include "nsTArray.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "gfxSkipChars.h"
 #include "gfxRect.h"
 #include "nsExpirationTracker.h"
-#include "nsMathUtils.h"
-#include "nsBidiUtils.h"
 
 #ifdef DEBUG
 #include <stdio.h>
 #endif
 
 class gfxContext;
 class gfxTextRun;
 class nsIAtom;
 class gfxFont;
 class gfxFontGroup;
+class gfxUserFontSet;
+class gfxUserFontData;
 
 #define FONT_STYLE_NORMAL              0
 #define FONT_STYLE_ITALIC              1
 #define FONT_STYLE_OBLIQUE             2
 
 #define FONT_WEIGHT_NORMAL             400
 #define FONT_WEIGHT_BOLD               700
 
@@ -135,87 +135,108 @@ struct THEBES_API gfxFontStyle {
             (systemFont == other.systemFont) &&
             (familyNameQuirks == other.familyNameQuirks) &&
             (weight == other.weight) &&
             (langGroup.Equals(other.langGroup)) &&
             (sizeAdjust == other.sizeAdjust);
     }
 };
 
-
 class gfxFontEntry {
 public:
     THEBES_INLINE_DECL_REFCOUNTING(gfxFontEntry)
 
     gfxFontEntry(const nsAString& aName) : 
-        mName(aName), mCmapInitialized(PR_FALSE)
+        mName(aName), mIsProxy(PR_FALSE), mIsValid(PR_TRUE), 
+        mIsBadUnderlineFont(PR_FALSE), 
+        mCmapInitialized(PR_FALSE), mUserFontData(nsnull)
     { }
 
     gfxFontEntry(const gfxFontEntry& aEntry) : 
-        mName(aEntry.mName), mItalic(aEntry.mItalic), mFixedPitch(aEntry.mFixedPitch),
-        mUnicodeFont(aEntry.mUnicodeFont), mSymbolFont(aEntry.mSymbolFont), mTrueType(aEntry.mTrueType),
-        mIsType1(aEntry.mIsType1), mWeight(aEntry.mWeight), mCmapInitialized(aEntry.mCmapInitialized),
-        mCharacterMap(aEntry.mCharacterMap)
+        mName(aEntry.mName), mItalic(aEntry.mItalic), 
+        mFixedPitch(aEntry.mFixedPitch), mUnicodeFont(aEntry.mUnicodeFont), 
+        mSymbolFont(aEntry.mSymbolFont), mTrueType(aEntry.mTrueType),
+        mIsType1(aEntry.mIsType1), mIsProxy(aEntry.mIsProxy), 
+        mIsValid(aEntry.mIsValid), mIsBadUnderlineFont(aEntry.mIsBadUnderlineFont),
+        mWeight(aEntry.mWeight), mCmapInitialized(aEntry.mCmapInitialized),
+        mCharacterMap(aEntry.mCharacterMap), mUserFontData(aEntry.mUserFontData)
     { }
 
     virtual ~gfxFontEntry();
 
     // unique name for the face, *not* the family
     const nsString& Name() const { return mName; }
 
     PRInt32 Weight() { return mWeight; }
 
     PRBool IsFixedPitch() { return mFixedPitch; }
     PRBool IsItalic() { return mItalic; }
-    PRBool IsBold() { return mWeight >= 6; } // bold == weights 600 and above
+    PRBool IsBold() { return mWeight >= 600; } // bold == weights 600 and above
 
     inline PRBool HasCharacter(PRUint32 ch) {
         if (mCharacterMap.test(ch))
             return PR_TRUE;
             
         return TestCharacterMap(ch);
     }
 
     virtual PRBool TestCharacterMap(PRUint32 aCh);
     virtual nsresult ReadCMAP() { return 0; }
 
-    nsString mName;
+    nsString         mName;
 
     PRPackedBool     mItalic      : 1;
     PRPackedBool     mFixedPitch  : 1;
 
     PRPackedBool     mUnicodeFont : 1;
     PRPackedBool     mSymbolFont  : 1;
     PRPackedBool     mTrueType    : 1;
     PRPackedBool     mIsType1     : 1;
+    PRPackedBool     mIsProxy     : 1;
+    PRPackedBool     mIsValid     : 1;
+
+    PRPackedBool     mIsBadUnderlineFont : 1;
 
     PRUint16         mWeight;
+    PRUint16         mStretch;
 
     PRPackedBool     mCmapInitialized;
     gfxSparseBitSet  mCharacterMap;
+    gfxUserFontData* mUserFontData;
+
+protected:
+    gfxFontEntry() :
+        mIsProxy(PR_FALSE), mIsValid(PR_TRUE), 
+        mCmapInitialized(PR_FALSE), mUserFontData(nsnull)
+    { }
 };
 
 
 class gfxFontFamily {
 public:
     THEBES_INLINE_DECL_REFCOUNTING(gfxFontFamily)
 
     gfxFontFamily(const nsAString& aName) :
         mName(aName) { }
 
     virtual ~gfxFontFamily() { }
 
     const nsString& Name() { return mName; }
 
-    // choose a specific face to match a style using CSS font matching rules (weight matching occurs here)
-    gfxFontEntry *FindFontForStyle(const gfxFontStyle& aFontStyle, PRBool& aNeedsBold);
+    // choose a specific face to match a style using CSS font matching
+    // rules (weight matching occurs here)
+    gfxFontEntry *FindFontForStyle(const gfxFontStyle& aFontStyle, 
+                                   PRBool& aNeedsBold);
 
 protected:
-    // fills in an array with weights of faces that match style, returns number of weights in array
-    virtual PRBool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], const gfxFontStyle& aFontStyle) { return PR_FALSE; }
+    // fills in an array with weights of faces that match style, returns
+   // number of weights in array
+    virtual PRBool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], 
+                                       const gfxFontStyle& aFontStyle) 
+    { return PR_FALSE; }
 
     nsString mName;
 };
 
 struct gfxTextRange {
     gfxTextRange(PRUint32 aStart,  PRUint32 aEnd) : start(aStart), end(aEnd) { }
     PRUint32 Length() const { return end - start; }
     nsRefPtr<gfxFont> font;
@@ -346,17 +367,17 @@ public:
 
     // returns INVALID_WIDTH => not a contained glyph
     // Otherwise the glyph has no before-bearing or vertical bearings,
     // and the result is its width measured from the baseline origin, in
     // appunits.
     PRUint16 GetContainedGlyphWidthAppUnits(PRUint32 aGlyphID) const {
         return mContainedGlyphWidths.Get(aGlyphID);
     }
-    
+
     PRBool IsGlyphKnown(PRUint32 aGlyphID) const {
         return mContainedGlyphWidths.Get(aGlyphID) != INVALID_WIDTH ||
             mTightGlyphExtents.GetEntry(aGlyphID) != nsnull;
     }
 
     PRBool IsGlyphKnownWithTightExtents(PRUint32 aGlyphID) const {
         return mTightGlyphExtents.GetEntry(aGlyphID) != nsnull;
     }
@@ -633,17 +654,17 @@ public:
     virtual void SetupGlyphExtents(gfxContext *aContext, PRUint32 aGlyphID,
                                    PRBool aNeedTight, gfxGlyphExtents *aExtents);
 
     // This is called by the default Draw() implementation above.
     virtual PRBool SetupCairoFont(gfxContext *aContext) = 0;
 
     PRBool IsSyntheticBold() { return mSyntheticBoldOffset != 0; }
     PRUint32 GetSyntheticBoldOffset() { return mSyntheticBoldOffset; }
-    
+
     gfxFontEntry *GetFontEntry() { return mFontEntry.get(); }
     PRBool HasCharacter(PRUint32 ch) {
         if (!mIsValid)
             return PR_FALSE;
         return mFontEntry->HasCharacter(ch); 
     }
 
 protected:
@@ -670,17 +691,17 @@ public:
     // Flags in the mask 0x0000F000 are reserved for per-platform fonts
     // Flags in the mask 0x00000FFF are set by the textrun creator.
     enum {
         CACHE_TEXT_FLAGS    = 0xF0000000,
         USER_TEXT_FLAGS     = 0x0FFF0000,
         PLATFORM_TEXT_FLAGS = 0x0000F000,
         TEXTRUN_TEXT_FLAGS  = 0x00000FFF,
         SETTABLE_FLAGS      = CACHE_TEXT_FLAGS | USER_TEXT_FLAGS,
-      
+
         /**
          * When set, the text string pointer used to create the text run
          * is guaranteed to be available during the lifetime of the text run.
          */
         TEXT_IS_PERSISTENT           = 0x0001,
         /**
          * When set, the text is known to be all-ASCII (< 128).
          */
@@ -1380,16 +1401,19 @@ public:
         // appunits width of the ligature part; includes before-spacing
         // when the part is at the start of the ligature, and after-spacing
         // when the part is as the end of the ligature
         gfxFloat mPartWidth;
         
         PRPackedBool mClipBeforePart;
         PRPackedBool mClipAfterPart;
     };
+    
+    // user font set generation when text run was created
+    PRUint64 GetUserFontSetGeneration() { return mUserFontSetGeneration; }
 
 #ifdef DEBUG
     // number of entries referencing this textrun in the gfxTextRunWordCache
     PRUint32 mCachedWords;
     
     void Dump(FILE* aOutput);
 #endif
 
@@ -1483,26 +1507,25 @@ private:
     void             *mUserData;
     gfxFontGroup     *mFontGroup; // addrefed
     gfxSkipChars      mSkipChars;
     nsExpirationState mExpirationState;
     PRUint32          mAppUnitsPerDevUnit;
     PRUint32          mFlags;
     PRUint32          mCharacterCount;
     PRUint32          mHashCode;
+    PRUint64          mUserFontSetGeneration; // user font set generation when text run created
 };
 
 class THEBES_API gfxFontGroup : public gfxTextRunFactory {
 protected:
-    gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle);
+    gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle, gfxUserFontSet *aUserFontSet = nsnull);
 
 public:
-    virtual ~gfxFontGroup() {
-        mFonts.Clear();
-    }
+    virtual ~gfxFontGroup();
 
     virtual gfxFont *GetFontAt(PRInt32 i) {
         return static_cast<gfxFont*>(mFonts[i]);
     }
     virtual PRUint32 FontListLength() const {
         return mFonts.Length();
     }
 
@@ -1514,30 +1537,18 @@ public:
     const gfxFontStyle *GetStyle() const { return &mStyle; }
 
     virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle) = 0;
 
     /**
      * The listed characters should not be passed in to MakeTextRun and should
      * be treated as invisible and zero-width.
      */
-    static PRBool IsInvalidChar(PRUnichar ch) {
-        if (ch >= 32) {
-            return ch == 0x0085/*NEL*/ ||
-                ((ch & 0xFF00) == 0x2000 /* Unicode control character */ &&
-                 (ch == 0x200B/*ZWSP*/ || ch == 0x2028/*LSEP*/ || ch == 0x2029/*PSEP*/ ||
-                  IS_BIDI_CONTROL_CHAR(ch)));
-        }
-        // We could just blacklist all control characters, but it seems better
-        // to only blacklist the ones we know cause problems for native font
-        // engines.
-        return ch == 0x0B || ch == '\t' || ch == '\r' || ch == '\n' || ch == '\f' ||
-            (ch >= 0x1c && ch <= 0x1f);
-    }
-
+    static PRBool IsInvalidChar(PRUnichar ch);
+    
     /**
      * Make a textrun for an empty string. This is fast; if you call it,
      * don't bother caching the result.
      */
     gfxTextRun *MakeEmptyTextRun(const Parameters *aParams, PRUint32 aFlags);
     /**
      * Make a textrun for a single ASCII space. This is fast; if you call it,
      * don't bother caching the result.
@@ -1562,17 +1573,17 @@ public:
                                     const Parameters *aParams, PRUint32 aFlags) = 0;
 
     /* helper function for splitting font families on commas and
      * calling a function for each family to fill the mFonts array
      */
     typedef PRBool (*FontCreationCallback) (const nsAString& aName,
                                             const nsACString& aGenericName,
                                             void *closure);
-    static PRBool ForEachFont(const nsAString& aFamilies,
+    /*static*/ PRBool ForEachFont(const nsAString& aFamilies,
                               const nsACString& aLangGroup,
                               FontCreationCallback fc,
                               void *closure);
     PRBool ForEachFont(FontCreationCallback fc, void *closure);
 
     const nsString& GetFamilies() { return mFamilies; }
 
     // This returns the preferred underline for this font group.
@@ -1590,37 +1601,50 @@ public:
     already_AddRefed<gfxFont> FindFontForChar(PRUint32 ch, PRUint32 prevCh, PRUint32 nextCh, gfxFont *aPrevMatchedFont);
 
     virtual already_AddRefed<gfxFont> WhichPrefFontSupportsChar(PRUint32 aCh) { return nsnull; }
 
     virtual already_AddRefed<gfxFont> WhichSystemFontSupportsChar(PRUint32 aCh) { return nsnull; }
 
     void ComputeRanges(nsTArray<gfxTextRange>& mRanges, const PRUnichar *aString, PRUint32 begin, PRUint32 end);
 
+    gfxUserFontSet* GetUserFontSet();
+    void SetUserFontSet(gfxUserFontSet *aUserFontSet);
+
+    // With downloadable fonts, the composition of the font group can change as fonts are downloaded
+    // for each change in state of the user font set, the generation value is bumped to avoid picking up
+    // previously created text runs in the text run word cache.  For font groups based on stylesheets
+    // with no @font-face rule, this always returns 0.
+    PRUint64 GetGeneration();
+
+    virtual void UpdateFontList() { }
 
 protected:
     nsString mFamilies;
     gfxFontStyle mStyle;
     nsTArray< nsRefPtr<gfxFont> > mFonts;
     gfxFloat mUnderlineOffset;
 
+    gfxUserFontSet* mUserFontSet;
+    PRUint64 mCurrGeneration;  // track the current user font set generation, rebuild font list if needed
+
     // Init this font group's font metrics. If there no bad fonts, you don't need to call this.
     // But if there are one or more bad fonts which have bad underline offset,
     // you should call this with the *first* bad font.
     void InitMetricsForBadFont(gfxFont* aBadFont);
 
     /* If aResolveGeneric is true, then CSS/Gecko generic family names are
      * replaced with preferred fonts.
      *
      * If aResolveFontName is true then fc() is called only for existing fonts
      * and with actual font names.  If false then fc() is called with each
      * family name in aFamilies (after resolving CSS/Gecko generic family names
      * if aResolveGeneric).
      */
-    static PRBool ForEachFontInternal(const nsAString& aFamilies,
+    /*static*/ PRBool ForEachFontInternal(const nsAString& aFamilies,
                                       const nsACString& aLangGroup,
                                       PRBool aResolveGeneric,
                                       PRBool aResolveFontName,
                                       FontCreationCallback fc,
                                       void *closure);
 
     static PRBool FontResolverProc(const nsAString& aName, void *aClosure);
 
--- a/gfx/thebes/public/gfxFontTest.h
+++ b/gfx/thebes/public/gfxFontTest.h
@@ -39,16 +39,17 @@
 #define GFX_FONT_TEST_H
 
 #include "nsString.h"
 #include "nsTArray.h"
 
 #include "cairo.h"
 
 #include "gfxFont.h"
+#include "gfxUserFontSet.h"
 
 struct THEBES_API gfxFontTestItem {
     gfxFontTestItem(const nsCString& fontName,
                     cairo_glyph_t *cglyphs, int nglyphs)
         : platformFont(fontName)
     {
         glyphs = new cairo_glyph_t[nglyphs];
         memcpy (glyphs, cglyphs, sizeof(cairo_glyph_t) * nglyphs);
--- a/gfx/thebes/public/gfxFontUtils.h
+++ b/gfx/thebes/public/gfxFontUtils.h
@@ -307,43 +307,58 @@ public:
         const PRUint8 *buf = (PRUint8*) aBuf;
         PRUint32 index = aIndex << 1;
         return (buf[index] << 8) | buf[index+1];
     }
     
     static inline PRUint32
     ReadLongAt(const PRUint8 *aBuf, PRUint32 aIndex)
     {
-        return ((aBuf[aIndex] << 24) | (aBuf[aIndex + 1] << 16) | (aBuf[aIndex + 2] << 8) | (aBuf[aIndex + 3]));
+        return ((aBuf[aIndex] << 24) | (aBuf[aIndex + 1] << 16) | 
+                (aBuf[aIndex + 2] << 8) | (aBuf[aIndex + 3]));
     }
     
     static nsresult
-    ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap);
+    ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength, 
+                          gfxSparseBitSet& aCharacterMap);
     
     static nsresult 
-    ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap);
+    ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength, 
+                         gfxSparseBitSet& aCharacterMap);
 
     static nsresult
     ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap,
              PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont);
+      
+#ifdef XP_WIN
+    // given a TrueType/OpenType data file, produce a EOT-format header
+    // for use with Windows T2Embed API AddFontResource type API's
+    // effectively hide existing fonts with matching names aHeaderLen is
+    // the size of the header buffer on input, the actual size of the
+    // EOT header on output aIsCFF returns whether the font has PS style
+    // glyphs or not (as opposed to TrueType glyphs)
+    static nsresult
+    MakeEOTHeader(nsIFile *aFontData, nsTArray<PRUint8> *aHeader, PRBool *aIsCFF);
+#endif
 
     static inline bool IsJoiner(PRUint32 ch) {
         return (ch == 0x200C ||
                 ch == 0x200D ||
                 ch == 0x2060);
     }
 
     static inline bool IsInvalid(PRUint32 ch) {
         return (ch == 0xFFFD);
     }
 
     static PRUint8 CharRangeBit(PRUint32 ch);
     
     // for a given font list pref name, set up a list of font names
-    static void GetPrefsFontList(const char *aPrefName, nsTArray<nsString>& aFontList);
+    static void GetPrefsFontList(const char *aPrefName, 
+                                 nsTArray<nsString>& aFontList);
 
 };
 
 // helper class for loading in font info spaced out at regular intervals
 
 class gfxFontInfoLoader {
 public:
 
@@ -395,17 +410,18 @@ public:
         } else {
             mState = stateTimerOnInterval;
             timerInterval = mInterval;
         }
 
         InitLoader();
 
         // start timer
-        mTimer->InitWithFuncCallback(LoaderTimerCallback, this, aDelay, nsITimer::TYPE_REPEATING_SLACK);
+        mTimer->InitWithFuncCallback(LoaderTimerCallback, this, aDelay, 
+                                     nsITimer::TYPE_REPEATING_SLACK);
     }
 
     // cancel the timer and cleanup
     void CancelLoader() {
         if (mState == stateInitial)
             return;
         mState = stateTimerOff;
         if (mTimer) {
--- a/gfx/thebes/public/gfxOS2Fonts.h
+++ b/gfx/thebes/public/gfxOS2Fonts.h
@@ -90,17 +90,17 @@ private:
     PRUint32 mSpaceGlyph;
     int mHinting;
     PRBool mAntialias;
 };
 
 
 class THEBES_API gfxOS2FontGroup : public gfxFontGroup {
 public:
-    gfxOS2FontGroup(const nsAString& aFamilies, const gfxFontStyle* aStyle);
+    gfxOS2FontGroup(const nsAString& aFamilies, const gfxFontStyle* aStyle, gfxUserFontSet *aUserFontSet);
     virtual ~gfxOS2FontGroup();
 
     virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
 
     // create and initialize the textRun using FreeType font
     virtual gfxTextRun *MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
                                     const Parameters* aParams, PRUint32 aFlags);
     virtual gfxTextRun *MakeTextRun(const PRUint8* aString, PRUint32 aLength,
--- a/gfx/thebes/public/gfxOS2Platform.h
+++ b/gfx/thebes/public/gfxOS2Platform.h
@@ -66,17 +66,18 @@ public:
                          nsStringArray& aListOfFonts);
     nsresult UpdateFontList();
     nsresult ResolveFontName(const nsAString& aFontName,
                              FontResolverCallback aCallback,
                              void *aClosure, PRBool& aAborted);
     nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
     gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
-                                  const gfxFontStyle *aStyle);
+                                  const gfxFontStyle *aStyle
+                                  gfxUserFontSet *aUserFontSet);
 
     // Given a string and a font we already have, find the font that
     // supports the most code points and most closely resembles aFont.
     // This simple version involves looking at the fonts on the machine to see
     // which code points they support.
     already_AddRefed<gfxOS2Font> FindFontForChar(PRUint32 aCh, gfxOS2Font *aFont);
 
     // return true if it's already known that we don't have a font for this char
--- a/gfx/thebes/public/gfxPangoFonts.h
+++ b/gfx/thebes/public/gfxPangoFonts.h
@@ -68,17 +68,18 @@ public:
 
     ~gfxPangoFontEntry() {}
         
 };
 
 class THEBES_API gfxPangoFontGroup : public gfxFontGroup {
 public:
     gfxPangoFontGroup (const nsAString& families,
-                       const gfxFontStyle *aStyle);
+                       const gfxFontStyle *aStyle,
+                       gfxUserFontSet *aUserFontSet);
     virtual ~gfxPangoFontGroup ();
 
     virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
 
     // Create and initialize a textrun using Pango
     virtual gfxTextRun *MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
                                     const Parameters *aParams, PRUint32 aFlags);
     virtual gfxTextRun *MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
--- a/gfx/thebes/public/gfxPlatform.h
+++ b/gfx/thebes/public/gfxPlatform.h
@@ -54,16 +54,20 @@
 
 typedef void* cmsHPROFILE;
 typedef void* cmsHTRANSFORM;
 
 class gfxImageSurface;
 class gfxFont;
 class gfxFontGroup;
 struct gfxFontStyle;
+class gfxUserFontSet;
+struct gfxDownloadedFontData;
+class gfxFontEntry;
+class nsIURI;
 
 // pref lang id's for font prefs
 // !!! needs to match the list of pref font.default.xx entries listed in all.js !!!
 
 enum eFontPrefLang {
     eFontPrefLang_Western     =  0,
     eFontPrefLang_CentEuro    =  1,
     eFontPrefLang_Japanese    =  2,
@@ -179,17 +183,40 @@ public:
      * If the name doesn't in the system, aFamilyName will be empty string, but not failed.
      */
     virtual nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) = 0;
 
     /**
      * Create the appropriate platform font group
      */
     virtual gfxFontGroup *CreateFontGroup(const nsAString& aFamilies,
-                                          const gfxFontStyle *aStyle) = 0;
+                                          const gfxFontStyle *aStyle,
+                                          gfxUserFontSet *aUserFontSet) = 0;
+                                          
+                                          
+    /**
+     * Look up a local platform font using the full font face name (needed to support @font-face src local() )
+     */
+    virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName) { return nsnull; }
+
+    /**
+     * Activate a platform font (needed to support @font-face src url() )
+     *
+     * Note: MakePlatformFont implementation is responsible for removing font file data, since data may need to 
+     * persist beyond this call.
+     */
+    virtual gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry, const gfxDownloadedFontData* aFontData) { return nsnull; }
+
+    /**
+     * Whether to allow downloadable fonts via @font-face rules
+     */
+    virtual PRBool DownloadableFontsEnabled();
+
+    // check whether format is supported on a platform or not (if unclear, returns true)
+    virtual PRBool IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags) { return PR_FALSE; }
 
     void GetPrefFonts(const char *aLangGroup, nsString& array, PRBool aAppendUnicode = PR_TRUE);
 
     /**
      * Iterate over pref fonts given a list of lang groups.  For a single lang
      * group, multiple pref fonts are possible.  If error occurs, returns PR_FALSE,
      * PR_TRUE otherwise.  Callback returns PR_FALSE to abort process.
      */
--- a/gfx/thebes/public/gfxPlatformGtk.h
+++ b/gfx/thebes/public/gfxPlatformGtk.h
@@ -74,17 +74,18 @@ public:
 
     nsresult ResolveFontName(const nsAString& aFontName,
                              FontResolverCallback aCallback,
                              void *aClosure, PRBool& aAborted);
 
     nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
     gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
-                                  const gfxFontStyle *aStyle);
+                                  const gfxFontStyle *aStyle,
+                                  gfxUserFontSet *aUserFontSet);
 
 #ifndef MOZ_PANGO
     FontFamily *FindFontFamily(const nsAString& aName);
     FontEntry *FindFontEntry(const nsAString& aFamilyName, const gfxFontStyle& aFontStyle);
 #endif
 
     static double DPI() {
         if (sDPI < 0.0) {
--- a/gfx/thebes/public/gfxPlatformMac.h
+++ b/gfx/thebes/public/gfxPlatformMac.h
@@ -61,17 +61,24 @@ public:
 
     nsresult ResolveFontName(const nsAString& aFontName,
                              FontResolverCallback aCallback,
                              void *aClosure, PRBool& aAborted);
 
     nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
     gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
-                                  const gfxFontStyle *aStyle);
+                                  const gfxFontStyle *aStyle,
+                                  gfxUserFontSet *aUserFontSet);
+
+    gfxFontEntry* LookupLocalFont(const nsAString& aFontName);
+
+    gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry, const gfxDownloadedFontData* aFontData);
+
+    PRBool IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags);
 
     nsresult GetFontList(const nsACString& aLangGroup,
                          const nsACString& aGenericFamily,
                          nsStringArray& aListOfFonts);
     nsresult UpdateFontList();
 
     // in some situations, need to make decisions about ambiguous characters, may need to look at multiple pref langs
     void GetLangPrefs(eFontPrefLang aPrefLangs[], PRUint32 &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang);
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/public/gfxUserFontSet.h
@@ -0,0 +1,266 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Foundation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   John Daggett <jdaggett@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef GFX_USER_FONT_SET_H
+#define GFX_USER_FONT_SET_H
+
+#include "gfxTypes.h"
+#include "gfxFont.h"
+#include "gfxFontUtils.h"
+#include "nsRefPtrHashtable.h"
+#include "nsAutoPtr.h"
+#include "nsCOMPtr.h"
+#include "nsIURI.h"
+#include "nsIFile.h"
+
+class nsIURI;
+class gfxMixedFontFamily;
+
+// parsed CSS @font-face rule information
+// lifetime: from when @font-face rule processed until font is loaded
+struct gfxFontFaceSrc {
+    PRPackedBool           mIsLocal;       // url or local
+    nsString               mLocalName;     // full font name if local
+    nsCOMPtr<nsIURI>       mURI;           // uri if url 
+
+    // format hint flags, union of all possible formats
+    // (e.g. TrueType, EOT, SVG, etc.)
+    // see FLAG_FORMAT_* enum values below
+    PRUint32               mFormatFlags;
+};
+
+// data needed to initialize platform font
+// After download completes, platform-specific code is responsible for
+// removing temp file and managing cache token. Depending on the
+// platform, these may need to persist after the platform font has been
+// created.
+// lifetime: time during which font is downloaded and active
+struct gfxDownloadedFontData {
+    nsCOMPtr<nsIFile>      mFontFile;     // file containing font data
+    nsCOMPtr<nsISupports>  mDownloader;   // need to a ref to this to prevent file from being deleted
+
+    // format hint flags, union of all possible formats
+    PRUint32               mFormatFlags;  // opentype, truetype, svg, etc. (if known)
+};
+
+// subclassed by loader code to contain needed context info
+// lifetime: user font set lifetime 
+class gfxFontLoaderContext {
+public:
+  gfxFontLoaderContext() { }
+  virtual ~gfxFontLoaderContext() { }
+};
+
+// subclassed to store platform-specific code cleaned out when font entry is deleted
+// lifetime: from when platform font is created until it is deactivated 
+class gfxUserFontData {
+public:
+    gfxUserFontData() { }
+    virtual ~gfxUserFontData() { }
+};
+
+// initially contains a set of proxy font entry objects, replaced with
+// platform/user fonts as downloaded
+
+class gfxMixedFontFamily : public gfxFontFamily {
+
+public:
+    gfxMixedFontFamily(const nsAString& aName)
+        : gfxFontFamily(aName)
+    { }
+
+    virtual ~gfxMixedFontFamily() { }
+
+    void AddFontEntry(gfxFontEntry *aFontEntry) {
+        nsRefPtr<gfxFontEntry> fe = aFontEntry;
+        mAvailableFonts.AppendElement(fe);
+    }
+
+    void ReplaceFontEntry(gfxFontEntry *aOldFontEntry, gfxFontEntry *aNewFontEntry) 
+    {
+        PRUint32 numFonts = mAvailableFonts.Length();
+        for (PRUint32 i = 0; i < numFonts; i++) {
+            gfxFontEntry *fe = mAvailableFonts[i];
+            if (fe == aOldFontEntry) {
+                mAvailableFonts[i] = aNewFontEntry;
+                return;
+            }
+        }
+    }
+
+    void RemoveFontEntry(gfxFontEntry *aFontEntry) 
+    {
+        PRUint32 numFonts = mAvailableFonts.Length();
+        for (PRUint32 i = 0; i < numFonts; i++) {
+            gfxFontEntry *fe = mAvailableFonts[i];
+            if (fe == aFontEntry) {
+                mAvailableFonts.RemoveElementAt(i);
+                return;
+            }
+        }
+    }
+
+    // temp method to determine if all proxies are loaded
+    PRBool AllLoaded() 
+    {
+        PRUint32 numFonts = mAvailableFonts.Length();
+        for (PRUint32 i = 0; i < numFonts; i++) {
+            gfxFontEntry *fe = mAvailableFonts[i];
+            if (fe->mIsProxy)
+                return PR_FALSE;
+        }
+        return PR_TRUE;
+    }
+
+    nsTArray<nsRefPtr<gfxFontEntry> >  mAvailableFonts;
+
+protected:
+    PRBool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], 
+                               const gfxFontStyle& aFontStyle);
+
+};
+
+class gfxProxyFontEntry;
+
+class THEBES_API gfxUserFontSet {
+
+public:
+    class LoaderContext;
+    typedef PRBool (*LoaderCallback) (gfxFontEntry *aFontToLoad, nsIURI *aSrcURL, 
+                                      LoaderContext *aContextData);
+
+    class LoaderContext {
+    public:
+        LoaderContext(LoaderCallback aLoader)
+            : mUserFontSet(nsnull), mLoaderProc(aLoader) { }
+        virtual ~LoaderContext() { }
+
+        gfxUserFontSet* mUserFontSet;
+        LoaderCallback  mLoaderProc;
+    };
+
+    THEBES_INLINE_DECL_REFCOUNTING(gfxUserFontSet)
+
+    gfxUserFontSet(LoaderContext *aContext);
+    virtual ~gfxUserFontSet();
+
+    enum {
+        // no flags ==> unknown
+        FLAG_FORMAT_OPENTYPE       = 1,
+        FLAG_FORMAT_TRUETYPE       = 2,
+        FLAG_FORMAT_TRUETYPE_AAT   = 4,
+        FLAG_FORMAT_EOT            = 8,
+        FLAG_FORMAT_SVG            = 16
+    };
+
+    enum LoadStatus {
+        STATUS_LOADING = 0,
+        STATUS_LOADED,
+        STATUS_FORMAT_NOT_SUPPORTED,
+        STATUS_ERROR,
+        STATUS_END_OF_LIST
+    };
+
+
+    // add in a font face
+    // weight, stretch - 0 == unknown, [1, 9] otherwise
+    // italic style = constants in gfxFont.h (e.g. FONT_STYLE_NORMAL)
+    // TODO: support for unicode ranges not yet implemented
+    void AddFontFace(const nsAString& aFamilyName, 
+                     const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList, 
+                     PRUint32 aWeight = 0, 
+                     PRUint32 aStretch = 0, 
+                     PRUint32 aItalicStyle = 0, 
+                     gfxSparseBitSet *aUnicodeRanges = nsnull);
+
+    // lookup a font entry for a given style, returns null if not loaded
+    gfxFontEntry *FindFontEntry(const nsAString& aName, 
+                                const gfxFontStyle& aFontStyle, PRBool& aNeedsBold);
+
+    // when download has been completed, pass back data here
+    // aDownloadStatus == NS_OK ==> download succeeded, error otherwise
+    // returns true if platform font creation sucessful (or local()
+    // reference was next in line)
+    PRBool OnLoadComplete(gfxFontEntry *aFontToLoad, 
+                          const gfxDownloadedFontData& aFontData, 
+                          nsresult aDownloadStatus);
+
+    // generation - each time a face is loaded, generation is
+    // incremented so that the change can be recognized 
+    PRUint64 GetGeneration() { return mGeneration; }
+
+protected:
+    // for a given proxy font entry, attempt to load the next resource
+    // in the src list
+    LoadStatus LoadNext(gfxProxyFontEntry *aProxyEntry);
+
+    // increment the generation on font load
+    void IncrementGeneration();
+
+    // remove family
+    void RemoveFamily(const nsAString& aFamilyName);
+
+    // font families defined by @font-face rules
+    nsRefPtrHashtable<nsStringHashKey, gfxMixedFontFamily> mFontFamilies;
+
+    PRUint64        mGeneration;
+
+    // owned by user font set obj, deleted within destructor
+    nsAutoPtr<LoaderContext> mLoaderContext;
+};
+
+// acts a placeholder until the real font is downloaded
+
+class gfxProxyFontEntry : public gfxFontEntry {
+
+public:
+    gfxProxyFontEntry(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList, 
+                      PRUint32 aWeight, 
+                      PRUint32 aStretch, 
+                      PRUint32 aItalicStyle, 
+                      gfxSparseBitSet *aUnicodeRanges);
+
+    virtual ~gfxProxyFontEntry();
+
+    PRPackedBool                           mIsLoading;
+    nsTArray<gfxFontFaceSrc>               mSrcList;
+    PRUint32                               mSrcIndex; // index of loading src item
+    gfxMixedFontFamily*                    mFamily;
+};
+
+
+#endif /* GFX_USER_FONT_SET_H */
--- a/gfx/thebes/public/gfxWindowsFonts.h
+++ b/gfx/thebes/public/gfxWindowsFonts.h
@@ -78,17 +78,17 @@ enum gfxWindowsFontType {
  * each FontEntry (maps more directly to a font face) which holds font type, charset info
  * and character map info.
  */
 class FontEntry;
 class FontFamily : public gfxFontFamily
 {
 public:
     FontFamily(const nsAString& aName) :
-        gfxFontFamily(aName), mHasStyles(PR_FALSE), mIsBadUnderlineFont(PR_FALSE) { }
+        gfxFontFamily(aName), mIsBadUnderlineFontFamily(PR_FALSE), mHasStyles(PR_FALSE) { }
 
     FontEntry *FindFontEntry(const gfxFontStyle& aFontStyle);
 
 private:
     friend class gfxWindowsPlatform;
 
     void FindStyleVariations();
 
@@ -96,48 +96,72 @@ private:
                                             const NEWTEXTMETRICEXW *nmetrics,
                                             DWORD fontType, LPARAM data);
 
 protected:
     PRBool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], const gfxFontStyle& aFontStyle);
 
 public:
     nsTArray<nsRefPtr<FontEntry> > mVariations;
-    PRPackedBool mIsBadUnderlineFont;
+    PRPackedBool mIsBadUnderlineFontFamily;
 
 private:
-    PRBool mHasStyles;
+    PRPackedBool mHasStyles;
 };
 
 class FontEntry : public gfxFontEntry
 {
 public:
-    FontEntry(const nsString& aFaceName) : 
+    FontEntry(const nsAString& aFaceName) : 
         gfxFontEntry(aFaceName), mFontType(GFX_FONT_TYPE_UNKNOWN),
-        mIsBadUnderlineFont(PR_FALSE), mForceGDI(PR_FALSE), mUnknownCMAP(PR_FALSE),
+        mForceGDI(PR_FALSE), mUnknownCMAP(PR_FALSE),
         mCharset(0), mUnicodeRanges(0)
     {
         mUnicodeFont = PR_FALSE;
         mSymbolFont = PR_FALSE;
     }
 
     FontEntry(const FontEntry& aFontEntry) :
         gfxFontEntry(aFontEntry),
         mWindowsFamily(aFontEntry.mWindowsFamily),
         mWindowsPitch(aFontEntry.mWindowsPitch),
         mFontType(aFontEntry.mFontType),
-        mIsBadUnderlineFont(aFontEntry.mIsBadUnderlineFont),
         mForceGDI(aFontEntry.mForceGDI),
         mUnknownCMAP(aFontEntry.mUnknownCMAP),
         mCharset(aFontEntry.mCharset),
         mUnicodeRanges(aFontEntry.mUnicodeRanges)
     {
 
     }
 
+    static FontEntry* CreateFontEntry(const nsAString& aName, gfxWindowsFontType aFontType, PRBool aItalic, PRUint16 aWeight, gfxUserFontData* aUserFontData, HDC hdc = 0, LOGFONTW *aLogFont = nsnull);
+
+    static void FillLogFont(LOGFONTW *aLogFont, FontEntry *aFontEntry, gfxFloat aSize, PRBool aItalic);
+
+    static gfxWindowsFontType DetermineFontType(const NEWTEXTMETRICW& metrics, DWORD fontType)
+    {
+        gfxWindowsFontType feType;
+        if (metrics.ntmFlags & NTM_TYPE1)
+            feType = GFX_FONT_TYPE_TYPE1;
+        else if (metrics.ntmFlags & NTM_PS_OPENTYPE)
+            feType = GFX_FONT_TYPE_PS_OPENTYPE;
+        else if (metrics.ntmFlags & NTM_TT_OPENTYPE)
+            feType = GFX_FONT_TYPE_TT_OPENTYPE;
+        else if (fontType == TRUETYPE_FONTTYPE)
+            feType = GFX_FONT_TYPE_TRUETYPE;
+        else if (fontType == RASTER_FONTTYPE)
+            feType = GFX_FONT_TYPE_RASTER;
+        else if (fontType == DEVICE_FONTTYPE)
+            feType = GFX_FONT_TYPE_DEVICE;
+        else
+            feType = GFX_FONT_TYPE_UNKNOWN;
+        
+        return feType;
+    }
+
     PRBool IsType1() const {
         return (mFontType == GFX_FONT_TYPE_TYPE1);
     }
 
     PRBool IsTrueType() const {
         return (mFontType == GFX_FONT_TYPE_TRUETYPE ||
                 mFontType == GFX_FONT_TYPE_PS_OPENTYPE ||
                 mFontType == GFX_FONT_TYPE_TT_OPENTYPE);
@@ -227,26 +251,22 @@ public:
 
         return PR_FALSE;
     }
 
     PRBool SupportsRange(PRUint8 range) {
         return mUnicodeRanges[range];
     }
 
-    // whether this font family is in "bad" underline offset blacklist.
-    PRBool IsBadUnderlineFont() { return mIsBadUnderlineFont != 0; }
-
     PRBool TestCharacterMap(PRUint32 aCh);
 
     PRUint8 mWindowsFamily;
     PRUint8 mWindowsPitch;
 
     gfxWindowsFontType mFontType;
-    PRPackedBool mIsBadUnderlineFont : 1;
     PRPackedBool mForceGDI    : 1;
     PRPackedBool mUnknownCMAP : 1;
 
     std::bitset<256> mCharset;
     std::bitset<128> mUnicodeRanges;
 };
 
 /**********************************************************************
@@ -312,17 +332,17 @@ private:
  *
  * class gfxWindowsFontGroup
  *
  **********************************************************************/
 
 class THEBES_API gfxWindowsFontGroup : public gfxFontGroup {
 
 public:
-    gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFontStyle* aStyle);
+    gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFontStyle* aStyle, gfxUserFontSet *aUserFontSet);
     virtual ~gfxWindowsFontGroup();
 
     virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
 
     virtual gfxTextRun *MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
                                     const Parameters* aParams, PRUint32 aFlags);
     virtual gfxTextRun *MakeTextRun(const PRUint8* aString, PRUint32 aLength,
                                     const Parameters* aParams, PRUint32 aFlags);
@@ -344,18 +364,20 @@ public:
 
     virtual gfxWindowsFont *GetFontAt(PRInt32 i);
 
     void GroupFamilyListToArrayList(nsTArray<nsRefPtr<FontEntry> > *list);
     void FamilyListToArrayList(const nsString& aFamilies,
                                const nsCString& aLangGroup,
                                nsTArray<nsRefPtr<FontEntry> > *list);
 
+    void UpdateFontList();
 
 protected:
+    void InitFontList();
     void InitTextRunGDI(gfxContext *aContext, gfxTextRun *aRun, const char *aString, PRUint32 aLength);
     void InitTextRunGDI(gfxContext *aContext, gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength);
 
     void InitTextRunUniscribe(gfxContext *aContext, gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength);
 
     already_AddRefed<gfxFont> WhichPrefFontSupportsChar(PRUint32 aCh);
     already_AddRefed<gfxFont> WhichSystemFontSupportsChar(PRUint32 aCh);
 
--- a/gfx/thebes/public/gfxWindowsPlatform.h
+++ b/gfx/thebes/public/gfxWindowsPlatform.h
@@ -70,17 +70,33 @@ public:
 
     nsresult ResolveFontName(const nsAString& aFontName,
                              FontResolverCallback aCallback,
                              void *aClosure, PRBool& aAborted);
 
     nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
     gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
-                                  const gfxFontStyle *aStyle);
+                                  const gfxFontStyle *aStyle,
+                                  gfxUserFontSet *aUserFontSet);
+
+    /**
+     * Look up a local platform font using the full font face name (needed to support @font-face src local() )
+     */
+    virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName);
+
+    /**
+     * Activate a platform font (needed to support @font-face src url() )
+     */
+    virtual gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry, const gfxDownloadedFontData* aFontData);
+
+    /**
+     * Check whether format is supported on a platform or not (if unclear, returns true)
+     */
+    virtual PRBool IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags);
 
     /* Given a string and a font we already have find the font that
      * supports the most code points and most closely resembles aFont
      *
      * this involves looking at the fonts on your machine and seeing which
      * code points they support as well as looking at things like the font
      * family, style, weight, etc.
      */
--- a/gfx/thebes/src/Makefile.in
+++ b/gfx/thebes/src/Makefile.in
@@ -33,16 +33,17 @@ CPPSRCS	= \
 	gfxMatrix.cpp \
 	gfxPath.cpp \
 	gfxPattern.cpp \
 	gfxPlatform.cpp \
 	gfxRect.cpp \
 	gfxSkipChars.cpp \
 	gfxTextRunCache.cpp \
 	gfxTextRunWordCache.cpp \
+	gfxUserFontSet.cpp \
 	$(NULL)
 
 EXTRA_DSO_LDOPTS += \
 	$(MOZ_CAIRO_LIBS) \
 	$(MOZ_UNICHARUTIL_LIBS) \
 	$(XPCOM_LIBS) \
 	$(NSPR_LIBS) \
 	$(ZLIB_LIBS) \
--- a/gfx/thebes/src/gfxAtsuiFonts.cpp
+++ b/gfx/thebes/src/gfxAtsuiFonts.cpp
@@ -53,16 +53,17 @@
 
 #include "gfxFontTest.h"
 #include "gfxFontUtils.h"
 
 #include "cairo-quartz.h"
 
 #include "gfxQuartzSurface.h"
 #include "gfxQuartzFontCache.h"
+#include "gfxUserFontSet.h"
 
 #include "nsUnicodeRange.h"
 
 // Uncomment this to dump all text runs created to stdout
 // #define DUMP_TEXT_RUNS
 
 #ifdef DUMP_TEXT_RUNS
 static PRLogModuleInfo *gAtsuiTextRunLog = PR_NewLogModule("atsuiTextRun");
@@ -268,18 +269,18 @@ gfxAtsuiFont::InitMetrics(ATSUFontID aFo
             InitMetrics(aFontID, aFontRef);
             return;
         }
         mAdjustedSize = size;
     }
 
     mMetrics.emHeight = size;
 
-    mMetrics.maxAscent = NS_ceil(atsMetrics.ascent * size);
-    mMetrics.maxDescent = NS_ceil(- (atsMetrics.descent * size));
+    mMetrics.maxAscent = atsMetrics.ascent * size;
+    mMetrics.maxDescent = - (atsMetrics.descent * size);
 
     mMetrics.maxHeight = mMetrics.maxAscent + mMetrics.maxDescent;
 
     if (mMetrics.maxHeight - mMetrics.emHeight > 0)
         mMetrics.internalLeading = mMetrics.maxHeight - mMetrics.emHeight; 
     else
         mMetrics.internalLeading = 0.0;
     mMetrics.externalLeading = atsMetrics.leading * size;
@@ -317,17 +318,17 @@ gfxAtsuiFont::InitMetrics(ATSUFontID aFo
     PRUint32 glyphID;
     mMetrics.spaceWidth = GetCharWidth(' ', &glyphID);
     mSpaceGlyph = glyphID;
 
     mMetrics.zeroOrAveCharWidth = GetCharWidth('0', &glyphID);
     if (glyphID == 0) // no zero in this font
         mMetrics.zeroOrAveCharWidth = mMetrics.aveCharWidth;
 
-    SanitizeMetrics(&mMetrics, GetFontEntry()->FamilyEntry()->IsBadUnderlineFontFamily());
+    SanitizeMetrics(&mMetrics, GetFontEntry()->mIsBadUnderlineFont);
 
 #if 0
     fprintf (stderr, "Font: %p size: %f (fixed: %d)", this, size, gfxQuartzFontCache::SharedFontCache()->IsFixedPitch(aFontID));
     fprintf (stderr, "    emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent);
     fprintf (stderr, "    maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance);
     fprintf (stderr, "    internalLeading: %f externalLeading: %f\n", mMetrics.externalLeading, mMetrics.internalLeading);
     fprintf (stderr, "    spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight);
     fprintf (stderr, "    uOff: %f uSize: %f stOff: %f stSize: %f suOff: %f suSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize, mMetrics.superscriptOffset, mMetrics.subscriptOffset);
@@ -435,16 +436,21 @@ gfxAtsuiFont::SetupGlyphExtents(gfxConte
         metrics.topLeft.y <= mMetrics.maxDescent) {
         PRUint32 appUnitsWidth =
             PRUint32(NS_ceil((metrics.topLeft.x + metrics.width)*appUnitsPerDevUnit));
         if (appUnitsWidth < gfxGlyphExtents::INVALID_WIDTH) {
             aExtents->SetContainedGlyphWidthAppUnits(aGlyphID, PRUint16(appUnitsWidth));
             return;
         }
     }
+#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
+    if (!aNeedTight) {
+        ++gGlyphExtentsSetupFallBackToTight;
+    }
+#endif
 
     double d2a = appUnitsPerDevUnit;
     gfxRect bounds(metrics.topLeft.x*d2a, (metrics.topLeft.y - metrics.height)*d2a,
                    metrics.width*d2a, metrics.height*d2a);
     aExtents->SetTightGlyphExtents(aGlyphID, bounds);
 }
 
 PRBool 
@@ -496,19 +502,21 @@ GetOrMakeFont(MacOSFontEntry *aFontEntry
         font = newFont;
         gfxFontCache::GetCache()->AddNew(font);
     }
     gfxFont *f = nsnull;
     font.swap(f);
     return static_cast<gfxAtsuiFont *>(f);
 }
 
+
 gfxAtsuiFontGroup::gfxAtsuiFontGroup(const nsAString& families,
-                                     const gfxFontStyle *aStyle)
-    : gfxFontGroup(families, aStyle)
+                                     const gfxFontStyle *aStyle,
+                                     gfxUserFontSet *aUserFontSet)
+    : gfxFontGroup(families, aStyle, aUserFontSet)
 {
     ForEachFont(FindATSUFont, this);
 
     if (mFonts.Length() == 0) {
         // XXX this will generate a list of the lang groups for which we have no
         // default fonts for on the mac; we should fix this!
         // Known:
         // ja x-beng x-devanagari x-tamil x-geor x-ethi x-gujr x-mlym x-armn
@@ -531,17 +539,17 @@ gfxAtsuiFontGroup::gfxAtsuiFontGroup(con
         }
     }
 
     mPageLang = gfxPlatform::GetFontPrefLangFor(mStyle.langGroup.get());
 
     if (!mStyle.systemFont) {
         for (PRUint32 i = 0; i < mFonts.Length(); ++i) {
             gfxAtsuiFont* font = static_cast<gfxAtsuiFont*>(mFonts[i].get());
-            if (font->GetFontEntry()->FamilyEntry()->IsBadUnderlineFontFamily()) {
+            if (font->GetFontEntry()->mIsBadUnderlineFont) {
                 gfxFloat first = mFonts[0]->GetMetrics().underlineOffset;
                 gfxFloat bad = font->GetMetrics().underlineOffset;
                 mUnderlineOffset = PR_MIN(first, bad);
                 break;
             }
         }
     }
 }
@@ -549,35 +557,48 @@ gfxAtsuiFontGroup::gfxAtsuiFontGroup(con
 PRBool
 gfxAtsuiFontGroup::FindATSUFont(const nsAString& aName,
                                 const nsACString& aGenericName,
                                 void *closure)
 {
     gfxAtsuiFontGroup *fontGroup = (gfxAtsuiFontGroup*) closure;
     const gfxFontStyle *fontStyle = fontGroup->GetStyle();
 
-    gfxQuartzFontCache *fc = gfxQuartzFontCache::SharedFontCache();
 
     PRBool needsBold;
-    MacOSFontEntry *fe = fc->FindFontForFamily(aName, fontStyle, needsBold);
+    MacOSFontEntry *fe = nsnull;
+    
+    // first, look up in the user font set
+    gfxUserFontSet *fs = fontGroup->GetUserFontSet();
+    gfxFontEntry *gfe;
+    if (fs && (gfe = fs->FindFontEntry(aName, *fontStyle, needsBold))) {
+        // assume for now platform font if not SVG
+        fe = static_cast<MacOSFontEntry*> (gfe);
+    }
+    
+    // nothing in the user font set ==> check system fonts
+    if (!fe) {
+        gfxQuartzFontCache *fc = gfxQuartzFontCache::SharedFontCache();
+        fe = fc->FindFontForFamily(aName, fontStyle, needsBold);
+    }
 
     if (fe && !fontGroup->HasFont(fe->GetFontID())) {
         nsRefPtr<gfxAtsuiFont> font = GetOrMakeFont(fe, fontStyle, needsBold);
         if (font) {
             fontGroup->mFonts.AppendElement(font);
         }
     }
 
     return PR_TRUE;
 }
 
 gfxFontGroup *
 gfxAtsuiFontGroup::Copy(const gfxFontStyle *aStyle)
 {
-    return new gfxAtsuiFontGroup(mFamilies, aStyle);
+    return new gfxAtsuiFontGroup(mFamilies, aStyle, mUserFontSet);
 }
 
 static void
 SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aString)
 {
     TextBreakLocatorRef locator;
     OSStatus status = UCCreateTextBreakLocator(NULL, 0, kUCTextBreakClusterMask,
                                                &locator);
@@ -928,16 +949,29 @@ gfxAtsuiFontGroup::WhichSystemFontSuppor
         nsRefPtr<gfxAtsuiFont> atsuiFont = GetOrMakeFont(fe, &mStyle, PR_FALSE); // ignore bolder considerations in system fallback case...
         nsRefPtr<gfxFont> font = (gfxFont*) atsuiFont; 
         return font.forget();
     }
 
     return nsnull;
 }
 
+void
+gfxAtsuiFontGroup::UpdateFontList()
+{
+    // if user font set is set, check to see if font list needs updating
+    if (mUserFontSet && mCurrGeneration != GetGeneration()) {
+        // xxx - can probably improve this to detect when all fonts were found, so no need to update list
+        mFonts.Clear();
+        ForEachFont(FindATSUFont, this);
+        mCurrGeneration = GetGeneration();
+    }
+}
+
+
 /**
  * Simple wrapper for ATSU "direct data arrays"
  */
 class AutoLayoutDataArrayPtr {
 public:
     AutoLayoutDataArrayPtr(ATSULineRef aLineRef,
                            ATSUDirectDataSelector aSelector)
         : mLineRef(aLineRef), mSelector(aSelector)
@@ -1387,18 +1421,18 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRu
 
 #ifdef DUMP_TEXT_RUNS
     NS_ConvertUTF16toUTF8 str(layoutString, aLengthInTextRun);
     NS_ConvertUTF16toUTF8 families(mFamilies);
     PR_LOG(gAtsuiTextRunLog, PR_LOG_DEBUG,\
            ("InitTextRun %p fontgroup %p (%s) lang: %s len %d TEXTRUN \"%s\" ENDTEXTRUN\n",
             aRun, this, families.get(), mStyle.langGroup.get(), aLengthInTextRun, str.get()) );
     PR_LOG(gAtsuiTextRunLog, PR_LOG_DEBUG,
-           ("InitTextRun font: %s\n",
-            NS_ConvertUTF16toUTF8(firstFont->GetUniqueName()).get()) );
+           ("InitTextRun font: %s user font set: %p (%8.8x)\n",
+            NS_ConvertUTF16toUTF8(firstFont->GetUniqueName()).get(), mUserFontSet, PRUint32(mCurrGeneration)) );
 #endif
 
     if (aRun->GetFlags() & TEXT_DISABLE_OPTIONAL_LIGATURES) {
         status = ATSUCreateAndCopyStyle(mainStyle, &mainStyle);
         if (status == noErr) {
             stylesToDispose.AppendElement(mainStyle);
             DisableCommonLigatures(mainStyle);
         }
--- a/gfx/thebes/src/gfxFont.cpp
+++ b/gfx/thebes/src/gfxFont.cpp
@@ -44,17 +44,19 @@
 
 #include "gfxFont.h"
 #include "gfxPlatform.h"
 
 #include "prtypes.h"
 #include "gfxTypes.h"
 #include "gfxContext.h"
 #include "gfxFontMissingGlyphs.h"
+#include "gfxUserFontSet.h"
 #include "nsMathUtils.h"
+#include "nsBidiUtils.h"
 
 #include "cairo.h"
 #include "gfxFontTest.h"
 
 #include "nsCRT.h"
 
 gfxFontCache *gfxFontCache::gGlobalCache = nsnull;
 
@@ -69,34 +71,38 @@ static PRUint32 gFontCount = 0;
 static PRUint32 gGlyphExtentsCount = 0;
 static PRUint32 gGlyphExtentsWidthsTotalSize = 0;
 static PRUint32 gGlyphExtentsSetupEagerSimple = 0;
 static PRUint32 gGlyphExtentsSetupEagerTight = 0;
 static PRUint32 gGlyphExtentsSetupLazyTight = 0;
 static PRUint32 gGlyphExtentsSetupFallBackToTight = 0;
 #endif
 
-gfxFontEntry::~gfxFontEntry() {
-
+gfxFontEntry::~gfxFontEntry() 
+{
+    if (mUserFontData)
+        delete mUserFontData;
 }
 
 
 PRBool gfxFontEntry::TestCharacterMap(PRUint32 aCh) {
     if (!mCmapInitialized) ReadCMAP();
     return mCharacterMap.test(aCh);
 }
 
 
 gfxFontEntry *gfxFontFamily::FindFontForStyle(const gfxFontStyle& aFontStyle, PRBool& aNeedsBold)
 {
     gfxFontEntry *weightList[10] = { 0 };
 
     aNeedsBold = PR_FALSE;
 
-    FindWeightsForStyle(weightList, aFontStyle);
+    PRBool foundWeights = FindWeightsForStyle(weightList, aFontStyle);
+    if (!foundWeights)
+        return nsnull;
 
     PRInt8 baseWeight, weightDistance;
     aFontStyle.ComputeWeightAndOffset(&baseWeight, &weightDistance);
 
     // 500 isn't quite bold so we want to treat it as 400 if we don't
     // have a 500 weight
     if (baseWeight == 5 && weightDistance == 0) {
         // If we have a 500 weight then use it
@@ -851,20 +857,42 @@ gfxGlyphExtents::SetTightGlyphExtents(PR
     if (!entry)
         return;
     entry->x = aExtentsAppUnits.pos.x;
     entry->y = aExtentsAppUnits.pos.y;
     entry->width = aExtentsAppUnits.size.width;
     entry->height = aExtentsAppUnits.size.height;
 }
 
-gfxFontGroup::gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle)
+gfxFontGroup::gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle, gfxUserFontSet *aUserFontSet)
     : mFamilies(aFamilies), mStyle(*aStyle), mUnderlineOffset(UNDERLINE_OFFSET_NOT_SET)
 {
+    mUserFontSet = nsnull;
+    SetUserFontSet(aUserFontSet);
+}
 
+gfxFontGroup::~gfxFontGroup() {
+    mFonts.Clear();
+    SetUserFontSet(nsnull);
+}
+
+
+PRBool 
+gfxFontGroup::IsInvalidChar(PRUnichar ch) {
+    if (ch >= 32) {
+        return ch == 0x0085/*NEL*/ ||
+            ((ch & 0xFF00) == 0x2000 /* Unicode control character */ &&
+             (ch == 0x200B/*ZWSP*/ || ch == 0x2028/*LSEP*/ || ch == 0x2029/*PSEP*/ ||
+              IS_BIDI_CONTROL_CHAR(ch)));
+    }
+    // We could just blacklist all control characters, but it seems better
+    // to only blacklist the ones we know cause problems for native font
+    // engines.
+    return ch == 0x0B || ch == '\t' || ch == '\r' || ch == '\n' || ch == '\f' ||
+        (ch >= 0x1c && ch <= 0x1f);
 }
 
 PRBool
 gfxFontGroup::ForEachFont(FontCreationCallback fc,
                           void *closure)
 {
     return ForEachFontInternal(mFamilies, mStyle.langGroup,
                                PR_TRUE, PR_TRUE, fc, closure);
@@ -984,21 +1012,28 @@ gfxFontGroup::ForEachFontInternal(const 
         }
 
         if (generic) {
             ForEachFontInternal(family, lang, PR_FALSE, aResolveFontName, fc, closure);
         } else if (!family.IsEmpty()) {
             NS_LossyConvertUTF16toASCII gf(genericFamily);
             if (aResolveFontName) {
                 ResolveData data(fc, gf, closure);
-                PRBool aborted;
-                gfxPlatform *pf = gfxPlatform::GetPlatform();
-                nsresult rv = pf->ResolveFontName(family,
+                PRBool aborted, needsBold;
+                nsresult rv;
+
+                if (mUserFontSet && mUserFontSet->FindFontEntry(family, mStyle, needsBold)) {
+                    gfxFontGroup::FontResolverProc(family, &data);
+                    rv = NS_OK;
+                } else {
+                    gfxPlatform *pf = gfxPlatform::GetPlatform();
+                    rv = pf->ResolveFontName(family,
                                                   gfxFontGroup::FontResolverProc,
                                                   &data, aborted);
+                }
                 if (NS_FAILED(rv) || aborted)
                     return PR_FALSE;
             }
             else {
                 if (!fc(family, gf, closure))
                     return PR_FALSE;
             }
         }
@@ -1084,17 +1119,17 @@ gfxFontGroup::FindFontForChar(PRUint32 a
         nsRefPtr<gfxFont> font = GetFontAt(i);
         if (font->HasCharacter(aCh))
             return font.forget();
     }
 
     // if match, return
     if (selectedFont)
         return selectedFont.forget();
-        
+
     // if character is in Private Use Area, don't do matching against pref or system fonts
     if ((aCh >= 0xE000  && aCh <= 0xF8FF) || (aCh >= 0xF0000 && aCh <= 0x10FFFD))
         return nsnull;
 
     // 2. search pref fonts
     if ((selectedFont = WhichPrefFontSupportsChar(aCh))) {
         return selectedFont.forget();
     }
@@ -1164,16 +1199,39 @@ void gfxFontGroup::ComputeRanges(nsTArra
                 r.font = font;
                 aRanges.AppendElement(r);
             }
         }
     }
     aRanges[aRanges.Length()-1].end = len;
 }
 
+gfxUserFontSet* 
+gfxFontGroup::GetUserFontSet()
+{
+    return mUserFontSet;
+}
+
+void 
+gfxFontGroup::SetUserFontSet(gfxUserFontSet *aUserFontSet)
+{
+    NS_IF_RELEASE(mUserFontSet);
+    mUserFontSet = aUserFontSet;
+    NS_IF_ADDREF(mUserFontSet);
+    mCurrGeneration = GetGeneration();
+}
+
+PRUint64
+gfxFontGroup::GetGeneration()
+{
+    if (!mUserFontSet)
+        return 0;
+    return mUserFontSet->GetGeneration();
+}
+
 
 #define DEFAULT_PIXEL_FONT_SIZE 16.0f
 
 gfxFontStyle::gfxFontStyle() :
     style(FONT_STYLE_NORMAL), systemFont(PR_TRUE), familyNameQuirks(PR_FALSE),
     weight(FONT_WEIGHT_NORMAL), size(DEFAULT_PIXEL_FONT_SIZE),
     langGroup(NS_LITERAL_CSTRING("x-western")), sizeAdjust(0.0f)
 {
@@ -1326,16 +1384,18 @@ gfxTextRun::gfxTextRun(const gfxTextRunF
             PRUnichar *newText = reinterpret_cast<PRUnichar*>(mCharacterGlyphs + aLength);
             memcpy(newText, aText, aLength*sizeof(PRUnichar));
             mText.mDouble = newText;    
         }
     }
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
     AccountStorageForTextRun(this, 1);
 #endif
+
+    mUserFontSetGeneration = mFontGroup->GetGeneration();
 }
 
 gfxTextRun::~gfxTextRun()
 {
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
     AccountStorageForTextRun(this, -1);
 #endif
     NS_RELEASE(mFontGroup);
--- a/gfx/thebes/src/gfxFontUtils.cpp
+++ b/gfx/thebes/src/gfxFontUtils.cpp
@@ -40,16 +40,18 @@
 
 #include "nsIPref.h"  // for pref handling code
 #include "nsServiceManagerUtils.h"
 
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 #include "nsIPrefLocalizedString.h"
 #include "nsISupportsPrimitives.h"
+#include "nsIStreamBufferAccess.h"
+#include "nsILocalFile.h"
 
 #define NO_RANGE_FOUND 126 // bit 126 in the font unicode ranges is required to be 0
 
 /* Unicode subrange table
  *   from: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/unicode_63ub.asp
  *
  * Use something like:
  * perl -pi -e 's/^(\d+)\s+([\dA-Fa-f]+)\s+-\s+([\dA-Fa-f]+)\s+\b(.*)/    { \1, 0x\2, 0x\3,\"\4\" },/' < unicoderanges.txt
@@ -464,9 +466,563 @@ void gfxFontUtils::GetPrefsFontList(cons
         
         // append it to the list
         aFontList.AppendElement(fontname);
         ++p;
     }
 
 }
 
+// for now, this is only needed on Windows
 
+#ifdef XP_WIN
+
+// TrueType/OpenType table handling code
+
+// need byte aligned structs
+#pragma pack(1)
+
+struct AutoSwap_PRUint16 {
+    operator PRUint16() { return NS_SWAP16(value); }
+    operator PRUint32() { return NS_SWAP16(value); }
+    PRUint16  value;
+};
+
+struct AutoSwap_PRInt16 {
+    operator PRInt16() { return NS_SWAP16(value); }
+    operator PRUint32() { return NS_SWAP16(value); }
+    PRInt16  value;
+};
+
+struct AutoSwap_PRUint32 {
+    operator PRUint32() { return NS_SWAP32(value); }
+    PRUint32  value;
+};
+
+struct AutoSwap_PRUint64 {
+    operator PRUint64() { return NS_SWAP64(value); }
+    PRUint64  value;
+};
+
+struct SFNTHeader {
+    AutoSwap_PRUint32    sfntVersion;            // Fixed, 0x00010000 for version 1.0.
+    AutoSwap_PRUint16    numTables;              // Number of tables.
+    AutoSwap_PRUint16    searchRange;            // (Maximum power of 2 <= numTables) x 16.
+    AutoSwap_PRUint16    entrySelector;          // Log2(maximum power of 2 <= numTables).
+    AutoSwap_PRUint16    rangeShift;             // NumTables x 16-searchRange.        
+};
+
+struct TableDirEntry {
+    AutoSwap_PRUint32    tag;                    // 4 -byte identifier.
+    AutoSwap_PRUint32    checkSum;               // CheckSum for this table.
+    AutoSwap_PRUint32    offset;                 // Offset from beginning of TrueType font file.
+    AutoSwap_PRUint32    length;                 // Length of this table.        
+};
+
+struct HeadTable {
+    enum {
+        HEAD_MAGIC_NUMBER = 0x5F0F3CF5
+    };
+
+    AutoSwap_PRUint32    tableVersionNumber;    // Fixed, 0x00010000 for version 1.0.
+    AutoSwap_PRUint32    fontRevision;          // Set by font manufacturer.
+    AutoSwap_PRUint32    checkSumAdjustment;    // To compute: set it to 0, sum the entire font as ULONG, then store 0xB1B0AFBA - sum.
+    AutoSwap_PRUint32    magicNumber;           // Set to 0x5F0F3CF5.
+    AutoSwap_PRUint16    flags;
+    AutoSwap_PRUint16    unitsPerEm;            // Valid range is from 16 to 16384. This value should be a power of 2 for fonts that have TrueType outlines.
+    AutoSwap_PRUint64    created;               // Number of seconds since 12:00 midnight, January 1, 1904. 64-bit integer
+    AutoSwap_PRUint64    modified;              // Number of seconds since 12:00 midnight, January 1, 1904. 64-bit integer
+    AutoSwap_PRInt16     xMin;                  // For all glyph bounding boxes.
+    AutoSwap_PRInt16     yMin;                  // For all glyph bounding boxes.
+    AutoSwap_PRInt16     xMax;                  // For all glyph bounding boxes.
+    AutoSwap_PRInt16     yMax;                  // For all glyph bounding boxes.
+    AutoSwap_PRUint16    macStyle;              // Bit 0: Bold (if set to 1);
+    AutoSwap_PRUint16    lowestRecPPEM;         // Smallest readable size in pixels.
+    AutoSwap_PRInt16     fontDirectionHint;
+    AutoSwap_PRInt16     indexToLocFormat;
+    AutoSwap_PRInt16     glyphDataFormat;
+};
+
+// name table has a header, followed by name records, followed by string data
+struct NameHeader {
+    AutoSwap_PRUint16    format;                 // Format selector (=0).
+    AutoSwap_PRUint16    count;                  // Number of name records.
+    AutoSwap_PRUint16    stringOffset;           // Offset to start of string storage (from start of table)
+};
+
+struct NameRecord {
+    AutoSwap_PRUint16    platformID;             // Platform ID
+    AutoSwap_PRUint16    encodingID;             // Platform-specific encoding ID
+    AutoSwap_PRUint16    languageID;             // Language ID
+    AutoSwap_PRUint16    nameID;                 // Name ID.
+    AutoSwap_PRUint16    length;                 // String length (in bytes).
+    AutoSwap_PRUint16    offset;                 // String offset from start of storage area (in bytes).
+
+    enum {
+        NAME_ID_FAMILY = 1,
+        NAME_ID_STYLE = 2,
+        NAME_ID_FULL = 4,
+        NAME_ID_VERSION = 5,
+        PLATFORM_ID_UNICODE = 0,                 // Mac OS uses this typically
+        PLATFORM_ID_MICROSOFT = 3,
+        ENCODING_ID_MICROSOFT_UNICODEBMP = 1,    // with Microsoft platformID, BMP-only Unicode encoding
+        LANG_ID_MICROSOFT_EN_US = 0x0409         // with Microsoft platformID, EN US lang code
+    };
+};
+
+struct OS2Table {
+    AutoSwap_PRUint16    version;                // 0004 = OpenType 1.5
+    AutoSwap_PRInt16     xAvgCharWidth;
+    AutoSwap_PRUint16    usWeightClass;
+    AutoSwap_PRUint16    usWidthClass;
+    AutoSwap_PRUint16    fsType;
+    AutoSwap_PRInt16     ySubscriptXSize;
+    AutoSwap_PRInt16     ySubscriptYSize;
+    AutoSwap_PRInt16     ySubscriptXOffset;
+    AutoSwap_PRInt16     ySubscriptYOffset;
+    AutoSwap_PRInt16     ySuperscriptXSize;
+    AutoSwap_PRInt16     ySuperscriptYSize;
+    AutoSwap_PRInt16     ySuperscriptXOffset;
+    AutoSwap_PRInt16     ySuperscriptYOffset;
+    AutoSwap_PRInt16     yStrikeoutSize;
+    AutoSwap_PRInt16     yStrikeoutPosition;
+    AutoSwap_PRInt16     sFamilyClass;
+    PRUint8              panose[10];
+    AutoSwap_PRUint32    unicodeRange1;
+    AutoSwap_PRUint32    unicodeRange2;
+    AutoSwap_PRUint32    unicodeRange3;
+    AutoSwap_PRUint32    unicodeRange4;
+    PRUint8              achVendID[4];
+    AutoSwap_PRUint16    fsSelection;
+    AutoSwap_PRUint16    usFirstCharIndex;
+    AutoSwap_PRUint16    usLastCharIndex;
+    AutoSwap_PRInt16     sTypoAscender;
+    AutoSwap_PRInt16     sTypoDescender;
+    AutoSwap_PRInt16     sTypoLineGap;
+    AutoSwap_PRUint16    usWinAscent;
+    AutoSwap_PRUint16    usWinDescent;
+    AutoSwap_PRUint32    codePageRange1;
+    AutoSwap_PRUint32    codePageRange2;
+    AutoSwap_PRInt16     sxHeight;
+    AutoSwap_PRInt16     sCapHeight;
+    AutoSwap_PRUint16    usDefaultChar;
+    AutoSwap_PRUint16    usBreakChar;
+    AutoSwap_PRUint16    usMaxContext;
+};
+
+// Embedded OpenType (EOT) handling
+// needed for dealing with downloadable fonts on Windows
+//
+// EOT version 0x00020001
+// based on http://www.w3.org/Submission/2008/SUBM-EOT-20080305/
+//
+// EOT header consists of a fixed-size portion containing general font
+// info, followed by a variable-sized portion containing name data,
+// followed by the actual TT/OT font data (non-byte values are always
+// stored in big-endian format)
+//
+// EOT header is stored in *little* endian order!!
+
+struct EOTFixedHeader {
+
+    PRUint32      eotSize;            // Total structure length in PRUint8s (including string and font data)
+    PRUint32      fontDataSize;       // Length of the OpenType font (FontData) in PRUint8s
+    PRUint32      version;            // Version number of this format - 0x00010000
+    PRUint32      flags;              // Processing Flags
+    PRUint8       panose[10];         // The PANOSE value for this font - See http://www.microsoft.com/typography/otspec/os2.htm#pan
+    PRUint8       charset;            // In Windows this is derived from TEXTMETRIC.tmCharSet. This value specifies the character set of the font. DEFAULT_CHARSET (0x01) indicates no preference. - See http://msdn2.microsoft.com/en-us/library/ms534202.aspx
+    PRUint8       italic;             // If the bit for ITALIC is set in OS/2.fsSelection, the value will be 0x01 - See http://www.microsoft.com/typography/otspec/os2.htm#fss
+    PRUint32      weight;             // The weight value for this font - See http://www.microsoft.com/typography/otspec/os2.htm#wtc
+    PRUint16      fsType;             // Type flags that provide information about embedding permissions - See http://www.microsoft.com/typography/otspec/os2.htm#fst
+    PRUint16      magicNumber;        // Magic number for EOT file - 0x504C. Used to check for data corruption.
+    PRUint32      unicodeRange1;      // OS/2.UnicodeRange1 (bits 0-31) - See http://www.microsoft.com/typography/otspec/os2.htm#ur
+    PRUint32      unicodeRange2;      // OS/2.UnicodeRange2 (bits 32-63) - See http://www.microsoft.com/typography/otspec/os2.htm#ur
+    PRUint32      unicodeRange3;      // OS/2.UnicodeRange3 (bits 64-95) - See http://www.microsoft.com/typography/otspec/os2.htm#ur
+    PRUint32      unicodeRange4;      // OS/2.UnicodeRange4 (bits 96-127) - See http://www.microsoft.com/typography/otspec/os2.htm#ur
+    PRUint32      codePageRange1;     // CodePageRange1 (bits 0-31) - See http://www.microsoft.com/typography/otspec/os2.htm#cpr
+    PRUint32      codePageRange2;     // CodePageRange2 (bits 32-63) - See http://www.microsoft.com/typography/otspec/os2.htm#cpr
+    PRUint32      checkSumAdjustment; // head.CheckSumAdjustment - See http://www.microsoft.com/typography/otspec/head.htm
+    PRUint32      reserved[4];        // Reserved - must be 0
+    PRUint16      padding1;           // Padding to maintain long alignment. Padding value must always be set to 0x0000.
+
+    enum {
+        EOT_VERSION = 0x00020001,
+        EOT_MAGIC_NUMBER = 0x504c,
+        EOT_DEFAULT_CHARSET = 0x01,
+        EOT_EMBED_PRINT_PREVIEW = 0x0004,
+        EOT_FAMILY_NAME_INDEX = 0,    // order of names in variable portion of EOT header
+        EOT_STYLE_NAME_INDEX = 1,
+        EOT_VERSION_NAME_INDEX = 2,
+        EOT_FULL_NAME_INDEX = 3,
+        EOT_NUM_NAMES = 4
+    };
+
+};
+
+// EOT variable-sized header (version 0x00020001 - contains 4 name
+// fields, each with the structure):
+//
+//   // number of bytes in the name array
+//   PRUint16 size;
+//   // array of UTF-16 chars, total length = <size> bytes
+//   // note: english version of name record string
+//   PRUint8  name[size]; 
+//
+// This structure is used for the following names, each separated by two
+// bytes of padding (always 0 with no padding after the rootString):
+//
+//   familyName  - based on name ID = 1
+//   styleName   - based on name ID = 2
+//   versionName - based on name ID = 5
+//   fullName    - based on name ID = 4
+//   rootString  - used to restrict font usage to a specific domain
+//
+
+class AutoCloseFile {
+public:
+    AutoCloseFile(PRFileDesc *aFileDesc) 
+        : mFile(aFileDesc) { }
+    ~AutoCloseFile() { PR_Close(mFile); }
+    PRFileDesc *mFile;
+};
+
+static PRFileDesc *
+OpenFontFile(nsIFile *aFontData)
+{
+    // open up the font file
+    nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(aFontData);
+    if (!localFile)
+        return nsnull;
+
+    PRFileDesc *fd;
+    nsresult rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
+    if (NS_FAILED(rv) || !fd)
+        return nsnull;
+
+    return fd;
+}
+
+static PRBool
+IsValidVersion(PRUint32 version)
+{
+    // normally 0x00010000, CFF-style OT fonts == 'OTTO' and Apple TT fonts = 'true'
+    return version == 0x10000 || version == 'OTTO' || version == 'true';
+}
+
+// copy and swap UTF-16 values, assume no surrogate pairs, can be in place
+static void
+CopySwapUTF16(PRUint16 *aInBuf, PRUint16 *aOutBuf, PRUint32 aLen)
+{
+    PRUint16 *end = aInBuf + aLen;
+    while (aInBuf < end) {
+        PRUint16 value = *aInBuf;
+        *aOutBuf = (value >> 8) | (value & 0xff) << 8;
+        aOutBuf++;
+        aInBuf++;
+    }
+}
+
+// name table stores set of name record structures, followed by
+// large block containing all the strings.  name record offset and length
+// indicates the offset and length within that block.
+// http://www.microsoft.com/typography/otspec/name.htm
+struct NameRecordData {
+    PRUint32  offset;
+    PRUint32  length;
+};
+
+#if DEBUG
+static void DumpEOTHeader(PRUint8 *aHeader, PRUint32 aHeaderLen)
+{
+    PRUint32 offset = 0;
+    PRUint8 *ch = aHeader;
+
+    printf("\n\nlen == %d\n\n", aHeaderLen);
+    while (offset < aHeaderLen) {
+        printf("%7.7x    ", offset);
+        int i;
+        for (i = 0; i < 16; i++) {
+            printf("%2.2x  ", *ch++);
+        }
+        printf("\n");
+        offset += 16;
+    }
+}
+#endif
+
+nsresult
+gfxFontUtils::MakeEOTHeader(nsIFile *aFontData, nsTArray<PRUint8> *aHeader, 
+                            PRBool *aIsCFF)
+{
+    PRInt32 bytesRead;
+
+    // assume TrueType
+    *aIsCFF = PR_FALSE;
+
+    NS_ASSERTION(aHeader, "null header");
+    NS_ASSERTION(aHeader->Length() == 0, "non-empty header passed in");
+    NS_ASSERTION(aIsCFF, "null boolean ptr");
+
+    if (!aHeader->AppendElements(sizeof(EOTFixedHeader)))
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    EOTFixedHeader *eotHeader = reinterpret_cast<EOTFixedHeader*> (aHeader->Elements());
+    memset(eotHeader, 0, sizeof(EOTFixedHeader));
+
+    // open the font file
+    PRFileDesc *fd = OpenFontFile(aFontData);
+    if (!fd)
+        return NS_ERROR_FAILURE;
+
+    AutoCloseFile autoCloseFile(fd);
+
+    PRFileInfo64 fileInfo;
+    if (PR_GetOpenFileInfo64(fd, &fileInfo) != PR_SUCCESS 
+        || fileInfo.size > PRInt64(0xFFFFFFFF)) 
+        return NS_ERROR_FAILURE;
+
+    PRUint32 fontDataSize = PRUint32(fileInfo.size);
+
+    // set up header fields
+    eotHeader->fontDataSize = fontDataSize;
+    eotHeader->version = EOTFixedHeader::EOT_VERSION;
+    eotHeader->flags = 0;  // don't specify any special processing
+    eotHeader->charset = EOTFixedHeader::EOT_DEFAULT_CHARSET;
+    eotHeader->fsType = EOTFixedHeader::EOT_EMBED_PRINT_PREVIEW;
+    eotHeader->magicNumber = EOTFixedHeader::EOT_MAGIC_NUMBER;
+
+    // read in the sfnt header
+    SFNTHeader sfntHeader;
+    bytesRead = PR_Read(fd, &sfntHeader, sizeof(SFNTHeader));
+    if (bytesRead != sizeof(SFNTHeader) || !IsValidVersion(sfntHeader.sfntVersion))
+        return NS_ERROR_FAILURE;
+
+    // iterate through the table headers to find the head, name and OS/2 tables
+    PRBool foundHead = PR_FALSE, foundOS2 = PR_FALSE, foundName = PR_FALSE, foundGlyphs = PR_FALSE;
+    PRUint32 headOffset, headLen, nameOffset, nameLen, os2Offset, os2Len;
+    PRUint32 i, numTables;
+
+    numTables = sfntHeader.numTables;
+    for (i = 0; i < numTables; i++) {
+        TableDirEntry dirEntry;
+        bytesRead = PR_Read(fd, &dirEntry, sizeof(TableDirEntry));
+        if (bytesRead != sizeof(TableDirEntry))
+            return NS_ERROR_FAILURE;
+
+        switch (dirEntry.tag) {
+
+        case 'head':
+            foundHead = PR_TRUE;
+            headOffset = dirEntry.offset;
+            headLen = dirEntry.length;
+            if (headLen < sizeof(HeadTable))
+                return NS_ERROR_FAILURE;
+            break;
+
+        case 'name':
+            foundName = PR_TRUE;
+            nameOffset = dirEntry.offset;
+            nameLen = dirEntry.length;
+            break;
+
+        case 'OS/2':
+            foundOS2 = PR_TRUE;
+            os2Offset = dirEntry.offset;
+            os2Len = dirEntry.length;
+            break;
+
+        case 'glyf':  // TrueType-style quadratic glyph table
+            foundGlyphs = PR_TRUE;
+            break;
+
+        case 'CFF ':  // PS-style cubic glyph table
+            foundGlyphs = PR_TRUE;
+            *aIsCFF = PR_TRUE;
+            break;
+
+        default:
+            break;
+        }
+
+        if (foundHead && foundName && foundOS2 && foundGlyphs)
+            break;
+    }
+
+    // require these three tables on Windows
+    if (!foundHead || !foundName || !foundOS2)
+        return NS_ERROR_FAILURE;
+
+    // read in the data from those tables
+    PROffset64 offset;
+
+    // -- head table data
+    HeadTable  headData;
+    offset = PR_Seek64(fd, PROffset64(headOffset), PR_SEEK_SET);
+    if (offset == -1)
+        return NS_ERROR_FAILURE;
+    bytesRead = PR_Read(fd, &headData, sizeof(HeadTable));
+    if (bytesRead != sizeof(HeadTable) || headData.magicNumber != HeadTable::HEAD_MAGIC_NUMBER)
+        return NS_ERROR_FAILURE;
+
+    eotHeader->checkSumAdjustment = headData.checkSumAdjustment;
+
+    // -- name table data
+
+    // -- first, read name table header
+    NameHeader nameHeader;
+
+    offset = PR_Seek64(fd, PROffset64(nameOffset), PR_SEEK_SET);
+    if (offset == -1)
+        return NS_ERROR_FAILURE;
+    bytesRead = PR_Read(fd, &nameHeader, sizeof(NameHeader));
+    if (bytesRead != sizeof(NameHeader))
+        return NS_ERROR_FAILURE;
+
+    // -- seek point is now at the start of name records
+
+    // -- iterate through name records, look for specific name ids with
+    //    matching platform/encoding/etc. and store offset/lengths
+    NameRecordData names[EOTFixedHeader::EOT_NUM_NAMES] = {0};
+    PRUint32 nameCount = nameHeader.count;
+
+    for (i = 0; i < nameCount; i++) {
+        NameRecord nameRecord;
+
+        bytesRead = PR_Read(fd, &nameRecord, sizeof(NameRecord));
+        if (bytesRead != sizeof(NameRecord))
+            return NS_ERROR_FAILURE;
+
+        // looking for Microsoft English US name strings, skip others
+        if (PRUint32(nameRecord.platformID) != NameRecord::PLATFORM_ID_MICROSOFT || 
+                PRUint32(nameRecord.encodingID) != NameRecord::ENCODING_ID_MICROSOFT_UNICODEBMP || 
+                PRUint32(nameRecord.languageID) != NameRecord::LANG_ID_MICROSOFT_EN_US)
+            continue;
+
+        switch ((PRUint32)nameRecord.nameID) {
+
+        case NameRecord::NAME_ID_FAMILY:
+            names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].offset = nameRecord.offset;
+            names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].length = nameRecord.length;
+            break;
+
+        case NameRecord::NAME_ID_STYLE:
+            names[EOTFixedHeader::EOT_STYLE_NAME_INDEX].offset = nameRecord.offset;
+            names[EOTFixedHeader::EOT_STYLE_NAME_INDEX].length = nameRecord.length;
+            break;
+
+        case NameRecord::NAME_ID_FULL:
+            names[EOTFixedHeader::EOT_FULL_NAME_INDEX].offset = nameRecord.offset;
+            names[EOTFixedHeader::EOT_FULL_NAME_INDEX].length = nameRecord.length;
+            break;
+
+        case NameRecord::NAME_ID_VERSION:
+            names[EOTFixedHeader::EOT_VERSION_NAME_INDEX].offset = nameRecord.offset;
+            names[EOTFixedHeader::EOT_VERSION_NAME_INDEX].length = nameRecord.length;
+            break;
+
+        default:
+            break;
+        }
+
+        if (names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].length &&
+            names[EOTFixedHeader::EOT_STYLE_NAME_INDEX].length &&
+            names[EOTFixedHeader::EOT_FULL_NAME_INDEX].length &&
+            names[EOTFixedHeader::EOT_VERSION_NAME_INDEX].length)
+            break;
+    }
+
+    if (!(names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].length &&
+          names[EOTFixedHeader::EOT_STYLE_NAME_INDEX].length &&
+          names[EOTFixedHeader::EOT_FULL_NAME_INDEX].length &&
+          names[EOTFixedHeader::EOT_VERSION_NAME_INDEX].length)) 
+    {
+        return NS_ERROR_FAILURE;
+    }        
+
+    // -- expand buffer if needed to include variable-length portion
+    PRUint32 eotVariableLength = 0;
+    eotVariableLength = (names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].length & (~1)) +
+                        (names[EOTFixedHeader::EOT_STYLE_NAME_INDEX].length & (~1)) +
+                        (names[EOTFixedHeader::EOT_FULL_NAME_INDEX].length & (~1)) +
+                        (names[EOTFixedHeader::EOT_VERSION_NAME_INDEX].length & (~1)) +
+                        EOTFixedHeader::EOT_NUM_NAMES * (2 /* size */ 
+                                                         + 2 /* padding */) +
+                        2 /* null root string size */;
+
+    if (!aHeader->AppendElements(eotVariableLength))
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    // append the string data to the end of the EOT header
+    PRUint8 *eotEnd = aHeader->Elements() + sizeof(EOTFixedHeader);
+    PROffset64 strOffset;
+    PRUint32 strLen;
+
+    for (i = 0; i < EOTFixedHeader::EOT_NUM_NAMES; i++) {
+        PRUint32 namelen = names[i].length;
+        PRUint32 nameoff = names[i].offset;  // offset from base of string storage
+
+        strOffset = nameOffset + PRUint32(nameHeader.stringOffset) + nameoff;
+        offset = PR_Seek64(fd, strOffset, PR_SEEK_SET);
+        if (offset == -1)
+            return NS_ERROR_FAILURE;
+
+        // output 2-byte str size   
+        strLen = namelen & (~1);  // UTF-16 string len must be even
+        *((PRUint16*) eotEnd) = PRUint16(strLen);
+        eotEnd += 2;
+
+        // read in actual string and swap bytes from big-endian
+        // (TrueType/OpenType) to little-endian (EOT)
+        bytesRead = PR_Read(fd, eotEnd, strLen);
+        if (PRUint32(bytesRead) != strLen)
+            return NS_ERROR_FAILURE;
+
+        // length is number of UTF-16 chars, not bytes    
+        CopySwapUTF16(reinterpret_cast<PRUint16*>(eotEnd), 
+                      reinterpret_cast<PRUint16*>(eotEnd), 
+                      (strLen >> 1));  
+        eotEnd += strLen;
+
+        // add 2-byte zero padding to the end of each string
+        *eotEnd++ = 0;
+        *eotEnd++ = 0;
+
+       // Note: Microsoft's WEFT tool produces name strings which
+       // include an extra null at the end of each string, in addition
+       // to the 2-byte zero padding that separates the string fields. 
+       // Don't think this is important to imitate...
+    }
+
+    // append null root string size
+    *eotEnd++ = 0;
+    *eotEnd++ = 0;
+
+    NS_ASSERTION(eotEnd == aHeader->Elements() + aHeader->Length(), 
+                 "header length calculation incorrect");
+                 
+    // -- OS/2 table data
+    OS2Table  os2Data;
+    offset = PR_Seek64(fd, PROffset64(os2Offset), PR_SEEK_SET);
+    if (offset == -1)
+        return NS_ERROR_FAILURE;
+    bytesRead = PR_Read(fd, &os2Data, sizeof(OS2Table));
+    if (bytesRead != sizeof(OS2Table))
+        return NS_ERROR_FAILURE;
+
+    memcpy(eotHeader->panose, os2Data.panose, sizeof(eotHeader->panose));
+
+    eotHeader->italic = (PRUint16) os2Data.fsSelection & 0x01;
+    eotHeader->weight = os2Data.usWeightClass;
+    eotHeader->unicodeRange1 = os2Data.unicodeRange1;
+    eotHeader->unicodeRange2 = os2Data.unicodeRange2;
+    eotHeader->unicodeRange3 = os2Data.unicodeRange3;
+    eotHeader->unicodeRange4 = os2Data.unicodeRange4;
+    eotHeader->codePageRange1 = os2Data.codePageRange1;
+    eotHeader->codePageRange2 = os2Data.codePageRange2;
+
+    eotHeader->eotSize = aHeader->Length() + fontDataSize;
+
+    // DumpEOTHeader(aHeader->Elements(), aHeader->Length());
+
+    return NS_OK;
+}
+
+#endif
--- a/gfx/thebes/src/gfxOS2Fonts.cpp
+++ b/gfx/thebes/src/gfxOS2Fonts.cpp
@@ -452,18 +452,19 @@ already_AddRefed<gfxOS2Font> gfxOS2Font:
     return static_cast<gfxOS2Font *>(f);
 }
 
 /**********************************************************************
  * class gfxOS2FontGroup
  **********************************************************************/
 
 gfxOS2FontGroup::gfxOS2FontGroup(const nsAString& aFamilies,
-                                 const gfxFontStyle* aStyle)
-    : gfxFontGroup(aFamilies, aStyle)
+                                 const gfxFontStyle* aStyle,
+                                 gfxUserFontSet *aUserFontSet)
+    : gfxFontGroup(aFamilies, aStyle, aUserFontSet)
 {
 #ifdef DEBUG_thebes_2
     printf("gfxOS2FontGroup[%#x]::gfxOS2FontGroup(\"%s\", %#x)\n",
            (unsigned)this, NS_LossyConvertUTF16toASCII(aFamilies).get(),
            (unsigned)aStyle);
 #endif
 
     // check for WarpSans and as we cannot display that (yet), replace
@@ -505,17 +506,17 @@ gfxOS2FontGroup::~gfxOS2FontGroup()
 {
 #ifdef DEBUG_thebes_2
     printf("gfxOS2FontGroup[%#x]::~gfxOS2FontGroup()\n", (unsigned)this);
 #endif
 }
 
 gfxFontGroup *gfxOS2FontGroup::Copy(const gfxFontStyle *aStyle)
 {
-    return new gfxOS2FontGroup(mFamilies, aStyle);
+    return new gfxOS2FontGroup(mFamilies, aStyle, mUserFontSet);
 }
 
 /**
  * We use this to append an LTR or RTL Override character to the start of the
  * string. This forces Pango to honour our direction even if there are neutral
  * characters in the string.
  */
 static PRInt32 AppendDirectionalIndicatorUTF8(PRBool aIsRTL, nsACString& aString)
--- a/gfx/thebes/src/gfxOS2Platform.cpp
+++ b/gfx/thebes/src/gfxOS2Platform.cpp
@@ -159,19 +159,20 @@ gfxOS2Platform::ResolveFontName(const ns
 nsresult
 gfxOS2Platform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
 {
     return sFontconfigUtils->GetStandardFamilyName(aFontName, aFamilyName);
 }
 
 gfxFontGroup *
 gfxOS2Platform::CreateFontGroup(const nsAString &aFamilies,
-                                const gfxFontStyle *aStyle)
+                const gfxFontStyle *aStyle,
+                gfxUserFontSet *aUserFontSet)
 {
-    return new gfxOS2FontGroup(aFamilies, aStyle);
+    return new gfxOS2FontGroup(aFamilies, aStyle, aUserFontSet);
 }
 
 already_AddRefed<gfxOS2Font>
 gfxOS2Platform::FindFontForChar(PRUint32 aCh, gfxOS2Font *aFont)
 {
 #ifdef DEBUG_thebes
     printf("gfxOS2Platform::FindFontForChar(%d, ...)\n", aCh);
 #endif
--- a/gfx/thebes/src/gfxPangoFonts.cpp
+++ b/gfx/thebes/src/gfxPangoFonts.cpp
@@ -779,33 +779,34 @@ FontCallback (const nsAString& fontName,
     if (sa->IndexOf(fontName) < 0) {
         sa->AppendString(fontName);
     }
 
     return PR_TRUE;
 }
 
 gfxPangoFontGroup::gfxPangoFontGroup (const nsAString& families,
-                                      const gfxFontStyle *aStyle)
-    : gfxFontGroup(families, aStyle),
+                                      const gfxFontStyle *aStyle,
+                                      gfxUserFontSet *aUserFontSet)
+    : gfxFontGroup(families, aStyle, aUserFontSet),
       mBasePangoFont(nsnull), mAdjustedSize(0)
 {
     mFonts.AppendElements(1);
 }
 
 gfxPangoFontGroup::~gfxPangoFontGroup()
 {
     if (mBasePangoFont)
         g_object_unref(mBasePangoFont);
 }
 
 gfxFontGroup *
 gfxPangoFontGroup::Copy(const gfxFontStyle *aStyle)
 {
-    return new gfxPangoFontGroup(mFamilies, aStyle);
+    return new gfxPangoFontGroup(mFamilies, aStyle, mUserFontSet);
 }
 
 // A string of family names suitable for fontconfig
 void
 gfxPangoFontGroup::GetFcFamilies(nsAString& aFcFamilies)
 {
     nsStringArray familyArray;
 
--- a/gfx/thebes/src/gfxPlatform.cpp
+++ b/gfx/thebes/src/gfxPlatform.cpp
@@ -51,16 +51,17 @@
 #elif defined(XP_OS2)
 #include "gfxOS2Platform.h"
 #endif
 
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
 #include "gfxTextRunCache.h"
 #include "gfxTextRunWordCache.h"
+#include "gfxUserFontSet.h"
 
 #include "nsIPref.h"
 #include "nsServiceManagerUtils.h"
 
 #include "nsWeakReference.h"
 
 #include "cairo.h"
 #include "lcms.h"
@@ -299,16 +300,39 @@ gfxPlatform::GetFontList(const nsACStrin
 }
 
 nsresult
 gfxPlatform::UpdateFontList()
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+#define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
+
+PRBool
+gfxPlatform::DownloadableFontsEnabled()
+{
+    static PRBool initialized = PR_FALSE;
+    static PRBool allowDownloadableFonts = PR_FALSE;
+
+    if (initialized == PR_FALSE) {
+        initialized = PR_TRUE;
+        nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
+        if (prefs) {
+            PRBool allow;
+            nsresult rv = prefs->GetBoolPref(GFX_DOWNLOADABLE_FONTS_ENABLED, &allow);
+            if (NS_SUCCEEDED(rv))
+                allowDownloadableFonts = allow;
+        }
+    }
+
+    return allowDownloadableFonts;
+}
+
+
 static void
 AppendGenericFontFromPref(nsString& aFonts, const char *aLangGroup, const char *aGenericName)
 {
     nsresult rv;
 
     nsCOMPtr<nsIPref> prefs(do_GetService(NS_PREF_CONTRACTID));
     if (!prefs)
         return;
--- a/gfx/thebes/src/gfxPlatformGtk.cpp
+++ b/gfx/thebes/src/gfxPlatformGtk.cpp
@@ -262,19 +262,20 @@ gfxPlatformGtk::ResolveFontName(const ns
 nsresult
 gfxPlatformGtk::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
 {
     return sFontconfigUtils->GetStandardFamilyName(aFontName, aFamilyName);
 }
 
 gfxFontGroup *
 gfxPlatformGtk::CreateFontGroup(const nsAString &aFamilies,
-                                const gfxFontStyle *aStyle)
+                                const gfxFontStyle *aStyle,
+                                gfxUserFontSet *aUserFontSet)
 {
-    return new gfxPangoFontGroup(aFamilies, aStyle);
+    return new gfxPangoFontGroup(aFamilies, aStyle, aUserFontSet);
 }
 
 #else
 
 nsresult
 gfxPlatformGtk::GetFontList(const nsACString& aLangGroup,
                             const nsACString& aGenericFamily,
                             nsStringArray& aListOfFonts)
--- a/gfx/thebes/src/gfxPlatformMac.cpp
+++ b/gfx/thebes/src/gfxPlatformMac.cpp
@@ -39,16 +39,17 @@
 #include "gfxPlatformMac.h"
 
 #include "gfxImageSurface.h"
 #include "gfxQuartzSurface.h"
 #include "gfxQuartzImageSurface.h"
 
 #include "gfxQuartzFontCache.h"
 #include "gfxAtsuiFonts.h"
+#include "gfxUserFontSet.h"
 
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 #include "nsIPrefLocalizedString.h"
 #include "nsServiceManagerUtils.h"
 #include "nsCRT.h"
 
 #include "lcms.h"
@@ -110,19 +111,46 @@ nsresult
 gfxPlatformMac::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
 {
     gfxQuartzFontCache::SharedFontCache()->GetStandardFamilyName(aFontName, aFamilyName);
     return NS_OK;
 }
 
 gfxFontGroup *
 gfxPlatformMac::CreateFontGroup(const nsAString &aFamilies,
-                                const gfxFontStyle *aStyle)
+                                const gfxFontStyle *aStyle,
+                                gfxUserFontSet *aUserFontSet)
+{
+    return new gfxAtsuiFontGroup(aFamilies, aStyle, aUserFontSet);
+}
+
+gfxFontEntry* 
+gfxPlatformMac::LookupLocalFont(const nsAString& aFontName)
+{
+    return gfxQuartzFontCache::SharedFontCache()->LookupLocalFont(aFontName);
+}
+
+gfxFontEntry* 
+gfxPlatformMac::MakePlatformFont(const gfxFontEntry *aProxyEntry, const gfxDownloadedFontData* aFontData)
 {
-    return new gfxAtsuiFontGroup(aFamilies, aStyle);
+    return gfxQuartzFontCache::SharedFontCache()->MakePlatformFont(aProxyEntry, aFontData);
+}
+
+PRBool
+gfxPlatformMac::IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags)
+{
+    // reject based on format flags
+    if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_EOT | gfxUserFontSet::FLAG_FORMAT_SVG)) {
+        return PR_FALSE;
+    }
+
+    // reject based on filetype in URI
+
+    // otherwise, return true
+    return PR_TRUE;
 }
 
 nsresult
 gfxPlatformMac::GetFontList(const nsACString& aLangGroup,
                             const nsACString& aGenericFamily,
                             nsStringArray& aListOfFonts)
 {
     gfxQuartzFontCache::SharedFontCache()->
--- a/gfx/thebes/src/gfxQuartzFontCache.h
+++ b/gfx/thebes/src/gfxQuartzFontCache.h
@@ -78,39 +78,40 @@ public:
 
     const nsString& FamilyName();
 
     PRUint32 Traits() { return mTraits; }
     
     ATSUFontID GetFontID();
     nsresult ReadCMAP();
 
-    MacOSFamilyEntry* FamilyEntry() { return mFamily; }
 protected:
+    // for use with data fonts
+    MacOSFontEntry(ATSUFontID aFontID, PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle, gfxUserFontData *aUserFontData);
+
     PRUint32 mTraits;
     MacOSFamilyEntry *mFamily;
 
+    ATSUFontID mATSUFontID;
     PRPackedBool mATSUIDInitialized;
-    ATSUFontID mATSUFontID;
 };
 
 // helper class for adding other family names back into font cache
 class AddOtherFamilyNameFunctor;
 
 // a single font family, referencing one or more faces 
 class MacOSFamilyEntry : public gfxFontFamily
 {
 public:
 
     friend class gfxQuartzFontCache;
 
     // name is canonical font family name returned from NSFontManager
-    MacOSFamilyEntry(nsString &aName) :
-        gfxFontFamily(aName), mOtherFamilyNamesInitialized(PR_FALSE), mHasOtherFamilyNames(PR_FALSE),
-        mIsBadUnderlineFontFamily(PR_FALSE)
+    MacOSFamilyEntry(nsAString &aName) :
+        gfxFontFamily(aName), mOtherFamilyNamesInitialized(PR_FALSE), mHasOtherFamilyNames(PR_FALSE)
     {}
   
     virtual ~MacOSFamilyEntry() {}
         
     virtual void LocalizedName(nsAString& aLocalizedName);
     virtual PRBool HasOtherFamilyNames();
     
     nsTArray<nsRefPtr<MacOSFontEntry> >& GetFontList() { return mAvailableFonts; }
@@ -127,50 +128,52 @@ public:
     // iterates over faces looking for a match with a given characters
     // used as part of the font fallback process
     void FindFontForChar(FontSearch *aMatchData);
     
     // read in other family names, if any, and use functor to add each into cache
     virtual void ReadOtherFamilyNames(AddOtherFamilyNameFunctor& aOtherFamilyFunctor);
     
     // search for a specific face using the Postscript name
-    MacOSFontEntry* FindFont(const nsString& aPostscriptName);
+    MacOSFontEntry* FindFont(const nsAString& aPostscriptName);
 
     // read in cmaps for all the faces
     void ReadCMAP() {
         PRUint32 i, numFonts = mAvailableFonts.Length();
         for (i = 0; i < numFonts; i++)
             mAvailableFonts[i]->ReadCMAP();
     }
 
-
-    // whether this font family is in "bad" underline offset blacklist.
-    PRBool IsBadUnderlineFontFamily() { return mIsBadUnderlineFontFamily != 0; }
+    // set whether this font family is in "bad" underline offset blacklist.
+    void SetBadUnderlineFont(PRBool aIsBadUnderlineFont) {
+        PRUint32 i, numFonts = mAvailableFonts.Length();
+        for (i = 0; i < numFonts; i++)
+            mAvailableFonts[i]->mIsBadUnderlineFont = aIsBadUnderlineFont;
+    }
 
 protected:
     
     // add font entries into array that match specified traits, returned in array listed by weight
     // i.e. aFontsForWeights[4] ==> pointer to the font entry for a 400-weight face on return
     // returns true if one or more faces found
     PRBool FindFontsWithTraits(gfxFontEntry* aFontsForWeights[], PRUint32 aPosTraitsMask, 
                                 PRUint32 aNegTraitsMask);
 
     PRBool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], const gfxFontStyle& aFontStyle);
 
     nsTArray<nsRefPtr<MacOSFontEntry> >  mAvailableFonts;
     PRPackedBool mOtherFamilyNamesInitialized;
     PRPackedBool mHasOtherFamilyNames;
-    PRPackedBool mIsBadUnderlineFontFamily;
 };
 
 // special-case situation where specific faces need to be treated as separate font family
 class SingleFaceFamily : public MacOSFamilyEntry
 {
 public:
-    SingleFaceFamily(nsString &aName) :
+    SingleFaceFamily(nsAString &aName) :
         MacOSFamilyEntry(aName)
     {}
     
     virtual ~SingleFaceFamily() {}
     
     virtual void LocalizedName(nsAString& aLocalizedName);
     
     // read in other family names, if any, and use functor to add each into cache
@@ -217,16 +220,20 @@ public:
 
     static PRInt32 AppleWeightToCSSWeight(PRInt32 aAppleWeight);
     
     PRBool GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<MacOSFamilyEntry> > *array);
     void SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<MacOSFamilyEntry> >& array);
     
     void AddOtherFamilyName(MacOSFamilyEntry *aFamilyEntry, nsAString& aOtherFamilyName);
 
+    gfxFontEntry* LookupLocalFont(const nsAString& aFontName);
+    
+    gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry, const gfxDownloadedFontData* aFontData);
+
 private:
     static PLDHashOperator PR_CALLBACK FindFontForCharProc(nsStringHashKey::KeyType aKey,
                                                              nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
                                                              void* userArg);
 
     static gfxQuartzFontCache *sSharedFontCache;
 
     gfxQuartzFontCache();
@@ -239,17 +246,17 @@ private:
     void InitOtherFamilyNames();
     
     // special case font faces treated as font families (set via prefs)
     void InitSingleFaceList();
     
     // commonly used fonts for which the name table should be loaded at startup
     void PreloadNamesList();
 
-    // initialize the MacOSFamilyEntry::mIsBadUnderlineFontFamily from pref.
+    // initialize the bad underline blacklist from pref.
     void InitBadUnderlineList();
 
     // eliminate faces which have the same ATSUI id
     void EliminateDuplicateFaces(const nsAString& aFamilyName);
                                                              
     // explicitly set font traits for all faces to fixed-pitch
     void SetFixedPitch(const nsAString& aFamilyName);
                                                              
@@ -288,11 +295,18 @@ private:
     // flag set after InitOtherFamilyNames is called upon first name lookup miss
     PRPackedBool mOtherFamilyNamesInitialized;
 
     // data used as part of the font cmap loading process
     nsTArray<nsRefPtr<MacOSFamilyEntry> > mFontFamiliesToLoad;
     PRUint32 mStartIndex;
     PRUint32 mIncrement;
     PRUint32 mNumFamilies;
+    
+    // keep track of ATS generation to prevent unneeded updates when loading downloaded fonts
+    PRUint32 mATSGeneration;
+    
+    enum {
+        kATSGenerationInitial = -1
+    };
 };
 
 #endif /* GFXQUARTZFONTCACHE_H_ */
--- a/gfx/thebes/src/gfxQuartzFontCache.mm
+++ b/gfx/thebes/src/gfxQuartzFontCache.mm
@@ -39,20 +39,28 @@
 
 #include <Carbon.h>
 
 #import <AppKit/AppKit.h>
 
 #include "gfxPlatformMac.h"
 #include "gfxQuartzFontCache.h"
 #include "gfxAtsuiFonts.h"
+#include "gfxUserFontSet.h"
 
 #include "nsIPref.h"  // for pref changes callback notification
 #include "nsServiceManagerUtils.h"
 
+#include "nsDirectoryServiceUtils.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsISimpleEnumerator.h"
+
+#include <unistd.h>
+#include <time.h>
+
 // _atsFontID is private; add it in our new category to NSFont
 @interface NSFont (MozillaCategory)
 - (ATSUFontID)_atsFontID;
 @end
 
 // font info loader constants
 static const PRUint32 kDelayBeforeLoadingCmaps = 8 * 1000; // 8secs
 static const PRUint32 kIntervalBetweenLoadingCmaps = 150; // 150ms
@@ -108,22 +116,57 @@ gfxQuartzFontCache::GenerateFontListKey(
 /* MacOSFontEntry */
 #pragma mark-
 
 MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, 
                                 PRInt32 aAppleWeight, PRUint32 aTraits, MacOSFamilyEntry *aFamily)
     : gfxFontEntry(aPostscriptName), mTraits(aTraits), mFamily(aFamily), mATSUFontID(0),
         mATSUIDInitialized(0)
 {
-    mWeight = gfxQuartzFontCache::AppleWeightToCSSWeight(aAppleWeight);
+    mWeight = gfxQuartzFontCache::AppleWeightToCSSWeight(aAppleWeight) * 100;
 
     mItalic = (mTraits & NSItalicFontMask ? 1 : 0);
     mFixedPitch = (mTraits & NSFixedPitchFontMask ? 1 : 0);
 }
 
+MacOSFontEntry::MacOSFontEntry(ATSUFontID aFontID, PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle, gfxUserFontData *aUserFontData)
+{
+    // xxx - stretch is basically ignored for now
+    
+    mATSUIDInitialized = PR_TRUE;
+    mATSUFontID = aFontID;
+    mUserFontData = aUserFontData;
+    mWeight = aWeight;
+    mStretch = aStretch;
+    mFixedPitch = PR_FALSE; // xxx - do we need this for downloaded fonts?
+    mItalic = (aItalicStyle & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
+    
+    mTraits = (mItalic ? NSItalicFontMask : NSUnitalicFontMask) |
+              (mFixedPitch ? NSFixedPitchFontMask : 0) |
+              (mWeight >= 600 ? NSBoldFontMask : NSUnboldFontMask);
+              
+    // get the postscript name
+    OSStatus err;
+    NSString *psname = NULL;
+
+    // now lookup the Postscript name
+    err = ATSFontGetPostScriptName((ATSFontRef) aFontID, kATSOptionFlagsDefault, (CFStringRef*) (&psname));
+    if (err == noErr) {
+        GetStringForNSString(psname, mName);
+        [psname release];
+    } else {
+        mIsValid = PR_FALSE;
+#if DEBUG
+        char warnBuf[1024];
+        sprintf(warnBuf, "ATSFontGetPostScriptName err = %d", (PRInt32)err);
+        NS_WARNING(warnBuf);
+#endif    
+    }
+}
+
 const nsString& 
 MacOSFontEntry::FamilyName()
 {
     return mFamily->Name();
 }
 
 ATSUFontID MacOSFontEntry::GetFontID() 
 {
@@ -169,17 +212,24 @@ MacOSFontEntry::ReadCMAP()
     if (mCmapInitialized) return NS_OK;
     ATSUFontID fontID = GetFontID();
 
     // attempt this once, if errors occur leave a blank cmap
     mCmapInitialized = PR_TRUE;
 
     status = ATSFontGetTable(fontID, 'cmap', 0, 0, 0, &size);
     cmapSize = size;
-    //printf( "cmap size: %s %d\n", NS_ConvertUTF16toUTF8(mName).get(), size );
+    //printf( "cmap size: %s %d", NS_ConvertUTF16toUTF8(mName).get(), size );
+#if DEBUG
+    if (status != noErr) {
+        char warnBuf[1024];
+        sprintf(warnBuf, "ATSFontGetTable returned %d for (%s)", (PRInt32)status, NS_ConvertUTF16toUTF8(mName).get());
+        NS_WARNING(warnBuf);
+    }   
+#endif    
     NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
 
     nsAutoTArray<PRUint8,16384> buffer;
     if (!buffer.AppendElements(size))
         return NS_ERROR_OUT_OF_MEMORY;
     PRUint8 *cmap = buffer.Elements();
 
     status = ATSFontGetTable(fontID, 'cmap', 0, size, cmap, &size);
@@ -293,17 +343,17 @@ static const PRUint32 kTraits_NonNormalW
 
 MacOSFontEntry*
 MacOSFamilyEntry::FindFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold)
 {
     return static_cast<MacOSFontEntry*> (FindFontForStyle(*aStyle, aNeedsBold));
 }
 
 MacOSFontEntry*
-MacOSFamilyEntry::FindFont(const nsString& aPostscriptName)
+MacOSFamilyEntry::FindFont(const nsAString& aPostscriptName)
 {
     // find the font using a simple linear search
     PRUint32 numFonts = mAvailableFonts.Length();
     for (PRUint32 i = 0; i < numFonts; i++) {
         MacOSFontEntry *fe = mAvailableFonts[i];
         if (fe->Name() == aPostscriptName)
             return fe;
     }
@@ -334,29 +384,29 @@ MacOSFamilyEntry::FindFontForChar(FontSe
         // omitting from original windows code -- family name, lang group, pitch
         // not available in current FontEntry implementation
 
         if (aMatchData->fontToMatch) { 
             const gfxFontStyle *style = aMatchData->fontToMatch->GetStyle();
             
             // italics
             if (fe->IsItalic() && 
-                    (style->style == FONT_STYLE_ITALIC || style->style == FONT_STYLE_ITALIC)) {
+                    (style->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0) {
                 rank += 5;
             }
             
             // weight
             PRInt8 baseWeight, weightDistance;
             style->ComputeWeightAndOffset(&baseWeight, &weightDistance);
 
             // xxx - not entirely correct, the one unit of weight distance reflects 
             // the "next bolder/lighter face"
             PRUint32 targetWeight = (baseWeight * 100) + (weightDistance * 100);
 
-            PRUint32 entryWeight = fe->Weight() * 100;
+            PRUint32 entryWeight = fe->Weight();
             if (entryWeight == targetWeight) {
                 rank += 5;
             } else {
                 PRUint32 diffWeight = abs(entryWeight - targetWeight);
                 if (diffWeight <= 100)  // favor faces close in weight
                     rank += 2;
             }
         } else {
@@ -388,17 +438,18 @@ MacOSFamilyEntry::FindFontsWithTraits(gf
     for (PRUint32 i = 0; i < numFonts; i++) {
         MacOSFontEntry *fe = mAvailableFonts[i];
         
         // if traits match, add to list of fonts
         PRUint32 traits = fe->Traits();
         
         // aPosTraitsMask == 0 ==> match all
         if ((!aPosTraitsMask || (traits & aPosTraitsMask)) && !(traits & aNegTraitsMask)) {
-            PRInt32 weight = fe->Weight();
+            PRInt32 weight = fe->Weight() / 100;
+            NS_ASSERTION(weight >= 1 && weight <= 9, "bogus font weight value!");
             
             // always prefer the first font for a given weight, helps deal a bit with 
             // families with lots of faces (e.g. Minion Pro)
             if (!aFontsForWeights[weight]) {
                 aFontsForWeights[weight] = fe;
                 found = PR_TRUE;
             }
         }
@@ -407,23 +458,24 @@ MacOSFamilyEntry::FindFontsWithTraits(gf
 }
 
 PRBool 
 MacOSFamilyEntry::FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], const gfxFontStyle& aFontStyle)
 {
     // short-circuit the single face per family case
     if (mAvailableFonts.Length() == 1) {
         MacOSFontEntry *fe = mAvailableFonts[0];
-        PRUint32 weight = fe->Weight();
+        PRUint32 weight = fe->Weight() / 100;
+        NS_ASSERTION(weight >= 1 && weight <= 9, "bogus font weight value!");
         aFontsForWeights[weight] = fe;
         return PR_TRUE;
     }
 
     PRBool found = PR_FALSE;
-    PRBool isItalic = (aFontStyle.style == FONT_STYLE_ITALIC || aFontStyle.style == FONT_STYLE_OBLIQUE);
+    PRBool isItalic = (aFontStyle.style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
 
     // match italic faces
     if (isItalic) {    
         // first search for italic normal width fonts
         found = FindFontsWithTraits(aFontsForWeights, NSItalicFontMask, kTraits_NonNormalWidthMask);
         
         // if not found, italic any width ones
         if (!found) {
@@ -624,16 +676,18 @@ void SingleFaceFamily::ReadOtherFamilyNa
 /* gfxQuartzFontCache */
 #pragma mark-
 
 gfxQuartzFontCache *gfxQuartzFontCache::sSharedFontCache = nsnull;
 
 gfxQuartzFontCache::gfxQuartzFontCache()
     : mStartIndex(0), mIncrement(kNumFontsPerSlice), mNumFamilies(0)
 {
+    mATSGeneration = PRUint32(kATSGenerationInitial);
+
     mFontFamilies.Init(100);
     mOtherFamilyNames.Init(30);
     mOtherFamilyNamesInitialized = PR_FALSE;
     mPrefFonts.Init(10);
 
     InitFontList();
     ::ATSFontNotificationSubscribe(ATSNotification,
                                    kATSFontNotifyOptionDefault,
@@ -647,16 +701,25 @@ gfxQuartzFontCache::gfxQuartzFontCache()
 
 }
 
 const PRUint32 kNonNormalTraits = NSItalicFontMask | NSBoldFontMask | NSNarrowFontMask | NSExpandedFontMask | NSCondensedFontMask | NSCompressedFontMask;
 
 void
 gfxQuartzFontCache::InitFontList()
 {
+    ATSGeneration currentGeneration = ATSGeneration();
+    
+    // need to ignore notifications after adding each font
+    if (mATSGeneration == currentGeneration)
+        return;
+
+    mATSGeneration = currentGeneration;
+    PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit) updating to generation: %d", mATSGeneration));                                         
+    
     mFontFamilies.Clear();
     mOtherFamilyNames.Clear();
     mOtherFamilyNamesInitialized = PR_FALSE;
     mPrefFonts.Clear();
     mCodepointsWithNoFonts.reset();
     CancelLoader();
 
     // iterate over available families
@@ -913,17 +976,17 @@ gfxQuartzFontCache::InitBadUnderlineList
     PRUint32 numFonts = blacklist.Length();
     for (PRUint32 i = 0; i < numFonts; i++) {
         PRBool found;
         nsAutoString key;
         GenerateFontListKey(blacklist[i], key);
 
         MacOSFamilyEntry *familyEntry = mFontFamilies.GetWeak(key, &found);
         if (familyEntry)
-            familyEntry->mIsBadUnderlineFontFamily = 1;
+            familyEntry->SetBadUnderlineFont(PR_TRUE);
     }
 }
 
 PRBool 
 gfxQuartzFontCache::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName)
 {
     MacOSFamilyEntry *family = FindFamily(aFontName);
     if (family) {
@@ -1200,16 +1263,168 @@ gfxQuartzFontCache::AddOtherFamilyName(M
     if (!mOtherFamilyNames.GetWeak(key, &found)) {
         mOtherFamilyNames.Put(key, aFamilyEntry);
         PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit-otherfamily) canonical family: %s, other family: %s\n", 
                                             NS_ConvertUTF16toUTF8(aFamilyEntry->Name()).get(), 
                                             NS_ConvertUTF16toUTF8(aOtherFamilyName).get()));
     }
 }
 
+gfxFontEntry* 
+gfxQuartzFontCache::LookupLocalFont(const nsAString& aFontName)
+{
+    NSString *faceName = GetNSStringForString(aFontName);
+    NSFont *font = [NSFont fontWithName:faceName size:0.0];
+
+    if (font) {
+        nsAutoString availableFamilyName;
+        NSString *availableFamily = [font familyName];
+        GetStringForNSString(availableFamily, availableFamilyName);
+
+        MacOSFamilyEntry *familyEntry = FindFamily(availableFamilyName);
+        if (familyEntry) {
+            MacOSFontEntry *fontEntry = familyEntry->FindFont(aFontName);
+            return fontEntry;
+        }
+    }
+
+    // didn't find the font
+    return nsnull;
+}
+
+// grumble, another non-publised Apple API dependency (found in Webkit code)
+// activated with this value, font will not be found via system lookup routines
+// it can only be used via the created ATSUFontID
+// needed to prevent one doc from finding a font used in a separate doc
+
+enum {
+    kPrivateATSFontContextPrivate = 3
+};
+
+class MacOSUserFontData : public gfxUserFontData {
+public:
+    MacOSUserFontData(ATSFontContainerRef aContainerRef, nsIFile *aFontFile, 
+                      nsISupports *aDownloader)
+        : mContainerRef(aContainerRef), mFontFile(aFontFile), 
+          mDownloader(aDownloader)
+    { }
+
+    virtual ~MacOSUserFontData()
+    {
+        // deactivate font
+        if (mContainerRef)
+            ATSFontDeactivate(mContainerRef, NULL, kATSOptionFlagsDefault);
+
+        if (mFontFile) {
+            mFontFile->Remove(PR_FALSE); // ignore errors
+        }
+    }
+
+    ATSFontContainerRef     mContainerRef;
+    nsCOMPtr<nsIFile>       mFontFile;
+
+    // maintaining a ref to this keeps temp file around or cache file pinned
+    nsCOMPtr<nsISupports>   mDownloader;  
+};
+
+static OSStatus
+MakeFSSpec(FSSpec *aFSSpec, NSString *path)
+{
+    FSRef fsref;
+    OSStatus err = FSPathMakeRef((UInt8*)([path fileSystemRepresentation]), &fsref, NULL);
+
+    if (err == noErr)
+        err = FSGetCatalogInfo(&fsref, kFSCatInfoNone, NULL, NULL, aFSSpec, NULL);
+
+    return err;
+}
+
+gfxFontEntry* 
+gfxQuartzFontCache::MakePlatformFont(const gfxFontEntry *aProxyEntry, 
+                                     const gfxDownloadedFontData* aFontData)
+{
+    OSStatus err;
+    FSSpec spec;
+    nsAutoString filePath;
+
+    NS_ASSERTION(aFontData && aFontData->mFontFile, 
+                 "MakePlatformFont called with null file ptr");
+
+    if (!aFontData->mFontFile)
+        return nsnull;
+
+    aFontData->mFontFile->GetPath(filePath);
+
+    NSString *path = GetNSStringForString(filePath);
+    if (!path)
+        return nsnull;
+
+    // assumption: filename is already in the form xxx.ttf, otherwise
+    // ATS will reject
+
+    err = MakeFSSpec(&spec, path);
+    if (err != noErr)
+        return nsnull;
+
+    ATSUFontID fontID;
+    ATSFontContainerRef containerRef;
+
+    err = ATSFontActivateFromFileSpecification(&spec, 
+                                               kPrivateATSFontContextPrivate, 
+                                               kATSFontFormatUnspecified,
+                                               NULL, 
+                                               kATSOptionFlagsDoNotNotify, 
+                                               &containerRef);
+    if (err != noErr)
+        return nsnull;
+
+    mATSGeneration = ATSGeneration();
+
+    // ignoring containers with multiple fonts, use the first face only for now
+    err = ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1, 
+                                   (ATSFontRef*)&fontID, NULL);
+    if (err != noErr)
+        return nsnull;
+
+    // font entry will own this
+    MacOSUserFontData *userFontData = new MacOSUserFontData(containerRef, 
+                                                            aFontData->mFontFile, 
+                                                            aFontData->mDownloader);
+    if (!userFontData)
+        return nsnull;
+
+    PRUint16 w = aProxyEntry->mWeight;
+    NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
+
+    MacOSFontEntry *newFontEntry = 
+        new MacOSFontEntry(fontID, w, aProxyEntry->mStretch, 
+                           (PRUint32(aProxyEntry->mItalic) ? 
+                                       FONT_STYLE_ITALIC : 
+                                       FONT_STYLE_NORMAL), 
+                           userFontData);
+
+    // if something is funky about this font, delete immediately
+    if (newFontEntry && !newFontEntry->mIsValid) {
+#if DEBUG
+        char warnBuf[1024];
+        const gfxProxyFontEntry *proxyEntry = 
+            static_cast<const gfxProxyFontEntry*> (aProxyEntry);
+        sprintf(warnBuf, "downloaded font not loaded properly, removed (%s) for (%s)", 
+                [path UTF8String], 
+                NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
+        NS_WARNING(warnBuf);
+#endif    
+        delete newFontEntry;
+        return nsnull;
+    }
+
+    return newFontEntry;
+}
+
+
 void 
 gfxQuartzFontCache::InitLoader()
 {
     GetFontFamilyList(mFontFamiliesToLoad);
     mStartIndex = 0;
     mNumFamilies = mFontFamiliesToLoad.Length();
 }
 
--- a/gfx/thebes/src/gfxTextRunWordCache.cpp
+++ b/gfx/thebes/src/gfxTextRunWordCache.cpp
@@ -108,27 +108,29 @@ public:
 
 protected:
     struct CacheHashKey {
         void        *mFontOrGroup;
         const void  *mString;
         PRUint32     mLength;
         PRUint32     mAppUnitsPerDevUnit;
         PRUint32     mStringHash;
+        PRUint64     mUserFontSetGeneration;
         PRPackedBool mIsDoubleByteText;
         PRPackedBool mIsRTL;
         PRPackedBool mEnabledOptionalLigatures;
         PRPackedBool mOptimizeSpeed;
         
         CacheHashKey(gfxTextRun *aBaseTextRun, void *aFontOrGroup,
                      PRUint32 aStart, PRUint32 aLength, PRUint32 aHash)
             : mFontOrGroup(aFontOrGroup), mString(aBaseTextRun->GetTextAt(aStart)),
               mLength(aLength),
               mAppUnitsPerDevUnit(aBaseTextRun->GetAppUnitsPerDevUnit()),
               mStringHash(aHash),
+              mUserFontSetGeneration(aBaseTextRun->GetUserFontSetGeneration()),
               mIsDoubleByteText((aBaseTextRun->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) == 0),
               mIsRTL(aBaseTextRun->IsRightToLeft()),
               mEnabledOptionalLigatures((aBaseTextRun->GetFlags() & gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES) == 0),
               mOptimizeSpeed((aBaseTextRun->GetFlags() & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED) != 0)
         {
         }
     };
 
@@ -192,24 +194,27 @@ static PRLogModuleInfo *gWordCacheLog = 
 static inline PRUint32
 HashMix(PRUint32 aHash, PRUnichar aCh)
 {
     return (aHash >> 28) ^ (aHash << 4) ^ aCh;
 }
 
 // If the substring of the textrun is rendered entirely in the first font
 // of the textrun's fontgroup, then return that font. Otherwise return the
-// fontgroup.
+// fontgroup.  When a user font set is in use, always return the font group.
 static void *GetWordFontOrGroup(gfxTextRun *aTextRun, PRUint32 aOffset,
                                 PRUint32 aLength)
 {
+    gfxFontGroup *fontGroup = aTextRun->GetFontGroup();
+    if (fontGroup->GetUserFontSet() != nsnull)
+        return fontGroup;
+        
     PRUint32 glyphRunCount;
     const gfxTextRun::GlyphRun *glyphRuns = aTextRun->GetGlyphRuns(&glyphRunCount);
     PRUint32 glyphRunIndex = aTextRun->FindFirstGlyphRunContaining(aOffset);
-    gfxFontGroup *fontGroup = aTextRun->GetFontGroup();
     gfxFont *firstFont = fontGroup->GetFontAt(0);
     if (glyphRuns[glyphRunIndex].mFont != firstFont)
         return fontGroup;
 
     PRUint32 glyphRunEnd = glyphRunIndex == glyphRunCount - 1
         ? aTextRun->GetLength() : glyphRuns[glyphRunIndex + 1].mCharacterOffset;
     if (aOffset + aLength <= glyphRunEnd)
         return firstFont;
@@ -255,26 +260,32 @@ IsWordBoundary(PRUnichar aChar)
  */
 PRBool
 TextRunWordCache::LookupWord(gfxTextRun *aTextRun, gfxFont *aFirstFont,
                              PRUint32 aStart, PRUint32 aEnd, PRUint32 aHash,
                              nsTArray<DeferredWord>* aDeferredWords)
 {
     if (aEnd <= aStart)
         return PR_TRUE;
+        
+    gfxFontGroup *fontGroup = aTextRun->GetFontGroup();
 
-    CacheHashKey key(aTextRun, aFirstFont, aStart, aEnd - aStart, aHash);
+    PRBool useFontGroup = (fontGroup->GetUserFontSet() != nsnull);
+    CacheHashKey key(aTextRun, (useFontGroup ? (void*)fontGroup : (void*)aFirstFont), aStart, aEnd - aStart, aHash);
     CacheHashEntry *fontEntry = mCache.PutEntry(key);
     if (!fontEntry)
         return PR_FALSE;
     CacheHashEntry *existingEntry = nsnull;
 
     if (fontEntry->mTextRun) {
         existingEntry = fontEntry;
+    } else if (useFontGroup) {
+        PR_LOG(gWordCacheLog, PR_LOG_DEBUG, ("%p(%d-%d,%d): added using font group", aTextRun, aStart, aEnd - aStart, aHash));
     } else {
+        // test to see if this can be found using the font group instead
         PR_LOG(gWordCacheLog, PR_LOG_DEBUG, ("%p(%d-%d,%d): added using font", aTextRun, aStart, aEnd - aStart, aHash));
         key.mFontOrGroup = aTextRun->GetFontGroup();
         CacheHashEntry *groupEntry = mCache.GetEntry(key);
         if (groupEntry) {
             existingEntry = groupEntry;
             mCache.RawRemoveEntry(fontEntry);
             PR_LOG(gWordCacheLog, PR_LOG_DEBUG, ("%p(%d-%d,%d): removed using font", aTextRun, aStart, aEnd - aStart, aHash));
             fontEntry = nsnull;
@@ -299,17 +310,18 @@ TextRunWordCache::LookupWord(gfxTextRun 
 
 #ifdef DEBUG
     ++aTextRun->mCachedWords;
 #endif
     // Set up the cache entry so that if later in this textrun we hit this
     // entry, we'll copy within our own textrun
     fontEntry->mTextRun = aTextRun;
     fontEntry->mWordOffset = aStart;
-    fontEntry->mHashedByFont = PR_TRUE;
+    if (!useFontGroup)
+        fontEntry->mHashedByFont = PR_TRUE;
     return PR_FALSE;
 }
 
 /**
  * Processes all deferred words. Each word is copied from the source
  * textrun to the output textrun. (The source may be an earlier word in the
  * output textrun.) If the word was not matched by the textrun's fontgroup's
  * first font, then we remove the entry we optimistically added to the cache
@@ -326,16 +338,21 @@ TextRunWordCache::FinishTextRun(gfxTextR
                                 const nsTArray<DeferredWord>& aDeferredWords,
                                 PRBool aSuccessful)
 {
     aTextRun->SetFlagBits(gfxTextRunWordCache::TEXT_IN_CACHE);
 
     PRUint32 i;
     gfxFontGroup *fontGroup = aTextRun->GetFontGroup();
     gfxFont *font = fontGroup->GetFontAt(0);
+    
+    // need to use the font group when user font set is around, since
+    // the first font may change as the result of a font download
+    PRBool useFontGroup = (fontGroup->GetUserFontSet() != nsnull);
+
     // copy deferred words from various sources into destination textrun
     for (i = 0; i < aDeferredWords.Length(); ++i) {
         const DeferredWord *word = &aDeferredWords[i];
         gfxTextRun *source = word->mSourceTextRun;
         if (!source) {
             source = aNewRun;
         }
         // If the word starts inside a cluster we don't want this word
@@ -345,21 +362,21 @@ TextRunWordCache::FinishTextRun(gfxTextR
         PRBool wordStartsInsideLigature =
             !source->IsLigatureGroupStart(word->mSourceOffset);
         if (source == aNewRun) {
             // We created a cache entry for this word based on the assumption
             // that the word matches GetFontAt(0). If this assumption is false,
             // we need to remove that cache entry and replace it with an entry
             // keyed off the fontgroup.
             PRBool rekeyWithFontGroup =
-                GetWordFontOrGroup(aNewRun, word->mSourceOffset, word->mLength) != font;
+                GetWordFontOrGroup(aNewRun, word->mSourceOffset, word->mLength) != font && !useFontGroup;
             if (!aSuccessful || rekeyWithFontGroup ||
                 wordStartsInsideCluster || wordStartsInsideLigature) {
                 // We need to remove the current placeholder cache entry
-                CacheHashKey key(aTextRun, font, word->mDestOffset, word->mLength,
+                CacheHashKey key(aTextRun, (useFontGroup ? (void*)fontGroup : (void*)font), word->mDestOffset, word->mLength,
                                  word->mHash);
                 NS_ASSERTION(mCache.GetEntry(key),
                              "This entry should have been added previously!");
                 mCache.RemoveEntry(key);
 #ifdef DEBUG
                 --aTextRun->mCachedWords;
 #endif
                 PR_LOG(gWordCacheLog, PR_LOG_DEBUG, ("%p(%d-%d,%d): removed using font", aTextRun, word->mDestOffset, word->mLength, word->mHash));
@@ -454,16 +471,19 @@ MakeBlankTextRun(const void* aText, PRUi
 }
 
 gfxTextRun *
 TextRunWordCache::MakeTextRun(const PRUnichar *aText, PRUint32 aLength,
                               gfxFontGroup *aFontGroup,
                               const gfxFontGroup::Parameters *aParams,
                               PRUint32 aFlags)
 {
+    // update font list when using user fonts (assures generation is current)
+    aFontGroup->UpdateFontList();
+
     if (aFontGroup->GetStyle()->size == 0) {
         // Short-circuit for size-0 fonts, as Windows and ATSUI can't handle
         // them, and always create at least size 1 fonts, i.e. they still
         // render something for size 0 fonts.
         return MakeBlankTextRun(aText, aLength, aFontGroup, aParams, aFlags);
     }
 
     nsAutoPtr<gfxTextRun> textRun;
@@ -525,27 +545,30 @@ TextRunWordCache::MakeTextRun(const PRUn
     }
 
     // create textrun for unknown words
     gfxTextRunFactory::Parameters params =
         { aParams->mContext, nsnull, nsnull, nsnull, 0, aParams->mAppUnitsPerDevUnit };
     nsAutoPtr<gfxTextRun> newRun;
     newRun = aFontGroup->MakeTextRun(tempString.Elements(), tempString.Length(),
                                      &params, aFlags | gfxTextRunFactory::TEXT_IS_PERSISTENT);
-
+    
     FinishTextRun(textRun, newRun, aParams, deferredWords, newRun != nsnull);
     return textRun.forget();
 }
 
 gfxTextRun *
 TextRunWordCache::MakeTextRun(const PRUint8 *aText, PRUint32 aLength,
                               gfxFontGroup *aFontGroup,
                               const gfxFontGroup::Parameters *aParams,
                               PRUint32 aFlags)
 {
+    // update font list when using user fonts (assures generation is current)
+    aFontGroup->UpdateFontList();
+
     if (aFontGroup->GetStyle()->size == 0) {
         // Short-circuit for size-0 fonts, as Windows and ATSUI can't handle
         // them, and always create at least size 1 fonts, i.e. they still
         // render something for size 0 fonts.
         return MakeBlankTextRun(aText, aLength, aFontGroup, aParams, aFlags);
     }
 
     aFlags |= gfxTextRunFactory::TEXT_IS_8BIT;
@@ -623,16 +646,17 @@ TextRunWordCache::RemoveWord(gfxTextRun 
                              PRUint32 aEnd, PRUint32 aHash)
 {
     if (aEnd <= aStart)
         return;
 
     PRUint32 length = aEnd - aStart;
     CacheHashKey key(aTextRun, GetWordFontOrGroup(aTextRun, aStart, length),
                      aStart, length, aHash);
+                     
     CacheHashEntry *entry = mCache.GetEntry(key);
     if (entry && entry->mTextRun == aTextRun) {
         // XXX would like to use RawRemoveEntry here plus some extra method
         // that conditionally shrinks the hashtable
         mCache.RemoveEntry(key);
 #ifdef DEBUG
         --aTextRun->mCachedWords;
 #endif
@@ -705,17 +729,18 @@ TextRunWordCache::CacheHashEntry::KeyEqu
 
     PRUint32 length = aKey->mLength;
     gfxFontGroup *fontGroup = mTextRun->GetFontGroup();
     if (!IsWordEnd(mTextRun, mWordOffset + length) ||
         GetFontOrGroup(fontGroup, mHashedByFont) != aKey->mFontOrGroup ||
         aKey->mAppUnitsPerDevUnit != mTextRun->GetAppUnitsPerDevUnit() ||
         aKey->mIsRTL != mTextRun->IsRightToLeft() ||
         aKey->mEnabledOptionalLigatures != ((mTextRun->GetFlags() & gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES) == 0) ||
-        aKey->mOptimizeSpeed != ((mTextRun->GetFlags() & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED) != 0))
+        aKey->mOptimizeSpeed != ((mTextRun->GetFlags() & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED) != 0) ||
+        aKey->mUserFontSetGeneration != (mTextRun->GetUserFontSetGeneration()))
         return PR_FALSE;
 
     if (mTextRun->GetFlags() & gfxFontGroup::TEXT_IS_8BIT) {
         const PRUint8 *text = mTextRun->GetText8Bit() + mWordOffset;
         if (!aKey->mIsDoubleByteText)
             return memcmp(text, aKey->mString, length) == 0;
         return CompareDifferentWidthStrings(text,
                                             static_cast<const PRUnichar *>(aKey->mString), length);
@@ -726,17 +751,22 @@ TextRunWordCache::CacheHashEntry::KeyEqu
         return CompareDifferentWidthStrings(static_cast<const PRUint8 *>(aKey->mString),
                                             text, length);
     }
 }
 
 PLDHashNumber
 TextRunWordCache::CacheHashEntry::HashKey(const KeyTypePointer aKey)
 {
-    return aKey->mStringHash + (long)aKey->mFontOrGroup + aKey->mAppUnitsPerDevUnit +
+    // only use lower 32 bits of generation counter in hash key, 
+    // since these vary the most
+    PRUint32 fontSetGen;
+    LL_L2UI(fontSetGen, aKey->mUserFontSetGeneration);
+
+    return aKey->mStringHash + fontSetGen + (long)aKey->mFontOrGroup + aKey->mAppUnitsPerDevUnit +
         aKey->mIsDoubleByteText + aKey->mIsRTL*2 + aKey->mEnabledOptionalLigatures*4 +
         aKey->mOptimizeSpeed*8;
 }
 
 #ifdef DEBUG
 PLDHashOperator PR_CALLBACK
 TextRunWordCache::CacheDumpEntry(CacheHashEntry* aEntry, void* userArg)
 {
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/gfxUserFontSet.cpp
@@ -0,0 +1,404 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is thebes gfx code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   John Daggett <jdaggett@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifdef MOZ_LOGGING
+#define FORCE_PR_LOG /* Allow logging in the release build */
+#endif /* MOZ_LOGGING */
+#include "prlog.h"
+
+#include "gfxUserFontSet.h"
+#include "gfxPlatform.h"
+#include "nsReadableUtils.h"
+#include "nsUnicharUtils.h"
+#include "nsVoidArray.h"
+#include "prlong.h"
+
+#ifdef PR_LOGGING
+static PRLogModuleInfo *gUserFontsLog = PR_NewLogModule("userfonts");
+#endif /* PR_LOGGING */
+
+#define LOG(args) PR_LOG(gUserFontsLog, PR_LOG_DEBUG, args)
+#define LOG_ENABLED() PR_LOG_TEST(gUserFontsLog, PR_LOG_DEBUG)
+
+static PRUint64 sFontSetGeneration = LL_INIT(0, 0);
+
+// TODO: support for unicode ranges not yet implemented
+
+gfxProxyFontEntry::gfxProxyFontEntry(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList, 
+             PRUint32 aWeight, 
+             PRUint32 aStretch, 
+             PRUint32 aItalicStyle, 
+             gfxSparseBitSet *aUnicodeRanges)
+    : gfxFontEntry(NS_LITERAL_STRING("Proxy")), mIsLoading(PR_FALSE)
+{
+    mIsProxy = PR_TRUE;
+    mSrcList = aFontFaceSrcList;
+    mSrcIndex = 0;
+    mWeight = aWeight;
+    mStretch = aStretch;
+    mItalic = (aItalicStyle & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
+}
+
+gfxProxyFontEntry::~gfxProxyFontEntry()
+{
+
+}
+
+
+PRBool
+gfxMixedFontFamily::FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], 
+                                        const gfxFontStyle& aFontStyle)
+{
+    PRBool italic = (aFontStyle.style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
+    PRBool matchesSomething;
+
+    for (PRUint32 j = 0; j < 2; j++) {
+        matchesSomething = PR_FALSE;
+        PRUint32 numFonts = mAvailableFonts.Length();
+        // build up an array of weights that match the italicness we're looking for
+        for (PRUint32 i = 0; i < numFonts; i++) {
+            gfxFontEntry *fe = mAvailableFonts[i];
+            PRUint32 weight = fe->mWeight/100;
+            if (fe->mItalic == italic) {
+                aFontsForWeights[weight] = fe;
+                matchesSomething = PR_TRUE;
+            }
+        }
+        if (matchesSomething)
+            break;
+        italic = !italic;
+    }
+
+    return matchesSomething;
+}
+
+
+gfxUserFontSet::gfxUserFontSet(LoaderContext *aContext)
+    : mLoaderContext(aContext)
+{
+    NS_ASSERTION(mLoaderContext, "font set loader context not initialized");
+    mFontFamilies.Init(5);
+    mLoaderContext->mUserFontSet = this;
+
+    IncrementGeneration();
+}
+
+gfxUserFontSet::~gfxUserFontSet()
+{
+
+}
+
+void
+gfxUserFontSet::AddFontFace(const nsAString& aFamilyName, 
+                            const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList, 
+                            PRUint32 aWeight, 
+                            PRUint32 aStretch, 
+                            PRUint32 aItalicStyle, 
+                            gfxSparseBitSet *aUnicodeRanges)
+{
+    nsAutoString key(aFamilyName);
+    ToLowerCase(key);
+
+    PRBool found;
+
+    if (aWeight == 0)
+        aWeight = FONT_WEIGHT_NORMAL;
+
+    // stretch, italic/oblique ==> zero implies normal
+
+    gfxMixedFontFamily *family = mFontFamilies.GetWeak(key, &found);
+    if (!family) {
+        family = new gfxMixedFontFamily(aFamilyName);
+        mFontFamilies.Put(key, family);
+    }
+
+    // construct a new face and add it into the family
+    if (family) {
+        gfxProxyFontEntry *proxyEntry = 
+            new gfxProxyFontEntry(aFontFaceSrcList, aWeight, aStretch, 
+                                                  aItalicStyle, aUnicodeRanges);
+        family->AddFontEntry(proxyEntry);
+        proxyEntry->mFamily = family;
+#ifdef PR_LOGGING
+        if (LOG_ENABLED()) {
+            LOG(("userfonts (%p) added (%s) with style: %s weight: %d stretch: %d", 
+                 this, NS_ConvertUTF16toUTF8(aFamilyName).get(), 
+                 (aItalicStyle & FONT_STYLE_ITALIC ? "italic" : 
+                     (aItalicStyle & FONT_STYLE_OBLIQUE ? "oblique" : "normal")), 
+                 aWeight, aStretch));
+        }
+#endif
+    }
+}
+
+gfxFontEntry*
+gfxUserFontSet::FindFontEntry(const nsAString& aName, 
+                              const gfxFontStyle& aFontStyle, 
+                              PRBool& aNeedsBold)
+{
+    nsAutoString key(aName);
+    ToLowerCase(key);
+
+    PRBool found;
+
+    gfxMixedFontFamily *family = mFontFamilies.GetWeak(key, &found);
+
+    // no user font defined for this name
+    if (!family)
+        return nsnull;
+
+    gfxFontEntry* fe = family->FindFontForStyle(aFontStyle, aNeedsBold);
+
+    // if not a proxy, font has already been loaded
+    if (!fe->mIsProxy)
+        return fe;
+
+    gfxProxyFontEntry *proxyEntry = static_cast<gfxProxyFontEntry*> (fe);
+
+    // if currently loading, return null for now
+    if (proxyEntry->mIsLoading)
+        return nsnull;
+
+    // hasn't been loaded yet, start the load process
+    LoadStatus status;
+
+    status = LoadNext(proxyEntry);
+
+    // if the load succeeded immediately, the font entry was replaced so
+    // search again
+    if (status == STATUS_LOADED)
+        return family->FindFontForStyle(aFontStyle, aNeedsBold);
+
+    // if either loading or an error occurred, return null
+    return nsnull;
+}
+
+
+PRBool 
+gfxUserFontSet::OnLoadComplete(gfxFontEntry *aFontToLoad, 
+                               const gfxDownloadedFontData& aFontData, 
+                               nsresult aDownloadStatus)
+{
+    NS_ASSERTION(aFontToLoad->mIsProxy, "trying to load font data for wrong font entry type");
+
+    if (!aFontToLoad->mIsProxy)
+        return PR_FALSE;
+
+    gfxProxyFontEntry *pe = static_cast<gfxProxyFontEntry*> (aFontToLoad);
+
+    // download successful, make platform font using font data
+    if (NS_SUCCEEDED(aDownloadStatus)) {
+        gfxFontEntry *fe = gfxPlatform::GetPlatform()->MakePlatformFont(pe, &aFontData);
+        if (fe) {
+            pe->mFamily->ReplaceFontEntry(pe, fe);
+            IncrementGeneration();
+#ifdef PR_LOGGING
+            if (LOG_ENABLED()) {
+                nsCAutoString fontURI;
+                pe->mSrcList[pe->mSrcIndex].mURI->GetSpec(fontURI);
+
+                nsAutoString filePath;
+                aFontData.mFontFile->GetPath(filePath);
+
+                LOG(("userfonts (%p) [src %d] loaded uri: (%s) file: (%s) for (%s) gen: %8.8x\n", 
+                     this, pe->mSrcIndex, fontURI.get(), 
+                     NS_ConvertUTF16toUTF8(filePath).get(), 
+                     NS_ConvertUTF16toUTF8(pe->mFamily->Name()).get(), PRUint32(mGeneration)));
+            }
+#endif
+            return PR_TRUE;
+        } else {
+#ifdef PR_LOGGING
+            if (LOG_ENABLED()) {
+                nsCAutoString fontURI;
+                pe->mSrcList[pe->mSrcIndex].mURI->GetSpec(fontURI);
+                LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s) error making platform font\n", 
+                     this, pe->mSrcIndex, fontURI.get(), 
+                     NS_ConvertUTF16toUTF8(pe->mFamily->Name()).get()));
+            }
+#endif
+        }
+    } else {
+        // download failed
+#ifdef PR_LOGGING
+        if (LOG_ENABLED()) {
+            nsCAutoString fontURI;
+            pe->mSrcList[pe->mSrcIndex].mURI->GetSpec(fontURI);
+            LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s) error %8.8x downloading font data\n", 
+                 this, pe->mSrcIndex, fontURI.get(), 
+                 NS_ConvertUTF16toUTF8(pe->mFamily->Name()).get(), 
+                 aDownloadStatus));
+        }
+#endif
+    }
+
+    // error occurred, load next src
+    LoadStatus status;
+
+    status = LoadNext(pe);
+    if (status == STATUS_LOADED)
+        return PR_TRUE;
+
+    return PR_FALSE;
+}
+
+
+gfxUserFontSet::LoadStatus
+gfxUserFontSet::LoadNext(gfxProxyFontEntry *aProxyEntry)
+{
+    PRUint32 numSrc = aProxyEntry->mSrcList.Length();
+
+    NS_ASSERTION(aProxyEntry->mSrcIndex < numSrc, "already at the end of the src list for user font");
+
+    NS_ASSERTION(mLoaderContext, "user font loader context not initialized");
+    if (!mLoaderContext)
+        return STATUS_ERROR; 
+
+    if (aProxyEntry->mIsLoading) {
+        aProxyEntry->mSrcIndex++;
+    } else {
+        aProxyEntry->mIsLoading = PR_TRUE;
+    }
+
+    // load each src entry in turn, until a local face is found or a download begins successfully
+    while (aProxyEntry->mSrcIndex < numSrc) {
+        const gfxFontFaceSrc& currSrc = aProxyEntry->mSrcList[aProxyEntry->mSrcIndex];
+
+        // src local ==> lookup and load   
+
+        if (currSrc.mIsLocal) {
+            gfxFontEntry *fe = gfxPlatform::GetPlatform()->LookupLocalFont(currSrc.mLocalName);
+            if (fe) {
+                aProxyEntry->mFamily->ReplaceFontEntry(aProxyEntry, fe);
+                IncrementGeneration();
+                LOG(("userfonts (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n", 
+                     this, aProxyEntry->mSrcIndex, 
+                     NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(), 
+                     NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get(), 
+                     PRUint32(mGeneration)));
+                return STATUS_LOADED;
+            } else {
+                LOG(("userfonts (%p) [src %d] failed local: (%s) for (%s)\n", 
+                     this, aProxyEntry->mSrcIndex, 
+                     NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(), 
+                     NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get()));            
+            }
+        } 
+
+        // src url ==> start the load process
+        else {
+            if (gfxPlatform::GetPlatform()->IsFontFormatSupported(currSrc.mURI, 
+                    currSrc.mFormatFlags)) {
+                PRBool loadOK = mLoaderContext->mLoaderProc(aProxyEntry, 
+                                                            currSrc.mURI, 
+                                                            mLoaderContext);
+                if (loadOK) {
+#ifdef PR_LOGGING
+                    if (LOG_ENABLED()) {
+                        nsCAutoString fontURI;
+                        currSrc.mURI->GetSpec(fontURI);
+                        LOG(("userfonts (%p) [src %d] loading uri: (%s) for (%s)\n", 
+                             this, aProxyEntry->mSrcIndex, fontURI.get(), 
+                             NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get()));
+                    }
+#endif
+                    return STATUS_LOADING;                  
+                } else {
+#ifdef PR_LOGGING
+                    if (LOG_ENABLED()) {
+                        nsCAutoString fontURI;
+                        currSrc.mURI->GetSpec(fontURI);
+                        LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s) download failed\n", 
+                             this, aProxyEntry->mSrcIndex, fontURI.get(), 
+                             NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get()));
+                    }
+#endif
+                }
+            } else {
+#ifdef PR_LOGGING
+                if (LOG_ENABLED()) {
+                    nsCAutoString fontURI;
+                    currSrc.mURI->GetSpec(fontURI);
+                    LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s) format not supported\n", 
+                         this, aProxyEntry->mSrcIndex, fontURI.get(), 
+                         NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get()));
+                }
+#endif
+            }
+        }
+
+        aProxyEntry->mSrcIndex++;
+    }
+
+    // all src's failed, remove this face
+    LOG(("userfonts (%p) failed all src for (%s)\n", 
+               this, NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get()));            
+
+    gfxMixedFontFamily *family = aProxyEntry->mFamily;
+
+    aProxyEntry->mFamily->RemoveFontEntry(aProxyEntry);
+
+    // no more faces?  remove the entire family
+    if (family->mAvailableFonts.Length() == 0) {
+        LOG(("userfonts (%p) failed all faces, remove family (%s)\n", 
+             this, NS_ConvertUTF16toUTF8(family->Name()).get()));            
+        RemoveFamily(family->Name());
+    }
+
+    return STATUS_END_OF_LIST;
+}
+
+
+void
+gfxUserFontSet::IncrementGeneration()
+{
+    // add one, increment again if zero
+    LL_ADD(sFontSetGeneration, sFontSetGeneration, 1);
+    if (LL_IS_ZERO(sFontSetGeneration))
+        LL_ADD(sFontSetGeneration, sFontSetGeneration, 1);
+    mGeneration = sFontSetGeneration;
+}
+
+
+void 
+gfxUserFontSet::RemoveFamily(const nsAString& aFamilyName)
+{
+    nsAutoString key(aFamilyName);
+    ToLowerCase(key);
+
+    mFontFamilies.Remove(key);
+}
--- a/gfx/thebes/src/gfxWindowsFonts.cpp
+++ b/gfx/thebes/src/gfxWindowsFonts.cpp
@@ -187,31 +187,18 @@ FontFamily::FamilyAddStylesProc(const EN
 
     FamilyAddStyleProcData *faspd = reinterpret_cast<FamilyAddStyleProcData*>(data);
     FontFamily *ff = faspd->ff;
     HDC hdc = faspd->dc;
 
     // Some fonts claim to support things > 900, but we don't so clamp the sizes
     logFont.lfWeight = PR_MAX(PR_MIN(logFont.lfWeight, 900), 100);
 
-    gfxWindowsFontType feType;
-    if (metrics.ntmFlags & NTM_TYPE1)
-        feType = GFX_FONT_TYPE_TYPE1;
-    else if (metrics.ntmFlags & (NTM_PS_OPENTYPE))
-        feType = GFX_FONT_TYPE_PS_OPENTYPE;
-    else if (metrics.ntmFlags & (NTM_TT_OPENTYPE))
-        feType = GFX_FONT_TYPE_TT_OPENTYPE;
-    else if (fontType == TRUETYPE_FONTTYPE)
-        feType = GFX_FONT_TYPE_TRUETYPE;
-    else if (fontType == RASTER_FONTTYPE)
-        feType = GFX_FONT_TYPE_RASTER;
-    else if (fontType == DEVICE_FONTTYPE)
-        feType = GFX_FONT_TYPE_DEVICE;
-    else
-        feType = GFX_FONT_TYPE_UNKNOWN;
+
+    gfxWindowsFontType feType = FontEntry::DetermineFontType(metrics, fontType);
 
     FontEntry *fe = nsnull;
     for (PRUint32 i = 0; i < ff->mVariations.Length(); ++i) {
         fe = ff->mVariations[i];
         if (feType > fe->mFontType) {
             // if the new type is better than the old one, remove the old entries
             ff->mVariations.RemoveElementAt(i);
             --i;
@@ -227,25 +214,24 @@ FontFamily::FamilyAddStylesProc(const EN
         if (fe->mWeight == logFont.lfWeight &&
             fe->mItalic == (logFont.lfItalic == 0xFF)) {
             // update the charset bit here since this could be different
             fe->mCharset[metrics.tmCharSet] = 1;
             return 1; 
         }
     }
 
-    fe = new FontEntry(ff->mName);
-    ff->mVariations.AppendElement(fe);
-    fe->mFontType = feType;
+    logFont.lfCharSet = DEFAULT_CHARSET;
+    logFont.lfOutPrecision = FontTypeToOutPrecision(feType);
+    fe = FontEntry::CreateFontEntry(ff->mName, feType, (logFont.lfItalic == 0xFF), (PRUint16) (logFont.lfWeight), nsnull, hdc, &logFont);
 
-    fe->mItalic = (logFont.lfItalic == 0xFF);
-    fe->mWeight = logFont.lfWeight;
+    if (!fe)
+        return 1;
 
-    if (fe->IsType1())
-        fe->mForceGDI = PR_TRUE;
+    ff->mVariations.AppendElement(fe);
 
     // mark the charset bit
     fe->mCharset[metrics.tmCharSet] = 1;
 
     fe->mWindowsFamily = logFont.lfPitchAndFamily & 0xF0;
     fe->mWindowsPitch = logFont.lfPitchAndFamily & 0x0F;
 
     if (nmetrics->ntmFontSig.fsUsb[0] != 0x00000000 &&
@@ -258,49 +244,17 @@ FontFamily::FamilyAddStylesProc(const EN
         for (PRUint32 i = 0; i < 4; ++i) {
             DWORD range = nmetrics->ntmFontSig.fsUsb[i];
             for (PRUint32 k = 0; k < 32; ++k) {
                 fe->mUnicodeRanges[x++] = (range & (1 << k)) != 0;
             }
         }
     }
 
-    fe->mIsBadUnderlineFont = ff->mIsBadUnderlineFont;
-
-    // read in the character map
-    logFont.lfCharSet = DEFAULT_CHARSET;
-    logFont.lfOutPrecision = FontTypeToOutPrecision(fe->mFontType);
-
-    HFONT font = CreateFontIndirectW(&logFont);
-
-    NS_ASSERTION(font, "This font creation should never ever ever fail");
-    if (font) {
-        HFONT oldFont = (HFONT)SelectObject(hdc, font);
-
-        // ReadCMAP may change the values of mUnicodeFont and mSymbolFont
-        if (NS_FAILED(ReadCMAP(hdc, fe))) {
-            // Type1 fonts aren't necessarily Unicode but
-            // this is the best guess we can make here
-            if (fe->IsType1())
-                fe->mUnicodeFont = PR_TRUE;
-            else
-                fe->mUnicodeFont = PR_FALSE;
-
-            // For fonts where we failed to read the character map,
-            // we can take a slow path to look up glyphs character by character
-            fe->mUnknownCMAP = PR_TRUE;
-
-            //printf("(fontinit-cmap) %s failed to get cmap, type1:%d \n", NS_ConvertUTF16toUTF8(fe->mFaceName).get(), (PRUint32)(fe->mIsType1));
-        } else {
-            //printf("(fontinit-cmap) %s cmap loaded, italic:%d, weight:%d\n", NS_ConvertUTF16toUTF8(fe->mFaceName).get(), (PRUint32)(fe->mItalic), (PRUint32)(fe->mWeight));
-        }
-
-        SelectObject(hdc, oldFont);
-        DeleteObject(font);
-    }
+    fe->mIsBadUnderlineFont = ff->mIsBadUnderlineFontFamily;
 
     return 1;
 }
 
 // general cmap reading routines moved to gfxFontUtils.cpp
 void
 FontFamily::FindStyleVariations()
 {
@@ -388,16 +342,112 @@ FontFamily::FindWeightsForStyle(gfxFontE
         if (matchesSomething)
             break;
         italic = !italic;
     }
 
     return matchesSomething;
 }
 
+FontEntry* 
+FontEntry::CreateFontEntry(const nsAString& aName, gfxWindowsFontType aFontType, PRBool aItalic, PRUint16 aWeight, gfxUserFontData* aUserFontData, HDC hdc, LOGFONTW *aLogFont)
+{
+    LOGFONTW logFont;
+    PRBool needRelease = PR_FALSE;
+
+    // jtdfix - need to set charset, unicode ranges, pitch/family
+
+    FontEntry *fe;
+
+    fe = new FontEntry(aName);
+    fe->mFontType = aFontType;
+    fe->mUserFontData = aUserFontData;
+
+    fe->mItalic = aItalic;
+    fe->mWeight = aWeight;
+
+    if (fe->IsType1())
+        fe->mForceGDI = PR_TRUE;
+
+    if (!aLogFont) {
+        aLogFont = &logFont;
+        FontEntry::FillLogFont(aLogFont, fe, 0, aItalic);
+    }
+
+    if (!hdc) {
+        hdc = GetDC(nsnull);
+        SetGraphicsMode(hdc, GM_ADVANCED);
+        needRelease = PR_TRUE;
+    }
+
+    HFONT font = CreateFontIndirectW(aLogFont);
+
+    if (font) {
+        HFONT oldFont = (HFONT)SelectObject(hdc, font);
+
+        // ReadCMAP may change the values of mUnicodeFont and mSymbolFont
+        if (NS_FAILED(::ReadCMAP(hdc, fe))) {
+            // Type1 fonts aren't necessarily Unicode but
+            // this is the best guess we can make here
+            if (fe->IsType1())
+                fe->mUnicodeFont = PR_TRUE;
+            else
+                fe->mUnicodeFont = PR_FALSE;
+
+            // For fonts where we failed to read the character map,
+            // we can take a slow path to look up glyphs character by character
+            fe->mUnknownCMAP = PR_TRUE;
+
+        } 
+
+        SelectObject(hdc, oldFont);
+        DeleteObject(font);
+    }
+
+    if (needRelease)
+        ReleaseDC(nsnull, hdc);
+
+    return fe;
+}
+
+
+void
+FontEntry::FillLogFont(LOGFONTW *aLogFont, FontEntry *aFontEntry, gfxFloat aSize, PRBool aItalic)
+{
+#define CLIP_TURNOFF_FONTASSOCIATION 0x40
+    
+    aLogFont->lfHeight = (LONG)-ROUND(aSize);
+
+    if (aLogFont->lfHeight == 0)
+        aLogFont->lfHeight = -1;
+
+    // Fill in logFont structure
+    aLogFont->lfWidth          = 0;
+    aLogFont->lfEscapement     = 0;
+    aLogFont->lfOrientation    = 0;
+    aLogFont->lfUnderline      = FALSE;
+    aLogFont->lfStrikeOut      = FALSE;
+    aLogFont->lfCharSet        = DEFAULT_CHARSET;
+    aLogFont->lfOutPrecision   = FontTypeToOutPrecision(aFontEntry->mFontType);
+    aLogFont->lfClipPrecision  = CLIP_TURNOFF_FONTASSOCIATION;
+    aLogFont->lfQuality        = DEFAULT_QUALITY;
+    aLogFont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+    // always force lfItalic if we want it.  Font selection code will
+    // do its best to give us an italic font entry, but if no face exists
+    // it may give us a regular one based on weight.  Windows should
+    // do fake italic for us in that case.
+    aLogFont->lfItalic         = aItalic;
+    aLogFont->lfWeight         = aFontEntry->mWeight;
+
+    int len = PR_MIN(aFontEntry->Name().Length(), LF_FACESIZE - 1);
+    memcpy(aLogFont->lfFaceName, nsPromiseFlatString(aFontEntry->Name()).get(), len * 2);
+    aLogFont->lfFaceName[len] = '\0';
+}
+
+
 PRBool 
 FontEntry::TestCharacterMap(PRUint32 aCh)
 {
     if (mUnknownCMAP) {
         if (aCh > 0xFFFF)
             return PR_FALSE;
 
         // previous code was using the group style
@@ -659,50 +709,23 @@ gfxWindowsFont::ComputeMetrics()
             mSpaceGlyph = glyph;
         }
     }
 
     SelectObject(dc, oldFont);
 
     ReleaseDC((HWND)nsnull, dc);
 
-    SanitizeMetrics(mMetrics, GetFontEntry()->IsBadUnderlineFont());
+    SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont);
 }
 
 void
 gfxWindowsFont::FillLogFont(gfxFloat aSize)
 {
-#define CLIP_TURNOFF_FONTASSOCIATION 0x40
-    
-    mLogFont.lfHeight = (LONG)-ROUND(aSize);
-
-    if (mLogFont.lfHeight == 0)
-        mLogFont.lfHeight = -1;
-
-    // Fill in logFont structure
-    mLogFont.lfWidth          = 0;
-    mLogFont.lfEscapement     = 0;
-    mLogFont.lfOrientation    = 0;
-    mLogFont.lfUnderline      = FALSE;
-    mLogFont.lfStrikeOut      = FALSE;
-    mLogFont.lfCharSet        = DEFAULT_CHARSET;
-    mLogFont.lfOutPrecision   = FontTypeToOutPrecision(GetFontEntry()->mFontType);
-    mLogFont.lfClipPrecision  = CLIP_TURNOFF_FONTASSOCIATION;
-    mLogFont.lfQuality        = DEFAULT_QUALITY;
-    mLogFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
-    // always force lfItalic if we want it.  Font selection code will
-    // do its best to give us an italic font entry, but if no face exists
-    // it may give us a regular one based on weight.  Windows should
-    // do fake italic for us in that case.
-    mLogFont.lfItalic         = (GetStyle()->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) ? TRUE : FALSE;
-    mLogFont.lfWeight         = GetFontEntry()->mWeight;
-
-    int len = PR_MIN(GetName().Length(), LF_FACESIZE - 1);
-    memcpy(mLogFont.lfFaceName, nsPromiseFlatString(mFontEntry->Name()).get(), len * 2);
-    mLogFont.lfFaceName[len] = '\0';
+    FontEntry::FillLogFont(&mLogFont, GetFontEntry(), aSize, (GetStyle()->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)));
 }
 
 
 nsString
 gfxWindowsFont::GetUniqueName()
 {
     nsString uniqueName;
 
@@ -801,26 +824,44 @@ AddFontNameToArray(const nsAString& aNam
 
         if (list->IndexOf(aName) == list->NoIndex)
             list->AppendElement(aName);
     }
 
     return PR_TRUE;
 }
 
+
 void
 gfxWindowsFontGroup::GroupFamilyListToArrayList(nsTArray<nsRefPtr<FontEntry> > *list)
 {
     nsAutoTArray<nsString, 15> fonts;
     ForEachFont(AddFontNameToArray, &fonts);
 
     PRUint32 len = fonts.Length();
     for (PRUint32 i = 0; i < len; ++i) {
-        nsRefPtr<FontEntry> fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(fonts[i], mStyle);
-        list->AppendElement(fe);
+        nsRefPtr<FontEntry> fe;
+        
+        // first, look up in the user font set
+        gfxFontEntry *gfe;
+        PRBool needsBold;
+        if (mUserFontSet && (gfe = mUserFontSet->FindFontEntry(fonts[i], mStyle, needsBold))) {
+            // assume for now platform font if not SVG
+            fe = static_cast<FontEntry*> (gfe);
+        }
+    
+        // nothing in the user font set ==> check system fonts
+        if (!fe) {
+            fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(fonts[i], mStyle);
+        }
+
+        // if found, add to the list
+        if (fe) {
+            list->AppendElement(fe);
+        }
     }
 }
 
 void
 gfxWindowsFontGroup::FamilyListToArrayList(const nsString& aFamilies,
                                            const nsCString& aLangGroup,
                                            nsTArray<nsRefPtr<FontEntry> > *list)
 {
@@ -830,18 +871,60 @@ gfxWindowsFontGroup::FamilyListToArrayLi
     PRUint32 len = fonts.Length();
     for (PRUint32 i = 0; i < len; ++i) {
         const nsString& str = fonts[i];
         nsRefPtr<FontEntry> fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(str, mStyle);
         list->AppendElement(fe);
     }
 }
 
-gfxWindowsFontGroup::gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle)
-    : gfxFontGroup(aFamilies, aStyle)
+gfxWindowsFontGroup::gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle, gfxUserFontSet *aUserFontSet)
+    : gfxFontGroup(aFamilies, aStyle, aUserFontSet)
+{
+    InitFontList();
+}
+
+gfxWindowsFontGroup::~gfxWindowsFontGroup()
+{
+}
+
+gfxWindowsFont *
+gfxWindowsFontGroup::GetFontAt(PRInt32 i)
+{
+    if (!mFonts[i]) {
+        nsRefPtr<gfxWindowsFont> font =
+            gfxWindowsFont::GetOrMakeFont(mFontEntries[i], &mStyle);
+        mFonts[i] = font;
+    }
+
+    return static_cast<gfxWindowsFont*>(mFonts[i].get());
+}
+
+gfxFontGroup *
+gfxWindowsFontGroup::Copy(const gfxFontStyle *aStyle)
+{
+    return new gfxWindowsFontGroup(mFamilies, aStyle, mUserFontSet);
+}
+
+void 
+gfxWindowsFontGroup::UpdateFontList()
+{
+    // if user font set is set, check to see if font list needs updating
+    if (mUserFontSet && mCurrGeneration != GetGeneration()) {
+        // xxx - can probably improve this to detect when all fonts were found, so no need to update list
+        mFonts.Clear();
+        mFontEntries.Clear();
+        InitFontList();
+        mCurrGeneration = GetGeneration();
+    }
+
+}
+
+void 
+gfxWindowsFontGroup::InitFontList()
 {
     GroupFamilyListToArrayList(&mFontEntries);
 
     mFonts.AppendElements(mFontEntries.Length());
 
     // Ensure that the first font is usable. Precompute its metrics since
     // we'll surely need them anyway.
     while (mFontEntries.Length() > 0) {
@@ -887,46 +970,25 @@ gfxWindowsFontGroup::gfxWindowsFontGroup
         // its mUnknownCMAP will be set to true, and HasCharacter will
         // just report false for all characters, so the fact that the font
         // is bogus should not cause problems.
         mFonts.AppendElements(mFontEntries.Length());
     }
 
     if (!mStyle.systemFont) {
         for (PRUint32 i = 0; i < mFontEntries.Length(); ++i) {
-            if (mFontEntries[i]->IsBadUnderlineFont()) {
+            if (mFontEntries[i]->mIsBadUnderlineFont) {
                 gfxFloat first = GetFontAt(0)->GetMetrics().underlineOffset;
                 gfxFloat bad = GetFontAt(i)->GetMetrics().underlineOffset;
                 mUnderlineOffset = PR_MIN(first, bad);
                 break;
             }
         }
     }
-}
 
-gfxWindowsFontGroup::~gfxWindowsFontGroup()
-{
-}
-
-gfxWindowsFont *
-gfxWindowsFontGroup::GetFontAt(PRInt32 i)
-{
-    if (!mFonts[i]) {
-        nsRefPtr<gfxWindowsFont> font =
-            gfxWindowsFont::GetOrMakeFont(mFontEntries[i], &mStyle);
-        mFonts[i] = font;
-    }
-
-    return static_cast<gfxWindowsFont*>(mFonts[i].get());
-}
-
-gfxFontGroup *
-gfxWindowsFontGroup::Copy(const gfxFontStyle *aStyle)
-{
-    return new gfxWindowsFontGroup(mFamilies, aStyle);
 }
 
 static PRBool
 CanTakeFastPath(PRUint32 aFlags)
 {
     // Can take fast path only if OPTIMIZE_SPEED is set and IS_RTL isn't
     // We need to always use Uniscribe for RTL text, in case glyph mirroring is required
     return (aFlags &
--- a/gfx/thebes/src/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/src/gfxWindowsPlatform.cpp
@@ -44,24 +44,28 @@
 #include "gfxWindowsSurface.h"
 
 #include "nsUnicharUtils.h"
 
 #include "nsIPref.h"
 #include "nsServiceManagerUtils.h"
 
 #include "nsIWindowsRegKey.h"
+#include "nsILocalFile.h"
+#include "plbase64.h"
 
 #include "gfxWindowsFonts.h"
+#include "gfxUserFontSet.h"
 
 #include <string>
+#include <time.h>
 
 #include "lcms.h"
 
-//#define DEBUG_CMAP_SIZE 1
+static void InitializeFontEmbeddingProcs();
 
 // font info loader constants
 static const PRUint32 kDelayBeforeLoadingCmaps = 8 * 1000; // 8secs
 static const PRUint32 kIntervalBetweenLoadingCmaps = 150; // 150ms
 static const PRUint32 kNumFontsPerSlice = 10; // read in info 10 fonts at a time
 
 static __inline void
 BuildKeyNameFromFontName(nsAString &aName)
@@ -91,16 +95,18 @@ gfxWindowsPlatform::gfxWindowsPlatform()
 
     UpdateFontList();
 
     nsCOMPtr<nsIPref> pref = do_GetService(NS_PREF_CONTRACTID);
     pref->RegisterCallback("font.", PrefChangedCallback, this);
     pref->RegisterCallback("font.name-list.", PrefChangedCallback, this);
     pref->RegisterCallback("intl.accept_languages", PrefChangedCallback, this);
     // don't bother unregistering.  We'll get shutdown after the pref service
+
+    InitializeFontEmbeddingProcs();
 }
 
 gfxWindowsPlatform::~gfxWindowsPlatform()
 {
 }
 
 already_AddRefed<gfxASurface>
 gfxWindowsPlatform::CreateOffscreenSurface(const gfxIntSize& size,
@@ -314,17 +320,17 @@ gfxWindowsPlatform::InitBadUnderlineList
         PRBool aborted;
         nsAutoString resolved;
         ResolveFontName(blacklist[i], SimpleResolverCallback, &resolved, aborted);
         if (resolved.IsEmpty())
             continue;
         FontFamily *ff = FindFontFamily(resolved);
         if (!ff)
             continue;
-        ff->mIsBadUnderlineFont = 1;
+        ff->mIsBadUnderlineFontFamily = 1;
     }
 }
 
 nsresult
 gfxWindowsPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
 {
     aFamilyName.Truncate();
     PRBool aborted;
@@ -512,19 +518,374 @@ gfxWindowsPlatform::FindFontForChar(PRUi
 
     // no match? add to set of non-matching codepoints
     mCodepointsWithNoFonts.set(aCh);
     return nsnull;
 }
 
 gfxFontGroup *
 gfxWindowsPlatform::CreateFontGroup(const nsAString &aFamilies,
-                                    const gfxFontStyle *aStyle)
+                                    const gfxFontStyle *aStyle,
+                                    gfxUserFontSet *aUserFontSet)
+{
+    return new gfxWindowsFontGroup(aFamilies, aStyle, aUserFontSet);
+}
+
+
+struct FullFontNameSearch {
+    FullFontNameSearch(const nsAString& aFullName)
+        : mFound(PR_FALSE), mFullName(aFullName), mDC(nsnull), mFontEntry(nsnull)
+    { }
+
+    PRPackedBool mFound;
+    nsString     mFullName;
+    nsString     mFamilyName;
+    HDC          mDC;
+    gfxFontEntry *mFontEntry;
+};
+
+// callback called for each face within a single family
+// match against elfFullName
+
+static int CALLBACK 
+FindFullNameForFace(const ENUMLOGFONTEXW *lpelfe,
+                    const NEWTEXTMETRICEXW *nmetrics,
+                    DWORD fontType, LPARAM userArg)
+{
+    FullFontNameSearch *data = reinterpret_cast<FullFontNameSearch*>(userArg);
+
+    // does the full name match?
+    if (!data->mFullName.Equals(nsDependentString(lpelfe->elfFullName)))
+        return 1;  // continue
+
+    // found match, create a new font entry
+    data->mFound = PR_TRUE;
+
+    const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
+    LOGFONTW logFont = lpelfe->elfLogFont;
+
+    // Some fonts claim to support things > 900, but we don't so clamp the sizes
+    logFont.lfWeight = PR_MAX(PR_MIN(logFont.lfWeight, 900), 100);
+
+    gfxWindowsFontType feType = FontEntry::DetermineFontType(metrics, fontType);
+
+    data->mFontEntry = FontEntry::CreateFontEntry(data->mFamilyName, feType, (logFont.lfItalic == 0xFF), (PRUint16) (logFont.lfWeight), nsnull, data->mDC, &logFont);
+    
+    return 0;  // stop iteration
+}
+
+
+// callback called for each family name, based on the assumption that the 
+// first part of the full name is the family name
+
+static PLDHashOperator PR_CALLBACK
+FindFullName(nsStringHashKey::KeyType aKey,
+             nsRefPtr<FontFamily>& aFontFamily,
+             void* userArg)
+{
+    FullFontNameSearch *data = reinterpret_cast<FullFontNameSearch*>(userArg);
+
+    // does the family name match up to the length of the family name?
+    const nsString& family = aFontFamily->Name();
+    
+    nsString fullNameFamily;
+    data->mFullName.Left(fullNameFamily, family.Length());
+
+    // if so, iterate over faces in this family to see if there is a match
+    if (family.Equals(fullNameFamily)) {
+        HDC hdc;
+        
+        if (!data->mDC) {
+            data->mDC= GetDC(nsnull);
+            SetGraphicsMode(data->mDC, GM_ADVANCED);
+        }
+        hdc = data->mDC;
+
+        LOGFONTW logFont;
+        memset(&logFont, 0, sizeof(LOGFONTW));
+        logFont.lfCharSet = DEFAULT_CHARSET;
+        logFont.lfPitchAndFamily = 0;
+        PRUint32 l = PR_MIN(family.Length(), LF_FACESIZE - 1);
+        memcpy(logFont.lfFaceName,
+               nsPromiseFlatString(family).get(),
+               l * sizeof(PRUnichar));
+        logFont.lfFaceName[l] = 0;
+        data->mFamilyName.Assign(family);
+
+        EnumFontFamiliesExW(hdc, &logFont, (FONTENUMPROCW)FindFullNameForFace, (LPARAM)data, 0);
+    }
+
+    if (data->mFound)
+        return PL_DHASH_STOP;
+
+    return PL_DHASH_NEXT;
+}
+
+gfxFontEntry* 
+gfxWindowsPlatform::LookupLocalFont(const nsAString& aFontName)
+{
+    // walk over list of names
+    FullFontNameSearch data(aFontName);
+
+    // find fonts that support the character
+    mFonts.Enumerate(FindFullName, &data);
+
+    if (data.mDC)
+        ReleaseDC(nsnull, data.mDC);
+    
+    return data.mFontEntry;
+}
+
+// make a unique font name, limited on Windows to 31 two-byte characters
+static void MakeUniqueFontName(PRUnichar aName[LF_FACESIZE])
+{
+    static PRUint32 fontCount = 0;
+    ++fontCount;
+    PRUint32 time = (PRUint32) _time32(nsnull);
+
+    char buf[LF_FACESIZE];
+
+    sprintf(buf, "mozfont%8.8x%8.8x", time, fontCount);  // slightly retarded, figure something better later...
+
+    nsCAutoString fontName(buf);
+
+    PRUint32 nameLen = PR_MIN(fontName.Length(), LF_FACESIZE - 1);
+    memcpy(aName, nsPromiseFlatString(NS_ConvertUTF8toUTF16(fontName)).get(), nameLen * 2);
+    aName[nameLen] = 0;
+}
+
+// from t2embapi.h, included in Platform SDK 6.1 but not 6.0
+
+#ifndef __t2embapi__
+
+#define TTLOAD_PRIVATE                  0x00000001
+#define LICENSE_PREVIEWPRINT            0x0004
+#define E_NONE                          0x0000L
+
+typedef unsigned long( WINAPIV *READEMBEDPROC ) ( void*, void*, const unsigned long );
+
+typedef struct
+{
+    unsigned short usStructSize;    // size in bytes of structure client should set to sizeof(TTLOADINFO)
+    unsigned short usRefStrSize;    // size in wide characters of pusRefStr including NULL terminator
+    unsigned short *pusRefStr;      // reference or actual string.
+}TTLOADINFO;
+
+LONG WINAPI TTLoadEmbeddedFont
+(
+    __out HANDLE*   phFontReference,            // on completion, contains handle to identify embedded font installed
+                                        // on system
+    __in ULONG    ulFlags,                  // flags specifying the request 
+    __out ULONG*    pulPrivStatus,          // on completion, contains the embedding status
+    __in ULONG     ulPrivs,                 // allows for the reduction of licensing privileges
+    __out ULONG*    pulStatus,              // on completion, may contain status flags for request 
+    __in READEMBEDPROC lpfnReadFromStream,  // callback function for doc/disk reads
+    __in LPVOID    lpvReadStream,           // the input stream tokin
+    __in_opt LPWSTR    szWinFamilyName,         // the new 16 bit windows family name can be NULL
+    __in_opt LPSTR    szMacFamilyName,          // the new 8 bit mac family name can be NULL
+    __in_opt TTLOADINFO* pTTLoadInfo                // optional security
+);
+
+#endif // __t2embapi__
+
+typedef LONG( WINAPI *TTLoadEmbeddedFontProc ) (HANDLE* phFontReference, ULONG ulFlags, ULONG* pulPrivStatus, ULONG ulPrivs, ULONG* pulStatus, 
+                                             READEMBEDPROC lpfnReadFromStream, LPVOID lpvReadStream, LPWSTR szWinFamilyName, 
+                                             LPSTR szMacFamilyName, TTLOADINFO* pTTLoadInfo);
+
+typedef LONG( WINAPI *TTDeleteEmbeddedFontProc ) (HANDLE hFontReference, ULONG ulFlags, ULONG* pulStatus);
+
+
+static TTLoadEmbeddedFontProc TTLoadEmbeddedFontPtr = nsnull;
+static TTDeleteEmbeddedFontProc TTDeleteEmbeddedFontPtr = nsnull;
+
+static void InitializeFontEmbeddingProcs()
 {
-    return new gfxWindowsFontGroup(aFamilies, aStyle);
+    HMODULE fontlib = LoadLibrary("t2embed.dll");
+    if (!fontlib)
+        return;
+    TTLoadEmbeddedFontPtr = (TTLoadEmbeddedFontProc) GetProcAddress(fontlib, "TTLoadEmbeddedFont");
+    TTDeleteEmbeddedFontPtr = (TTDeleteEmbeddedFontProc) GetProcAddress(fontlib, "TTDeleteEmbeddedFont");
+}
+
+class WinUserFontData : public gfxUserFontData {
+public:
+    WinUserFontData(HANDLE aFontRef)
+        : mFontRef(aFontRef)
+    { }
+
+    virtual ~WinUserFontData()
+    {
+        ULONG pulStatus;
+        TTDeleteEmbeddedFontPtr(mFontRef, 0, &pulStatus);
+    }
+    
+    HANDLE mFontRef;
+};
+
+// used to control stream read by Windows TTLoadEmbeddedFont API
+
+class EOTFontStreamReader {
+public:
+    EOTFontStreamReader(nsILocalFile *aFontFile, PRUint8 *aEOTHeader, 
+                        PRUint32 aEOTHeaderLen)
+        : mFontFile(aFontFile), mFd(nsnull), mOpenError(PR_FALSE), 
+          mInHeader(PR_TRUE), mHeaderOffset(0), mEOTHeader(aEOTHeader), 
+          mEOTHeaderLen(aEOTHeaderLen)
+    {
+    
+    }
+
+    ~EOTFontStreamReader() 
+    { 
+        if (mFd) {
+            PR_Close(mFd);
+        }
+
+        mFontFile->Remove(PR_FALSE);
+    }
+
+    nsCOMPtr<nsILocalFile>  mFontFile;
+    PRFileDesc              *mFd;
+    PRPackedBool            mOpenError;
+    PRPackedBool            mInHeader;
+    PRUint32                mHeaderOffset;
+    PRUint8                 *mEOTHeader;
+    PRUint32                mEOTHeaderLen;
+
+    PRBool OpenFontFile()
+    {
+        nsresult rv;
+
+        rv = mFontFile->OpenNSPRFileDesc(PR_RDONLY, 0, &mFd);
+        if (NS_FAILED(rv) || !mFd)
+            return PR_FALSE;
+
+        return PR_TRUE;
+    }
+
+    unsigned long Read(void *outBuffer, const unsigned long aBytesToRead)
+    {
+        PRUint32 bytesLeft = aBytesToRead;
+        PRUint8 *out = static_cast<PRUint8*> (outBuffer);
+
+        if (mOpenError)
+            return 0;
+
+        if (!mFd) {
+            if (!OpenFontFile()) {
+                mOpenError = PR_TRUE;
+                return 0;
+            }
+        }
+
+        // read from EOT header
+        if (mInHeader) {
+            PRUint32 toCopy = PR_MIN(aBytesToRead, mEOTHeaderLen - mHeaderOffset);
+            memcpy(out, mEOTHeader + mHeaderOffset, toCopy);
+            bytesLeft -= toCopy;
+            mHeaderOffset += toCopy;
+            out += toCopy;
+            if (mHeaderOffset == mEOTHeaderLen)
+                mInHeader = PR_FALSE;
+        }
+
+        if (bytesLeft) {
+            PRInt32 bytesRead = PR_Read(mFd, out, bytesLeft);
+            if (bytesRead > 0)
+                bytesLeft -= bytesRead;
+        }
+
+        return aBytesToRead - bytesLeft;
+    }
+
+    static unsigned long ReadEOTStream(void *aReadStream, void *outBuffer, 
+                                       const unsigned long aBytesToRead) 
+    {
+        EOTFontStreamReader *eotReader = 
+                               static_cast<EOTFontStreamReader*> (aReadStream);
+        return eotReader->Read(outBuffer, aBytesToRead);
+    }        
+        
+};
+
+gfxFontEntry* 
+gfxWindowsPlatform::MakePlatformFont(const gfxFontEntry *aProxyEntry, 
+                                     const gfxDownloadedFontData* aFontData)
+{
+    // if calls aren't available, bail
+    if (!TTLoadEmbeddedFontPtr || !TTDeleteEmbeddedFontPtr)
+        return nsnull;
+
+    // create an eot header
+    nsAutoTArray<PRUint8,2048> eotHeader;
+    PRUint8 *buffer;
+    PRUint32 eotlen;
+    PRUnichar fontName[LF_FACESIZE];
+    PRBool isCFF;
+    
+    nsresult rv;
+    HANDLE fontRef;
+    PRInt32 ret;
+
+    {
+        nsCOMPtr<nsILocalFile> fontFile(do_QueryInterface(aFontData->mFontFile, &rv));
+        if (NS_FAILED(rv))
+            return nsnull;
+
+        rv = gfxFontUtils::MakeEOTHeader(fontFile, &eotHeader, &isCFF);
+        if (NS_FAILED(rv))
+            return nsnull;
+
+        // load in embedded font data
+        eotlen = eotHeader.Length();
+        buffer = reinterpret_cast<PRUint8*> (eotHeader.Elements());
+        
+        ULONG privStatus, pulStatus;
+        MakeUniqueFontName(fontName);
+        EOTFontStreamReader eotReader(fontFile, buffer, eotlen);
+
+        ret = TTLoadEmbeddedFontPtr(&fontRef, TTLOAD_PRIVATE, &privStatus, 
+                                   LICENSE_PREVIEWPRINT, &pulStatus, 
+                                   EOTFontStreamReader::ReadEOTStream, 
+                                   &eotReader, fontName, 0, 0);
+    }
+
+    if (ret != E_NONE)
+        return nsnull;
+    
+    // make a new font entry using the unique name
+    WinUserFontData *winUserFontData = new WinUserFontData(fontRef);
+    PRUint16 w = (aProxyEntry->mWeight == 0 ? 400 : aProxyEntry->mWeight);
+
+    return FontEntry::CreateFontEntry(nsDependentString(fontName), 
+        gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/, 
+        PRUint32(aProxyEntry->mItalic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL), 
+        w, winUserFontData);
+}
+
+PRBool
+gfxWindowsPlatform::IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags)
+{
+    // reject based on format flags
+    if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_EOT | gfxUserFontSet::FLAG_FORMAT_SVG)) {
+        return PR_FALSE;
+    }
+
+    // exclude AAT fonts on platforms other than Mac OS X, this allows
+    // fonts for complex scripts which require AAT tables to be omitted
+    // on other platforms
+    if ((aFormatFlags & gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT) 
+         && !(aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_OPENTYPE | gfxUserFontSet::FLAG_FORMAT_TRUETYPE))) {
+        return PR_FALSE;
+    }
+
+    // reject based on filetype in URI
+
+    // otherwise, return true
+    return PR_TRUE;
 }
 
 FontFamily *
 gfxWindowsPlatform::FindFontFamily(const nsAString& aName)
 {
     nsAutoString name(aName);
     BuildKeyNameFromFontName(name);
 
--- a/gfx/thebes/test/Makefile.in
+++ b/gfx/thebes/test/Makefile.in
@@ -47,17 +47,19 @@ include $(DEPTH)/config/autoconf.mk
 
 REQUIRES = \
 	xpcom \
 	string \
 	thebes \
 	cairo \
 	pref \
 	lcms \
+	necko \
 	unicharutil \
+	nspr \
 	$(NULL)
 
 # All platforms
 CPPSRCS = \
 	gfxSurfaceRefCountTest.cpp \
 	gfxFontSelectionTest.cpp \
 	gfxTextRunPerfTest.cpp \
 	gfxWordCacheTest.cpp \
--- a/gfx/thebes/test/gfxFontSelectionTest.cpp
+++ b/gfx/thebes/test/gfxFontSelectionTest.cpp
@@ -283,17 +283,17 @@ DumpTestExpect (TestEntry *test) {
         printf ("\n");
     }
 }
 
 PRBool
 RunTest (TestEntry *test, gfxContext *ctx) {
     nsRefPtr<gfxFontGroup> fontGroup;
 
-    fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(NS_ConvertUTF8toUTF16(test->utf8FamilyString), &test->fontStyle);
+    fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(NS_ConvertUTF8toUTF16(test->utf8FamilyString), &test->fontStyle, nsnull);
 
     nsAutoPtr<gfxTextRun> textRun;
     gfxTextRunFactory::Parameters params = {
       ctx, nsnull, nsnull, nsnull, 0, 60
     };
     PRUint32 flags = gfxTextRunFactory::TEXT_IS_PERSISTENT;
     if (test->isRTL) {
         flags |= gfxTextRunFactory::TEXT_IS_RTL;
--- a/gfx/thebes/test/gfxTextRunPerfTest.cpp
+++ b/gfx/thebes/test/gfxTextRunPerfTest.cpp
@@ -91,17 +91,17 @@ RunTest (TestEntry *test, gfxContext *ct
     if (!lastFamilies || strcmp(lastFamilies, test->mFamilies)) {
         gfxFontStyle style_western_normal_16 (FONT_STYLE_NORMAL,
                                               400,
                                               16.0,
                                               nsDependentCString("x-western"),
                                               0.0,
                                               PR_FALSE, PR_FALSE);
 
-        fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(NS_ConvertUTF8toUTF16(test->mFamilies), &style_western_normal_16);
+        fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(NS_ConvertUTF8toUTF16(test->mFamilies), &style_western_normal_16, nsnull);
     }
 
     nsAutoPtr<gfxTextRun> textRun;
     PRUint32 i;
     PRBool isASCII = PR_TRUE;
     for (i = 0; test->mString[i]; ++i) {
         if (test->mString[i] & 0x80) {
             isASCII = PR_FALSE;
--- a/gfx/thebes/test/gfxWordCacheTest.cpp
+++ b/gfx/thebes/test/gfxWordCacheTest.cpp
@@ -158,17 +158,17 @@ main (int argc, char **argv) {
        gfxFontStyle style (FONT_STYLE_NORMAL,
                            139,
                            10.0,
                            nsDependentCString("x-western"),
                            0.0,
                            PR_FALSE, PR_FALSE);
 
        nsRefPtr<gfxFontGroup> fontGroup =
-           gfxPlatform::GetPlatform()->CreateFontGroup(NS_LITERAL_STRING("Geneva, MS Sans Serif, Helvetica,serif"), &style);
+           gfxPlatform::GetPlatform()->CreateFontGroup(NS_LITERAL_STRING("Geneva, MS Sans Serif, Helvetica,serif"), &style, nsnull);
 
        gfxTextRunFactory::Parameters params = {
            ctx, nsnull, nsnull, nsnull, 0, 60
        };
 
        PRUint32 flags = gfxTextRunFactory::TEXT_IS_PERSISTENT;
 
        // First load an Arabic word into the cache
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -73,16 +73,17 @@
 #include "nsThemeConstants.h"
 #include "nsPIDOMWindow.h"
 #include "nsIBaseWindow.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIWidget.h"
 #include "gfxMatrix.h"
 #include "gfxTypes.h"
+#include "gfxUserFontSet.h"
 
 #ifdef MOZ_SVG
 #include "nsSVGUtils.h"
 #include "nsSVGIntegrationUtils.h"
 #include "nsSVGForeignObjectFrame.h"
 #include "nsSVGOuterSVGFrame.h"
 #endif
 
@@ -1488,20 +1489,23 @@ nsLayoutUtils::GetFontMetricsForFrame(ns
   return nsLayoutUtils::GetFontMetricsForStyleContext(aFrame->GetStyleContext(),
                                                       aFontMetrics);
 }
 
 nsresult
 nsLayoutUtils::GetFontMetricsForStyleContext(nsStyleContext* aStyleContext,
                                              nsIFontMetrics** aFontMetrics)
 {
-  return aStyleContext->PresContext()->DeviceContext()->
-    GetMetricsFor(aStyleContext->GetStyleFont()->mFont,
+  // pass the user font set object into the device context to pass along to CreateFontGroup
+  gfxUserFontSet* fs = aStyleContext->PresContext()->GetUserFontSet();
+  
+  return aStyleContext->PresContext()->DeviceContext()->GetMetricsFor(
+                  aStyleContext->GetStyleFont()->mFont,
                   aStyleContext->GetStyleVisibility()->mLangGroup,
-                  *aFontMetrics);
+                  *aFontMetrics, fs);
 }
 
 nsIFrame*
 nsLayoutUtils::FindChildContainingDescendant(nsIFrame* aParent, nsIFrame* aDescendantFrame)
 {
   nsIFrame* result = aDescendantFrame;
 
   while (result) {
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -78,16 +78,17 @@
 #include "nsFrameManager.h"
 #include "nsLayoutUtils.h"
 #include "nsIViewManager.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsCSSRuleProcessor.h"
 #include "nsStyleChangeList.h"
 #include "nsRuleNode.h"
 #include "nsEventDispatcher.h"
+#include "gfxUserFontSet.h"
 
 #ifdef IBMBIDI
 #include "nsBidiPresUtils.h"
 #endif // IBMBIDI
 
 #include "nsContentUtils.h"
 
 // Needed for Start/Stop of Image Animation
@@ -221,16 +222,17 @@ nsPresContext::nsPresContext(nsIDocument
   if (!IsDynamic()) {
     mImageAnimationMode = imgIContainer::kDontAnimMode;
     mNeverAnimate = PR_TRUE;
   } else {
     mImageAnimationMode = imgIContainer::kNormalAnimMode;
     mNeverAnimate = PR_FALSE;
   }
   NS_ASSERTION(mDocument, "Null document");
+  mUserFontSet = nsnull;
 }
 
 nsPresContext::~nsPresContext()
 {
   mImageLoaders.Enumerate(destroy_loads, nsnull);
 
   NS_PRECONDITION(!mShell, "Presshell forgot to clear our mShell pointer");
   SetShell(nsnull);
@@ -278,16 +280,18 @@ nsPresContext::~nsPresContext()
 #endif // IBMBIDI
   nsContentUtils::UnregisterPrefCallback("layout.css.dpi",
                                          nsPresContext::PrefChangedCallback,
                                          this);
 
   NS_IF_RELEASE(mDeviceContext);
   NS_IF_RELEASE(mLookAndFeel);
   NS_IF_RELEASE(mLangGroup);
+  
+  SetUserFontSet(nsnull);
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsPresContext)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPresContext)
    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
    NS_INTERFACE_MAP_ENTRY(nsIObserver)
 NS_INTERFACE_MAP_END
@@ -1571,16 +1575,29 @@ nsPresContext::IsChrome() const
 
 /* virtual */ PRBool
 nsPresContext::HasAuthorSpecifiedRules(nsIFrame *aFrame, PRUint32 ruleTypeMask) const
 {
   return nsRuleNode::
     HasAuthorSpecifiedRules(aFrame->GetStyleContext(), ruleTypeMask);
 }
 
+gfxUserFontSet* 
+nsPresContext::GetUserFontSet() {
+  return mUserFontSet;
+}
+
+void 
+nsPresContext::SetUserFontSet(gfxUserFontSet *aUserFontSet)
+{
+  NS_IF_RELEASE(mUserFontSet);
+  mUserFontSet = aUserFontSet;
+  NS_IF_ADDREF(mUserFontSet);
+}
+
 void
 nsPresContext::FireDOMPaintEvent()
 {
   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
   if (!docShell)
     return;
   nsCOMPtr<nsPIDOMWindow> ourWindow = do_GetInterface(docShell);
   nsISupports* eventTarget = ourWindow;
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -61,16 +61,17 @@
 #include "nsGkAtoms.h"
 #include "nsIDocument.h"
 #include "nsInterfaceHashtable.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsChangeHint.h"
 // This also pulls in gfxTypes.h, which we cannot include directly.
 #include "gfxRect.h"
 #include "nsRegion.h"
+
 class nsImageLoader;
 #ifdef IBMBIDI
 class nsBidiPresUtils;
 #endif // IBMBIDI
 
 struct nsRect;
 
 class imgIRequest;
@@ -86,16 +87,17 @@ class nsIAtom;
 class nsIEventStateManager;
 class nsIURI;
 class nsILookAndFeel;
 class nsICSSPseudoComparator;
 class nsIAtom;
 struct nsStyleBackground;
 template <class T> class nsRunnableMethod;
 class nsIRunnable;
+class gfxUserFontSet;
 
 #ifdef MOZ_REFLOW_PERF
 class nsIRenderingContext;
 #endif
 
 enum nsWidgetType {
   eWidgetType_Button  	= 1,
   eWidgetType_Checkbox	= 2,
@@ -773,16 +775,19 @@ public:
   virtual PRBool HasAuthorSpecifiedRules(nsIFrame *aFrame, PRUint32 ruleTypeMask) const;
 
   // Is it OK to let the page specify colors and backgrounds?
   PRBool UseDocumentColors() const {
     return GetCachedBoolPref(kPresContext_UseDocumentColors) || IsChrome();
   }
 
   PRBool           SupressingResizeReflow() const { return mSupressResizeReflow; }
+  
+  gfxUserFontSet* GetUserFontSet();
+  void SetUserFontSet(gfxUserFontSet *aUserFontSet);
 
   void NotifyInvalidation(const nsRect& aRect, PRBool aIsCrossDoc);
   void FireDOMPaintEvent();
 
 protected:
   friend class nsRunnableMethod<nsPresContext>;
   NS_HIDDEN_(void) ThemeChangedInternal();
   NS_HIDDEN_(void) SysColorChangedInternal();
@@ -840,16 +845,19 @@ protected:
   nsCOMPtr<nsIPrintSettings> mPrintSettings;
   nsCOMPtr<nsITimer>    mPrefChangedTimer;
 
   nsPropertyTable       mPropertyTable;
 
   nsRegion              mSameDocDirtyRegion;
   nsRegion              mCrossDocDirtyRegion;
 
+  // container for per-context fonts (downloadable, SVG, etc.)
+  gfxUserFontSet* mUserFontSet;
+  
   nsLanguageSpecificTransformType mLanguageSpecificTransformType;
   PRInt32               mFontScaler;
   nscoord               mMinimumFontSize;
 
   nsRect                mVisibleArea;
   nsSize                mPageSize;
   float                 mPageScale;
   float                 mPPScale;
--- a/layout/build/nsLayoutCID.h
+++ b/layout/build/nsLayoutCID.h
@@ -220,17 +220,9 @@
 
 // {14632191-AC21-4BDF-83E7-2363AD17E838}
 #define NS_XULPOPUPMANAGER_CID \
 { 0x14632191, 0xac21, 0x4bdf, { 0x83, 0xe7, 0x23, 0x63, 0xad, 0x17, 0xe8, 0x38 } }
 
 // {93ad72a6-02cd-4716-9626-d47d5ec275ec}
 #define NS_DOMJSON_CID \
 { 0x93ad72a6, 0x02cd, 0x4716, { 0x96, 0x26, 0xd4, 0x7d, 0x5e, 0xc2, 0x75, 0xec } }
-
-#ifdef MOZ_MEDIA
-#define NS_HTMLAUDIOELEMENT_CID                   \
-{ /* 1d40026b-4c44-4f6f-b158-26bb5e9c65e9 */      \
- 0x1d40026b, 0x4c44, 0x4f6f,                      \
- {0xb1, 0x58, 0x26, 0xbb, 0x5e, 0x9c, 0x65, 0xe9}}
-#endif
-
 #endif /* nsLayoutCID_h__ */
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -218,21 +218,16 @@ class nsIDocumentLoaderFactory;
 #define PRODUCT_NAME "Gecko"
 
 #define NS_HTMLIMGELEMENT_CONTRACTID \
   "@mozilla.org/content/element/html;1?name=img"
 
 #define NS_HTMLOPTIONELEMENT_CONTRACTID \
   "@mozilla.org/content/element/html;1?name=option"
 
-#ifdef MOZ_MEDIA
-#define NS_HTMLAUDIOELEMENT_CONTRACTID \
-  "@mozilla.org/content/element/html;1?name=audio"
-#endif
-
 /* 0ddf4df8-4dbb-4133-8b79-9afb966514f5 */
 #define NS_PLUGINDOCLOADERFACTORY_CID \
 { 0x0ddf4df8, 0x4dbb, 0x4133, { 0x8b, 0x79, 0x9a, 0xfb, 0x96, 0x65, 0x14, 0xf5 } }
 
 #define NS_WINDOWCOMMANDTABLE_CID \
  { /* 0DE2FBFA-6B7F-11D7-BBBA-0003938A9D96 */        \
   0x0DE2FBFA, 0x6B7F, 0x11D7, {0xBB, 0xBA, 0x00, 0x03, 0x93, 0x8A, 0x9D, 0x96} }
 
@@ -492,17 +487,16 @@ MAKE_CTOR(CreateDOMSelection,           
 MAKE_CTOR(CreateSelection,                nsFrameSelection,            NS_NewSelection)
 MAKE_CTOR(CreateRange,                    nsIDOMRange,                 NS_NewRange)
 MAKE_CTOR(CreateRangeUtils,               nsIRangeUtils,               NS_NewRangeUtils)
 MAKE_CTOR(CreateContentIterator,          nsIContentIterator,          NS_NewContentIterator)
 MAKE_CTOR(CreatePreContentIterator,       nsIContentIterator,          NS_NewPreContentIterator)
 MAKE_CTOR(CreateSubtreeIterator,          nsIContentIterator,          NS_NewContentSubtreeIterator)
 // CreateHTMLImgElement, see below
 // CreateHTMLOptionElement, see below
-// CreateHTMLAudioElement, see below
 MAKE_CTOR(CreateTextEncoder,              nsIDocumentEncoder,          NS_NewTextEncoder)
 MAKE_CTOR(CreateHTMLCopyTextEncoder,      nsIDocumentEncoder,          NS_NewHTMLCopyTextEncoder)
 MAKE_CTOR(CreateXMLContentSerializer,     nsIContentSerializer,        NS_NewXMLContentSerializer)
 MAKE_CTOR(CreateHTMLContentSerializer,    nsIContentSerializer,        NS_NewHTMLContentSerializer)
 MAKE_CTOR(CreatePlainTextSerializer,      nsIContentSerializer,        NS_NewPlainTextSerializer)
 MAKE_CTOR(CreateHTMLFragmentSink,         nsIFragmentContentSink,      NS_NewHTMLFragmentContentSink)
 MAKE_CTOR(CreateHTMLFragmentSink2,        nsIFragmentContentSink,      NS_NewHTMLFragmentContentSink2)
 MAKE_CTOR(CreateHTMLParanoidFragmentSink, nsIFragmentContentSink,      NS_NewHTMLParanoidFragmentSink)
@@ -669,63 +663,16 @@ UnregisterHTMLOptionElement(nsIComponent
                             nsIFile* aPath,
                             const char* aRegistryLocation,
                             const nsModuleComponentInfo* aInfo)
 {
   // XXX remove category entry
   return NS_OK;
 }
 
-#ifdef MOZ_MEDIA
-static NS_IMETHODIMP
-CreateHTMLAudioElement(nsISupports* aOuter, REFNSIID aIID, void** aResult)
-{
-  *aResult = nsnull;
-  if (aOuter)
-    return NS_ERROR_NO_AGGREGATION;
-  // Note! NS_NewHTMLAudioElement is special cased to handle a null nodeinfo
-  nsCOMPtr<nsIContent> inst(NS_NewHTMLAudioElement(nsnull));
-  return inst ? inst->QueryInterface(aIID, aResult) : NS_ERROR_OUT_OF_MEMORY;
-}
-
-static NS_IMETHODIMP
-RegisterHTMLAudioElement(nsIComponentManager *aCompMgr,
-                         nsIFile* aPath,
-                         const char* aRegistryLocation,
-                         const char* aComponentType,
-                         const nsModuleComponentInfo* aInfo)
-{
-  nsCOMPtr<nsICategoryManager> catman =
-    do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
-
-  if (!catman)
-    return NS_ERROR_FAILURE;
-
-  nsXPIDLCString previous;
-  nsresult rv = catman->AddCategoryEntry(JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY,
-                                         "Audio", NS_HTMLAUDIOELEMENT_CONTRACTID,
-                                         PR_TRUE, PR_TRUE, getter_Copies(previous));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return catman->AddCategoryEntry(JAVASCRIPT_GLOBAL_CONSTRUCTOR_PROTO_ALIAS_CATEGORY,
-                                  "Audio", "HTMLAudioElement",
-                                  PR_TRUE, PR_TRUE, getter_Copies(previous));
-}
-
-static NS_IMETHODIMP
-UnregisterHTMLAudioElement(nsIComponentManager* aCompMgr,
-                           nsIFile* aPath,
-                           const char* aRegistryLocation,
-                           const nsModuleComponentInfo* aInfo)
-{
-  // XXX remove category entry
-  return NS_OK;
-}
-#endif
-
 static NS_METHOD
 RegisterDataDocumentContentPolicy(nsIComponentManager *aCompMgr,
                                   nsIFile* aPath,
                                   const char* aRegistryLocation,
                                   const char* aComponentType,
                                   const nsModuleComponentInfo* aInfo)
 {
   nsresult rv;
@@ -1048,40 +995,31 @@ static const nsModuleComponentInfo gComp
     nsnull,
     nsCSSOMFactoryConstructor },
 
   { "Inspector CSS Utils",
     NS_INSPECTORCSSUTILS_CID,
     nsnull,
     nsInspectorCSSUtilsConstructor },
 
-  // Needed to support "new Option;", "new Image;" and "new Audio;" in JavaScript
+  // Needed to support "new Option;" and "new Image;" in JavaScript
   { "HTML img element",
     NS_HTMLIMAGEELEMENT_CID,
     NS_HTMLIMGELEMENT_CONTRACTID,
     CreateHTMLImgElement,
     RegisterHTMLImgElement, 
     UnregisterHTMLImgElement },
 
   { "HTML option element",
     NS_HTMLOPTIONELEMENT_CID,
     NS_HTMLOPTIONELEMENT_CONTRACTID,
     CreateHTMLOptionElement,
     RegisterHTMLOptionElement,
     UnregisterHTMLOptionElement },
 
-#ifdef MOZ_MEDIA
-  { "HTML audio element",
-    NS_HTMLAUDIOELEMENT_CID,
-    NS_HTMLAUDIOELEMENT_CONTRACTID,
-    CreateHTMLAudioElement,
-    RegisterHTMLAudioElement, 
-    UnregisterHTMLAudioElement },
-#endif
-
 #ifdef MOZ_ENABLE_CANVAS
   { "Canvas 2D Rendering Context",
     NS_CANVASRENDERINGCONTEXT2D_CID,
     "@mozilla.org/content/canvas-rendering-context;1?id=2d",
     CreateCanvasRenderingContext2D },
 #endif
 
   { "XML document encoder",
--- a/layout/style/Makefile.in
+++ b/layout/style/Makefile.in
@@ -146,16 +146,17 @@ CPPSRCS		= \
 		nsCSSStyleSheet.cpp \
 		nsCSSValue.cpp \
 		nsComputedDOMStyle.cpp \
 		nsDOMCSSAttrDeclaration.cpp \
 		nsDOMCSSDeclaration.cpp \
 		nsDOMCSSRGBColor.cpp \
 		nsDOMCSSRect.cpp \
 		nsDOMCSSValueList.cpp \
+		nsFontFaceLoader.cpp \
 		nsHTMLCSSStyleSheet.cpp \
 		nsHTMLStyleSheet.cpp \
 		nsInspectorCSSUtils.cpp \
 		nsLayoutStylesheetCache.cpp \
 		nsMediaFeatures.cpp \
 		nsROCSSPrimitiveValue.cpp \
 		nsRuleNode.cpp \
 		nsStyleContext.cpp \
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -77,16 +77,20 @@
 #include "nsAttrValue.h"
 #include "nsAttrName.h"
 #include "nsILookAndFeel.h"
 #include "nsWidgetsCID.h"
 #include "nsServiceManagerUtils.h"
 #include "nsTArray.h"
 #include "nsContentUtils.h"
 #include "nsIMediaList.h"
+#include "gfxPlatform.h"
+#include "gfxUserFontSet.h"
+#include "nsCSSRules.h"
+#include "nsFontFaceLoader.h"
 
 static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
 static nsTArray< nsCOMPtr<nsIAtom> >* sSystemMetrics = 0;
 
 struct RuleValue {
   /**
    * |RuleValue|s are constructed before they become part of the
    * |RuleHash|, to act as rule/selector pairs.  |Add| is called when
@@ -2287,16 +2291,139 @@ struct CascadeEnumData {
   nsPresContext* mPresContext;
   nsMediaQueryResultCacheKey& mCacheKey;
   // Hooray, a manual PLDHashTable since nsClassHashtable doesn't
   // provide a getter that gives me a *reference* to the value.
   PLDHashTable mRulesByWeight; // of RuleValue* linked lists (?)
   PLArenaPool& mArena;
 };
 
+static void
+InsertFontFaceRule(nsICSSRule* aRule, gfxUserFontSet* fs)
+{
+  nsCSSFontFaceRule *fontFace = static_cast<nsCSSFontFaceRule*> (aRule);
+  PRInt32 type;
+  NS_ASSERTION(NS_SUCCEEDED(aRule->GetType(type)) 
+               && type == nsICSSRule::FONT_FACE_RULE, 
+               "InsertFontFaceRule passed a non-fontface CSS rule");
+  
+  // fontFace->List();
+  
+  nsAutoString fontfamily, valueString;
+  nsCSSValue val;
+  
+  PRUint32 unit;
+  PRUint32 weight = NS_STYLE_FONT_WEIGHT_NORMAL;
+  PRUint32 stretch = NS_STYLE_FONT_STRETCH_NORMAL;
+  PRUint32 italicStyle = FONT_STYLE_NORMAL;
+  
+  // set up family name
+  fontFace->GetDesc(eCSSFontDesc_Family, val);
+  unit = val.GetUnit();
+  if (unit == eCSSUnit_String) {
+    val.GetStringValue(fontfamily);
+    fontfamily.Trim("\"");
+  } else {
+    NS_ASSERTION(unit == eCSSUnit_String, 
+                 "@font-face family name has non-string unit type");
+    return;
+  }
+  
+  // set up weight
+  fontFace->GetDesc(eCSSFontDesc_Weight, val);
+  unit = val.GetUnit();
+  if (unit != eCSSUnit_Null) {
+    if (unit == eCSSUnit_Normal) {
+      weight = NS_STYLE_FONT_WEIGHT_NORMAL;
+    } else {
+      weight = val.GetIntValue();
+    }
+  }
+  
+  // set up stretch
+  fontFace->GetDesc(eCSSFontDesc_Stretch, val);
+  unit = val.GetUnit();
+  if (unit != eCSSUnit_Null) {
+    if (unit == eCSSUnit_Normal) {
+      stretch = NS_STYLE_FONT_STRETCH_NORMAL;
+    } else {
+      stretch = val.GetIntValue();
+    }
+  }
+  
+  // set up font style
+  fontFace->GetDesc(eCSSFontDesc_Style, val);
+  if (val.GetUnit() != eCSSUnit_Null) {
+    if (val.GetUnit() == eCSSUnit_Normal) {
+      italicStyle = FONT_STYLE_NORMAL;
+    } else {
+      italicStyle = val.GetIntValue();
+    }
+  }
+  
+  // set up src array
+  nsTArray<gfxFontFaceSrc> srcArray;
+
+  fontFace->GetDesc(eCSSFontDesc_Src, val);
+  unit = val.GetUnit();
+  if (unit == eCSSUnit_Array) {
+    nsCSSValue::Array *srcArr = val.GetArrayValue();
+    PRUint32 i, numSrc = srcArr->Count(), faceIndex = 0;
+    
+    for (i = 0; i < numSrc; i++) {
+      val = srcArr->Item(i);
+      unit = val.GetUnit();
+      gfxFontFaceSrc *face = srcArray.AppendElements(1);
+      if (!face)
+        return;
+            
+      switch (unit) {
+       
+      case eCSSUnit_Local_Font:
+        val.GetStringValue(face->mLocalName);
+        face->mIsLocal = PR_TRUE;
+        face->mURI = nsnull;
+        face->mFormatFlags = 0;
+        break;
+      case eCSSUnit_URL:
+        face->mIsLocal = PR_FALSE;
+        face->mURI = val.GetURLValue();
+        face->mLocalName.Truncate();
+        face->mFormatFlags = 0;
+        while (i + 1 < numSrc && (val = srcArr->Item(i+1), 
+                 val.GetUnit() == eCSSUnit_Font_Format)) {
+          nsDependentString valueString(val.GetStringBufferValue());
+          if (valueString.LowerCaseEqualsASCII("opentype")) {
+            face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_OPENTYPE; 
+          } else if (valueString.LowerCaseEqualsASCII("truetype")) {
+            face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_TRUETYPE; 
+          } else if (valueString.LowerCaseEqualsASCII("truetype-aat")) {
+            face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT; 
+          } else if (valueString.LowerCaseEqualsASCII("embedded-opentype")) {
+            face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_EOT;   
+          } else if (valueString.LowerCaseEqualsASCII("svg")) {
+            face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_SVG;   
+          }
+          i++;
+        }
+        break;
+      default:
+        NS_ASSERTION(unit == eCSSUnit_Local_Font || unit == eCSSUnit_URL,
+                     "strange unit type in font-face src array");
+        break;
+      }
+     }
+  }
+  
+  if (!fontfamily.IsEmpty() && srcArray.Length() > 0) {
+    fs->AddFontFace(fontfamily, srcArray, weight, stretch, italicStyle);
+  }
+  
+}
+
 static PRBool
 InsertRuleByWeight(nsICSSRule* aRule, void* aData)
 {
   CascadeEnumData* data = (CascadeEnumData*)aData;
   PRInt32 type = nsICSSRule::UNKNOWN_RULE;
   aRule->GetType(type);
 
   if (nsICSSRule::STYLE_RULE == type) {
@@ -2320,20 +2447,38 @@ InsertRuleByWeight(nsICSSRule* aRule, vo
   }
   else if (nsICSSRule::MEDIA_RULE == type ||
            nsICSSRule::DOCUMENT_RULE == type) {
     nsICSSGroupRule* groupRule = (nsICSSGroupRule*)aRule;
     if (groupRule->UseForPresentation(data->mPresContext, data->mCacheKey))
       if (!groupRule->EnumerateRulesForwards(InsertRuleByWeight, aData))
         return PR_FALSE;
   }
+  else if (nsICSSRule::FONT_FACE_RULE == type 
+             && gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
+    nsPresContext *presContext = data->mPresContext;
+    gfxUserFontSet *fs = presContext->GetUserFontSet();
+    if (!fs) {
+      nsFontFaceLoaderContext *loaderCtx = new nsFontFaceLoaderContext(presContext);
+      if (!loaderCtx)
+        return PR_FALSE;
+      fs = new gfxUserFontSet(loaderCtx); // user font set owns loader context
+      if (!fs) {
+        delete loaderCtx;
+        return PR_FALSE;
+      }
+      presContext->SetUserFontSet(fs);
+    }
+    
+    InsertFontFaceRule(aRule, fs);
+  }
+
   return PR_TRUE;
 }
 
-
 static PRBool
 CascadeSheetRulesInto(nsICSSStyleSheet* aSheet, void* aData)
 {
   nsCSSStyleSheet*  sheet = static_cast<nsCSSStyleSheet*>(aSheet);
   CascadeEnumData* data = static_cast<CascadeEnumData*>(aData);
   PRBool bSheetApplicable = PR_TRUE;
   sheet->GetApplicable(bSheetApplicable);
 
new file mode 100644
--- /dev/null
+++ b/layout/style/nsFontFaceLoader.cpp
@@ -0,0 +1,245 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+// vim:cindent:ts=2:et:sw=2:
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Foundation code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   John Daggett <jdaggett@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* code for loading in @font-face defined font data */
+
+#ifdef MOZ_LOGGING
+#define FORCE_PR_LOG /* Allow logging in the release build */
+#endif /* MOZ_LOGGING */
+#include "prlog.h"
+
+#include "nsFontFaceLoader.h"
+
+#include "nsIFile.h"
+#include "nsILocalFile.h"
+#include "nsIStreamListener.h"
+#include "nsNetUtil.h"
+#include "nsIChannelEventSink.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsContentUtils.h"
+
+#include "nsPresContext.h"
+#include "nsIPresShell.h"
+#include "nsIDocument.h"
+#include "nsIFrame.h"
+#include "nsIPrincipal.h"
+#include "nsIScriptSecurityManager.h"
+
+#include "nsDirectoryServiceUtils.h"
+#include "nsDirectoryServiceDefs.h"
+
+
+#ifdef PR_LOGGING
+static PRLogModuleInfo *gFontDownloaderLog = PR_NewLogModule("fontdownloader");
+#endif /* PR_LOGGING */
+
+#define LOG(args) PR_LOG(gFontDownloaderLog, PR_LOG_DEBUG, args)
+#define LOG_ENABLED() PR_LOG_TEST(gFontDownloaderLog, PR_LOG_DEBUG)
+
+
+#define ENFORCE_SAME_SITE_ORIGIN "gfx.downloadable_fonts.enforce_same_site_origin"
+static PRBool gEnforceSameSiteOrigin = PR_TRUE;
+
+static PRBool
+CheckMayLoad(nsIDocument* aDoc, nsIURI* aURI)
+{
+  // allow this to be disabled via a pref
+  static PRBool init = PR_FALSE;
+
+  if (!init) {
+    init = PR_TRUE;
+    nsContentUtils::AddBoolPrefVarCache(ENFORCE_SAME_SITE_ORIGIN, &gEnforceSameSiteOrigin);
+  }
+
+  if (!gEnforceSameSiteOrigin)
+    return PR_TRUE;
+
+  if (!aDoc)
+    return PR_FALSE;
+
+  nsresult rv = aDoc->NodePrincipal()->CheckMayLoad(aURI, PR_TRUE);
+  return NS_SUCCEEDED(rv);
+}
+
+
+nsFontFaceLoader::nsFontFaceLoader(gfxFontEntry *aFontToLoad, nsIURI *aFontURI,
+                                   gfxUserFontSet::LoaderContext *aContext)
+  : mFontEntry(aFontToLoad), mFontURI(aFontURI), mLoaderContext(aContext)
+{
+
+}
+
+nsFontFaceLoader::~nsFontFaceLoader()
+{
+
+}
+
+NS_IMPL_ISUPPORTS1(nsFontFaceLoader, nsIDownloadObserver)
+
+static nsresult
+MakeTempFileName(nsIFile** tempFile)
+{
+  nsresult rv;
+
+  rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, tempFile);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // xxx - need something a little less lame here...
+  static PRUint16 count = 0;
+  PRTime now = PR_Now();
+  PRUint32 current = (PRUint32) now;
+
+  ++count;
+  char buf[256];
+  sprintf(buf, "mozfont_%8.8x%4.4x.ttf", current, count);
+
+  rv = (*tempFile)->AppendNative(nsDependentCString(buf));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return (*tempFile)->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
+}
+
+// initiate the load
+nsresult 
+nsFontFaceLoader::Init()
+{
+#ifdef PR_LOGGING
+  if (LOG_ENABLED()) {
+    nsCAutoString fontURI;
+    mFontURI->GetSpec(fontURI);
+    LOG(("fontdownloader (%p) download start - font uri: (%s)\n", 
+         this, fontURI.get()));
+  }
+#endif  
+
+  nsresult rv;
+
+  nsCOMPtr<nsIFile> tempFile;
+  rv = MakeTempFileName(getter_AddRefs(tempFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = NS_NewDownloader(getter_AddRefs(mDownloader), this, tempFile);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIInterfaceRequestor> sameOriginChecker 
+                                       = nsContentUtils::GetSameOriginChecker();
+
+  rv = NS_OpenURI(mDownloader, nsnull, mFontURI, nsnull, nsnull, 
+                  sameOriginChecker);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFontFaceLoader::OnDownloadComplete(nsIDownloader *aDownloader,
+                                     nsIRequest   *aRequest,
+                                     nsISupports  *aContext,
+                                     nsresult     aStatus,
+                                     nsIFile      *aFile)
+{
+
+#ifdef PR_LOGGING
+  if (LOG_ENABLED()) {
+    nsCAutoString fontURI;
+    mFontURI->GetSpec(fontURI);
+    if (NS_SUCCEEDED(aStatus)) {
+      LOG(("fontdownloader (%p) download completed - font uri: (%s)\n", 
+           this, fontURI.get()));
+    } else {
+      LOG(("fontdownloader (%p) download failed - font uri: (%s) error: %8.8x\n", 
+           this, fontURI.get(), aStatus));
+    }
+  }
+#endif
+
+  PRBool fontUpdate;
+
+  if (NS_SUCCEEDED(aStatus) && aFile) {
+    // font data download succeeded, try to load the font
+    mFaceData.mFormatFlags = 0;
+    mFaceData.mFontFile = aFile;
+    mFaceData.mDownloader = aDownloader;
+  }
+
+  // whether an error occurred or not, notify the user font set of the completion
+  fontUpdate = mLoaderContext->mUserFontSet->OnLoadComplete(mFontEntry, 
+                                                            mFaceData, 
+                                                            aStatus);
+
+  // when new font loaded, need to reflow
+  if (fontUpdate) {
+    nsFontFaceLoaderContext *loaderCtx 
+                       = static_cast<nsFontFaceLoaderContext*> (mLoaderContext);
+
+    nsIPresShell *ps = loaderCtx->mPresContext->PresShell();
+    if (ps) {
+      // reflow async so that reflows coalesce
+      ps->StyleChangeReflow();
+      LOG(("fontdownloader (%p) reflow\n", this));
+    }
+  }
+
+  return NS_OK;
+}
+
+PRBool
+nsFontFaceLoader::CreateHandler(gfxFontEntry *aFontToLoad, nsIURI *aFontURI, 
+                                gfxUserFontSet::LoaderContext *aContext)
+{
+  // check same-site origin
+  nsFontFaceLoaderContext *loaderCtx 
+                             = static_cast<nsFontFaceLoaderContext*> (aContext);
+
+  nsIPresShell *ps = loaderCtx->mPresContext->PresShell();
+  if (!ps)
+    return PR_FALSE;
+
+  if (!CheckMayLoad(ps->GetDocument(), aFontURI))
+    return PR_FALSE;
+
+  nsRefPtr<nsFontFaceLoader> loader = new nsFontFaceLoader(aFontToLoad, 
+                                                           aFontURI, 
+                                                           aContext);
+  if (!loader)
+    return PR_FALSE;
+
+  nsresult rv = loader->Init();
+  return NS_SUCCEEDED(rv);
+}
new file mode 100644
--- /dev/null
+++ b/layout/style/nsFontFaceLoader.h
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+// vim:cindent:ts=2:et:sw=2:
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Foundation code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   John Daggett <jdaggett@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* code for loading in @font-face defined font data */
+
+#ifndef nsFontFaceLoader_h_
+#define nsFontFaceLoader_h_
+
+#include "nsIDownloader.h"
+#include "nsIURI.h"
+#include "gfxUserFontSet.h"
+
+class nsIRequest;
+class nsISupports;
+class nsPresContext;
+
+class nsFontFaceLoader : public nsIDownloadObserver
+{
+public:
+
+  nsFontFaceLoader(gfxFontEntry *aFontToLoad, nsIURI *aFontURI, 
+                   gfxUserFontSet::LoaderContext *aContext);
+  virtual ~nsFontFaceLoader();
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOWNLOADOBSERVER 
+
+  // initiate the load
+  nsresult Init();  
+
+  // returns whether create succeeded or not
+  static PRBool CreateHandler(gfxFontEntry *aFontToLoad, nsIURI *aFontURI, 
+                              gfxUserFontSet::LoaderContext *aContext);
+
+private:
+  nsRefPtr<gfxFontEntry>              mFontEntry;
+  nsCOMPtr<nsIURI>                    mFontURI;
+  gfxUserFontSet::LoaderContext*      mLoaderContext;
+  gfxDownloadedFontData               mFaceData;
+  nsCOMPtr<nsIStreamListener>         mDownloader;
+};
+
+class nsFontFaceLoaderContext : public gfxUserFontSet::LoaderContext {
+public:
+  nsFontFaceLoaderContext(nsPresContext* aContext)
+    : gfxUserFontSet::LoaderContext(nsFontFaceLoader::CreateHandler), 
+      mPresContext(aContext)
+  {
+
+  }
+
+  nsPresContext*    mPresContext;
+};
+
+
+#endif /* !defined(nsFontFaceLoader_h_) */
--- a/layout/svg/base/src/nsSVGGlyphFrame.cpp
+++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp
@@ -1248,17 +1248,17 @@ nsSVGGlyphFrame::EnsureTextRun(float *aD
     }
 
     const nsFont& font = fontData->mFont;
     gfxFontStyle fontStyle(font.style, font.weight, textRunSize, langGroup,
                            font.sizeAdjust, font.systemFont,
                            font.familyNameQuirks);
 
     nsRefPtr<gfxFontGroup> fontGroup =
-      gfxPlatform::GetPlatform()->CreateFontGroup(font.name, &fontStyle);
+      gfxPlatform::GetPlatform()->CreateFontGroup(font.name, &fontStyle, presContext->GetUserFontSet());
 
     PRUint32 flags = gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX |
       nsLayoutUtils::GetTextRunFlagsForStyle(GetStyleContext(), GetStyleText(), GetStyleFont());
 
     // XXX We should use a better surface here! But then we'd have to
     // change things so we can ensure we always have the "right" sort of
     // surface available, by creating the textrun only at the right times
     nsRefPtr<gfxContext> tmpCtx = MakeTmpCtx();
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -129,16 +129,19 @@ pref("browser.chrome.image_icons.max_siz
 pref("browser.triple_click_selects_paragraph", true);
 
 // 0 = Off, 1 = Full, 2 = Tagged Images Only. 
 // See eCMSMode in gfx/thebes/public/gfxPlatform.h
 pref("gfx.color_management.mode", 2);
 pref("gfx.color_management.display_profile", "");
 pref("gfx.color_management.rendering_intent", 0);
 
+pref("gfx.downloadable_fonts.enabled", true);
+pref("gfx.downloadable_fonts.enforce_same_site_origin", true);
+
 pref("accessibility.browsewithcaret", false);
 pref("accessibility.warn_on_browsewithcaret", true);
 
 #ifndef XP_MACOSX
 // Tab focus model bit field:
 // 1 focuses text controls, 2 focuses other form elements, 4 adds links.
 // Most users will want 1, 3, or 7.
 // On OS X, we use Full Keyboard Access system preference,