Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 20 May 2013 16:21:45 -0400
changeset 143892 4236b11635084000d9921be88d4c45d53979bf5a
parent 143867 effa5e16f95ba508888954ccd683e12f98da0f70 (current diff)
parent 143891 1919510d5436179ca5a9f2c087a1d0e83a1bfabe (diff)
child 143899 4ac6c72b06c838aaabe8c8cb6c0a69047d23fc54
child 143944 ac24924abe718b0a844f4698f7ffafa433a6bb6e
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c.
dom/apps/src/Webapps.jsm
--- a/CLOBBER
+++ b/CLOBBER
@@ -12,12 +12,12 @@
 #          O               O
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
-Bug 549861 backout, on Windows due to bug 873809, tests due to...
+Landing bug 865806
 
 Alternative to clobber is to run ./config.status from the objdir and to
 touch the CLOBBER file in the objdir.
--- a/Makefile.in
+++ b/Makefile.in
@@ -72,21 +72,17 @@ export::
 	$(RM) -r $(DIST)/sdk
 	$(MAKE) -C config export
 	$(MAKE) tier_nspr
 
 backend.RecursiveMakeBackend.built:
 	@echo "Updating build backend because of moz.build changes."
 	@$(PYTHON) ./config.status
 
-ifdef .PYMAKE
-includedeps backend.RecursiveMakeBackend.built.pp
-else
 include backend.RecursiveMakeBackend.built.pp
-endif
 
 export MOZBUILD_BACKEND_CHECKED=1
 
 ifdef ENABLE_TESTS
 # Additional makefile targets to call automated test suites
 include $(topsrcdir)/testing/testsuite-targets.mk
 endif
 
--- a/caps/include/nsScriptSecurityManager.h
+++ b/caps/include/nsScriptSecurityManager.h
@@ -378,20 +378,21 @@ private:
                       JSMutableHandleValue vp);
     
     // Decides, based on CSP, whether or not eval() and stuff can be executed.
     static JSBool
     ContentSecurityPolicyPermitsJSAction(JSContext *cx);
 
     // Returns null if a principal cannot be found; generally callers
     // should error out at that point.
-    static nsIPrincipal* doGetObjectPrincipal(JSObject *obj);
+    static nsIPrincipal* doGetObjectPrincipal(JS::Handle<JSObject*> obj);
 #ifdef DEBUG
     static nsIPrincipal*
-    old_doGetObjectPrincipal(JSObject *obj, bool aAllowShortCircuit = true);
+    old_doGetObjectPrincipal(JS::Handle<JSObject*> obj,
+                             bool aAllowShortCircuit = true);
 #endif
 
     // Returns null if a principal cannot be found.  Note that rv can be NS_OK
     // when this happens -- this means that there was no JS running.
     nsIPrincipal*
     doGetSubjectPrincipal(nsresult* rv);
     
     nsresult
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -1628,17 +1628,17 @@ nsScriptSecurityManager::CheckFunctionAc
     if (!aTargetObj) {
         // We're done here
         return NS_OK;
     }
 
     /*
     ** Get origin of subject and object and compare.
     */
-    JSObject* obj = (JSObject*)aTargetObj;
+    JS::Rooted<JSObject*> obj(aCx, (JSObject*)aTargetObj);
     nsIPrincipal* object = doGetObjectPrincipal(obj);
 
     if (!object)
         return NS_ERROR_FAILURE;
 
     bool subsumes;
     rv = subject->Subsumes(object, &subsumes);
     if (NS_SUCCEEDED(rv) && !subsumes) {
@@ -2018,26 +2018,27 @@ nsScriptSecurityManager::GetSubjectPrinc
     JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
     return nsJSPrincipals::get(principals);
 }
 
 NS_IMETHODIMP
 nsScriptSecurityManager::GetObjectPrincipal(JSContext *aCx, JSObject *aObj,
                                             nsIPrincipal **result)
 {
-    *result = doGetObjectPrincipal(aObj);
+    JS::Rooted<JSObject*> obj(aCx, aObj);
+    *result = doGetObjectPrincipal(obj);
     if (!*result)
         return NS_ERROR_FAILURE;
     NS_ADDREF(*result);
     return NS_OK;
 }
 
 // static
 nsIPrincipal*
-nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj)
+nsScriptSecurityManager::doGetObjectPrincipal(JS::Handle<JSObject*> aObj)
 {
     JSCompartment *compartment = js::GetObjectCompartment(aObj);
     JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
     nsIPrincipal *principal = nsJSPrincipals::get(principals);
 
     // We leave the old code in for a little while to make sure that pulling
     // object principals directly off the compartment always gives an equivalent
     // result (from a security perspective).
@@ -2047,24 +2048,25 @@ nsScriptSecurityManager::doGetObjectPrin
 #endif
 
     return principal;
 }
 
 #ifdef DEBUG
 // static
 nsIPrincipal*
-nsScriptSecurityManager::old_doGetObjectPrincipal(JSObject *aObj,
+nsScriptSecurityManager::old_doGetObjectPrincipal(JS::Handle<JSObject*> aObj,
                                                   bool aAllowShortCircuit)
 {
     NS_ASSERTION(aObj, "Bad call to doGetObjectPrincipal()!");
     nsIPrincipal* result = nullptr;
 
-    JS::RootedObject obj(sXPConnect->GetCurrentJSContext(), aObj);
-    JSObject* origObj = obj;
+    JSContext* cx = sXPConnect->GetCurrentJSContext();
+    JS::RootedObject obj(cx, aObj);
+    JS::RootedObject origObj(cx, obj);
     js::Class *jsClass = js::GetObjectClass(obj);
 
     // A common case seen in this code is that we enter this function
     // with obj being a Function object, whose parent is a Call
     // object. Neither of those have object principals, so we can skip
     // those objects here before we enter the below loop. That way we
     // avoid wasting time checking properties of their classes etc in
     // the loop.
@@ -2287,18 +2289,18 @@ nsScriptSecurityManager::CheckXPCPermiss
         {
             nsresult rv;
             if (!jsObject)
             {
                 nsCOMPtr<nsIXPConnectWrappedJS> xpcwrappedjs =
                     do_QueryInterface(aObj);
                 if (xpcwrappedjs)
                 {
-                    rv = xpcwrappedjs->GetJSObject(jsObject.address());
-                    NS_ENSURE_SUCCESS(rv, rv);
+                    jsObject = xpcwrappedjs->GetJSObject();
+                    NS_ENSURE_STATE(jsObject);
                 }
             }
 
             if (!aSubjectPrincipal)
             {
                 // No subject principal passed in. Compute it.
                 aSubjectPrincipal = GetSubjectPrincipal(cx, &rv);
                 NS_ENSURE_SUCCESS(rv, rv);
--- a/config/stl-headers
+++ b/config/stl-headers
@@ -13,16 +13,17 @@
 #
 
 new
 
 # FIXME: these headers haven't been reviewed yet, but we use them
 # unsafely in Gecko, so we might as well prevent them from
 # throwing exceptions
 algorithm
+atomic
 deque
 iostream
 iterator
 limits
 list
 map
 memory
 set
@@ -33,8 +34,9 @@ vector
 cassert
 climits
 cstdarg
 cstdio
 cstdlib
 cstring
 cwchar
 tuple
+xutility
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -2199,17 +2199,17 @@ public:
 
       StructuredCloneData data;
       data.mData = mData.data();
       data.mDataLength = mData.nbytes();
       data.mClosure = mClosure;
 
       nsRefPtr<nsFrameMessageManager> mm = tabChild->GetInnerManager();
       mm->ReceiveMessage(static_cast<EventTarget*>(tabChild), mMessage,
-                         false, &data, nullptr, nullptr, nullptr);
+                         false, &data, JS::NullPtr(), nullptr, nullptr);
     }
     return NS_OK;
   }
   nsRefPtr<nsFrameLoader> mFrameLoader;
   nsString mMessage;
   JSAutoStructuredCloneBuffer mData;
   StructuredCloneClosure mClosure;
 };
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -621,17 +621,17 @@ public:
 
 // nsIMessageListener
 
 nsresult
 nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
                                       const nsAString& aMessage,
                                       bool aSync,
                                       const StructuredCloneData* aCloneData,
-                                      JSObject* aObjectsArray,
+                                      JS::Handle<JSObject*> aObjectsArray,
                                       InfallibleTArray<nsString>* aJSONRetVal,
                                       JSContext* aContext)
 {
   JSContext *cxToUse = mContext ? mContext
                                 : (aContext ? aContext
                                             : nsContentUtils::GetSafeJSContext());
   JS::Rooted<JSObject*> objectsArray(cxToUse, aObjectsArray);
   AutoPushJSContext ctx(cxToUse);
@@ -641,18 +641,17 @@ nsFrameMessageManager::ReceiveMessage(ns
 
     for (uint32_t i = 0; i < mListeners.Length(); ++i) {
       if (mListeners[i].mMessage == name) {
         nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS =
           do_QueryInterface(mListeners[i].mListener);
         if (!wrappedJS) {
           continue;
         }
-        JS::Rooted<JSObject*> object(ctx);
-        wrappedJS->GetJSObject(object.address());
+        JS::Rooted<JSObject*> object(ctx, wrappedJS->GetJSObject());
         if (!object) {
           continue;
         }
         nsCxPusher pusher;
         pusher.Push(ctx);
 
         JSAutoRequest ar(ctx);
         JSAutoCompartment ac(ctx, object);
@@ -1004,18 +1003,17 @@ nsFrameScriptExecutor::LoadFrameScriptIn
 
   if (holder) {
     nsCxPusher pusher;
     pusher.Push(mCx);
     {
       // Need to scope JSAutoRequest to happen after Push but before Pop,
       // at least for now. See bug 584673.
       JSAutoRequest ar(mCx);
-      JS::Rooted<JSObject*> global(mCx);
-      mGlobal->GetJSObject(global.address());
+      JS::Rooted<JSObject*> global(mCx, mGlobal->GetJSObject());
       if (global) {
         (void) JS_ExecuteScript(mCx, global, holder->mScript, nullptr);
       }
     }
   }
 }
 
 void
@@ -1063,18 +1061,17 @@ nsFrameScriptExecutor::TryCacheLoadAndCo
 
   if (!dataString.IsEmpty()) {
     nsCxPusher pusher;
     pusher.Push(mCx);
     {
       // Need to scope JSAutoRequest to happen after Push but before Pop,
       // at least for now. See bug 584673.
       JSAutoRequest ar(mCx);
-      JS::Rooted<JSObject*> global(mCx);
-      mGlobal->GetJSObject(global.address());
+      JS::Rooted<JSObject*> global(mCx, mGlobal->GetJSObject());
       if (global) {
         JSAutoCompartment ac(mCx, global);
         JS::CompileOptions options(mCx);
         options.setNoScriptRval(true)
                .setFileAndLine(url.get(), 1)
                .setPrincipals(nsJSPrincipals::get(mPrincipal));
         JS::RootedObject empty(mCx, nullptr);
         JS::Rooted<JSScript*> script(mCx,
@@ -1133,19 +1130,18 @@ nsFrameScriptExecutor::InitTabChildGloba
   JS_SetContextPrivate(cx, aScope);
 
   nsresult rv =
     xpc->InitClassesWithNewWrappedGlobal(cx, aScope, mPrincipal,
                                          flags, JS::SystemZone, getter_AddRefs(mGlobal));
   NS_ENSURE_SUCCESS(rv, false);
 
 
-  JS::Rooted<JSObject*> global(cx);
-  rv = mGlobal->GetJSObject(global.address());
-  NS_ENSURE_SUCCESS(rv, false);
+  JS::Rooted<JSObject*> global(cx, mGlobal->GetJSObject());
+  NS_ENSURE_TRUE(global, false);
 
   JS_SetGlobalObject(cx, global);
 
   // Set the location information for the new global, so that tools like
   // about:memory may use that information.
   xpc::SetLocationForGlobal(global, aID);
 
   DidCreateCx();
@@ -1201,17 +1197,17 @@ public:
     if (nsFrameMessageManager::sChildProcessManager) {
       StructuredCloneData data;
       data.mData = mData.data();
       data.mDataLength = mData.nbytes();
       data.mClosure = mClosure;
 
       nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sChildProcessManager;
       ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), mMessage,
-                          false, &data, nullptr, nullptr, nullptr);
+                          false, &data, JS::NullPtr(), nullptr, nullptr);
     }
     return NS_OK;
   }
   nsString mMessage;
   JSAutoStructuredCloneBuffer mData;
   StructuredCloneClosure mClosure;
 };
 
@@ -1331,17 +1327,17 @@ public:
       StructuredCloneData data;
       data.mData = mData.data();
       data.mDataLength = mData.nbytes();
       data.mClosure = mClosure;
 
       nsRefPtr<nsFrameMessageManager> ppm =
         nsFrameMessageManager::sSameProcessParentManager;
       ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
-                          mMessage, false, &data, nullptr, nullptr, nullptr);
+                          mMessage, false, &data, JS::NullPtr(), nullptr, nullptr);
      }
      return NS_OK;
   }
   nsString mMessage;
   JSAutoStructuredCloneBuffer mData;
   StructuredCloneClosure mClosure;
 };
 
@@ -1371,17 +1367,17 @@ public:
       for (uint32_t i = 0; i < len; ++i) {
         nsCOMPtr<nsIRunnable> async = asyncMessages[i];
         async->Run();
       }
     }
     if (nsFrameMessageManager::sSameProcessParentManager) {
       nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
       ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), aMessage,
-                          true, &aData, nullptr, aJSONRetVal);
+                          true, &aData, JS::NullPtr(), aJSONRetVal);
     }
     return true;
   }
 
   virtual bool DoSendAsyncMessage(const nsAString& aMessage,
                                   const mozilla::dom::StructuredCloneData& aData)
   {
     if (!nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
--- a/content/base/src/nsFrameMessageManager.h
+++ b/content/base/src/nsFrameMessageManager.h
@@ -177,17 +177,17 @@ public:
   NS_DECL_NSIFRAMESCRIPTLOADER
   NS_DECL_NSIPROCESSCHECKER
 
   static nsFrameMessageManager*
   NewProcessMessageManager(mozilla::dom::ContentParent* aProcess);
 
   nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage,
                           bool aSync, const StructuredCloneData* aCloneData,
-                          JSObject* aObjectsArray,
+                          JS::Handle<JSObject*> aObjectsArray,
                           InfallibleTArray<nsString>* aJSONRetVal,
                           JSContext* aContext = nullptr);
 
   void AddChildManager(nsFrameMessageManager* aManager,
                        bool aLoadScripts = true);
   void RemoveChildManager(nsFrameMessageManager* aManager)
   {
     mChildManagers.RemoveObject(aManager);
--- a/content/base/src/nsInProcessTabChildGlobal.cpp
+++ b/content/base/src/nsInProcessTabChildGlobal.cpp
@@ -33,17 +33,18 @@ nsInProcessTabChildGlobal::DoSendSyncMes
   asyncMessages.SwapElements(mASyncMessages);
   uint32_t len = asyncMessages.Length();
   for (uint32_t i = 0; i < len; ++i) {
     nsCOMPtr<nsIRunnable> async = asyncMessages[i];
     async->Run();
   }
   if (mChromeMessageManager) {
     nsRefPtr<nsFrameMessageManager> mm = mChromeMessageManager;
-    mm->ReceiveMessage(mOwner, aMessage, true, &aData, nullptr, aJSONRetVal);
+    mm->ReceiveMessage(mOwner, aMessage, true, &aData, JS::NullPtr(),
+                       aJSONRetVal);
   }
   return true;
 }
 
 class nsAsyncMessageToParent : public nsRunnable
 {
 public:
   nsAsyncMessageToParent(nsInProcessTabChildGlobal* aTabChild,
@@ -68,17 +69,17 @@ public:
     if (mTabChild->mChromeMessageManager) {
       StructuredCloneData data;
       data.mData = mData.data();
       data.mDataLength = mData.nbytes();
       data.mClosure = mClosure;
 
       nsRefPtr<nsFrameMessageManager> mm = mTabChild->mChromeMessageManager;
       mm->ReceiveMessage(mTabChild->mOwner, mMessage, false, &data,
-                         nullptr, nullptr, nullptr);
+                         JS::NullPtr(), nullptr, nullptr);
     }
     return NS_OK;
   }
   nsRefPtr<nsInProcessTabChildGlobal> mTabChild;
   nsString mMessage;
   JSAutoStructuredCloneBuffer mData;
   StructuredCloneClosure mClosure;
   // True if this runnable has already been called. This can happen if DoSendSyncMessage
--- a/content/base/src/nsInProcessTabChildGlobal.h
+++ b/content/base/src/nsInProcessTabChildGlobal.h
@@ -116,20 +116,17 @@ public:
 
   void DelayedDisconnect();
 
   virtual JSObject* GetGlobalJSObject() {
     if (!mGlobal) {
       return nullptr;
     }
 
-    JSObject* global;
-    mGlobal->GetJSObject(&global);
-
-    return global;
+    return mGlobal->GetJSObject();
   }
 protected:
   nsresult Init();
   nsresult InitTabChildGlobal();
   nsCOMPtr<nsIContentFrameMessageManager> mMessageManager;
   nsCOMPtr<nsIDocShell> mDocShell;
   bool mInitialized;
   bool mLoadingScript;
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -4287,24 +4287,21 @@ WebGLContext::CompileShader(WebGLShader 
         compiler = ShConstructCompiler((ShShaderType) shader->ShaderType(),
                                        SH_WEBGL_SPEC,
                                        targetShaderSourceLanguage,
                                        &resources);
 
         int compileOptions = SH_ATTRIBUTES_UNIFORMS |
                              SH_ENFORCE_PACKING_RESTRICTIONS;
 
-        // we want to do this everywhere, but:
-//TODO: Enable on windows:
-#ifndef XP_WIN // to do this on Windows, we need ANGLE r1719, 1733, 1734.
-#ifndef XP_MACOSX // to do this on Mac, we need to do it only on Mac OSX > 10.6 as this
+        // We want to do this everywhere, but:
+#ifndef XP_MACOSX // To do this on Mac, we need to do it only on Mac OSX > 10.6 as this
                   // causes the shader compiler in 10.6 to crash
         compileOptions |= SH_CLAMP_INDIRECT_ARRAY_BOUNDS;
 #endif
-#endif
 
         if (useShaderSourceTranslation) {
             compileOptions |= SH_OBJECT_CODE
                             | SH_MAP_LONG_VARIABLE_NAMES;
 #ifdef XP_MACOSX
             if (gl->WorkAroundDriverBugs()) {
                 // Work around bug 665578 and bug 769810
                 if (gl->Vendor() == gl::GLContext::VendorATI) {
--- a/content/events/src/nsEventListenerService.cpp
+++ b/content/events/src/nsEventListenerService.cpp
@@ -79,18 +79,18 @@ NS_IMPL_ISUPPORTS1(nsEventListenerServic
 bool
 nsEventListenerInfo::GetJSVal(JSContext* aCx,
                               mozilla::Maybe<JSAutoCompartment>& aAc,
                               JS::Value* aJSVal)
 {
   *aJSVal = JSVAL_NULL;
   nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = do_QueryInterface(mListener);
   if (wrappedJS) {
-    JS::Rooted<JSObject*> object(aCx, nullptr);
-    if (NS_FAILED(wrappedJS->GetJSObject(object.address()))) {
+    JS::Rooted<JSObject*> object(aCx, wrappedJS->GetJSObject());
+    if (!object) {
       return false;
     }
     aAc.construct(aCx, object);
     *aJSVal = OBJECT_TO_JSVAL(object);
     return true;
   }
 
   nsCOMPtr<nsIJSEventListener> jsl = do_QueryInterface(mListener);
--- a/content/media/wmf/DXVA2Manager.cpp
+++ b/content/media/wmf/DXVA2Manager.cpp
@@ -21,18 +21,20 @@ class D3D9DXVA2Manager : public DXVA2Man
 public:
   D3D9DXVA2Manager();
   virtual ~D3D9DXVA2Manager();
 
   HRESULT Init();
 
   IUnknown* GetDXVADeviceManager() MOZ_OVERRIDE;
 
+  // Copies a region (aRegion) of the video frame stored in aVideoSample
+  // into an image which is returned by aOutImage.
   HRESULT CopyToImage(IMFSample* aVideoSample,
-                      const nsIntSize& aSize,
+                      const nsIntRect& aRegion,
                       ImageContainer* aContainer,
                       Image** aOutImage) MOZ_OVERRIDE;
 
 private:
   nsRefPtr<IDirect3D9Ex> mD3D9;
   nsRefPtr<IDirect3DDevice9Ex> mDevice;
   nsRefPtr<IDirect3DDeviceManager9> mDeviceManager;
   UINT32 mResetToken;
@@ -132,17 +134,17 @@ D3D9DXVA2Manager::Init()
   mDevice = device;
   mDeviceManager = deviceManager;
 
   return S_OK;
 }
 
 HRESULT
 D3D9DXVA2Manager::CopyToImage(IMFSample* aSample,
-                              const nsIntSize& aSize,
+                              const nsIntRect& aRegion,
                               ImageContainer* aImageContainer,
                               Image** aOutImage)
 {
   nsRefPtr<IMFMediaBuffer> buffer;
   HRESULT hr = aSample->GetBufferByIndex(0, getter_AddRefs(buffer));
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   nsRefPtr<IDirect3DSurface9> surface;
@@ -154,17 +156,17 @@ D3D9DXVA2Manager::CopyToImage(IMFSample*
 
   ImageFormat format = D3D9_RGB32_TEXTURE;
   nsRefPtr<Image> image = aImageContainer->CreateImage(&format, 1);
   NS_ENSURE_TRUE(image, E_FAIL);
   NS_ASSERTION(image->GetFormat() == D3D9_RGB32_TEXTURE,
                "Wrong format?");
 
   D3D9SurfaceImage* videoImage = static_cast<D3D9SurfaceImage*>(image.get());
-  hr = videoImage->SetData(D3D9SurfaceImage::Data(surface, aSize));
+  hr = videoImage->SetData(D3D9SurfaceImage::Data(surface, aRegion));
 
   image.forget(aOutImage);
 
   return S_OK;
 }
 
 /* static */
 DXVA2Manager*
--- a/content/media/wmf/DXVA2Manager.h
+++ b/content/media/wmf/DXVA2Manager.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #if !defined(DXVA2Manager_h_)
 #define DXVA2Manager_h_
 
 #include "WMF.h"
 #include "nsAutoPtr.h"
 #include "mozilla/Mutex.h"
+#include "nsRect.h"
 
 class nsIntSize;
 
 namespace mozilla {
 
 namespace layers {
 class Image;
 class ImageContainer;
@@ -30,17 +31,17 @@ public:
   // Returns a pointer to the D3D device manager responsible for managing the
   // device we're using for hardware accelerated video decoding. If we're using
   // D3D9, this is an IDirect3DDeviceManager9. It is safe to call this on any
   // thread.
   virtual IUnknown* GetDXVADeviceManager() = 0;
 
   // Creates an Image for the video frame stored in aVideoSample.
   virtual HRESULT CopyToImage(IMFSample* aVideoSample,
-                              const nsIntSize& aSize,
+                              const nsIntRect& aRegion,
                               layers::ImageContainer* aContainer,
                               layers::Image** aOutImage) = 0;
 
   virtual ~DXVA2Manager();
 
 protected:
   Mutex mLock;
   DXVA2Manager();
--- a/content/media/wmf/WMFReader.cpp
+++ b/content/media/wmf/WMFReader.cpp
@@ -786,17 +786,17 @@ WMFReader::CreateD3DVideoFrame(IMFSample
   NS_ENSURE_TRUE(mDXVA2Manager, E_ABORT);
   NS_ENSURE_TRUE(mUseHwAccel, E_ABORT);
 
   *aOutVideoData = nullptr;
   HRESULT hr;
 
   nsRefPtr<Image> image;
   hr = mDXVA2Manager->CopyToImage(aSample,
-                                  nsIntSize(mPictureRegion.width, mPictureRegion.height),
+                                  mPictureRegion,
                                   mDecoder->GetImageContainer(),
                                   getter_AddRefs(image));
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   NS_ENSURE_TRUE(image, E_FAIL);
 
   VideoData *v = VideoData::CreateFromImage(mInfo,
                                             mDecoder->GetImageContainer(),
                                             aOffsetBytes,
--- a/content/svg/content/src/SVGAnimatedRect.cpp
+++ b/content/svg/content/src/SVGAnimatedRect.cpp
@@ -30,29 +30,25 @@ SVGAnimatedRect::SVGAnimatedRect(nsSVGVi
 }
 
 SVGAnimatedRect::~SVGAnimatedRect()
 {
   nsSVGViewBox::sSVGAnimatedRectTearoffTable.RemoveTearoff(mVal);
 }
 
 already_AddRefed<SVGIRect>
-SVGAnimatedRect::GetBaseVal(ErrorResult& aRv)
+SVGAnimatedRect::GetBaseVal()
 {
-  nsRefPtr<SVGIRect> rect;
-  aRv = mVal->ToDOMBaseVal(getter_AddRefs(rect), mSVGElement);
-  return rect.forget();
+  return mVal->ToDOMBaseVal(mSVGElement);
 }
 
 already_AddRefed<SVGIRect>
-SVGAnimatedRect::GetAnimVal(ErrorResult& aRv)
+SVGAnimatedRect::GetAnimVal()
 {
-  nsRefPtr<SVGIRect> rect;
-  aRv = mVal->ToDOMAnimVal(getter_AddRefs(rect), mSVGElement);
-  return rect.forget();
+  return mVal->ToDOMAnimVal(mSVGElement);
 }
 
 JSObject*
 SVGAnimatedRect::WrapObject(JSContext* aCx,
                             JS::Handle<JSObject*> aScope)
 {
   return SVGAnimatedRectBinding::Wrap(aCx, aScope, this);
 }
--- a/content/svg/content/src/SVGAnimatedRect.h
+++ b/content/svg/content/src/SVGAnimatedRect.h
@@ -32,19 +32,19 @@ public:
   nsSVGElement* GetParentObject() const
   {
     return mSVGElement;
   }
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
-  already_AddRefed<SVGIRect> GetBaseVal(ErrorResult& aRv);
+  already_AddRefed<SVGIRect> GetBaseVal();
 
-  already_AddRefed<SVGIRect> GetAnimVal(ErrorResult& aRv);
+  already_AddRefed<SVGIRect> GetAnimVal();
 
 private:
   nsSVGViewBox* mVal; // kept alive because it belongs to content
   nsRefPtr<nsSVGElement> mSVGElement;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/content/svg/content/src/SVGMarkerElement.cpp
+++ b/content/svg/content/src/SVGMarkerElement.cpp
@@ -104,19 +104,17 @@ SVGMarkerElement::SVGMarkerElement(alrea
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGMarkerElement)
 
 //----------------------------------------------------------------------
 
 already_AddRefed<SVGAnimatedRect>
 SVGMarkerElement::ViewBox()
 {
-  nsRefPtr<SVGAnimatedRect> rect;
-  mViewBox.ToDOMAnimatedRect(getter_AddRefs(rect), this);
-  return rect.forget();
+  return mViewBox.ToSVGAnimatedRect(this);
 }
 
 already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
 SVGMarkerElement::PreserveAspectRatio()
 {
   nsRefPtr<DOMSVGAnimatedPreserveAspectRatio> ratio;
   mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(getter_AddRefs(ratio), this);
   return ratio.forget();
--- a/content/svg/content/src/SVGPatternElement.cpp
+++ b/content/svg/content/src/SVGPatternElement.cpp
@@ -62,19 +62,17 @@ SVGPatternElement::SVGPatternElement(alr
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGPatternElement)
 
 //----------------------------------------------------------------------
 
 already_AddRefed<SVGAnimatedRect>
 SVGPatternElement::ViewBox()
 {
-  nsRefPtr<SVGAnimatedRect> rect;
-  mViewBox.ToDOMAnimatedRect(getter_AddRefs(rect), this);
-  return rect.forget();
+  return mViewBox.ToSVGAnimatedRect(this);
 }
 
 already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
 SVGPatternElement::PreserveAspectRatio()
 {
   nsRefPtr<DOMSVGAnimatedPreserveAspectRatio> ratio;
   mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(getter_AddRefs(ratio), this);
   return ratio.forget();
--- a/content/svg/content/src/SVGSVGElement.cpp
+++ b/content/svg/content/src/SVGSVGElement.cpp
@@ -440,19 +440,17 @@ SVGSVGElement::GetElementById(const nsAS
   return nullptr;
 }
 
 //----------------------------------------------------------------------
 
 already_AddRefed<SVGAnimatedRect>
 SVGSVGElement::ViewBox()
 {
-  nsRefPtr<SVGAnimatedRect> rect;
-  mViewBox.ToDOMAnimatedRect(getter_AddRefs(rect), this);
-  return rect.forget();
+  return mViewBox.ToSVGAnimatedRect(this);
 }
 
 already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
 SVGSVGElement::PreserveAspectRatio()
 {
   nsRefPtr<DOMSVGAnimatedPreserveAspectRatio> ratio;
   mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(getter_AddRefs(ratio), this);
   return ratio.forget();
--- a/content/svg/content/src/SVGSymbolElement.cpp
+++ b/content/svg/content/src/SVGSymbolElement.cpp
@@ -38,19 +38,17 @@ SVGSymbolElement::SVGSymbolElement(alrea
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGSymbolElement)
 
 //----------------------------------------------------------------------
 
 already_AddRefed<SVGAnimatedRect>
 SVGSymbolElement::ViewBox()
 {
-  nsRefPtr<SVGAnimatedRect> rect;
-  mViewBox.ToDOMAnimatedRect(getter_AddRefs(rect), this);
-  return rect.forget();
+  return mViewBox.ToSVGAnimatedRect(this);
 }
 
 already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
 SVGSymbolElement::PreserveAspectRatio()
 {
   nsRefPtr<DOMSVGAnimatedPreserveAspectRatio> ratio;
   mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(getter_AddRefs(ratio), this);
   return ratio.forget();
--- a/content/svg/content/src/SVGViewElement.cpp
+++ b/content/svg/content/src/SVGViewElement.cpp
@@ -62,19 +62,17 @@ SVGViewElement::SetZoomAndPan(uint16_t a
   rv.Throw(NS_ERROR_RANGE_ERR);
 }
 
 //----------------------------------------------------------------------
 
 already_AddRefed<SVGAnimatedRect>
 SVGViewElement::ViewBox()
 {
-  nsRefPtr<SVGAnimatedRect> box;
-  mViewBox.ToDOMAnimatedRect(getter_AddRefs(box), this);
-  return box.forget();
+  return mViewBox.ToSVGAnimatedRect(this);
 }
 
 already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
 SVGViewElement::PreserveAspectRatio()
 {
   nsRefPtr<DOMSVGAnimatedPreserveAspectRatio> ratio;
   mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(getter_AddRefs(ratio), this);
   return ratio.forget();
--- a/content/svg/content/src/nsSVGViewBox.cpp
+++ b/content/svg/content/src/nsSVGViewBox.cpp
@@ -52,17 +52,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 static nsSVGAttrTearoffTable<nsSVGViewBox, nsSVGViewBox::DOMBaseVal>
   sBaseSVGViewBoxTearoffTable;
 static nsSVGAttrTearoffTable<nsSVGViewBox, nsSVGViewBox::DOMAnimVal>
   sAnimSVGViewBoxTearoffTable;
-nsSVGAttrTearoffTable<nsSVGViewBox, mozilla::dom::SVGAnimatedRect>
+nsSVGAttrTearoffTable<nsSVGViewBox, dom::SVGAnimatedRect>
   nsSVGViewBox::sSVGAnimatedRectTearoffTable;
 
 
 /* Implementation of nsSVGViewBox methods */
 
 void
 nsSVGViewBox::Init()
 {
@@ -193,73 +193,68 @@ nsSVGViewBox::GetBaseValueString(nsAStri
   PRUnichar buf[200];
   nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
                             NS_LITERAL_STRING("%g %g %g %g").get(),
                             (double)mBaseVal.x, (double)mBaseVal.y,
                             (double)mBaseVal.width, (double)mBaseVal.height);
   aValue.Assign(buf);
 }
 
-nsresult
-nsSVGViewBox::ToDOMAnimatedRect(dom::SVGAnimatedRect **aResult,
-                                nsSVGElement* aSVGElement)
+
+already_AddRefed<dom::SVGAnimatedRect>
+nsSVGViewBox::ToSVGAnimatedRect(nsSVGElement* aSVGElement)
 {
   nsRefPtr<dom::SVGAnimatedRect> domAnimatedRect =
     sSVGAnimatedRectTearoffTable.GetTearoff(this);
   if (!domAnimatedRect) {
     domAnimatedRect = new dom::SVGAnimatedRect(this, aSVGElement);
     sSVGAnimatedRectTearoffTable.AddTearoff(this, domAnimatedRect);
   }
 
-  domAnimatedRect.forget(aResult);
-  return NS_OK;
+  return domAnimatedRect.forget();
 }
 
-nsresult
-nsSVGViewBox::ToDOMBaseVal(dom::SVGIRect **aResult,
-                           nsSVGElement *aSVGElement)
+already_AddRefed<dom::SVGIRect>
+nsSVGViewBox::ToDOMBaseVal(nsSVGElement *aSVGElement)
 {
   if (!mHasBaseVal || mBaseVal.none) {
-    *aResult = nullptr;
-    return NS_OK;
+    return nullptr;
   }
+
   nsRefPtr<DOMBaseVal> domBaseVal =
     sBaseSVGViewBoxTearoffTable.GetTearoff(this);
   if (!domBaseVal) {
     domBaseVal = new DOMBaseVal(this, aSVGElement);
     sBaseSVGViewBoxTearoffTable.AddTearoff(this, domBaseVal);
   }
 
-  domBaseVal.forget(aResult);
-  return NS_OK;
+ return domBaseVal.forget();
 }
 
 nsSVGViewBox::DOMBaseVal::~DOMBaseVal()
 {
   sBaseSVGViewBoxTearoffTable.RemoveTearoff(mVal);
 }
 
-nsresult
-nsSVGViewBox::ToDOMAnimVal(dom::SVGIRect **aResult,
-                           nsSVGElement *aSVGElement)
+already_AddRefed<dom::SVGIRect>
+nsSVGViewBox::ToDOMAnimVal(nsSVGElement *aSVGElement)
 {
   if ((mAnimVal && mAnimVal->none) ||
       (!mAnimVal && (!mHasBaseVal || mBaseVal.none))) {
-    *aResult = nullptr;
-    return NS_OK;
+    return nullptr;
   }
+
   nsRefPtr<DOMAnimVal> domAnimVal =
     sAnimSVGViewBoxTearoffTable.GetTearoff(this);
   if (!domAnimVal) {
     domAnimVal = new DOMAnimVal(this, aSVGElement);
     sAnimSVGViewBoxTearoffTable.AddTearoff(this, domAnimVal);
   }
 
-  domAnimVal.forget(aResult);
-  return NS_OK;
+  return domAnimVal.forget();
 }
 
 nsSVGViewBox::DOMAnimVal::~DOMAnimVal()
 {
   sAnimSVGViewBoxTearoffTable.RemoveTearoff(mVal);
 }
 
 void
--- a/content/svg/content/src/nsSVGViewBox.h
+++ b/content/svg/content/src/nsSVGViewBox.h
@@ -75,22 +75,25 @@ public:
   void SetAnimValue(const nsSVGViewBoxRect& aRect,
                     nsSVGElement *aSVGElement);
 
   nsresult SetBaseValueString(const nsAString& aValue,
                               nsSVGElement *aSVGElement,
                               bool aDoSetAttr);
   void GetBaseValueString(nsAString& aValue) const;
 
-  nsresult ToDOMAnimatedRect(mozilla::dom::SVGAnimatedRect **aResult,
-                             nsSVGElement *aSVGElement);
-  nsresult ToDOMBaseVal(mozilla::dom::SVGIRect **aResult,
-                        nsSVGElement* aSVGElement);
-  nsresult ToDOMAnimVal(mozilla::dom::SVGIRect **aResult,
-                        nsSVGElement* aSVGElement);
+  already_AddRefed<mozilla::dom::SVGAnimatedRect>
+  ToSVGAnimatedRect(nsSVGElement *aSVGElement);
+
+  already_AddRefed<mozilla::dom::SVGIRect>
+  ToDOMBaseVal(nsSVGElement* aSVGElement);
+
+  already_AddRefed<mozilla::dom::SVGIRect>
+  ToDOMAnimVal(nsSVGElement* aSVGElement);
+
   // Returns a new nsISMILAttr object that the caller must delete
   nsISMILAttr* ToSMILAttr(nsSVGElement* aSVGElement);
 
 private:
 
   nsSVGViewBoxRect mBaseVal;
   nsAutoPtr<nsSVGViewBoxRect> mAnimVal;
   bool mHasBaseVal;
--- a/content/xbl/src/nsXBLProtoImpl.cpp
+++ b/content/xbl/src/nsXBLProtoImpl.cpp
@@ -78,18 +78,18 @@ nsXBLProtoImpl::InstallImplementation(ns
 
   // Stash a strong reference to the JSClass in the binding.
   aBinding->SetJSClass(static_cast<nsXBLJSClass*>(JS_GetClass(targetClassObject)));
 
   // If the prototype already existed, we don't need to install anything. return early.
   if (!targetObjectIsNew)
     return NS_OK;
 
-  JS::Rooted<JSObject*> targetScriptObject(context->GetNativeContext());
-  holder->GetJSObject(targetScriptObject.address());
+  JS::Rooted<JSObject*> targetScriptObject(context->GetNativeContext(),
+                                           holder->GetJSObject());
 
   AutoPushJSContext cx(context->GetNativeContext());
   JSAutoRequest ar(cx);
   JSAutoCompartment ac(cx, targetClassObject);
   AutoVersionChecker avc(cx);
 
   // Walk our member list and install each one in turn.
   for (nsXBLProtoImplMember* curr = mMembers;
--- a/content/xbl/src/nsXBLProtoImplMethod.cpp
+++ b/content/xbl/src/nsXBLProtoImplMethod.cpp
@@ -259,17 +259,18 @@ nsXBLProtoImplMethod::Write(nsIScriptCon
 {
   if (mJSMethodObject) {
     nsresult rv = aStream->Write8(XBLBinding_Serialize_Method);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = aStream->WriteWStringZ(mName);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    return XBL_SerializeFunction(aContext, aStream, mJSMethodObject);
+    return XBL_SerializeFunction(aContext, aStream,
+                                 JS::Handle<JSObject*>::fromMarkedLocation(&mJSMethodObject));
   }
 
   return NS_OK;
 }
 
 nsresult
 nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
 {
@@ -364,14 +365,15 @@ nsresult
 nsXBLProtoImplAnonymousMethod::Write(nsIScriptContext* aContext,
                                      nsIObjectOutputStream* aStream,
                                      XBLBindingSerializeDetails aType)
 {
   if (mJSMethodObject) {
     nsresult rv = aStream->Write8(aType);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = XBL_SerializeFunction(aContext, aStream, mJSMethodObject);
+    rv = XBL_SerializeFunction(aContext, aStream,
+                               JS::Handle<JSObject*>::fromMarkedLocation(&mJSMethodObject));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
--- a/content/xbl/src/nsXBLProtoImplProperty.cpp
+++ b/content/xbl/src/nsXBLProtoImplProperty.cpp
@@ -368,19 +368,21 @@ nsXBLProtoImplProperty::Write(nsIScriptC
   }
 
   nsresult rv = aStream->Write8(type);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = aStream->WriteWStringZ(mName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (mJSAttributes & JSPROP_GETTER) {
-    rv = XBL_SerializeFunction(aContext, aStream, mJSGetterObject);
+    rv = XBL_SerializeFunction(aContext, aStream,
+      JS::Handle<JSObject*>::fromMarkedLocation(&mJSGetterObject));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (mJSAttributes & JSPROP_SETTER) {
-    rv = XBL_SerializeFunction(aContext, aStream, mJSSetterObject);
+    rv = XBL_SerializeFunction(aContext, aStream,
+      JS::Handle<JSObject*>::fromMarkedLocation(&mJSSetterObject));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
--- a/content/xbl/src/nsXBLSerialize.cpp
+++ b/content/xbl/src/nsXBLSerialize.cpp
@@ -8,21 +8,20 @@
 #include "nsContentUtils.h"
 #include "jsdbgapi.h"
 
 using namespace mozilla;
 
 nsresult
 XBL_SerializeFunction(nsIScriptContext* aContext,
                       nsIObjectOutputStream* aStream,
-                      JSObject* aFunctionObject)
+                      JS::Handle<JSObject*> aFunction)
 {
   AutoPushJSContext cx(aContext->GetNativeContext());
-  JS::RootedObject function(cx, aFunctionObject);
-  return nsContentUtils::XPConnect()->WriteFunction(aStream, cx, function);
+  return nsContentUtils::XPConnect()->WriteFunction(aStream, cx, aFunction);
 }
 
 nsresult
 XBL_DeserializeFunction(nsIScriptContext* aContext,
                         nsIObjectInputStream* aStream,
                         JS::MutableHandle<JSObject*> aFunctionObjectp)
 {
   AutoPushJSContext cx(aContext->GetNativeContext());
--- a/content/xbl/src/nsXBLSerialize.h
+++ b/content/xbl/src/nsXBLSerialize.h
@@ -74,16 +74,16 @@ typedef uint8_t XBLBindingSerializeDetai
 // are no more attributes.
 #define XBLBinding_Serialize_NoMoreAttributes 0xFF
 
 PR_STATIC_ASSERT(XBLBinding_Serialize_CustomNamespace >= kNameSpaceID_LastBuiltin);
 
 nsresult
 XBL_SerializeFunction(nsIScriptContext* aContext,
                       nsIObjectOutputStream* aStream,
-                      JSObject* aFunctionObject);
+                      JS::Handle<JSObject*> aFunctionObject);
 
 nsresult
 XBL_DeserializeFunction(nsIScriptContext* aContext,
                         nsIObjectInputStream* aStream,
                         JS::MutableHandle<JSObject*> aFunctionObject);
 
 #endif // nsXBLSerialize_h__
--- a/content/xslt/src/xslt/txMozillaXSLTProcessor.cpp
+++ b/content/xslt/src/xslt/txMozillaXSLTProcessor.cpp
@@ -1433,19 +1433,18 @@ txVariable::Convert(nsIVariant *aValue, 
 
             // Convert random JS Objects to a string.
             nsCOMPtr<nsIXPConnectJSObjectHolder> holder =
                 do_QueryInterface(supports);
             if (holder) {
                 JSContext* cx = nsContentUtils::GetCurrentJSContext();
                 NS_ENSURE_TRUE(cx, NS_ERROR_NOT_AVAILABLE);
 
-                JS::RootedObject jsobj(cx);
-                rv = holder->GetJSObject(jsobj.address());
-                NS_ENSURE_SUCCESS(rv, rv);
+                JS::RootedObject jsobj(cx, holder->GetJSObject());
+                NS_ENSURE_STATE(jsobj);
 
                 JS::RootedString str(cx, JS_ValueToString(cx, OBJECT_TO_JSVAL(jsobj)));
                 NS_ENSURE_TRUE(str, NS_ERROR_FAILURE);
 
                 nsDependentJSString value;
                 NS_ENSURE_TRUE(value.init(cx, str), NS_ERROR_FAILURE);
 
                 *aResult = new StringResult(value, nullptr);
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -2521,17 +2521,17 @@ nsXULPrototypeScript::DeserializeOutOfLi
             if (NS_SUCCEEDED(rv))
                 rv = Deserialize(objectInput, aGlobal, nullptr, nullptr);
 
             if (NS_SUCCEEDED(rv)) {
                 if (useXULCache && mSrcURI) {
                     bool isChrome = false;
                     mSrcURI->SchemeIs("chrome", &isChrome);
                     if (isChrome)
-                        cache->PutScript(mSrcURI, mScriptObject);
+                        cache->PutScript(mSrcURI, GetScriptObject());
                 }
                 cache->FinishInputStream(mSrcURI);
             } else {
                 // If mSrcURI is not in the cache,
                 // rv will be NS_ERROR_NOT_AVAILABLE and we'll try to
                 // update the cache file to hold a serialization of
                 // this script, once it has finished loading.
                 if (rv != NS_ERROR_NOT_AVAILABLE)
@@ -2623,19 +2623,19 @@ void
 nsXULPrototypeScript::Set(JSScript* aObject)
 {
     MOZ_ASSERT(!mScriptObject, "Leaking script object.");
     if (!aObject) {
         mScriptObject = nullptr;
         return;
     }
 
+    mScriptObject = aObject;
     nsContentUtils::HoldJSObjects(
         this, NS_CYCLE_COLLECTION_PARTICIPANT(nsXULPrototypeNode));
-    mScriptObject = aObject;
 }
 
 //----------------------------------------------------------------------
 //
 // nsXULPrototypeText
 //
 
 nsresult
--- a/content/xul/content/src/nsXULElement.h
+++ b/content/xul/content/src/nsXULElement.h
@@ -231,19 +231,23 @@ public:
                      nsIURI* aURI, uint32_t aLineNo,
                      nsIDocument* aDocument,
                      nsIScriptGlobalObjectOwner* aGlobalOwner);
 
     void UnlinkJSObjects();
 
     void Set(JSScript* aObject);
 
-    JSScript *GetScriptObject()
+    // It's safe to return a handle because we trace mScriptObject, no one ever
+    // uses the handle (or the script object) past the point at which the
+    // nsXULPrototypeScript dies, and we can't get memmoved so the
+    // &mScriptObject pointer can't go stale.
+    JS::Handle<JSScript*> GetScriptObject()
     {
-        return mScriptObject;
+        return JS::Handle<JSScript*>::fromMarkedLocation(&mScriptObject);
     }
 
     void TraceScriptObject(JSTracer* aTrc)
     {
         if (mScriptObject) {
             JS_CallScriptTracer(aTrc, &mScriptObject, "active window XUL prototype script");
         }
     }
--- a/content/xul/document/src/XULDocument.cpp
+++ b/content/xul/document/src/XULDocument.cpp
@@ -3639,28 +3639,28 @@ XULDocument::OnStreamComplete(nsIStreamL
         NS_RELEASE(doc);
     }
 
     return rv;
 }
 
 
 nsresult
-XULDocument::ExecuteScript(nsIScriptContext * aContext, JSScript* aScriptObject)
+XULDocument::ExecuteScript(nsIScriptContext * aContext,
+                           JS::Handle<JSScript*> aScriptObject)
 {
     NS_PRECONDITION(aScriptObject != nullptr && aContext != nullptr, "null ptr");
     if (! aScriptObject || ! aContext)
         return NS_ERROR_NULL_POINTER;
 
     NS_ENSURE_TRUE(mScriptGlobalObject, NS_ERROR_NOT_INITIALIZED);
 
     // Execute the precompiled script with the given version
-    JS::Rooted<JSScript*> script(aContext->GetNativeContext(), aScriptObject);
     JSObject* global = mScriptGlobalObject->GetGlobalJSObject();
-    return aContext->ExecuteScript(script, global);
+    return aContext->ExecuteScript(aScriptObject, global);
 }
 
 nsresult
 XULDocument::ExecuteScript(nsXULPrototypeScript *aScript)
 {
     NS_PRECONDITION(aScript != nullptr, "null ptr");
     NS_ENSURE_TRUE(aScript, NS_ERROR_NULL_POINTER);
     NS_ENSURE_TRUE(mScriptGlobalObject, NS_ERROR_NOT_INITIALIZED);
--- a/content/xul/document/src/XULDocument.h
+++ b/content/xul/document/src/XULDocument.h
@@ -398,17 +398,18 @@ protected:
      * completed, aBlock will be set to true.
      */
     nsresult LoadScript(nsXULPrototypeScript *aScriptProto, bool* aBlock);
 
     /**
      * Execute the precompiled script object scoped by this XUL document's
      * containing window object, and using its associated script context.
      */
-    nsresult ExecuteScript(nsIScriptContext *aContext, JSScript* aScriptObject);
+    nsresult ExecuteScript(nsIScriptContext *aContext,
+                           JS::Handle<JSScript*> aScriptObject);
 
     /**
      * Helper method for the above that uses aScript to find the appropriate
      * script context and object.
      */
     nsresult ExecuteScript(nsXULPrototypeScript *aScript);
 
     /**
--- a/content/xul/document/src/nsXULPrototypeCache.cpp
+++ b/content/xul/document/src/nsXULPrototypeCache.cpp
@@ -200,17 +200,18 @@ nsXULPrototypeCache::GetScript(nsIURI* a
     CacheScriptEntry entry;
     if (!mScriptTable.Get(aURI, &entry)) {
         return nullptr;
     }
     return entry.mScriptObject;
 }
 
 nsresult
-nsXULPrototypeCache::PutScript(nsIURI* aURI, JSScript* aScriptObject)
+nsXULPrototypeCache::PutScript(nsIURI* aURI,
+                               JS::Handle<JSScript*> aScriptObject)
 {
     CacheScriptEntry existingEntry;
     if (mScriptTable.Get(aURI, &existingEntry)) {
 #ifdef DEBUG
         nsAutoCString scriptName;
         aURI->GetSpec(scriptName);
         nsAutoCString message("Loaded script ");
         message += scriptName;
--- a/content/xul/document/src/nsXULPrototypeCache.h
+++ b/content/xul/document/src/nsXULPrototypeCache.h
@@ -64,17 +64,17 @@ public:
 
     // The following methods are used to put and retrive various items into and
     // from the cache.
 
     nsXULPrototypeDocument* GetPrototype(nsIURI* aURI);
     nsresult PutPrototype(nsXULPrototypeDocument* aDocument);
 
     JSScript* GetScript(nsIURI* aURI);
-    nsresult PutScript(nsIURI* aURI, JSScript* aScriptObject);
+    nsresult PutScript(nsIURI* aURI, JS::Handle<JSScript*> aScriptObject);
 
     nsXBLDocumentInfo* GetXBLDocumentInfo(nsIURI* aURL) {
         return mXBLDocTable.GetWeak(aURL);
     }
     nsresult PutXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo);
 
     /**
      * Get a style sheet by URI. If the style sheet is not in the cache,
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -1849,18 +1849,26 @@ this.DOMApplicationRegistry = {
               manifest.package_path)) {
           sendError("INVALID_MANIFEST");
         } else if (!AppsUtils.checkInstallAllowed(manifest, app.installOrigin)) {
           sendError("INSTALL_FROM_DENIED");
         } else {
           app.etag = xhr.getResponseHeader("Etag");
           app.manifestHash = this.computeManifestHash(manifest);
           debug("at install package got app etag=" + app.etag);
-          Services.obs.notifyObservers(aMm, "webapps-ask-install",
-                                       JSON.stringify(aData));
+          // We allow bypassing the install confirmation process to facilitate
+          // automation.
+          let prefName = "dom.mozApps.auto_confirm_install";
+          if (Services.prefs.prefHasUserValue(prefName) &&
+              Services.prefs.getBoolPref(prefName)) {
+            this.confirmInstall(aData);
+          } else {
+            Services.obs.notifyObservers(aMm, "webapps-ask-install",
+                                         JSON.stringify(aData));
+          }
         }
       }
       else {
         sendError("MANIFEST_URL_ERROR");
       }
     }).bind(this), false);
 
     xhr.addEventListener("error", (function() {
@@ -2006,29 +2014,28 @@ this.DOMApplicationRegistry = {
 
     this.queuedDownload[app.manifestURL] = {
       manifest: manifest,
       app: appObject,
       profileDir: aProfileDir,
       offlineCacheObserver: aOfflineCacheObserver
     }
 
-    let postFirstInstallTask = (function () {
-      // Only executed on install not involving sync.
-      this.broadcastMessage("Webapps:AddApp", { id: id, app: appObject });
-      this.broadcastMessage("Webapps:Install:Return:OK", aData);
-      Services.obs.notifyObservers(this, "webapps-sync-install", appNote);
-    }).bind(this);
+    // We notify about the successful installation via mgmt.oninstall and the
+    // corresponging DOMRequest.onsuccess event as soon as the app is properly
+    // saved in the registry.
+    if (!aFromSync) {
+      this._saveApps((function() {
+        this.broadcastMessage("Webapps:AddApp", { id: id, app: appObject });
+        this.broadcastMessage("Webapps:Install:Return:OK", aData);
+        Services.obs.notifyObservers(this, "webapps-sync-install", appNote);
+      }).bind(this));
+    }
 
     if (!aData.isPackage) {
-      if (!aFromSync) {
-        this._saveApps((function() {
-          postFirstInstallTask();
-        }).bind(this));
-      }
       this.updateAppHandlers(null, app.manifest, app);
       if (aInstallSuccessCallback) {
         aInstallSuccessCallback(manifest);
       }
     }
 
     if (manifest.package_path) {
       // origin for install apps is meaningless here, since it's app:// and this
@@ -2062,19 +2069,16 @@ this.DOMApplicationRegistry = {
                                                     manifestURL: appObject.manifestURL },
                                                   true);
           debug("About to fire Webapps:PackageEvent 'installed'");
           this.broadcastMessage("Webapps:PackageEvent",
                                 { type: "installed",
                                   manifestURL: appObject.manifestURL,
                                   app: app,
                                   manifest: aManifest });
-          if (!aFromSync) {
-            postFirstInstallTask();
-          }
           if (aInstallSuccessCallback) {
             aInstallSuccessCallback(aManifest);
           }
         }).bind(this));
       }).bind(this));
     }
   },
 
--- a/dom/apps/tests/Makefile.in
+++ b/dom/apps/tests/Makefile.in
@@ -7,21 +7,30 @@ topsrcdir        = @top_srcdir@
 srcdir           = @srcdir@
 VPATH            = @srcdir@
 
 relativesrcdir   = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_FILES = \
-  test_app_update.html \
   file_app.sjs \
   file_app.template.html \
-  file_hosted_app.template.webapp \
   file_cached_app.template.webapp \
   file_cached_app.template.appcache \
+  file_hosted_app.template.webapp \
+  test_app_update.html \
   $(NULL)
 
+ifdef MOZ_B2G
+MOCHITEST_FILES += \
+  file_packaged_app.sjs \
+  file_packaged_app.template.webapp \
+  file_packaged_app.template.html \
+  test_packaged_app_install.html \
+  $(NULL)
+endif
+
 MOCHITEST_CHROME_FILES = \
   test_apps_service.xul \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/dom/apps/tests/file_app.template.html
+++ b/dom/apps/tests/file_app.template.html
@@ -35,17 +35,20 @@ function finish() {
 function cbError() {
   ok(false, "Error callback invoked");
   finish();
 }
 
 function go() {
   ok(true, "Launched app");
   var request = window.navigator.mozApps.getSelf();
-  request.onsuccess = function() { var app = request.result; checkApp(app); }
+  request.onsuccess = function() {
+    var app = request.result;
+    checkApp(app);
+  }
   request.onerror = cbError;
 }
 
 function checkApp(app) {
   // If the app is installed, |app| will be non-null. If it is, verify its state.
   installed(!!app);
   if (app) {
     var appName = "Really Rapid Release (APPTYPETOKEN)";
new file mode 100644
--- /dev/null
+++ b/dom/apps/tests/file_packaged_app.sjs
@@ -0,0 +1,166 @@
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
+
+// From prio.h
+const PR_RDWR        = 0x04;
+const PR_CREATE_FILE = 0x08;
+const PR_TRUNCATE    = 0x20;
+
+Cu.import("resource://gre/modules/FileUtils.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
+
+var gBasePath = "tests/dom/apps/tests/";
+var gMiniManifestTemplate = "file_packaged_app.template.webapp";
+var gAppTemplate = "file_packaged_app.template.html";
+var gAppName = "appname";
+var gDevName = "devname";
+var gDevUrl = "http://dev.url";
+
+function handleRequest(request, response) {
+  var query = getQuery(request);
+
+  response.setHeader("Access-Control-Allow-Origin", "*", false);
+
+  var packageSize = ("packageSize" in query) ? query.packageSize : 0;
+  var appName = ("appName" in query) ? query.appName : gAppName;
+  var devName = ("devName" in query) ? query.devName : gDevName;
+  var devUrl = ("devUrl" in query) ? query.devUrl : gDevUrl;
+
+  // If this is a version update, update state, prepare the manifest,
+  // the application package and return.
+  if ("setVersion" in query) {
+    var version = query.setVersion;
+    setState("version", version);
+
+    var packageName = "test_packaged_app_" + version + ".zip";
+    setState("packageName", packageName);
+    var packagePath = "/" + gBasePath + "file_packaged_app.sjs?getPackage=" +
+                      packageName;
+    setState("packagePath", packagePath);
+
+    // Create the application package.
+    var zipWriter = Cc["@mozilla.org/zipwriter;1"]
+                    .createInstance(Ci.nsIZipWriter);
+    var zipFile = FileUtils.getFile("TmpD", [packageName]);
+    zipWriter.open(zipFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE);
+
+    // We want to run some tests without the manifest included in the zip.
+    if (version != "0") {
+      var manifestTemplate = gBasePath + gMiniManifestTemplate;
+      var manifest = makeResource(manifestTemplate, version, packagePath,
+                                  packageSize, appName, devName, devUrl);
+      addZipEntry(zipWriter, manifest, "manifest.webapp");
+    }
+
+    var appTemplate = gBasePath + gAppTemplate;
+    var app = makeResource(appTemplate, version, packagePath, packageSize,
+                           appName, devName, devUrl);
+    addZipEntry(zipWriter, app, "index.html");
+
+    zipWriter.close();
+
+    response.setHeader("Content-Type", "text/html", false);
+    response.write("OK");
+    return;
+  }
+
+  // Get the version from server state
+  var version = Number(getState("version"));
+  var packageName = String(getState("packageName"));
+  var packagePath = String(getState("packagePath"));
+
+  var etag = getEtag(request, version);
+
+  if (etagMatches(request, etag)) {
+    dump("Etags Match. Sending 304\n");
+    response.setStatusLine(request.httpVersion, "304", "Not modified");
+    return;
+  }
+
+  response.setHeader("Etag", etag, false);
+
+  // Serve the application package corresponding to the requested app version.
+  if ("getPackage" in query) {
+    var resource = readFile(packageName, true);
+    response.setHeader("Content-Type",
+                       "Content-Type: application/java-archive", false);
+    response.write(resource);
+    return;
+  }
+
+  // Serve the mini-manifest corresponding to the requested app version.
+  if ("getManifest" in query) {
+    var template = gBasePath + gMiniManifestTemplate;
+    if (!("noManifestContentType" in query)) {
+      response.setHeader("Content-Type",
+                         "application/x-web-app-manifest+json", false);
+    }
+    packagePath = "wrongPackagePath" in query ? "" : packagePath;
+    var manifest = makeResource(template, version, packagePath, packageSize,
+                                appName, devName, devUrl);
+    response.write(manifest);
+    return;
+  }
+
+  response.setHeader("Content-type", "text-html", false);
+  response.write("KO");
+}
+
+function getQuery(request) {
+  var query = {};
+  request.queryString.split('&').forEach(function (val) {
+    var [name, value] = val.split('=');
+    query[name] = unescape(value);
+  });
+  return query;
+}
+
+function getEtag(request, version) {
+  return request.queryString.replace(/&/g, '-').replace(/=/g, '-') +
+         '-' + version;
+}
+
+function etagMatches(request, etag) {
+  return request.hasHeader("If-None-Match") &&
+         request.getHeader("If-None-Match") == etag;
+}
+
+// File and resources helpers
+
+function addZipEntry(zipWriter, entry, entryName) {
+  var stream = Cc["@mozilla.org/io/string-input-stream;1"]
+               .createInstance(Ci.nsIStringInputStream);
+  stream.setData(entry, entry.length);
+  zipWriter.addEntryStream(entryName, Date.now(),
+                           Ci.nsIZipWriter.COMPRESSION_BEST, stream, false);
+}
+
+function readFile(path, fromTmp) {
+  var dir = fromTmp ? "TmpD" : "CurWorkD";
+  var file = Cc["@mozilla.org/file/directory_service;1"]
+             .getService(Ci.nsIProperties)
+             .get(dir, Ci.nsILocalFile);
+  var fstream = Cc["@mozilla.org/network/file-input-stream;1"]
+                .createInstance(Ci.nsIFileInputStream);
+  var split = path.split("/");
+  for(var i = 0; i < split.length; ++i) {
+    file.append(split[i]);
+  }
+  fstream.init(file, -1, 0, 0);
+  var data = NetUtil.readInputStreamToString(fstream, fstream.available());
+  fstream.close();
+  return data;
+}
+
+function makeResource(templatePath, version, packagePath, packageSize,
+                      appName, developerName, developerUrl) {
+  var res = readFile(templatePath, false)
+            .replace(/VERSIONTOKEN/g, version)
+            .replace(/PACKAGEPATHTOKEN/g, packagePath)
+            .replace(/PACKAGESIZETOKEN/g, packageSize)
+            .replace(/NAMETOKEN/g, appName)
+            .replace(/DEVELOPERTOKEN/g, developerName)
+            .replace(/DEVELOPERURLTOKEN/g, developerUrl);
+  return res;
+}
new file mode 100644
--- /dev/null
+++ b/dom/apps/tests/file_packaged_app.template.html
@@ -0,0 +1,7 @@
+<html>
+<head>
+</head>
+<body>
+App Body. Version: VERSIONTOKEN
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/apps/tests/file_packaged_app.template.webapp
@@ -0,0 +1,13 @@
+{
+  "name" : "NAMETOKEN",
+  "version" : "VERSIONTOKEN",
+  "size" : PACKAGESIZETOKEN,
+  "package_path": "PACKAGEPATHTOKEN",
+  "description": "Updated even faster than Firefox, just to annoy slashdotters",
+  "launch_path": "tests/dom/apps/tests/file_packaged_app.sjs",
+  "developer": {
+    "name": "DEVELOPERTOKEN",
+    "url": "DEVELOPERURLTOKEN"
+  },
+  "default_locale": "en-US"
+}
new file mode 100644
--- /dev/null
+++ b/dom/apps/tests/test_packaged_app_install.html
@@ -0,0 +1,401 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id={821589}
+-->
+<head>
+  <title>Test for Bug {821589} Packaged apps installation and update</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={821589}">Mozilla Bug {821589}</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+"use strict";
+
+var gInstallOrigin = "http://mochi.test:8888";
+var gSJSPath = "tests/dom/apps/tests/file_packaged_app.sjs";
+var gSJS = "http://test/" + gSJSPath;
+var gAppName = "appname";
+var gApp = null;
+
+var launchableValue = undefined;
+
+var index = -1;
+
+function debug(aMsg) {
+  //dump("== Tests debug == " + aMsg + "\n");
+}
+
+function next() {
+  index += 1;
+  if (index >= steps.length) {
+    ok(false, "Shouldn't get here!");
+    return;
+  }
+  try {
+    steps[index]();
+  } catch(ex) {
+    ok(false, "Caught exception", ex);
+  }
+}
+
+function go() {
+  next();
+}
+
+function finish() {
+  SpecialPowers.setAllAppsLaunchable(launchableValue);
+  SpecialPowers.removePermission("webapps-manage", document);
+  SimpleTest.finish();
+}
+
+function cbError(aError) {
+  ok(false, "Error callback invoked " + aError);
+  finish();
+}
+
+function setAppVersion(aVersion, aCb) {
+  var xhr = new XMLHttpRequest();
+  xhr.addEventListener("load", function() {
+    is(xhr.responseText, "OK", "setVersion OK");
+    aCb();
+  });
+  xhr.addEventListener("error", cbError);
+  xhr.addEventListener("abort", cbError);
+  xhr.open("GET", gSJS + "?setVersion=" + aVersion, true);
+  xhr.send();
+}
+
+function checkAppInstallError(aMiniManifestURL, aExpectedError) {
+  var req = navigator.mozApps.installPackage(aMiniManifestURL);
+  req.onsuccess = function() {
+    ok(false, "We are supposed to throw " + aExpectedError);
+    finish();
+  };
+  req.onerror = function(evt) {
+    var error = evt.target.error.name;
+    if (error == aExpectedError) {
+      ok(true, "Got expected " + aExpectedError);
+      next();
+    } else {
+      ok(false, "Got unexpected " + aError);
+      finish();
+    }
+  };
+}
+
+function checkUninstallApp(aApp) {
+  var req = navigator.mozApps.mgmt.uninstall(aApp);
+  req.onsuccess = function() {
+    ok(true, "App uninstalled");
+    aApp.ondownloadsuccess = null;
+    aApp.ondownloaderror = null;
+    aApp.onprogress = null;
+    next();
+  };
+  req.onerror = function(evt) {
+    ok(false, "Got unexpected " + evt.target.error.name);
+    finish();
+  };
+}
+
+function checkAppDownloadError(aMiniManifestURL,
+                               aExpectedError,
+                               aVersion,
+                               aUninstall,
+                               aDownloadAvailable,
+                               aName) {
+  var req = navigator.mozApps.installPackage(aMiniManifestURL);
+  req.onsuccess = function() {
+    ok(true, "App installed");
+  };
+  req.onerror = function(evt) {
+    ok(false, "Got unexpected " + evt.target.error.name);
+    finish();
+  };
+
+  navigator.mozApps.mgmt.oninstall = function(evt) {
+    var aApp = evt.application;
+    aApp.ondownloaderror = function(evt) {
+      var error = aApp.downloadError.name;
+      if (error == aExpectedError) {
+        ok(true, "Got expected " + aExpectedError);
+        var expected = {
+          name: aName,
+          manifestURL: aMiniManifestURL,
+          installOrigin: gInstallOrigin,
+          progress: 0,
+          installState: "pending",
+          downloadAvailable: aDownloadAvailable,
+          downloading: false,
+          downloadSize: 0,
+          size: 0,
+          readyToApplyDownload: false,
+        };
+        checkAppState(aApp, aVersion, expected, false, aUninstall, next);
+      } else {
+        ok(false, "Got unexpected " + error);
+        finish();
+      }
+    };
+    aApp.ondownloadsuccess = function(evt) {
+      ok(false, "We are supposed to throw " + aExpectedError);
+      finish();
+    };
+  };
+}
+
+function checkInstalledApp(aMiniManifestURL,
+                           aVersion,
+                           aExpectedApp,
+                           aLaunchable,
+                           aCb) {
+  var req = navigator.mozApps.checkInstalled(aMiniManifestURL);
+  req.onsuccess = function(evt) {
+    ok(true, "The app is installed");
+    checkAppState(evt.application, aVersion, aExpectedApp, aLaunchable,
+                  false, aCb);
+  };
+  req.onerror = function() {
+    ok(false, "The app is not installed");
+    finish();
+  };
+}
+
+function checkAppState(aApp,
+                       aVersion,
+                       aExpectedApp,
+                       aLaunchable,
+                       aUninstall,
+                       aCb) {
+  debug(JSON.stringify(aApp, null, 2));
+  if (aApp.manifest) {
+    debug(JSON.stringify(aApp.manifest, null, 2));
+  }
+
+  if (aExpectedApp.name) {
+    if (aApp.manifest) {
+      is(aApp.manifest.name, aExpectedApp.name, "Check name");
+    }
+    is(aApp.updateManifest.name, aExpectedApp.name, "Check name mini-manifest");
+  }
+  if (aApp.manifest) {
+    is(aApp.manifest.version, aVersion, "Check version");
+  }
+  if (typeof aExpectedApp.size !== "undefined" && aApp.manifest) {
+    is(aApp.manifest.size, aExpectedApp.size, "Check size");
+  }
+  if (aApp.manifest) {
+    is(aApp.manifest.launch_path, gSJSPath, "Check launch path");
+  }
+  if (aExpectedApp.manifestURL) {
+    is(aApp.manifestURL, aExpectedApp.manifestURL, "Check manifestURL");
+  }
+  if (aExpectedApp.installOrigin) {
+    is(aApp.installOrigin, aExpectedApp.installOrigin, "Check installOrigin");
+  }
+  ok(aApp.removable, "Removable app");
+  if (typeof aExpectedApp.progress !== "undefined") {
+    todo(aApp.progress == aExpectedApp.progress, "Check progress");
+  }
+  if (aExpectedApp.installState) {
+    is(aApp.installState, aExpectedApp.installState, "Check installState");
+  }
+  if (typeof aExpectedApp.downloadAvailable !== "undefined") {
+    is(aApp.downloadAvailable, aExpectedApp.downloadAvailable,
+       "Check download available");
+  }
+  if (typeof aExpectedApp.downloading !== "undefined") {
+    is(aApp.downloading, aExpectedApp.downloading, "Check downloading");
+  }
+  if (typeof aExpectedApp.downloadSize !== "undefined") {
+    is(aApp.downloadSize, aExpectedApp.downloadSize, "Check downloadSize");
+  }
+  if (typeof aExpectedApp.readyToApplyDownload !== "undefined") {
+    is(aApp.readyToApplyDownload, aExpectedApp.readyToApplyDownload,
+       "Check readyToApplyDownload");
+  }
+  if (aLaunchable) {
+    if (aUninstall) {
+      checkUninstallApp(aApp);
+    } else if (aCb && typeof aCb === 'function') {
+      aCb();
+    }
+    return;
+  }
+
+  // Check if app is not launchable.
+  var req = aApp.launch();
+  req.onsuccess = function () {
+    ok(false, "We shouldn't be here");
+    finish();
+  };
+  req.onerror = function() {
+    ok(true, "App is not launchable");
+    if (aUninstall) {
+      checkUninstallApp(aApp);
+    } else if (aCb && typeof aCb === 'function') {
+      aCb();
+    }
+    return;
+  };
+}
+
+SimpleTest.waitForExplicitFinish();
+
+var steps = [
+  function() {
+    // Set up
+    launchableValue = SpecialPowers.setAllAppsLaunchable(true);
+    SpecialPowers.addPermission("webapps-manage", true, document);
+    ok(true, "Set up");
+    next();
+  },
+  function() {
+    ok(true, "autoConfirmAppInstall");
+    SpecialPowers.autoConfirmAppInstall(next);
+  },
+  function() {
+    setAppVersion(0, next);
+  },
+  function() {
+    // Test network error.
+    ok(true, "== TEST == Network error");
+    checkAppInstallError("http://notvalidurl", "NETWORK_ERROR");
+  },
+  function() {
+    // Test wrong mini-manifest content type.
+    ok(true, "== TEST == Not valid mini-manifest content type");
+    var miniManifestURL = gSJS +
+                          "?getManifest=true" +
+                          "&noManifestContentType=true";
+    checkAppInstallError(miniManifestURL, "INVALID_MANIFEST");
+  },
+  function() {
+    // Test mini-manifest 'size' value is not number. Bug 839435.
+    ok(true, "== TEST == Size value is not a number");
+    var miniManifestURL = gSJS +
+                          "?getManifest=true" +
+                          "&packageSize=\"NotANumber\"";
+    checkAppInstallError(miniManifestURL, "INVALID_MANIFEST");
+  },
+  function() {
+    // Test mini-manifest  negative 'size' value. Bug 839435.
+    ok(true, "== TEST == Negative size value");
+    var miniManifestURL = gSJS +
+                          "?getManifest=true" +
+                          "&packageSize=-1";
+    checkAppInstallError(miniManifestURL, "INVALID_MANIFEST");
+  },
+  function() {
+    // Test wrong package path
+    ok(true, "== TEST == Installing app with wrong package path");
+    var miniManifestURL = gSJS +
+                          "?getManifest=true" +
+                          "&wrongPackagePath=true";
+    checkAppInstallError(miniManifestURL, "INVALID_MANIFEST");
+  },
+  function() {
+    // Test no manifest in zip file.
+    ok(true, "== TEST == No manifest in the zip file");
+    var miniManifestURL = gSJS + "?getManifest=true";
+    checkAppDownloadError(miniManifestURL, "MISSING_MANIFEST", 0, true, true,
+                          gAppName);
+  },
+  function() {
+    setAppVersion(1, next);
+  },
+  function() {
+    // Test mini-manifest app name is different from the webapp manifest name.
+    // Bug 844243.
+    ok(true, "== TEST == Mini-manifest app name is different from webapp " +
+             "manifest name");
+    var miniManifestURL = gSJS +
+                          "?getManifest=true" +
+                          "&appName=arandomname";
+    checkAppDownloadError(miniManifestURL, "MANIFEST_MISMATCH", 1, true, true,
+                          "arandomname");
+  },
+  function() {
+    // Test mini-manifest dev name is different from the webapp manifest dev
+    // name.
+    ok (true, "== TEST == Mini-manifest dev name is different from manifest " +
+              "dev name");
+    var miniManifestURL = gSJS +
+                          "?getManifest=true" +
+                          "&devName=arandomdevname";
+    checkAppDownloadError(miniManifestURL, "MANIFEST_MISMATCH", 1, true, true,
+                          gAppName);
+  },
+  function() {
+    // Test mini-manifest dev url is different from the webapp manifest dev
+    // url.
+    ok (true, "== TEST == Mini-manifest dev url is different from manifest " +
+              "dev url");
+    var miniManifestURL = gSJS +
+                          "?getManifest=true" +
+                          "&devUrl=arandomdevurl";
+    checkAppDownloadError(miniManifestURL, "MANIFEST_MISMATCH", 1, true, true,
+                          gAppName);
+  },
+  function() {
+    setAppVersion(2, next);
+  },
+  function() {
+    ok(true, "== TEST == Install packaged app");
+    var miniManifestURL = gSJS +
+                          "?getManifest=true";
+    navigator.mozApps.mgmt.oninstall = function(evt) {
+      ok(true, "Got oninstall event");
+      gApp = evt.application;
+      gApp.ondownloaderror = function() {
+        ok(false, "Download error " + gApp.downloadError.name);
+        finish();
+      };
+      gApp.ondownloadsuccess = function() {
+        ok(true, "App downloaded");
+        var expected = {
+          name: gAppName,
+          manifestURL: miniManifestURL,
+          installOrigin: gInstallOrigin,
+          progress: 0,
+          installState: "installed",
+          downloadAvailable: false,
+          downloading: false,
+          downloadSize: 0,
+          size: 0,
+          readyToApplyDownload: false,
+        };
+        checkAppState(gApp, 2, expected, true, false, next);
+      };
+    };
+
+    var request = navigator.mozApps.installPackage(miniManifestURL);
+    request.onerror = function(evt) {
+      cbError(evt.target.error.name);
+    };
+    request.onsuccess = function() {
+      ok(true, "Application installed");
+    };
+  },
+  function() {
+    ok(true, "all done!\n");
+    SimpleTest.finish();
+  }
+];
+
+addLoadEvent(go);
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -888,16 +888,18 @@ static nsDOMClassInfoData sClassInfoData
 
   NS_DEFINE_CLASSINFO_DATA(OpenWindowEventDetail, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(AsyncScrollEventDetail, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(LockedFile, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(CSSFontFeatureValuesRule, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
 #ifdef MOZ_TIME_MANAGER
   NS_DEFINE_CLASSINFO_DATA(MozTimeManager, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #endif
 };
 
 #define NS_DEFINE_CONTRACT_CTOR(_class, _contract_id)                           \
@@ -2252,16 +2254,20 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(AsyncScrollEventDetail, nsIAsyncScrollEventDetail)
     DOM_CLASSINFO_MAP_ENTRY(nsIAsyncScrollEventDetail)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(LockedFile, nsIDOMLockedFile)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMLockedFile)
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(CSSFontFeatureValuesRule, nsIDOMCSSFontFeatureValuesRule)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFeatureValuesRule)
+  DOM_CLASSINFO_MAP_END
+
 #ifdef MOZ_TIME_MANAGER
   DOM_CLASSINFO_MAP_BEGIN(MozTimeManager, nsIDOMMozTimeManager)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozTimeManager)
   DOM_CLASSINFO_MAP_END
 #endif
 
   MOZ_STATIC_ASSERT(MOZ_ARRAY_LENGTH(sClassInfoData) == eDOMClassInfoIDCount,
                     "The number of items in sClassInfoData doesn't match the "
@@ -2638,18 +2644,18 @@ nsDOMClassInfo::CheckAccess(nsIXPConnect
 {
   JS::Rooted<jsid> id(cx, aId);
   uint32_t mode_type = mode & JSACC_TYPEMASK;
 
   if ((mode_type == JSACC_WATCH || mode_type == JSACC_PROTO) && sSecMan) {
     nsresult rv;
     JS::Rooted<JSObject*> real_obj(cx);
     if (wrapper) {
-      rv = wrapper->GetJSObject(real_obj.address());
-      NS_ENSURE_SUCCESS(rv, rv);
+      real_obj = wrapper->GetJSObject();
+      NS_ENSURE_STATE(real_obj);
     }
     else {
       real_obj = obj;
     }
 
     rv =
       sSecMan->CheckPropertyAccess(cx, real_obj, mData->mName, id,
                                    nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
@@ -3349,18 +3355,17 @@ BaseStubConstructor(nsIWeakReference* aW
     if (initializer) {
       rv = initializer->Initialize(currentInner, cx, obj, args);
       if (NS_FAILED(rv)) {
         return rv;
       }
     } else {
       nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = do_QueryInterface(native);
 
-      JS::Rooted<JSObject*> thisObject(cx);
-      wrappedJS->GetJSObject(thisObject.address());
+      JS::Rooted<JSObject*> thisObject(cx, wrappedJS->GetJSObject());
       if (!thisObject) {
         return NS_ERROR_UNEXPECTED;
       }
 
       nsCxPusher pusher;
       pusher.Push(cx);
 
       JSAutoRequest ar(cx);
@@ -4095,18 +4100,17 @@ GetXPCProto(nsIXPConnect *aXPConnect, JS
   }
   NS_ENSURE_TRUE(ci, NS_ERROR_UNEXPECTED);
 
   nsresult rv =
     aXPConnect->GetWrappedNativePrototype(cx, aWin->GetGlobalJSObject(), ci,
                                           aProto);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  JS::Rooted<JSObject*> proto_obj(cx);
-  (*aProto)->GetJSObject(proto_obj.address());
+  JS::Rooted<JSObject*> proto_obj(cx, (*aProto)->GetJSObject());
   if (!JS_WrapObject(cx, proto_obj.address())) {
     return NS_ERROR_FAILURE;
   }
 
   NS_IF_RELEASE(*aProto);
   return aXPConnect->HoldObject(cx, proto_obj, aProto);
 }
 
@@ -4138,18 +4142,17 @@ ResolvePrototype(nsIXPConnect *aXPConnec
                   false, v.address(), getter_AddRefs(holder));
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (install) {
     rv = constructor->Install(cx, obj, v);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  JS::Rooted<JSObject*> class_obj(cx);
-  holder->GetJSObject(class_obj.address());
+  JS::Rooted<JSObject*> class_obj(cx, holder->GetJSObject());
   NS_ASSERTION(class_obj, "The return value lied");
 
   const nsIID *primary_iid = &NS_GET_IID(nsISupports);
 
   if (!ci_data) {
     primary_iid = &name_struct->mIID;
   }
   else if (ci_data->mProtoChainInterface) {
@@ -4416,18 +4419,17 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
     JS::Rooted<JS::Value> v(cx);
     rv = WrapNative(cx, obj, constructor, &NS_GET_IID(nsIDOMDOMConstructor),
                     false, v.address(), getter_AddRefs(holder));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = constructor->Install(cx, obj, v);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    JS::Rooted<JSObject*> class_obj(cx);
-    holder->GetJSObject(class_obj.address());
+    JS::Rooted<JSObject*> class_obj(cx, holder->GetJSObject());
     NS_ASSERTION(class_obj, "The return value lied");
 
     // ... and define the constants from the DOM interface on that
     // constructor object.
 
     JSAutoCompartment ac(cx, class_obj);
     rv = DefineInterfaceConstants(cx, class_obj, &name_struct->mIID);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -4445,19 +4447,18 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
 
     // Create the XPConnect prototype for our classinfo, PostCreateProto will
     // set up the prototype chain.
     nsCOMPtr<nsIXPConnectJSObjectHolder> proto_holder;
     rv = GetXPCProto(sXPConnect, cx, aWin, name_struct,
                      getter_AddRefs(proto_holder));
 
     if (NS_SUCCEEDED(rv) && obj != aWin->GetGlobalJSObject()) {
-      JS::Rooted<JSObject*> dot_prototype(cx);
-      rv = proto_holder->GetJSObject(dot_prototype.address());
-      NS_ENSURE_SUCCESS(rv, rv);
+      JS::Rooted<JSObject*> dot_prototype(cx, proto_holder->GetJSObject());
+      NS_ENSURE_STATE(dot_prototype);
 
       const nsDOMClassInfoData *ci_data;
       if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
         ci_data = &sClassInfoData[name_struct->mDOMClassInfoID];
       } else {
         ci_data = name_struct->mData;
       }
 
@@ -4487,19 +4488,18 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
     // We need to use the XPConnect prototype for the DOM class that this
     // constructor is an alias for (for example for Image we need the prototype
     // for HTMLImageElement).
     nsCOMPtr<nsIXPConnectJSObjectHolder> proto_holder;
     rv = GetXPCProto(sXPConnect, cx, aWin, alias_struct,
                      getter_AddRefs(proto_holder));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    JSObject* dot_prototype;
-    rv = proto_holder->GetJSObject(&dot_prototype);
-    NS_ENSURE_SUCCESS(rv, rv);
+    JSObject* dot_prototype = proto_holder->GetJSObject();
+    NS_ENSURE_STATE(dot_prototype);
 
     const nsDOMClassInfoData *ci_data;
     if (alias_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
       ci_data = &sClassInfoData[alias_struct->mDOMClassInfoID];
     } else if (alias_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
       ci_data = alias_struct->mData;
     } else {
       return NS_ERROR_UNEXPECTED;
@@ -4521,19 +4521,17 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
     rv = WrapNative(cx, obj, constructor, &NS_GET_IID(nsIDOMDOMConstructor),
                     false, val.address(), getter_AddRefs(holder));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = constructor->Install(cx, obj, val);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    JSObject* class_obj;
-    holder->GetJSObject(&class_obj);
-    NS_ASSERTION(class_obj, "Why didn't we get a JSObject?");
+    NS_ASSERTION(holder->GetJSObject(), "Why didn't we get a JSObject?");
 
     *did_resolve = true;
 
     return NS_OK;
   }
 
   if (name_struct->mType == nsGlobalNameStruct::eTypeProperty) {
     if (name_struct->mChromeOnly && !nsContentUtils::IsCallerChrome())
@@ -4868,18 +4866,17 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
     // here) since we must define window.location to prevent the
     // getter from being overriden (for security reasons).
 
     nsCOMPtr<nsIDOMLocation> location;
     nsresult rv = win->GetLocation(getter_AddRefs(location));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Make sure we wrap the location object in the window's scope.
-    JS::Rooted<JSObject*> scope(cx);
-    wrapper->GetJSObject(scope.address());
+    JS::Rooted<JSObject*> scope(cx, wrapper->GetJSObject());
 
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
     JS::Rooted<JS::Value> v(cx);
     rv = WrapNative(cx, scope, location, &NS_GET_IID(nsIDOMLocation), true,
                     v.address(), getter_AddRefs(holder));
     NS_ENSURE_SUCCESS(rv, rv);
 
     JSBool ok = JS_WrapValue(cx, v.address()) &&
@@ -5052,18 +5049,17 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
     return rv;
   }
 
   // Make a fast expando if we're assigning to (not declaring or
   // binding a name) a new undefined property that's not already
   // defined on our prototype chain. This way we can access this
   // expando w/o ever getting back into XPConnect.
   if (flags & JSRESOLVE_ASSIGNING) {
-    JS::Rooted<JSObject*> realObj(cx);
-    wrapper->GetJSObject(realObj.address());
+    JS::Rooted<JSObject*> realObj(cx, wrapper->GetJSObject());
 
     if (obj == realObj) {
       JS::Rooted<JSObject*> proto(cx);
       if (!js::GetObjectProto(cx, obj, &proto)) {
           *_retval = JS_FALSE;
           return NS_OK;
       }
       if (proto) {
@@ -5898,23 +5894,17 @@ nsNamedArraySH::NewResolve(nsIXPConnectW
                            JSObject **objp, bool *_retval)
 {
   JS::Rooted<JSObject*> obj(cx, aObj);
   JS::Rooted<jsid> id(cx, aId);
   if ((!(JSRESOLVE_ASSIGNING & flags)) && JSID_IS_STRING(id) &&
       !ObjectIsNativeWrapper(cx, obj)) {
 
     {
-      JS::Rooted<JSObject*> realObj(cx);
-
-      if (wrapper) {
-        wrapper->GetJSObject(realObj.address());
-      } else {
-        realObj = obj;
-      }
+      JS::Rooted<JSObject*> realObj(cx, wrapper ? wrapper->GetJSObject() : obj);
 
       JSAutoCompartment ac(cx, realObj);
       JS::Rooted<JSObject*> proto(cx);
       if (!::JS_GetPrototype(cx, realObj, proto.address())) {
         return NS_ERROR_FAILURE;
       }
 
       if (proto) {
@@ -6894,18 +6884,17 @@ nsStorage2SH::NewResolve(nsIXPConnectWra
                          JSObject *obj, jsid aId, uint32_t flags,
                          JSObject **objp, bool *_retval)
 {
   JS::Rooted<jsid> id(cx, aId);
   if (ObjectIsNativeWrapper(cx, obj)) {
     return NS_OK;
   }
 
-  JS::Rooted<JSObject*> realObj(cx);
-  wrapper->GetJSObject(realObj.address());
+  JS::Rooted<JSObject*> realObj(cx, wrapper->GetJSObject());
 
   JSAutoCompartment ac(cx, realObj);
 
   // First check to see if the property is defined on our prototype,
   // after converting id to a string if it's an integer.
 
   JS::Rooted<JSString*> jsstr(cx, IdToString(cx, id));
   if (!jsstr) {
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -227,14 +227,16 @@ DOMCI_CLASS(CameraManager)
 DOMCI_CLASS(CameraControl)
 DOMCI_CLASS(CameraCapabilities)
 
 DOMCI_CLASS(OpenWindowEventDetail)
 DOMCI_CLASS(AsyncScrollEventDetail)
 
 DOMCI_CLASS(LockedFile)
 
+DOMCI_CLASS(CSSFontFeatureValuesRule)
+
 #ifdef MOZ_TIME_MANAGER
 DOMCI_CLASS(MozTimeManager)
 #endif
 
 #ifdef MOZ_WEBRTC
 #endif
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2125,17 +2125,17 @@ CreateNativeGlobalForInner(JSContext* aC
 
   nsRefPtr<nsIXPConnectJSObjectHolder> jsholder;
   nsresult rv = xpc->InitClassesWithNewWrappedGlobal(
     aCx, ToSupports(aNewInner),
     aPrincipal, flags, zoneSpec, getter_AddRefs(jsholder));
   NS_ENSURE_SUCCESS(rv, rv);
 
   MOZ_ASSERT(jsholder);
-  jsholder->GetJSObject(aNativeGlobal);
+  *aNativeGlobal = jsholder->GetJSObject();
   jsholder.forget(aHolder);
 
   // Set the location information for the new global, so that tools like
   // about:memory may use that information
   MOZ_ASSERT(*aNativeGlobal);
   xpc::SetLocationForGlobal(*aNativeGlobal, aURI);
 
   return NS_OK;
--- a/dom/bindings/CallbackObject.h
+++ b/dom/bindings/CallbackObject.h
@@ -338,18 +338,18 @@ public:
 
     nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = do_QueryInterface(callback);
     if (!wrappedJS) {
       return nullptr;
     }
 
     AutoSafeJSContext cx;
 
-    JS::Rooted<JSObject*> obj(cx);
-    if (NS_FAILED(wrappedJS->GetJSObject(obj.address())) || !obj) {
+    JS::Rooted<JSObject*> obj(cx, wrappedJS->GetJSObject());
+    if (!obj) {
       return nullptr;
     }
 
     JSAutoCompartment ac(cx, obj);
 
     nsRefPtr<WebIDLCallbackT> newCallback = new WebIDLCallbackT(obj);
     return newCallback.forget();
   }
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -8992,17 +8992,18 @@ def genConstructorBody(descriptor, initC
     }
     // Extract the JS implementation from the XPCOM object.
     nsCOMPtr<nsIXPConnectWrappedJS> implWrapped = do_QueryInterface(implISupports);
     MOZ_ASSERT(implWrapped, "Failed to get wrapped JS from XPCOM component.");
     if (!implWrapped) {
       aRv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
-    if (NS_FAILED(implWrapped->GetJSObject(jsImplObj.address()))) {
+    jsImplObj = implWrapped->GetJSObject();
+    if (!jsImplObj) {
       aRv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
   }
   // Build the C++ implementation.
   nsRefPtr<${implClass}> impl = new ${implClass}(jsImplObj, window);${initCall}
   return impl.forget();""").substitute({"implClass" : descriptor.name,
                  "contractId" : descriptor.interface.getJSImplementation(),
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -213,19 +213,18 @@ IDBFactory::Create(ContentParent* aConte
 
   nsIXPConnect* xpc = nsContentUtils::XPConnect();
   NS_ASSERTION(xpc, "This should never be null!");
 
   nsCOMPtr<nsIXPConnectJSObjectHolder> globalHolder;
   nsresult rv = xpc->CreateSandbox(cx, principal, getter_AddRefs(globalHolder));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  JS::Rooted<JSObject*> global(cx);
-  rv = globalHolder->GetJSObject(global.address());
-  NS_ENSURE_SUCCESS(rv, rv);
+  JS::Rooted<JSObject*> global(cx, globalHolder->GetJSObject());
+  NS_ENSURE_STATE(global);
 
   // The CreateSandbox call returns a proxy to the actual sandbox object. We
   // don't need a proxy here.
   global = js::UncheckedUnwrap(global);
 
   JSAutoCompartment ac(cx, global);
 
   nsRefPtr<IDBFactory> factory;
--- a/dom/indexedDB/IDBKeyRange.cpp
+++ b/dom/indexedDB/IDBKeyRange.cpp
@@ -47,18 +47,18 @@ ReturnKeyRange(JSContext* aCx,
   nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
   if (NS_FAILED(xpc->WrapNative(aCx, global, aKeyRange,
                                 NS_GET_IID(nsIIDBKeyRange),
                                 getter_AddRefs(holder)))) {
     JS_ReportError(aCx, "Couldn't wrap IDBKeyRange object.");
     return false;
   }
 
-  JS::Rooted<JSObject*> result(aCx);
-  if (NS_FAILED(holder->GetJSObject(result.address()))) {
+  JS::Rooted<JSObject*> result(aCx, holder->GetJSObject());
+  if (!result) {
     JS_ReportError(aCx, "Couldn't get JSObject from wrapper.");
     return false;
   }
 
   JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(result));
   return true;
 }
 
--- a/dom/interfaces/base/domstubs.idl
+++ b/dom/interfaces/base/domstubs.idl
@@ -64,16 +64,17 @@ interface nsIDOMHTMLCollection;
 interface nsIDOMHTMLHeadElement;
 
 // CSS
 interface nsIDOMCSSValue;
 interface nsIDOMCSSPrimitiveValue;
 interface nsIDOMCSSRule;
 interface nsIDOMCSSRuleList;
 interface nsIDOMMozCSSKeyframeRule;
+interface nsIDOMCSSFontFeatureValuesRule;
 interface nsIDOMCSSStyleSheet;
 interface nsIDOMCSSStyleDeclaration;
 interface nsIDOMCounter;
 interface nsIDOMRect;
 interface nsIDOMCSSStyleRule;
 interface nsIDOMCSSStyleRuleCollection;
 interface nsIDOMHTMLTableCaptionElement;
 interface nsIDOMHTMLTableSectionElement;
--- a/dom/interfaces/css/moz.build
+++ b/dom/interfaces/css/moz.build
@@ -3,16 +3,17 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIDOMCSSCharsetRule.idl',
     'nsIDOMCSSConditionRule.idl',
     'nsIDOMCSSFontFaceRule.idl',
+    'nsIDOMCSSFontFeatureValuesRule.idl',
     'nsIDOMCSSGroupingRule.idl',
     'nsIDOMCSSImportRule.idl',
     'nsIDOMCSSMediaRule.idl',
     'nsIDOMCSSMozDocumentRule.idl',
     'nsIDOMCSSPageRule.idl',
     'nsIDOMCSSPrimitiveValue.idl',
     'nsIDOMCSSRule.idl',
     'nsIDOMCSSRuleList.idl',
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/css/nsIDOMCSSFontFeatureValuesRule.idl
@@ -0,0 +1,48 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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.org code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   John Daggett <jdaggett@mozilla.com> (original author)
+ *
+ * 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 ***** */
+
+#include "nsIDOMCSSRule.idl"
+
+[scriptable, uuid(f4cb1776-389d-4f52-a4d8-68bea5bd00c1)]
+interface nsIDOMCSSFontFeatureValuesRule : nsIDOMCSSRule
+{
+  attribute DOMString fontFamily;
+                      // raises(DOMException) on setting
+
+  attribute DOMString valueText;
+                      // raises(DOMException) on setting
+};
--- a/dom/interfaces/css/nsIDOMCSSRule.idl
+++ b/dom/interfaces/css/nsIDOMCSSRule.idl
@@ -27,16 +27,17 @@ interface nsIDOMCSSRule : nsISupports
   const unsigned short      KEYFRAMES_RULE                 = 7;
   const unsigned short      KEYFRAME_RULE                  = 8;
   // When layout.css.prefixes.animations is disabled/removed,
   // we should remove these two MOZ_* constants.
   const unsigned short      MOZ_KEYFRAMES_RULE             = 7;
   const unsigned short      MOZ_KEYFRAME_RULE              = 8;
   const unsigned short      NAMESPACE_RULE                 = 10;
   const unsigned short      SUPPORTS_RULE                  = 12;
+  const unsigned short      FONT_FEATURE_VALUES_RULE       = 14;
 
   readonly attribute unsigned short      type;
            attribute DOMString           cssText;
                                         // raises(DOMException) on setting
 
   readonly attribute nsIDOMCSSStyleSheet parentStyleSheet;
   readonly attribute nsIDOMCSSRule       parentRule;
 };
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1021,17 +1021,17 @@ ContentChild::RecvNotifyVisited(const UR
 bool
 ContentChild::RecvAsyncMessage(const nsString& aMsg,
                                      const ClonedMessageData& aData)
 {
   nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::sChildProcessManager;
   if (cpm) {
     StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData);
     cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()),
-                        aMsg, false, &cloneData, nullptr, nullptr);
+                        aMsg, false, &cloneData, JS::NullPtr(), nullptr);
   }
   return true;
 }
 
 bool
 ContentChild::RecvGeolocationUpdate(const GeoPosition& somewhere)
 {
   nsCOMPtr<nsIGeolocationUpdate> gs = do_GetService("@mozilla.org/geolocation/service;1");
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -861,17 +861,17 @@ ContentParent::ActorDestroy(ActorDestroy
         mForceKillTask->Cancel();
         mForceKillTask = nullptr;
     }
 
     nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
     if (ppm) {
       ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
                           CHILD_PROCESS_SHUTDOWN_MESSAGE, false,
-                          nullptr, nullptr, nullptr);
+                          nullptr, JS::NullPtr(), nullptr);
     }
     nsCOMPtr<nsIThreadObserver>
         kungFuDeathGrip(static_cast<nsIThreadObserver*>(this));
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "xpcom-shutdown");
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "memory-pressure");
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-memory-reporter-request");
@@ -2326,30 +2326,30 @@ bool
 ContentParent::RecvSyncMessage(const nsString& aMsg,
                                const ClonedMessageData& aData,
                                InfallibleTArray<nsString>* aRetvals)
 {
   nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
   if (ppm) {
     StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
     ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
-                        aMsg, true, &cloneData, nullptr, aRetvals);
+                        aMsg, true, &cloneData, JS::NullPtr(), aRetvals);
   }
   return true;
 }
 
 bool
 ContentParent::RecvAsyncMessage(const nsString& aMsg,
                                       const ClonedMessageData& aData)
 {
   nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
   if (ppm) {
     StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
     ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
-                        aMsg, false, &cloneData, nullptr, nullptr);
+                        aMsg, false, &cloneData, JS::NullPtr(), nullptr);
   }
   return true;
 }
 
 bool
 ContentParent::RecvFilePathUpdateNotify(const nsString& aType,
                                         const nsString& aStorageName,
                                         const nsString& aFilePath,
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1431,17 +1431,17 @@ TabChild::DispatchMessageManagerMessage(
     }
 
     nsFrameScriptCx cx(static_cast<nsIWebBrowserChrome*>(this), this);
     // Let the BrowserElementScrolling helper (if it exists) for this
     // content manipulate the frame state.
     nsRefPtr<nsFrameMessageManager> mm =
       static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
     mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal),
-                       aMessageName, false, &cloneData, nullptr, nullptr);
+                       aMessageName, false, &cloneData, JS::NullPtr(), nullptr);
 }
 
 static void
 ScrollWindowTo(nsIDOMWindow* aWindow, const mozilla::gfx::Point& aPoint)
 {
     nsGlobalWindow* window = static_cast<nsGlobalWindow*>(aWindow);
     nsIScrollableFrame* sf = window->GetScrollFrame();
 
@@ -1969,17 +1969,17 @@ TabChild::RecvAsyncMessage(const nsStrin
                            const ClonedMessageData& aData)
 {
   if (mTabChildGlobal) {
     nsFrameScriptCx cx(static_cast<nsIWebBrowserChrome*>(this), this);
     StructuredCloneData cloneData = UnpackClonedMessageDataForChild(aData);
     nsRefPtr<nsFrameMessageManager> mm =
       static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
     mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal),
-                       aMessage, false, &cloneData, nullptr, nullptr);
+                       aMessage, false, &cloneData, JS::NullPtr(), nullptr);
   }
   return true;
 }
 
 class UnloadScriptEvent : public nsRunnable
 {
 public:
   UnloadScriptEvent(TabChild* aTabChild, TabChildGlobal* aTabChildGlobal)
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1097,17 +1097,17 @@ TabParent::ReceiveMessage(const nsString
   if (frameLoader && frameLoader->GetFrameMessageManager()) {
     nsRefPtr<nsFrameMessageManager> manager =
       frameLoader->GetFrameMessageManager();
     JSContext* ctx = manager->GetJSContext();
     JSAutoRequest ar(ctx);
     uint32_t len = 0; //TODO: obtain a real value in bug 572685
     // Because we want JS messages to have always the same properties,
     // create array even if len == 0.
-    JSObject* objectsArray = JS_NewArrayObject(ctx, len, NULL);
+    JS::Rooted<JSObject*> objectsArray(ctx, JS_NewArrayObject(ctx, len, NULL));
     if (!objectsArray) {
       return false;
     }
 
     manager->ReceiveMessage(mFrameElement,
                             aMessage,
                             aSync,
                             aCloneData,
--- a/dom/locales/en-US/chrome/layout/css.properties
+++ b/dom/locales/en-US/chrome/layout/css.properties
@@ -110,16 +110,27 @@ PEMQExpectedExpressionStart=Expected '('
 PEMQExpressionEOF=contents of media query expression
 PEMQExpectedFeatureName=Expected media feature name but found '%1$S'.
 PEMQExpectedFeatureNameEnd=Expected ':' or ')' after media feature name but found '%1$S'.
 PEMQNoMinMaxWithoutValue=Media features with min- or max- must have a value.
 PEMQExpectedFeatureValue=Found invalid value for media feature.
 PEBadFontBlockStart=Expected '{' to begin @font-face rule but found '%1$S'.
 PEBadFontBlockEnd=Expected '}' to end @font-face rule but found '%1$S'.
 PEAnonBoxNotAlone=Did not expect anonymous box.
+PEFFVUnexpectedEOF=Unexpected end of @font-feature-values rule.
+PEFFVBlockStart=Expected opening { of @font-feature-values rule but found '%1$S'.
+PEFFVValueSetStart=Expected opening { of feature value set but found '%1$S'.
+PEFFVNoFamily=Expected font family list for @font-feature-values rule but found '%1$S'.
+PEFFVUnexpectedBlockEnd=Expected '}' to end @font-feature-values rule but found '%1$S'.
+PEFFVUnknownFontVariantPropValue=Unknown font-variant property value '%1$S'.
+PEFFVExpectedIdent=Expected identifier but found '%1$S'.
+PEFFVExpectedValue=Expected non-negative integer value but found '%1$S'.
+PEFFVTooManyValues=Too many values for feature type '%1$S'.
+PEFFVGenericInFamilyList=Family list cannot contain generic font family name.
+PEFFVValueDefinitionTrailing=Expected end of value definition but found '%1$S'.
 PEBadDirValue=Expected 'ltr' or 'rtl' in direction selector but found '%1$S'.
 PESupportsConditionStartEOF2='not', '(', or function
 PESupportsConditionInParensEOF=')'
 PESupportsConditionNotEOF='not'
 PESupportsWhitespaceRequired=Expected whitespace after 'not', 'and', or 'or'.
 PESupportsConditionExpectedOpenParenOrFunction=Expected '(' or function while parsing supports condition but found '%1$S'.
 PESupportsConditionExpectedCloseParen=Expected ')' while parsing supports condition but found '%1$S'.
 PESupportsConditionExpectedStart2=Expected 'not', '(', or function while parsing supports condition but found '%1$S'.
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -1240,18 +1240,17 @@ NPObject* NP_CALLBACK
   NS_ENSURE_TRUE(xpc, nullptr);
 
   nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
   xpc->WrapNative(cx, ::JS_GetGlobalObject(cx), element,
                   NS_GET_IID(nsIDOMElement),
                   getter_AddRefs(holder));
   NS_ENSURE_TRUE(holder, nullptr);
 
-  JS::Rooted<JSObject*> obj(cx);
-  holder->GetJSObject(obj.address());
+  JS::Rooted<JSObject*> obj(cx, holder->GetJSObject());
   NS_ENSURE_TRUE(obj, nullptr);
 
   return nsJSObjWrapper::GetNewOrUsed(npp, cx, obj);
 }
 
 NPIdentifier NP_CALLBACK
 _getstringidentifier(const NPUTF8* name)
 {
--- a/dom/src/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/src/jsurl/nsJSProtocolHandler.cpp
@@ -285,19 +285,18 @@ nsresult nsJSThunk::EvaluateScript(nsICh
         nsCOMPtr<nsIXPConnectJSObjectHolder> sandbox;
         rv = xpc->CreateSandbox(cx, principal, getter_AddRefs(sandbox));
         NS_ENSURE_SUCCESS(rv, rv);
 
         // The nsXPConnect sandbox API gives us a wrapper to the sandbox for
         // our current compartment. Because our current context doesn't necessarily
         // subsume that of the sandbox, we want to unwrap and enter the sandbox's
         // compartment. It's a shame that the APIs here are so clunkly. :-(
-        JS::Rooted<JSObject*> sandboxObj(cx);
-        rv = sandbox->GetJSObject(sandboxObj.address());
-        NS_ENSURE_SUCCESS(rv, rv);
+        JS::Rooted<JSObject*> sandboxObj(cx, sandbox->GetJSObject());
+        NS_ENSURE_STATE(sandboxObj);
         sandboxObj = js::UncheckedUnwrap(sandboxObj);
         JSAutoCompartment ac(cx, sandboxObj);
 
         // Push our JSContext on the context stack so the JS_ValueToString call (and
         // JS_ReportPendingException, if relevant) will use the principal of cx.
         nsCxPusher pusher;
         pusher.Push(cx);
         rv = xpc->EvalInSandboxObject(NS_ConvertUTF8toUTF16(script),
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -21,540 +21,541 @@ https://bugzilla.mozilla.org/show_bug.cg
 /** Test for Bug 766694 **/
 
 // This is a list of all interfaces that are exposed to every webpage.  Please only
 // add things to this list with great care.
 
 // IMPORTANT: Do not change this list without review from a DOM peer!
 var interfaceNamesInGlobalScope =
   [
-    "MozApplicationEvent",
-    "HTMLByteRanges",
-    "URL",
-    "BatteryManager",
-    "HTMLStyleElement",
-    "PropertyNodeList",
-    "SVGPatternElement",
-    "LinkStyle",
-    "IDBTransaction",
-    "CSSMediaRule",
-    "SVGFEMergeNodeElement",
-    "HTMLUnknownElement",
-    "SVGStylable",
-    "MozContactChangeEvent",
-    "ToString",
-    "MozBrowserFrame",
-    "UserDataHandler",
-    "HTMLDirectoryElement",
-    "SVGNumberList",
-    "SVGMaskElement",
-    "DeviceMotionEvent",
-    "GetSVGDocument",
-    "SVGAnimatedPreserveAspectRatio",
-    "SVGViewElement",
-    "HTMLTableSectionElement",
-    "HTMLCollection",
-    "HTMLProgressElement",
-    "CRMFObject",
-    "CSSStyleSheet",
-    "UIEvent",
-    "IDBOpenDBRequest",
-    "XMLHttpRequest",
-    "SVGTextPathElement",
-    "StorageItem",
-    "SVGPolygonElement",
-    "MutationRecord",
-    "TimeEvent",
-    "HTMLElement",
-    "HTMLOptionElement",
-    "Pkcs11",
-    "NotifyAudioAvailableEvent",
-    "ElementReplaceEvent",
+    "AnimationEvent",
     "Array",
-    "SVGZoomAndPan",
-    "XULPopupElement",
-    "MediaError",
-    "DeviceStorageCursor",
-    "DeviceStorageChangeEvent",
-    "PageTransitionEvent",
-    "DataContainerEvent",
-    "MozCSSKeyframesRule",
-    "SVGAnimatedInteger",
-    "TouchEvent",
-    "OpenWindowEventDetail",
-    "IDBIndex",
-    "EventListener",
-    "TransitionEvent",
-    "XULContainerItemElement",
-    "HTMLTableCaptionElement",
-    "SVGRect",
-    "IDBCursor",
-    "History",
-    "HTMLTableRowElement",
-    "NodeFilter",
-    "ClientRectList",
-    "CanvasRenderingContext2D",
-    "SVGPathSegLinetoVerticalRel",
-    "MozAlarmsManager",
-    "MozPowerManager",
-    "SVGElement",
-    "GeoPositionError",
-    "XPathEvaluator",
-    "NodeIterator",
-    "MozNavigatorNetwork",
-    "CryptoDialogs",
-    "SVGLocatable",
-    "XULElement",
-    "CSSRuleList",
-    "SVGMarkerElement",
-    "Rect",
-    "SVGPathElement",
-    "SVGUseElement",
-    "SVGAnimatedPoints",
-    "DeviceAcceleration",
-    "DOMError",
-    "SVGAnimateMotionElement",
-    "HTMLMeterElement",
-    "SmartCardEvent",
-    "CSSValueList",
-    "ValidityState",
-    "HTMLAppletElement",
-    "Touch",
-    "Controllers",
-    "AnimationEvent",
-    "NavigatorDesktopNotification",
-    "LoadStatus",
-    "MediaQueryList",
-    "Contact",
-    "MediaQueryListListener",
-    "DesktopNotificationCenter",
-    "PluginArray",
-    "XULSelectControlElement",
-    "TimeRanges",
-    "ImageData",
-    "SVGPathSegArcAbs",
-    "MimeTypeArray",
-    "DocumentFragment",
-    "ParserJS",
-    "CanvasPattern",
-    "GeoPosition",
-    "XPathExpression",
+    "AsyncScrollEventDetail",
+    "Attr",
     "BarProp",
-    "NSEditableElement",
-    "SVGRectElement",
-    "DOMRequest",
-    "WindowPerformance",
-    "DOMSettableTokenList",
-    "SVGTransformList",
-    "SVGTransformable",
-    "XULControlElement",
-    "HTMLFrameSetElement",
-    "CSSCharsetRule",
-    "TouchList",
-    "DOMStringList",
-    "HTMLCommandElement",
-    "FileList",
-    "XULRelatedElement",
+    "BatteryManager",
+    "BeforeUnloadEvent",
     "Blob",
-    "Node",
-    "HTMLEmbedElement",
-    "ProgressEvent",
-    "SVGAnimateElement",
-    "MutationEvent",
-    "TreeSelection",
-    "DeviceLightEvent",
-    "SVGCircleElement",
-    "SVGFEComponentTransferElement",
-    "SVGPathSeg",
-    "SVGSVGElement",
-    "GlobalPropertyInitializer",
-    "HTMLMenuItemElement",
-    "HTMLDataListElement",
-    "XPathResult",
-    "XMLDocument",
-    "DocumentType",
-    "MozNamedAttrMap",
-    "DeviceProximityEvent",
-    "XULLabeledControlElement",
-    "MozWakeLock",
-    "MozConnection",
-    "WebGLRenderingContext",
-    "JSON",
+    "BlobEvent",
+    "BoxObject",
+    "CameraCapabilities",
+    "CameraControl",
+    "CameraManager",
+    "CanvasGradient",
+    "CanvasPattern",
+    "CanvasRenderingContext2D",
+    "CDATASection",
+    "CharacterData",
+    "ChromeWindow",
+    "ClientInformation",
     "ClientRect",
-    "GetUserMediaSuccessCallback",
+    "ClientRectList",
+    "ClipboardEvent",
+    "CloseEvent",
     "CommandEvent",
-    "HTMLDocument",
-    "DeviceOrientationEvent",
-    "HTMLPreElement",
-    "StorageEvent",
-    "CSS2Properties",
-    "StorageIndexedDB",
-    "XULDocument",
-    "XULMultiSelectControlElement",
-    "SVGTitleElement",
-    "PerformanceTiming",
-    "LSProgressEvent",
-    "NSEvent",
-    "HTMLBRElement",
-    "MouseScrollEvent",
-    "WheelEvent",
-    "HashChangeEvent",
-    "TreeWalker",
-    "HTMLTitleElement",
-    "LockedFile",
-    "GetUserMediaErrorCallback",
-    "SVGFEMorphologyElement",
-    "SVGFETurbulenceElement",
-    "XULTextBoxElement",
-    "SVGDocument",
-    "CSSStyleDeclaration",
-    "SVGAltGlyphElement",
-    "Screen",
-    "FileReader",
-    "SVGSwitchElement",
-    "SVGPolylineElement",
-    "SVGPathSegLinetoAbs",
-    "NavigatorDeviceStorage",
-    "HTMLOptionsCollection",
-    "IDBKeyRange",
-    "Parser",
-    "HTMLDivElement",
-    "HTMLLinkElement",
-    "ClientInformation",
-    "SVGMpathElement",
-    "HTMLTextAreaElement",
-    "SVGAnimatedEnumeration",
-    "Attr",
-    "StyleSheet",
-    "HTMLBodyElement",
-    "SVGPathSegCurvetoQuadraticSmoothRel",
-    "HTMLHeadingElement",
-    "Document",
-    "FileHandle",
-    "HTMLAnchorElement",
-    "SVGZoomEvent",
-    "UserProximityEvent",
-    "SVGAnimateTransformElement",
-    "CSSMozDocumentRule",
-    "HTMLQuoteElement",
-    "PopStateEvent",
-    "IDBVersionChangeEvent",
-    "HTMLCanvasElement",
-    "MouseEvent",
-    "OfflineResourceList",
-    "Range",
-    "MozCSSKeyframeRule",
-    "SettingsLock",
-    "Screen",
-    "ImageDocument",
-    "TextMetrics",
-    "SVGScriptElement",
-    "CDATASection",
-    "CanvasGradient",
-    "SVGViewSpec",
-    "DOMException",
-    "MozSmsMessage",
-    "MozMmsMessage",
-    "SVGFESpecularLightingElement",
-    "StorageObsolete",
+    "Comment",
+    "CompositionEvent",
+    "Contact",
     "ContactManager",
-    "NSXPathExpression",
-    "SVGLineElement",
-    "SVGPathSegArcRel",
-    "XSLTProcessor",
-    "SVGPathSegLinetoVerticalAbs",
-    "SVGPathSegLinetoRel",
-    "HTMLImageElement",
-    "MozSmsEvent",
-    "MozMmsEvent",
-    "CustomEvent",
-    "XMLHttpRequestUpload",
-    "SVGFEFuncBElement",
-    "Text",
-    "SVGPathSegCurvetoCubicRel",
-    "DataTransfer",
-    "SVGTSpanElement",
-    "SVGRadialGradientElement",
-    "SVGFEDisplacementMapElement",
-    "SVGPathSegCurvetoCubicSmoothAbs",
-    "CSSValue",
-    "DesktopNotification",
-    "KeyEvent",
-    "HTMLAreaElement",
-    "XULLabelElement",
-    "FormData",
-    "IDBDatabase",
-    "CSSPrimitiveValue",
-    "SVGStopElement",
-    "XULCommandEvent",
-    "HTMLMediaElement",
-    "SVGPathSegLinetoHorizontalAbs",
-    "SVGAnimatedRect",
-    "SVGTextContentElement",
-    "TreeColumn",
-    "XPathNamespace",
-    "FontFace",
-    "SVGPathSegCurvetoCubicSmoothRel",
-    "HTMLMapElement",
-    "SVGImageElement",
-    "HTMLMetaElement",
-    "NotifyPaintEvent",
-    "XULTreeElement",
-    "DragEvent",
-    "ClipboardEvent",
-    "IDBObjectStore",
-    "NodeSelector",
-    "NavigatorUserMedia",
-    "TreeContentView",
-    "MimeType",
-    "SVGForeignObjectElement",
-    "MozMobileNetworkInfo",
-    "SVGAnimatedString",
-    "HTMLPropertiesCollection",
-    "WindowInternal",
-    "Serializer",
-    "SVGFEFuncGElement",
-    "XULCheckboxElement",
-    "SVGFEPointLightElement",
-    "ModalContentWindow",
+    "Controllers",
+    "Counter",
+    "CRMFObject",
     "Crypto",
-    "StorageManager",
-    "SVGAngle",
-    "Navigator",
-    "SVGPathSegCurvetoQuadraticSmoothAbs",
-    "HTMLButtonElement",
-    "SVGPointList",
-    "SVGFEColorMatrixElement",
-    "USSDReceivedEvent",
-    "SettingsManager",
-    "DeviceRotationRate",
-    "HTMLAudioElement",
-    "SVGFEDistantLightElement",
-    "HTMLOListElement",
-    "ProcessingInstruction",
+    "CryptoDialogs",
+    "CSS2Properties",
+    "CSSCharsetRule",
+    "CSSConditionRule",
+    "CSSFontFaceRule",
+    "CSSFontFeatureValuesRule",
+    "CSSGroupingRule",
+    "CSSImportRule",
+    "CSSMediaRule",
+    "CSSMozDocumentRule",
+    "CSSPageRule",
+    "CSSPrimitiveValue",
+    "CSSRule",
+    "CSSRuleList",
+    "CSSStyleDeclaration",
+    "CSSStyleRule",
+    "CSSStyleSheet",
+    "CSSSupportsRule",
     "CSSUnknownRule",
-    "SVGComponentTransferFunctionElement",
-    "SVGEvent",
-    "SVGPathSegLinetoHorizontalRel",
-    "SVGAnimatedNumber",
-    "HTMLHtmlElement",
-    "MozSmsManager",
-    "MozMobileMessageManager",
-    "MozSmsFilter",
-    "SVGFETileElement",
-    "MozMobileConnectionInfo",
-    "CSSRule",
-    "HTMLSelectElement",
-    "MessageEvent",
-    "SVGFEImageElement",
-    "URL",
+    "CSSValue",
+    "CSSValueList",
+    "CustomEvent",
+    "DataChannel",
+    "DataContainerEvent",
+    "DataErrorEvent",
+    "DataTransfer",
+    "DesktopNotification",
+    "DesktopNotificationCenter",
+    "DeviceAcceleration",
+    "DeviceLightEvent",
+    "DeviceMotionEvent",
+    "DeviceOrientationEvent",
+    "DeviceProximityEvent",
+    "DeviceRotationRate",
     "DeviceStorage",
-    "SVGFEOffsetElement",
+    "DeviceStorageChangeEvent",
+    "DeviceStorageCursor",
+    "Document",
+    "DocumentFragment",
+    "DocumentTouch",
+    "DocumentType",
+    "DocumentXBL",
+    "DOMCursor",
+    "DOMError",
+    "DOMException",
     "DOMImplementation",
-    "SVGFECompositeElement",
-    "MediaList",
-    "HTMLFrameElement",
-    "NodeList",
-    "SVGPathSegCurvetoQuadraticRel",
-    "IDBFactory",
-    "SVGFilterPrimitiveStandardAttributes",
-    "CSSImportRule",
-    "SVGPathSegClosePath",
-    "HTMLTableCellElement",
-    "WindowUtils",
-    "SVGAnimatedNumberList",
-    "WindowCollection",
-    "SVGPathSegMovetoRel",
-    "ChromeWindow",
-    "Comment",
-    "HTMLSourceElement",
-    "SVGStringList",
-    "Storage",
-    "HTMLModElement",
-    "PaintRequest",
-    "XPathNSResolver",
-    "XULDescriptionElement",
-    "SVGLinearGradientElement",
-    "JSWindow",
-    "SVGGElement",
-    "BoxObject",
-    "SVGFEBlendElement",
+    "DOMRequest",
+    "DOMSettableTokenList",
+    "DOMStringList",
+    "DOMStringMap",
+    "DOMTokenList",
+    "DOMTransactionEvent",
+    "DragEvent",
+    "Element",
+    "ElementCSSInlineStyle",
+    "ElementReplaceEvent",
+    "ElementTimeControl",
     "Event",
-    "File",
-    "HTMLOptGroupElement",
-    "SVGAnimatedLengthList",
-    "SVGAnimatedTransformList",
-    "MozTouchEvent",
-    "MozWakeLockListener",
-    "Selection",
-    "XULTreeBuilder",
-    "ScrollAreaEvent",
-    "SVGStyleElement",
-    "XULContainerElement",
-    "DOMTokenList",
-    "HTMLHRElement",
-    "HTMLFontElement",
-    "SVGFEFloodElement",
-    "HTMLDListElement",
-    "SVGSymbolElement",
-    "SVGLengthList",
-    "TreeColumns",
-    "PaintRequestList",
-    "SVGTextElement",
-    "SimpleGestureEvent",
-    "SVGMatrix",
-    "HTMLUListElement",
-    "SVGFEConvolveMatrixElement",
-    "SVGAnimationElement",
-    "SVGMetadataElement",
+    "EventListener",
     "EventListenerInfo",
-    "CSSStyleRule",
-    "IDBRequest",
-    "Performance",
-    "XULMenuListElement",
-    "SVGTransform",
-    "SVGTextPositioningElement",
-    "SVGFEMergeElement",
-    "FileRequest",
-    "SVGDefsElement",
-    "Element",
-    "HTMLBaseElement",
-    "GeoPositionErrorCallback",
-    "HTMLVideoElement",
-    "MozSettingsEvent",
-    "SVGAnimatedPathData",
-    "SVGUnitTypes",
-    "SVGTests",
-    "RGBColor",
-    "HTMLLabelElement",
     "EventSource",
-    "MozNavigatorSms",
-    "MozNavigatorMobileMessage",
-    "SVGSetElement",
-    "GlobalObjectConstructor",
-    "SVGAnimatedBoolean",
-    "HTMLTableElement",
-    "Window",
-    "SVGNumber",
-    "XULImageElement",
-    "Plugin",
-    "SVGAnimatedLength",
-    "FontFaceList",
     "EventTarget",
-    "SVGFEFuncRElement",
-    "SVGPathSegMovetoAbs",
-    "SVGPoint",
-    "GeoPositionCoords",
-    "HTMLIFrameElement",
-    "PerformanceNavigation",
-    "MediaStream",
-    "DOMStringMap",
-    "HTMLFieldSetElement",
-    "SVGFEDiffuseLightingElement",
-    "StyleSheetList",
-    "ElementCSSInlineStyle",
-    "HTMLInputElement",
-    "CharacterData",
-    "HTMLObjectElement",
-    "SVGURIReference",
-    "GeoGeolocation",
-    "HTMLParamElement",
-    "HTMLTableColElement",
-    "MozBlobBuilder",
-    "SVGFESpotLightElement",
-    "PopupBlockedEvent",
-    "XULButtonElement",
-    "CSSPageRule",
-    "Location",
-    "DocumentXBL",
-    "HTMLHeadElement",
-    "XULTemplateBuilder",
-    "GeoPositionCallback",
-    "XULCommandDispatcher",
-    "DocumentTouch",
-    "XULSelectControlItemElement",
-    "SVGPathSegCurvetoQuadraticAbs",
-    "MutationObserver",
-    "RequestService",
-    "Counter",
-    "SVGAnimatedAngle",
-    "SVGPathSegList",
-    "SVGFEFuncAElement",
-    "WebSocket",
-    "ElementTimeControl",
-    "HTMLLegendElement",
-    "SVGFEGaussianBlurElement",
-    "SVGEllipseElement",
-    "SVGDescElement",
-    "BeforeUnloadEvent",
-    "NSRGBAColor",
-    "MozBrowserFrame",
-    "SVGPreserveAspectRatio",
-    "HTMLMenuElement",
-    "CloseEvent",
-    "IDBCursorWithValue",
-    "CSSFontFaceRule",
-    "XMLHttpRequestEventTarget",
-    "CompositionEvent",
-    "HTMLOutputElement",
-    "HTMLFormElement",
-    "SVGLength",
-    "SVGFilterElement",
-    "HTMLScriptElement",
-    "SVGPathSegCurvetoCubicAbs",
-    "HTMLLIElement",
-    "SVGClipPathElement",
-    "NavigatorGeolocation",
-    "HTMLParagraphElement",
     "EventTarget",
     "File",
-    "SVGGradientElement",
-    "SVGFitToViewBox",
-    "SVGAElement",
-    "NavigatorCamera",
-    "CameraControl",
-    "CameraCapabilities",
-    "CameraManager",
-    "CSSSupportsRule",
+    "File",
+    "FileHandle",
+    "FileList",
+    "FileReader",
+    "FileRequest",
+    "FontFace",
+    "FontFaceList",
+    "FormData",
+    "Gamepad",
+    "GamepadAxisMoveEvent",
+    "GamepadButtonEvent",
+    "GamepadEvent",
+    "GeoGeolocation",
+    "GeoPosition",
+    "GeoPositionCallback",
+    "GeoPositionCoords",
+    "GeoPositionError",
+    "GeoPositionErrorCallback",
+    "GetSVGDocument",
+    "GetUserMediaErrorCallback",
+    "GetUserMediaSuccessCallback",
+    "GlobalObjectConstructor",
+    "GlobalPropertyInitializer",
+    "HashChangeEvent",
+    "History",
+    "HTMLAnchorElement",
+    "HTMLAppletElement",
+    "HTMLAreaElement",
+    "HTMLAudioElement",
+    "HTMLBaseElement",
+    "HTMLBodyElement",
+    "HTMLBRElement",
+    "HTMLButtonElement",
+    "HTMLByteRanges",
+    "HTMLCanvasElement",
+    "HTMLCollection",
+    "HTMLCommandElement",
+    "HTMLDataListElement",
+    "HTMLDirectoryElement",
+    "HTMLDivElement",
+    "HTMLDListElement",
+    "HTMLDocument",
+    "HTMLElement",
+    "HTMLEmbedElement",
+    "HTMLFieldSetElement",
+    "HTMLFontElement",
+    "HTMLFormElement",
+    "HTMLFrameElement",
+    "HTMLFrameSetElement",
+    "HTMLHeadElement",
+    "HTMLHeadingElement",
+    "HTMLHRElement",
+    "HTMLHtmlElement",
+    "HTMLIFrameElement",
+    "HTMLImageElement",
+    "HTMLInputElement",
+    "HTMLLabelElement",
+    "HTMLLegendElement",
+    "HTMLLIElement",
+    "HTMLLinkElement",
+    "HTMLMapElement",
+    "HTMLMediaElement",
+    "HTMLMenuElement",
+    "HTMLMenuItemElement",
+    "HTMLMetaElement",
+    "HTMLMeterElement",
+    "HTMLModElement",
+    "HTMLObjectElement",
+    "HTMLOListElement",
+    "HTMLOptGroupElement",
+    "HTMLOptionElement",
+    "HTMLOptionsCollection",
+    "HTMLOutputElement",
+    "HTMLParagraphElement",
+    "HTMLParamElement",
+    "HTMLPreElement",
+    "HTMLProgressElement",
+    "HTMLPropertiesCollection",
+    "HTMLQuoteElement",
+    "HTMLScriptElement",
+    "HTMLSelectElement",
+    "HTMLSourceElement",
+    "HTMLStyleElement",
+    "HTMLTableCaptionElement",
+    "HTMLTableCellElement",
+    "HTMLTableColElement",
+    "HTMLTableElement",
+    "HTMLTableRowElement",
+    "HTMLTableSectionElement",
+    "HTMLTextAreaElement",
+    "HTMLTitleElement",
+    "HTMLUListElement",
+    "HTMLUnknownElement",
+    "HTMLVideoElement",
+    "IDBCursor",
+    "IDBCursorWithValue",
+    "IDBDatabase",
+    "IDBFactory",
+    "IDBIndex",
+    "IDBKeyRange",
+    "IDBObjectStore",
+    "IDBOpenDBRequest",
+    "IDBRequest",
+    "IDBTransaction",
+    "IDBVersionChangeEvent",
+    "ImageData",
+    "ImageDocument",
+    "JSON",
+    "JSWindow",
+    "KeyEvent",
+    "LinkStyle",
+    "LoadStatus",
+    "LocalMediaStream",
+    "Location",
+    "LockedFile",
+    "LSProgressEvent",
+    "MediaError",
+    "MediaList",
+    "MediaQueryList",
+    "MediaQueryListListener",
+    "MediaStream",
+    "MessageEvent",
+    "MimeType",
+    "MimeTypeArray",
+    "ModalContentWindow",
+    "MouseEvent",
+    "MouseScrollEvent",
+    "MozAlarmsManager",
+    "MozApplicationEvent",
+    "MozBlobBuilder",
+    "MozBrowserFrame",
+    "MozBrowserFrame",
+    "MozCanvasPrintState",
+    "MozConnection",
+    "MozContactChangeEvent",
+    "MozCSSKeyframeRule",
+    "MozCSSKeyframesRule",
+    "MozMmsEvent",
+    "MozMmsMessage",
     "MozMobileCellInfo",
-    "UndoManager",
-    "DOMTransactionEvent",
-    "MozCanvasPrintState",
-    "TCPSocket",
-    "MozTimeManager",
+    "MozMobileConnectionInfo",
+    "MozMobileMessageManager",
+    "MozMobileMessageThread",
+    "MozMobileNetworkInfo",
+    "MozNamedAttrMap",
+    "MozNavigatorMobileMessage",
+    "MozNavigatorNetwork",
+    "MozNavigatorSms",
     "MozNavigatorTime",
-    "PermissionSettings",
-    "DataErrorEvent",
-    "DataChannel",
-    "MozNetworkStatsManager",
     "MozNetworkStats",
     "MozNetworkStatsData",
-    "RTCSessionDescription",
+    "MozNetworkStatsManager",
+    "MozPowerManager",
+    "MozSettingsEvent",
+    "MozSmsEvent",
+    "MozSmsFilter",
+    "MozSmsManager",
+    "MozSmsMessage",
+    "MozSmsSegmentInfo",
+    "MozTimeManager",
+    "MozTouchEvent",
+    "MozWakeLock",
+    "MozWakeLockListener",
+    "MutationEvent",
+    "MutationObserver",
+    "MutationRecord",
+    "Navigator",
+    "NavigatorCamera",
+    "NavigatorDesktopNotification",
+    "NavigatorDeviceStorage",
+    "NavigatorGeolocation",
+    "NavigatorUserMedia",
+    "Node",
+    "NodeFilter",
+    "NodeIterator",
+    "NodeList",
+    "NodeSelector",
+    "NotifyAudioAvailableEvent",
+    "NotifyPaintEvent",
+    "NSEditableElement",
+    "NSEvent",
+    "NSRGBAColor",
+    "NSXPathExpression",
+    "OfflineResourceList",
+    "OpenWindowEventDetail",
+    "PageTransitionEvent",
+    "PaintRequest",
+    "PaintRequestList",
+    "Parser",
+    "ParserJS",
+    "PaymentRequestInfo",
+    "Performance",
+    "PerformanceNavigation",
+    "PerformanceTiming",
+    "PermissionSettings",
+    "Pkcs11",
+    "Plugin",
+    "PluginArray",
+    "PopStateEvent",
+    "PopupBlockedEvent",
+    "ProcessingInstruction",
+    "ProgressEvent",
+    "PropertyNodeList",
+    "PushManager",
+    "Range",
+    "Rect",
+    "RequestService",
+    "RGBColor",
     "RTCIceCandidate",
     "RTCPeerConnection",
-    "LocalMediaStream",
-    "CSSConditionRule",
-    "CSSGroupingRule",
-    "AsyncScrollEventDetail",
-    "MozSmsSegmentInfo",
-    "DOMCursor",
-    "BlobEvent",
-    "Gamepad",
-    "GamepadEvent",
-    "GamepadButtonEvent",
-    "GamepadAxisMoveEvent",
+    "RTCSessionDescription",
+    "Screen",
+    "Screen",
+    "ScrollAreaEvent",
+    "Selection",
+    "Serializer",
+    "SettingsLock",
+    "SettingsManager",
+    "SimpleGestureEvent",
+    "SmartCardEvent",
+    "SpeechRecognitionError",
     "SpeechRecognitionEvent",
-    "SpeechRecognitionError",
     "SpeechSynthesisEvent",
-    "PushManager",
+    "Storage",
+    "StorageEvent",
+    "StorageIndexedDB",
+    "StorageItem",
+    "StorageManager",
+    "StorageObsolete",
     "StyleRuleChangeEvent",
-    "StyleSheetChangeEvent",
+    "StyleSheet",
     "StyleSheetApplicableStateChangeEvent",
-    "MozMobileMessageThread",
-    "PaymentRequestInfo",
+    "StyleSheetChangeEvent",
+    "StyleSheetList",
+    "SVGAElement",
+    "SVGAltGlyphElement",
+    "SVGAngle",
+    "SVGAnimatedAngle",
+    "SVGAnimatedBoolean",
+    "SVGAnimatedEnumeration",
+    "SVGAnimatedInteger",
+    "SVGAnimatedLength",
+    "SVGAnimatedLengthList",
+    "SVGAnimatedNumber",
+    "SVGAnimatedNumberList",
+    "SVGAnimatedPathData",
+    "SVGAnimatedPoints",
+    "SVGAnimatedPreserveAspectRatio",
+    "SVGAnimatedRect",
+    "SVGAnimatedString",
+    "SVGAnimatedTransformList",
+    "SVGAnimateElement",
+    "SVGAnimateMotionElement",
+    "SVGAnimateTransformElement",
+    "SVGAnimationElement",
+    "SVGCircleElement",
+    "SVGClipPathElement",
+    "SVGComponentTransferFunctionElement",
+    "SVGDefsElement",
+    "SVGDescElement",
+    "SVGDocument",
+    "SVGElement",
+    "SVGEllipseElement",
+    "SVGEvent",
+    "SVGFEBlendElement",
+    "SVGFEColorMatrixElement",
+    "SVGFEComponentTransferElement",
+    "SVGFECompositeElement",
+    "SVGFEConvolveMatrixElement",
+    "SVGFEDiffuseLightingElement",
+    "SVGFEDisplacementMapElement",
+    "SVGFEDistantLightElement",
+    "SVGFEFloodElement",
+    "SVGFEFuncAElement",
+    "SVGFEFuncBElement",
+    "SVGFEFuncGElement",
+    "SVGFEFuncRElement",
+    "SVGFEGaussianBlurElement",
+    "SVGFEImageElement",
+    "SVGFEMergeElement",
+    "SVGFEMergeNodeElement",
+    "SVGFEMorphologyElement",
+    "SVGFEOffsetElement",
+    "SVGFEPointLightElement",
+    "SVGFESpecularLightingElement",
+    "SVGFESpotLightElement",
+    "SVGFETileElement",
+    "SVGFETurbulenceElement",
+    "SVGFilterElement",
+    "SVGFilterPrimitiveStandardAttributes",
+    "SVGFitToViewBox",
+    "SVGForeignObjectElement",
+    "SVGGElement",
+    "SVGGradientElement",
+    "SVGImageElement",
+    "SVGLength",
+    "SVGLengthList",
+    "SVGLinearGradientElement",
+    "SVGLineElement",
+    "SVGLocatable",
+    "SVGMarkerElement",
+    "SVGMaskElement",
+    "SVGMatrix",
+    "SVGMetadataElement",
+    "SVGMpathElement",
+    "SVGNumber",
+    "SVGNumberList",
+    "SVGPathElement",
+    "SVGPathSeg",
+    "SVGPathSegArcAbs",
+    "SVGPathSegArcRel",
+    "SVGPathSegClosePath",
+    "SVGPathSegCurvetoCubicAbs",
+    "SVGPathSegCurvetoCubicRel",
+    "SVGPathSegCurvetoCubicSmoothAbs",
+    "SVGPathSegCurvetoCubicSmoothRel",
+    "SVGPathSegCurvetoQuadraticAbs",
+    "SVGPathSegCurvetoQuadraticRel",
+    "SVGPathSegCurvetoQuadraticSmoothAbs",
+    "SVGPathSegCurvetoQuadraticSmoothRel",
+    "SVGPathSegLinetoAbs",
+    "SVGPathSegLinetoHorizontalAbs",
+    "SVGPathSegLinetoHorizontalRel",
+    "SVGPathSegLinetoRel",
+    "SVGPathSegLinetoVerticalAbs",
+    "SVGPathSegLinetoVerticalRel",
+    "SVGPathSegList",
+    "SVGPathSegMovetoAbs",
+    "SVGPathSegMovetoRel",
+    "SVGPatternElement",
+    "SVGPoint",
+    "SVGPointList",
+    "SVGPolygonElement",
+    "SVGPolylineElement",
+    "SVGPreserveAspectRatio",
+    "SVGRadialGradientElement",
+    "SVGRect",
+    "SVGRectElement",
+    "SVGScriptElement",
+    "SVGSetElement",
+    "SVGStopElement",
+    "SVGStringList",
+    "SVGStylable",
+    "SVGStyleElement",
+    "SVGSVGElement",
+    "SVGSwitchElement",
+    "SVGSymbolElement",
+    "SVGTests",
+    "SVGTextContentElement",
+    "SVGTextElement",
+    "SVGTextPathElement",
+    "SVGTextPositioningElement",
+    "SVGTitleElement",
+    "SVGTransform",
+    "SVGTransformable",
+    "SVGTransformList",
+    "SVGTSpanElement",
+    "SVGUnitTypes",
+    "SVGURIReference",
+    "SVGUseElement",
+    "SVGViewElement",
+    "SVGViewSpec",
+    "SVGZoomAndPan",
+    "SVGZoomEvent",
+    "TCPSocket",
+    "Text",
+    "TextMetrics",
+    "TimeEvent",
+    "TimeRanges",
+    "ToString",
+    "Touch",
+    "TouchEvent",
+    "TouchList",
+    "TransitionEvent",
+    "TreeColumn",
+    "TreeColumns",
+    "TreeContentView",
+    "TreeSelection",
+    "TreeWalker",
+    "UIEvent",
+    "UndoManager",
+    "URL",
+    "URL",
+    "UserDataHandler",
+    "UserProximityEvent",
+    "USSDReceivedEvent",
+    "ValidityState",
+    "WebGLRenderingContext",
+    "WebSocket",
+    "WheelEvent",
+    "Window",
+    "WindowCollection",
+    "WindowInternal",
+    "WindowPerformance",
+    "WindowUtils",
+    "XMLDocument",
+    "XMLHttpRequest",
+    "XMLHttpRequestEventTarget",
+    "XMLHttpRequestUpload",
+    "XPathEvaluator",
+    "XPathExpression",
+    "XPathNamespace",
+    "XPathNSResolver",
+    "XPathResult",
+    "XSLTProcessor",
+    "XULButtonElement",
+    "XULCheckboxElement",
+    "XULCommandDispatcher",
+    "XULCommandEvent",
+    "XULContainerElement",
+    "XULContainerItemElement",
+    "XULControlElement",
+    "XULDescriptionElement",
+    "XULDocument",
+    "XULElement",
+    "XULImageElement",
+    "XULLabeledControlElement",
+    "XULLabelElement",
+    "XULMenuListElement",
+    "XULMultiSelectControlElement",
+    "XULPopupElement",
+    "XULRelatedElement",
+    "XULSelectControlElement",
+    "XULSelectControlItemElement",
+    "XULTemplateBuilder",
+    "XULTextBoxElement",
+    "XULTreeBuilder",
+    "XULTreeElement",
   ]
 // IMPORTANT: Do not change this list without review from a DOM peer!
 
 // If your interface is named nsIDOMSomeInterface and you don't mean to expose
 // it to every webpage, simply change its name to nsISomeInterface to fix this problem.
 
 for (var i in SpecialPowers.Components.interfaces) {
   var s = i.toString();
--- a/dom/webidl/SVGAnimatedRect.webidl
+++ b/dom/webidl/SVGAnimatedRect.webidl
@@ -6,13 +6,11 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGAnimatedRect {
-  [GetterThrows]
   readonly attribute SVGRect? baseVal;
-  [GetterThrows]
   readonly attribute SVGRect? animVal;
 };
--- a/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
+++ b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
@@ -52,18 +52,18 @@ nsresult CentralizedAdminPrefManagerInit
     // Create a sandbox.
     AutoSafeJSContext cx;
     JSAutoRequest ar(cx);
     nsCOMPtr<nsIXPConnectJSObjectHolder> sandbox;
     rv = xpc->CreateSandbox(cx, principal, getter_AddRefs(sandbox));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Unwrap, store and root the sandbox.
-    rv = sandbox->GetJSObject(&autoconfigSb);
-    NS_ENSURE_SUCCESS(rv, rv);
+    autoconfigSb = sandbox->GetJSObject();
+    NS_ENSURE_STATE(autoconfigSb);
     autoconfigSb = js::UncheckedUnwrap(autoconfigSb);
     JSAutoCompartment ac(cx, autoconfigSb);
     if (!JS_AddNamedObjectRoot(cx, &autoconfigSb, "AutoConfig Sandbox"))
         return NS_ERROR_FAILURE;
 
     return NS_OK;
 }
 
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -347,16 +347,17 @@ GLContext::InitWithPrefix(const char *pr
         // defined in GLContext.h for renderer IDs
         glRendererString = (const char *)fGetString(LOCAL_GL_RENDERER);
         if (!glRendererString)
             mInitialized = false;
 
         const char *rendererMatchStrings[RendererOther] = {
                 "Adreno 200",
                 "Adreno 205",
+                "Adreno (TM) 205",
                 "Adreno (TM) 320",
                 "PowerVR SGX 530",
                 "PowerVR SGX 540"
         };
 
         mRenderer = RendererOther;
         for (int i = 0; i < RendererOther; ++i) {
             if (DoesStringMatch(glRendererString, rendererMatchStrings[i])) {
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -292,17 +292,18 @@ public:
         VendorImagination,
         VendorNouveau,
         VendorOther
     };
 
     enum {
         RendererAdreno200,
         RendererAdreno205,
-        RendererAdreno320,
+        RendererAdrenoTM205,
+        RendererAdrenoTM320,
         RendererSGX530,
         RendererSGX540,
         RendererOther
     };
 
     int Vendor() const {
         return mVendor;
     }
--- a/gfx/layers/D3D9SurfaceImage.cpp
+++ b/gfx/layers/D3D9SurfaceImage.cpp
@@ -32,51 +32,53 @@ D3D9SurfaceImage::SetData(const Data& aD
                                          D3DDEVTYPE_HAL,
                                          desc.Format,
                                          D3DFMT_X8R8G8B8);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   // DXVA surfaces aren't created sharable, so we need to copy the surface
   // to a sharable texture to that it's accessible to the layer manager's
   // device.
+  const nsIntRect& region = aData.mRegion;
   RefPtr<IDirect3DTexture9> texture;
   HANDLE shareHandle = NULL;
-  hr = device->CreateTexture(desc.Width,
-                             desc.Height,
+  hr = device->CreateTexture(region.width,
+                             region.height,
                              1,
                              D3DUSAGE_RENDERTARGET,
                              D3DFMT_X8R8G8B8,
                              D3DPOOL_DEFAULT,
                              byRef(texture),
                              &shareHandle);
   NS_ENSURE_TRUE(SUCCEEDED(hr) && shareHandle, hr);
 
   // Copy the image onto the texture, preforming YUV -> RGB conversion if necessary.
   RefPtr<IDirect3DSurface9> textureSurface;
   hr = texture->GetSurfaceLevel(0, byRef(textureSurface));
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   // Stash the surface description for later use.
   textureSurface->GetDesc(&mDesc);
 
-  hr = device->StretchRect(surface, NULL, textureSurface, NULL, D3DTEXF_NONE);
+  RECT src = { region.x, region.y, region.x+region.width, region.y+region.height };
+  hr = device->StretchRect(surface, &src, textureSurface, NULL, D3DTEXF_NONE);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   // Flush the draw command now, so that by the time we come to draw this
   // image, we're less likely to need to wait for the draw operation to
   // complete.
   RefPtr<IDirect3DQuery9> query;
   hr = device->CreateQuery(D3DQUERYTYPE_EVENT, byRef(query));
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   hr = query->Issue(D3DISSUE_END);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   mTexture = texture;
   mShareHandle = shareHandle;
-  mSize = gfxIntSize(aData.mSize.width, aData.mSize.height);
+  mSize = gfxIntSize(region.width, region.height);
   mQuery = query;
 
   return S_OK;
 }
 
 void
 D3D9SurfaceImage::EnsureSynchronized()
 {
--- a/gfx/layers/D3D9SurfaceImage.h
+++ b/gfx/layers/D3D9SurfaceImage.h
@@ -17,20 +17,20 @@ namespace layers {
 // Image class that wraps a IDirect3DSurface9. This class copies the image
 // passed into SetData(), so that it can be accessed from other D3D devices.
 // This class also manages the synchronization of the copy, to ensure the
 // resource is ready to use.
 class D3D9SurfaceImage : public Image {
 public:
 
   struct Data {
-    Data(IDirect3DSurface9* aSurface, const nsIntSize& aSize)
-      : mSurface(aSurface), mSize(aSize) {}
+    Data(IDirect3DSurface9* aSurface, const nsIntRect& aRegion)
+      : mSurface(aSurface), mRegion(aRegion) {}
     RefPtr<IDirect3DSurface9> mSurface;
-    nsIntSize mSize;
+    nsIntRect mRegion;
   };
 
   D3D9SurfaceImage() : Image(NULL, D3D9_RGB32_TEXTURE), mSize(0, 0) {}
   virtual ~D3D9SurfaceImage() {}
 
   // Copies the surface into a sharable texture's surface, and initializes
   // the image.
   HRESULT SetData(const Data& aData);
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -308,17 +308,16 @@ SampleAnimations(Layer* aLayer, TimeStam
     case eCSSProperty_transform:
     {
       gfx3DMatrix matrix = interpolatedValue.get_ArrayOfTransformFunction()[0].get_TransformMatrix().value();
       if (ContainerLayer* c = aLayer->AsContainerLayer()) {
         matrix.ScalePost(c->GetInheritedXScale(),
                          c->GetInheritedYScale(),
                          1);
       }
-      NS_ASSERTION(!aLayer->GetIsFixedPosition(), "Can't animate transforms on fixed-position layers");
       layerComposite->SetShadowTransform(matrix);
       layerComposite->SetShadowTransformSetByAnimation(true);
       break;
     }
     default:
       NS_WARNING("Unhandled animated property");
     }
   }
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -834,16 +834,29 @@ GrallocTextureHostOGL::Unlock()
    * The job of this function is to ensure that we release any read lock placed on
    * our android::GraphicBuffer by any drawing code that sourced it via this TextureHost.
    *
    * Indeed, as soon as we draw with a texture that's tied to a android::GraphicBuffer,
    * the GL may place read locks on it. We must ensure that we release them early enough,
    * i.e. before the next time that we will try to acquire a write lock on the same buffer,
    * because read and write locks on gralloc buffers are mutually exclusive.
    */
+  if (mGL->Renderer() == GLContext::RendererAdrenoTM205) {
+    /* XXX This is working around a driver bug exhibited on at least the
+     * Geeksphone Peak, where retargeting to a different EGL image is very
+     * slow. See Bug 869696.
+     */
+    if (mGLTexture) {
+      mGL->MakeCurrent();
+      mGL->fDeleteTextures(1, &mGLTexture);
+      mGLTexture = 0;
+    }
+    return;
+  }
+
   mGL->MakeCurrent();
   mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
   mGL->fBindTexture(mTextureTarget, mGLTexture);
   mGL->fEGLImageTargetTexture2D(mTextureTarget, mGL->GetNullEGLImage());
 }
 
 gfx::SurfaceFormat
 GrallocTextureHostOGL::GetFormat() const
--- a/gfx/src/nsFont.cpp
+++ b/gfx/src/nsFont.cpp
@@ -6,67 +6,87 @@
 #include "nsFont.h"
 #include "nsString.h"
 #include "nsUnicharUtils.h"
 #include "nsCRT.h"
 #include "gfxFont.h"
 
 nsFont::nsFont(const char* aName, uint8_t aStyle, uint8_t aVariant,
                uint16_t aWeight, int16_t aStretch, uint8_t aDecoration,
-               nscoord aSize, float aSizeAdjust,
-               const nsString* aLanguageOverride)
+               nscoord aSize)
 {
   NS_ASSERTION(aName && IsASCII(nsDependentCString(aName)),
                "Must only pass ASCII names here");
   name.AssignASCII(aName);
   style = aStyle;
   systemFont = false;
   variant = aVariant;
   weight = aWeight;
   stretch = aStretch;
   decorations = aDecoration;
   size = aSize;
-  sizeAdjust = aSizeAdjust;
-  if (aLanguageOverride) {
-    languageOverride = *aLanguageOverride;
-  }
+  sizeAdjust = 0.0;
+  kerning = NS_FONT_KERNING_AUTO;
+  synthesis = NS_FONT_SYNTHESIS_WEIGHT | NS_FONT_SYNTHESIS_STYLE;
+
+  variantAlternates = 0;
+  variantCaps = NS_FONT_VARIANT_CAPS_NORMAL;
+  variantEastAsian = 0;
+  variantLigatures = 0;
+  variantNumeric = 0;
+  variantPosition = NS_FONT_VARIANT_POSITION_NORMAL;
 }
 
-nsFont::nsFont(const nsString& aName, uint8_t aStyle, uint8_t aVariant,
+nsFont::nsFont(const nsSubstring& aName, uint8_t aStyle, uint8_t aVariant,
                uint16_t aWeight, int16_t aStretch, uint8_t aDecoration,
-               nscoord aSize, float aSizeAdjust,
-               const nsString* aLanguageOverride)
+               nscoord aSize)
   : name(aName)
 {
   style = aStyle;
   systemFont = false;
   variant = aVariant;
   weight = aWeight;
   stretch = aStretch;
   decorations = aDecoration;
   size = aSize;
-  sizeAdjust = aSizeAdjust;
-  if (aLanguageOverride) {
-    languageOverride = *aLanguageOverride;
-  }
+  sizeAdjust = 0.0;
+  kerning = NS_FONT_KERNING_AUTO;
+  synthesis = NS_FONT_SYNTHESIS_WEIGHT | NS_FONT_SYNTHESIS_STYLE;
+
+  variantAlternates = 0;
+  variantCaps = NS_FONT_VARIANT_CAPS_NORMAL;
+  variantEastAsian = 0;
+  variantLigatures = 0;
+  variantNumeric = 0;
+  variantPosition = NS_FONT_VARIANT_POSITION_NORMAL;
 }
 
 nsFont::nsFont(const nsFont& aOther)
   : name(aOther.name)
 {
   style = aOther.style;
   systemFont = aOther.systemFont;
   variant = aOther.variant;
   weight = aOther.weight;
   stretch = aOther.stretch;
   decorations = aOther.decorations;
   size = aOther.size;
   sizeAdjust = aOther.sizeAdjust;
+  kerning = aOther.kerning;
+  synthesis = aOther.synthesis;
+  fontFeatureSettings = aOther.fontFeatureSettings;
   languageOverride = aOther.languageOverride;
-  fontFeatureSettings = aOther.fontFeatureSettings;
+  variantAlternates = aOther.variantAlternates;
+  variantCaps = aOther.variantCaps;
+  variantEastAsian = aOther.variantEastAsian;
+  variantLigatures = aOther.variantLigatures;
+  variantNumeric = aOther.variantNumeric;
+  variantPosition = aOther.variantPosition;
+  alternateValues = aOther.alternateValues;
+  featureValueLookup = aOther.featureValueLookup;
 }
 
 nsFont::nsFont()
 {
 }
 
 nsFont::~nsFont()
 {
@@ -76,18 +96,28 @@ bool nsFont::BaseEquals(const nsFont& aO
 {
   if ((style == aOther.style) &&
       (systemFont == aOther.systemFont) &&
       (weight == aOther.weight) &&
       (stretch == aOther.stretch) &&
       (size == aOther.size) &&
       (sizeAdjust == aOther.sizeAdjust) &&
       name.Equals(aOther.name, nsCaseInsensitiveStringComparator()) &&
+      (kerning == aOther.kerning) &&
+      (synthesis == aOther.synthesis) &&
+      (fontFeatureSettings == aOther.fontFeatureSettings) &&
       (languageOverride == aOther.languageOverride) &&
-      (fontFeatureSettings == aOther.fontFeatureSettings)) {
+      (variantAlternates == aOther.variantAlternates) &&
+      (variantCaps == aOther.variantCaps) &&
+      (variantEastAsian == aOther.variantEastAsian) &&
+      (variantLigatures == aOther.variantLigatures) &&
+      (variantNumeric == aOther.variantNumeric) &&
+      (variantPosition == aOther.variantPosition) &&
+      (alternateValues == aOther.alternateValues) &&
+      (featureValueLookup == aOther.featureValueLookup)) {
     return true;
   }
   return false;
 }
 
 bool nsFont::Equals(const nsFont& aOther) const
 {
   if (BaseEquals(aOther) &&
@@ -104,26 +134,37 @@ nsFont& nsFont::operator=(const nsFont& 
   style = aOther.style;
   systemFont = aOther.systemFont;
   variant = aOther.variant;
   weight = aOther.weight;
   stretch = aOther.stretch;
   decorations = aOther.decorations;
   size = aOther.size;
   sizeAdjust = aOther.sizeAdjust;
+  kerning = aOther.kerning;
+  synthesis = aOther.synthesis;
+  fontFeatureSettings = aOther.fontFeatureSettings;
   languageOverride = aOther.languageOverride;
-  fontFeatureSettings = aOther.fontFeatureSettings;
+  variantAlternates = aOther.variantAlternates;
+  variantCaps = aOther.variantCaps;
+  variantEastAsian = aOther.variantEastAsian;
+  variantLigatures = aOther.variantLigatures;
+  variantNumeric = aOther.variantNumeric;
+  variantPosition = aOther.variantPosition;
+  alternateValues = aOther.alternateValues;
+  featureValueLookup = aOther.featureValueLookup;
   return *this;
 }
 
 void
-nsFont::AddFontFeaturesToStyle(gfxFontStyle *aStyle) const
+nsFont::CopyAlternates(const nsFont& aOther)
 {
-  // simple copy for now, font-variant implementation will expand
-  aStyle->featureSettings.AppendElements(fontFeatureSettings);
+  variantAlternates = aOther.variantAlternates;
+  alternateValues = aOther.alternateValues;
+  featureValueLookup = aOther.featureValueLookup;
 }
 
 static bool IsGenericFontFamily(const nsString& aFamily)
 {
   uint8_t generic;
   nsFont::GetGenericID(aFamily, &generic);
   return generic != kGenericFont_NONE;
 }
@@ -179,16 +220,209 @@ bool nsFont::EnumerateFamilies(nsFontFam
       return false;
 
     ++p; // may advance past p_end
   }
 
   return true;
 }
 
+// mapping from bitflag to font feature tag/value pair
+//
+// these need to be kept in sync with the constants listed
+// in gfxFontConstants.h (e.g. NS_FONT_VARIANT_EAST_ASIAN_JIS78)
+
+// NS_FONT_VARIANT_EAST_ASIAN_xxx values
+const gfxFontFeature eastAsianDefaults[] = {
+  { TRUETYPE_TAG('j','p','7','8'), 1 },
+  { TRUETYPE_TAG('j','p','8','3'), 1 },
+  { TRUETYPE_TAG('j','p','9','0'), 1 },
+  { TRUETYPE_TAG('j','p','0','4'), 1 },
+  { TRUETYPE_TAG('s','m','p','l'), 1 },
+  { TRUETYPE_TAG('t','r','a','d'), 1 },
+  { TRUETYPE_TAG('f','w','i','d'), 1 },
+  { TRUETYPE_TAG('p','w','i','d'), 1 },
+  { TRUETYPE_TAG('r','u','b','y'), 1 }
+};
+
+PR_STATIC_ASSERT(NS_ARRAY_LENGTH(eastAsianDefaults) ==
+                 eFeatureEastAsian_numFeatures);
+
+// NS_FONT_VARIANT_LIGATURES_xxx values
+const gfxFontFeature ligDefaults[] = {
+  { TRUETYPE_TAG('l','i','g','a'), 1 },
+  { TRUETYPE_TAG('l','i','g','a'), 0 },
+  { TRUETYPE_TAG('d','l','i','g'), 1 },
+  { TRUETYPE_TAG('d','l','i','g'), 0 },
+  { TRUETYPE_TAG('h','l','i','g'), 1 },
+  { TRUETYPE_TAG('h','l','i','g'), 0 },
+  { TRUETYPE_TAG('c','a','l','t'), 1 },
+  { TRUETYPE_TAG('c','a','l','t'), 0 }
+};
+
+PR_STATIC_ASSERT(NS_ARRAY_LENGTH(ligDefaults) ==
+                 eFeatureLigatures_numFeatures);
+
+// NS_FONT_VARIANT_NUMERIC_xxx values
+const gfxFontFeature numericDefaults[] = {
+  { TRUETYPE_TAG('l','n','u','m'), 1 },
+  { TRUETYPE_TAG('o','n','u','m'), 1 },
+  { TRUETYPE_TAG('p','n','u','m'), 1 },
+  { TRUETYPE_TAG('t','n','u','m'), 1 },
+  { TRUETYPE_TAG('f','r','a','c'), 1 },
+  { TRUETYPE_TAG('a','f','r','c'), 1 },
+  { TRUETYPE_TAG('z','e','r','o'), 1 },
+  { TRUETYPE_TAG('o','r','d','n'), 1 }
+};
+
+PR_STATIC_ASSERT(NS_ARRAY_LENGTH(numericDefaults) ==
+                 eFeatureNumeric_numFeatures);
+
+static void
+AddFontFeaturesBitmask(uint32_t aValue, uint32_t aMin, uint32_t aMax,
+                      const gfxFontFeature aFeatureDefaults[],
+                      nsTArray<gfxFontFeature>& aFeaturesOut)
+
+{
+  uint32_t i, m;
+
+  for (i = 0, m = aMin; m <= aMax; i++, m <<= 1) {
+    if (m & aValue) {
+      const gfxFontFeature& feature = aFeatureDefaults[i];
+      aFeaturesOut.AppendElement(feature);
+    }
+  }
+}
+
+void nsFont::AddFontFeaturesToStyle(gfxFontStyle *aStyle) const
+{
+  // add in font-variant features
+  gfxFontFeature setting;
+
+  // -- kerning
+  setting.mTag = TRUETYPE_TAG('k','e','r','n');
+  switch (kerning) {
+    case NS_FONT_KERNING_NONE:
+      setting.mValue = 0;
+      aStyle->featureSettings.AppendElement(setting);
+      break;
+    case NS_FONT_KERNING_NORMAL:
+      setting.mValue = 1;
+      aStyle->featureSettings.AppendElement(setting);
+      break;
+    default:
+      // auto case implies use user agent default
+      break;
+  }
+
+  // -- alternates
+  if (variantAlternates & NS_FONT_VARIANT_ALTERNATES_HISTORICAL) {
+    setting.mValue = 1;
+    setting.mTag = TRUETYPE_TAG('h','i','s','t');
+    aStyle->featureSettings.AppendElement(setting);
+  }
+
+
+  // -- copy font-specific alternate info into style
+  //    (this will be resolved after font-matching occurs)
+  aStyle->alternateValues.AppendElements(alternateValues);
+  aStyle->featureValueLookup = featureValueLookup;
+
+  // -- caps
+  setting.mValue = 1;
+  switch (variantCaps) {
+    case NS_FONT_VARIANT_CAPS_ALLSMALL:
+      setting.mTag = TRUETYPE_TAG('c','2','s','c');
+      aStyle->featureSettings.AppendElement(setting);
+      // fall through to the small-caps case
+    case NS_FONT_VARIANT_CAPS_SMALLCAPS:
+      setting.mTag = TRUETYPE_TAG('s','m','c','p');
+      aStyle->featureSettings.AppendElement(setting);
+      break;
+
+    case NS_FONT_VARIANT_CAPS_ALLPETITE:
+      setting.mTag = TRUETYPE_TAG('c','2','p','c');
+      aStyle->featureSettings.AppendElement(setting);
+      // fall through to the petite-caps case
+    case NS_FONT_VARIANT_CAPS_PETITECAPS:
+      setting.mTag = TRUETYPE_TAG('p','c','a','p');
+      aStyle->featureSettings.AppendElement(setting);
+      break;
+
+    case NS_FONT_VARIANT_CAPS_TITLING:
+      setting.mTag = TRUETYPE_TAG('t','i','t','l');
+      aStyle->featureSettings.AppendElement(setting);
+      break;
+
+    case NS_FONT_VARIANT_CAPS_UNICASE:
+      setting.mTag = TRUETYPE_TAG('u','n','i','c');
+      aStyle->featureSettings.AppendElement(setting);
+      break;
+
+    default:
+      break;
+  }
+
+  // -- east-asian
+  if (variantEastAsian) {
+    AddFontFeaturesBitmask(variantEastAsian,
+                           NS_FONT_VARIANT_EAST_ASIAN_JIS78,
+                           NS_FONT_VARIANT_EAST_ASIAN_RUBY,
+                           eastAsianDefaults, aStyle->featureSettings);
+  }
+
+  // -- ligatures
+  if (variantLigatures) {
+    AddFontFeaturesBitmask(variantLigatures,
+                           NS_FONT_VARIANT_LIGATURES_COMMON,
+                           NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL,
+                           ligDefaults, aStyle->featureSettings);
+
+    // special case common ligs, which also enable/disable clig
+    if (variantLigatures & NS_FONT_VARIANT_LIGATURES_COMMON) {
+      setting.mTag = TRUETYPE_TAG('c','l','i','g');
+      setting.mValue = 1;
+      aStyle->featureSettings.AppendElement(setting);
+    } else if (variantLigatures & NS_FONT_VARIANT_LIGATURES_NO_COMMON) {
+      setting.mTag = TRUETYPE_TAG('c','l','i','g');
+      setting.mValue = 0;
+      aStyle->featureSettings.AppendElement(setting);
+    }
+  }
+
+  // -- numeric
+  if (variantNumeric) {
+    AddFontFeaturesBitmask(variantNumeric,
+                           NS_FONT_VARIANT_NUMERIC_LINING,
+                           NS_FONT_VARIANT_NUMERIC_ORDINAL,
+                           numericDefaults, aStyle->featureSettings);
+  }
+
+  // -- position
+  setting.mTag = 0;
+  setting.mValue = 1;
+  switch (variantPosition) {
+    case NS_FONT_VARIANT_POSITION_SUPER:
+      setting.mTag = TRUETYPE_TAG('s','u','p','s');
+      aStyle->featureSettings.AppendElement(setting);
+      break;
+
+    case NS_FONT_VARIANT_POSITION_SUB:
+      setting.mTag = TRUETYPE_TAG('s','u','b','s');
+      aStyle->featureSettings.AppendElement(setting);
+      break;
+
+    default:
+      break;
+  }
+
+  // add in features from font-feature-settings
+  aStyle->featureSettings.AppendElements(fontFeatureSettings);
+}
+
 static bool FontEnumCallback(const nsString& aFamily, bool aGeneric, void *aData)
 {
   *((nsString*)aData) = aFamily;
   return false;
 }
 
 void nsFont::GetFirstFamily(nsString& aFamily) const
 {
--- a/gfx/src/nsFont.h
+++ b/gfx/src/nsFont.h
@@ -7,16 +7,17 @@
 #define nsFont_h___
 
 #include "gfxCore.h"
 #include "nsCoord.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
 #include "gfxFontConstants.h"
 #include "gfxFontFeatures.h"
+#include "nsAutoPtr.h"
 
 // XXX we need a method to enumerate all of the possible fonts on the
 // system across family, weight, style, size, etc. But not here!
 
 // Enumerator callback function. Return false to stop
 typedef bool (*nsFontFamilyEnumFunc)(const nsString& aFamily, bool aGeneric, void *aData);
 
 // IDs for generic fonts
@@ -45,16 +46,32 @@ struct NS_GFX nsFont {
 
   // Force this font to not be considered a 'generic' font, even if
   // the name is the same as a CSS generic font family.
   uint8_t systemFont;
 
   // The variant of the font (normal, small-caps)
   uint8_t variant;
 
+  // Variant subproperties
+  // (currently -moz- versions, will replace variant above eventually)
+  uint8_t variantCaps;
+  uint8_t variantLigatures;
+  uint8_t variantNumeric;
+  uint8_t variantPosition;
+
+  uint16_t variantEastAsian;
+
+  // Some font-variant-alternates property values require
+  // font-specific settings defined via @font-feature-values rules.
+  // These are resolved *after* font matching occurs.
+
+  // -- bitmask for both enumerated and functional propvals
+  uint16_t variantAlternates;
+
   // The decorations on the font (underline, overline,
   // line-through). The decorations can be binary or'd together.
   uint8_t decorations;
 
   // The weight of the font; see gfxFontConstants.h.
   uint16_t weight;
 
   // The stretch of the font (the sum of various NS_FONT_STRETCH_*
@@ -65,35 +82,45 @@ struct NS_GFX nsFont {
   nscoord size;
 
   // The aspect-value (ie., the ratio actualsize:actualxheight) that any
   // actual physical font created from this font structure must have when
   // rendering or measuring a string. A value of 0 means no adjustment
   // needs to be done.
   float sizeAdjust;
 
+  // -- list of value tags for font-specific alternate features
+  nsTArray<gfxAlternateValue> alternateValues;
+
+  // -- object used to look these up once the font is matched
+  nsRefPtr<gfxFontFeatureValueSet> featureValueLookup;
+
   // Font features from CSS font-feature-settings
   nsTArray<gfxFontFeature> fontFeatureSettings;
 
   // Language system tag, to override document language;
   // this is an OpenType "language system" tag represented as a 32-bit integer
   // (see http://www.microsoft.com/typography/otspec/languagetags.htm).
   nsString languageOverride;
 
+  // Kerning
+  uint8_t kerning;
+
+  // Synthesis setting, controls use of fake bolding/italics
+  uint8_t synthesis;
+
   // Initialize the font struct with an ASCII name
   nsFont(const char* aName, uint8_t aStyle, uint8_t aVariant,
          uint16_t aWeight, int16_t aStretch, uint8_t aDecoration,
-         nscoord aSize, float aSizeAdjust=0.0f,
-         const nsString* aLanguageOverride = nullptr);
+         nscoord aSize);
 
   // Initialize the font struct with a (potentially) unicode name
-  nsFont(const nsString& aName, uint8_t aStyle, uint8_t aVariant,
+  nsFont(const nsSubstring& aName, uint8_t aStyle, uint8_t aVariant,
          uint16_t aWeight, int16_t aStretch, uint8_t aDecoration,
-         nscoord aSize, float aSizeAdjust=0.0f,
-         const nsString* aLanguageOverride = nullptr);
+         nscoord aSize);
 
   // Make a copy of the given font
   nsFont(const nsFont& aFont);
 
   nsFont();
   ~nsFont();
 
   bool operator==(const nsFont& aOther) const {
@@ -101,16 +128,18 @@ struct NS_GFX nsFont {
   }
 
   bool Equals(const nsFont& aOther) const ;
   // Compare ignoring differences in 'variant' and 'decoration'
   bool BaseEquals(const nsFont& aOther) const;
 
   nsFont& operator=(const nsFont& aOther);
 
+  void CopyAlternates(const nsFont& aOther);
+
   // Add featureSettings into style
   void AddFontFeaturesToStyle(gfxFontStyle *aStyle) const;
 
   // Utility method to interpret name string
   // enumerates all families specified by this font only
   // returns true if completed, false if stopped
   // enclosing quotes will be removed, and whitespace compressed (as needed)
   bool EnumerateFamilies(nsFontFamilyEnumFunc aFunc, void* aData) const;
--- a/gfx/tests/gfxFontSelectionTests.h
+++ b/gfx/tests/gfxFontSelectionTests.h
@@ -75,27 +75,25 @@ SetupTests()
     /* some common styles */
     gfxFontStyle style_western_normal_16 (FONT_STYLE_NORMAL,
                                           NS_FONT_STRETCH_NORMAL,
                                           400,
                                           16.0,
                                           NS_NewPermanentAtom(NS_LITERAL_STRING("en")),
                                           0.0,
                                           false, false, false,
-                                          NS_LITERAL_STRING(""),
                                           NS_LITERAL_STRING(""));
 
     gfxFontStyle style_western_bold_16 (FONT_STYLE_NORMAL,
                                         NS_FONT_STRETCH_NORMAL,
                                         700,
                                         16.0,
                                         NS_NewPermanentAtom(NS_LITERAL_STRING("en")),
                                         0.0,
                                         false, false, false,
-                                        NS_LITERAL_STRING(""),
                                         NS_LITERAL_STRING(""));
 
     /* Test 0 */
     t = AddTest ("sans-serif",
                  style_western_normal_16,
                  S_ASCII,
                  "ABCD");
 
--- a/gfx/tests/gfxTextRunPerfTest.cpp
+++ b/gfx/tests/gfxTextRunPerfTest.cpp
@@ -61,17 +61,16 @@ RunTest (TestEntry *test, gfxContext *ct
     if (!lastFamilies || strcmp(lastFamilies, test->mFamilies)) {
         gfxFontStyle style_western_normal_16 (FONT_STYLE_NORMAL,
                                               NS_FONT_STRETCH_NORMAL,
                                               400,
                                               16.0,
                                               NS_NewPermanentAtom(NS_LITERAL_STRING("en")),
                                               0.0,
                                               false, false, false,
-                                              NS_LITERAL_STRING(""),
                                               NS_LITERAL_STRING(""));
 
         fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(NS_ConvertUTF8toUTF16(test->mFamilies), &style_western_normal_16, nullptr);
     }
 
     nsAutoPtr<gfxTextRun> textRun;
     uint32_t i;
     bool isASCII = true;
--- a/gfx/tests/gfxWordCacheTest.cpp
+++ b/gfx/tests/gfxWordCacheTest.cpp
@@ -119,17 +119,16 @@ main (int argc, char **argv) {
    {
        gfxFontStyle style (FONT_STYLE_NORMAL,
                            NS_FONT_STRETCH_NORMAL,
                            139,
                            10.0,
                            NS_NewPermanentAtom(NS_LITERAL_STRING("en")),
                            0.0,
                            false, false, false,
-                           NS_LITERAL_STRING(""),
                            NS_LITERAL_STRING(""));
 
        nsRefPtr<gfxFontGroup> fontGroup =
            gfxPlatform::GetPlatform()->CreateFontGroup(NS_LITERAL_STRING("Geneva, MS Sans Serif, Helvetica,serif"), &style, nullptr);
 
        gfxTextRunFactory::Parameters params = {
            ctx, nullptr, nullptr, nullptr, 0, 60
        };
--- a/gfx/thebes/Makefile.in
+++ b/gfx/thebes/Makefile.in
@@ -29,16 +29,17 @@ CPPSRCS	= \
 	gfxASurface.cpp \
 	gfxAlphaRecovery.cpp \
 	gfxBlur.cpp \
 	gfxCachedTempSurface.cpp \
 	gfxContext.cpp \
 	gfxDrawable.cpp \
 	gfxImageSurface.cpp \
 	gfxFont.cpp \
+	gfxFontFeatures.cpp \
 	gfxFontMissingGlyphs.cpp \
 	gfxFontTest.cpp \
 	gfxFontUtils.cpp \
 	gfxMatrix.cpp \
 	gfxPath.cpp \
 	gfxPattern.cpp \
 	gfxPlatform.cpp \
 	gfxPlatformFontList.cpp \
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -17,16 +17,18 @@
 #include "nsCharSeparatedTokenizer.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 
 #include "gfxGDIFontList.h"
 
 #include "nsIWindowsRegKey.h"
 
+#include "harfbuzz/hb.h"
+
 using namespace mozilla;
 
 #define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
                                PR_LOG_DEBUG, args)
 #define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
                                    gfxPlatform::GetLog(eGfxLog_fontlist), \
                                    PR_LOG_DEBUG)
 
@@ -259,18 +261,18 @@ UsingArabicOrHebrewScriptSystemLocale()
     case LANG_HEBREW:
         return true;
     default:
         return false;
     }
 }
 
 nsresult
-gfxDWriteFontEntry::GetFontTable(uint32_t aTableTag,
-                                 FallibleTArray<uint8_t> &aBuffer)
+gfxDWriteFontEntry::CopyFontTable(uint32_t aTableTag,
+                                  FallibleTArray<uint8_t> &aBuffer)
 {
     gfxDWriteFontList *pFontList = gfxDWriteFontList::PlatformFontList();
 
     // Don't use GDI table loading for symbol fonts or for
     // italic fonts in Arabic-script system locales because of
     // potential cmap discrepancies, see bug 629386.
     // Ditto for Hebrew, bug 837498.
     if (mFont && pFontList->UseGDIFontTableAccess() &&
@@ -296,103 +298,123 @@ gfxDWriteFontEntry::GetFontTable(uint32_
                     return NS_OK;
                 }
                 return NS_ERROR_OUT_OF_MEMORY;
             }
         }
         return NS_ERROR_FAILURE;
     }
 
-    HRESULT hr;
-    nsresult rv;
     nsRefPtr<IDWriteFontFace> fontFace;
-
-    rv = CreateFontFace(getter_AddRefs(fontFace));
-
+    nsresult rv = CreateFontFace(getter_AddRefs(fontFace));
     if (NS_FAILED(rv)) {
         return rv;
     }
 
     uint8_t *tableData;
     uint32_t len;
     void *tableContext = NULL;
     BOOL exists;
-    hr = fontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTableTag),
-                                   (const void**)&tableData,
-                                   &len,
-                                   &tableContext,
-                                   &exists);
-
+    HRESULT hr =
+        fontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTableTag),
+                                  (const void**)&tableData, &len,
+                                  &tableContext, &exists);
     if (FAILED(hr) || !exists) {
         return NS_ERROR_FAILURE;
     }
-    if (!aBuffer.SetLength(len)) {
-        return NS_ERROR_OUT_OF_MEMORY;
+
+    if (aBuffer.SetLength(len)) {
+        memcpy(aBuffer.Elements(), tableData, len);
+        rv = NS_OK;
+    } else {
+        rv = NS_ERROR_OUT_OF_MEMORY;
     }
-    memcpy(aBuffer.Elements(), tableData, len);
+
     if (tableContext) {
         fontFace->ReleaseFontTable(&tableContext);
     }
-    return NS_OK;
+
+    return rv;
+}
+
+// Access to font tables packaged in hb_blob_t form
+
+// object attached to the Harfbuzz blob, used to release
+// the table when the blob is destroyed
+class FontTableRec {
+public:
+    FontTableRec(IDWriteFontFace *aFontFace, void *aContext)
+        : mFontFace(aFontFace), mContext(aContext)
+    { }
+
+    ~FontTableRec() {
+        mFontFace->ReleaseFontTable(mContext);
+    }
+
+private:
+    IDWriteFontFace *mFontFace;
+    void            *mContext;
+};
+
+static void
+DestroyBlobFunc(void* aUserData)
+{
+    FontTableRec *ftr = static_cast<FontTableRec*>(aUserData);
+    delete ftr;
+}
+
+hb_blob_t *
+gfxDWriteFontEntry::GetFontTable(uint32_t aTag)
+{
+    // try to avoid potentially expensive DWrite call if we haven't actually
+    // created the font face yet, by using the gfxFontEntry method that will
+    // use CopyFontTable and then cache the data
+    if (!mFontFace) {
+        return gfxFontEntry::GetFontTable(aTag);
+    }
+
+    const void *data;
+    UINT32      size;
+    void       *context;
+    BOOL        exists;
+    HRESULT hr = mFontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTag),
+                                            &data, &size, &context, &exists);
+    if (SUCCEEDED(hr) && exists) {
+        FontTableRec *ftr = new FontTableRec(mFontFace, context);
+        return hb_blob_create(static_cast<const char*>(data), size,
+                              HB_MEMORY_MODE_READONLY,
+                              ftr, DestroyBlobFunc);
+    }
+
+    return nullptr;
 }
 
 nsresult
 gfxDWriteFontEntry::ReadCMAP()
 {
-    HRESULT hr;
     nsresult rv;
 
     // attempt this once, if errors occur leave a blank cmap
     if (mCharacterMap) {
         return NS_OK;
     }
 
     nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
 
-    // if loading via GDI, just use GetFontTable
-    if (mFont && gfxDWriteFontList::PlatformFontList()->UseGDIFontTableAccess()) {
-        uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
-    
-        AutoFallibleTArray<uint8_t,16384> cmap;
-        rv = GetFontTable(kCMAP, cmap);
-    
+    uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
+    AutoTable cmapTable(this, kCMAP);
+    if (cmapTable) {
         bool unicodeFont = false, symbolFont = false; // currently ignored
-    
-        if (NS_SUCCEEDED(rv)) {
-            rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
-                                        *charmap, mUVSOffset,
-                                        unicodeFont, symbolFont);
-        }
-    } else {
-        // loading using dwrite, don't use GetFontTable to avoid copy
-        nsRefPtr<IDWriteFontFace> fontFace;
-        rv = CreateFontFace(getter_AddRefs(fontFace));
-    
-        if (NS_SUCCEEDED(rv)) {
-            const uint32_t kCmapTag = DWRITE_MAKE_OPENTYPE_TAG('c', 'm', 'a', 'p');
-            uint8_t *tableData;
-            uint32_t len;
-            void *tableContext = NULL;
-            BOOL exists;
-            hr = fontFace->TryGetFontTable(kCmapTag, (const void**)&tableData,
-                                           &len, &tableContext, &exists);
-
-            if (SUCCEEDED(hr)) {
-                bool isSymbol = fontFace->IsSymbolFont();
-                bool isUnicode = true;
-                if (exists) {
-                    rv = gfxFontUtils::ReadCMAP(tableData, len, *charmap,
-                                                mUVSOffset, isUnicode, 
-                                                isSymbol);
-                }
-                fontFace->ReleaseFontTable(tableContext);
-            } else {
-                rv = NS_ERROR_FAILURE;
-            }
-        }
+        uint32_t cmapLen;
+        const uint8_t* cmapData =
+            reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable,
+                                                              &cmapLen));
+        rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen,
+                                    *charmap, mUVSOffset,
+                                    unicodeFont, symbolFont);
     }
 
     mHasCmapTable = NS_SUCCEEDED(rv);
     if (mHasCmapTable) {
         gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
         mCharacterMap = pfl->FindCharMap(charmap);
     } else {
         // if error occurred, initialize to null cmap
@@ -421,62 +443,70 @@ gfxDWriteFontEntry::CreateFontInstance(c
 {
     return new gfxDWriteFont(this, aFontStyle, aNeedsBold);
 }
 
 nsresult
 gfxDWriteFontEntry::CreateFontFace(IDWriteFontFace **aFontFace,
                                    DWRITE_FONT_SIMULATIONS aSimulations)
 {
-    HRESULT hr;
-    if (mFont) {
-        hr = mFont->CreateFontFace(aFontFace);
-        if (SUCCEEDED(hr) && (aSimulations & DWRITE_FONT_SIMULATIONS_BOLD) &&
-            !((*aFontFace)->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD)) {
-            // need to replace aFontFace with a version that has the Bold
-            // simulation - unfortunately, DWrite doesn't provide a simple API
-            // for this
-            nsRefPtr<IDWriteFontFace> origFace = (*aFontFace);
-            (*aFontFace)->Release();
-            *aFontFace = NULL;
-            UINT32 numberOfFiles = 0;
-            hr = origFace->GetFiles(&numberOfFiles, NULL);
-            if (FAILED(hr)) {
-                return NS_ERROR_FAILURE;
-            }
-            nsAutoTArray<IDWriteFontFile*,1> files;
-            files.AppendElements(numberOfFiles);
-            hr = origFace->GetFiles(&numberOfFiles, files.Elements());
-            if (FAILED(hr)) {
-                return NS_ERROR_FAILURE;
-            }
+    // initialize mFontFace if this hasn't been done before
+    if (!mFontFace) {
+        HRESULT hr;
+        if (mFont) {
+            hr = mFont->CreateFontFace(getter_AddRefs(mFontFace));
+        } else if (mFontFile) {
+            IDWriteFontFile *fontFile = mFontFile.get();
             hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
-                CreateFontFace(origFace->GetType(),
-                               numberOfFiles,
-                               files.Elements(),
-                               origFace->GetIndex(),
-                               aSimulations,
-                               aFontFace);
-            for (UINT32 i = 0; i < numberOfFiles; ++i) {
-                files[i]->Release();
-            }
+                CreateFontFace(mFaceType,
+                               1,
+                               &fontFile,
+                               0,
+                               DWRITE_FONT_SIMULATIONS_NONE,
+                               getter_AddRefs(mFontFace));
+        } else {
+            NS_NOTREACHED("invalid font entry");
+            return NS_ERROR_FAILURE;
+        }
+        if (FAILED(hr)) {
+            return NS_ERROR_FAILURE;
         }
-    } else if (mFontFile) {
-        IDWriteFontFile *fontFile = mFontFile.get();
-        hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
-            CreateFontFace(mFaceType,
-                           1,
-                           &fontFile,
-                           0,
+    }
+
+    // check whether we need to add a DWrite simulated style
+    if ((aSimulations & DWRITE_FONT_SIMULATIONS_BOLD) &&
+        !(mFontFace->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD)) {
+        // if so, we need to return not mFontFace itself but a version that
+        // has the Bold simulation - unfortunately, DWrite doesn't provide
+        // a simple API for this
+        UINT32 numberOfFiles = 0;
+        if (FAILED(mFontFace->GetFiles(&numberOfFiles, NULL))) {
+            return NS_ERROR_FAILURE;
+        }
+        nsAutoTArray<IDWriteFontFile*,1> files;
+        files.AppendElements(numberOfFiles);
+        if (FAILED(mFontFace->GetFiles(&numberOfFiles, files.Elements()))) {
+            return NS_ERROR_FAILURE;
+        }
+        HRESULT hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
+            CreateFontFace(mFontFace->GetType(),
+                           numberOfFiles,
+                           files.Elements(),
+                           mFontFace->GetIndex(),
                            aSimulations,
                            aFontFace);
+        for (UINT32 i = 0; i < numberOfFiles; ++i) {
+            files[i]->Release();
+        }
+        return FAILED(hr) ? NS_ERROR_FAILURE : NS_OK;
     }
-    if (FAILED(hr)) {
-        return NS_ERROR_FAILURE;
-    }
+
+    // no simulation: we can just add a reference to mFontFace and return that
+    *aFontFace = mFontFace;
+    (*aFontFace)->AddRef();
     return NS_OK;
 }
 
 bool
 gfxDWriteFontEntry::InitLogFont(IDWriteFont *aFont, LOGFONTW *aLogFont)
 {
     HRESULT hr;
 
@@ -493,17 +523,17 @@ gfxDWriteFontEntry::IsCJKFont()
     if (mIsCJK != UNINITIALIZED_VALUE) {
         return mIsCJK;
     }
 
     mIsCJK = false;
 
     const uint32_t kOS2Tag = TRUETYPE_TAG('O','S','/','2');
     AutoFallibleTArray<uint8_t,128> buffer;
-    if (GetFontTable(kOS2Tag, buffer) != NS_OK) {
+    if (CopyFontTable(kOS2Tag, buffer) != NS_OK) {
         return mIsCJK;
     }
 
     // ulCodePageRange bit definitions for the CJK codepages,
     // from http://www.microsoft.com/typography/otspec/os2.htm#cpr
     const uint32_t CJK_CODEPAGE_BITS =
         (1 << 17) | // codepage 932 - JIS/Japan
         (1 << 18) | // codepage 936 - Chinese (simplified)
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -138,18 +138,17 @@ public:
         mIsUserFont = true;
         mIsCJK = UNINITIALIZED_VALUE;
     }
 
     virtual ~gfxDWriteFontEntry();
 
     virtual bool IsSymbolFont();
 
-    virtual nsresult GetFontTable(uint32_t aTableTag,
-                                  FallibleTArray<uint8_t>& aBuffer);
+    virtual hb_blob_t* GetFontTable(uint32_t aTableTag) MOZ_OVERRIDE;
 
     nsresult ReadCMAP();
 
     bool IsCJKFont();
 
     void SetForceGDIClassic(bool aForce) { mForceGDIClassic = aForce; }
     bool GetForceGDIClassic() { return mForceGDIClassic; }
 
@@ -157,31 +156,39 @@ public:
                                      FontListSizes*    aSizes) const;
     virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontListSizes*    aSizes) const;
 
 protected:
     friend class gfxDWriteFont;
     friend class gfxDWriteFontList;
 
+    virtual nsresult CopyFontTable(uint32_t aTableTag,
+                                   FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
+
     virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle,
                                         bool aNeedsBold);
     
     nsresult CreateFontFace(
         IDWriteFontFace **aFontFace,
         DWRITE_FONT_SIMULATIONS aSimulations = DWRITE_FONT_SIMULATIONS_NONE);
 
     static bool InitLogFont(IDWriteFont *aFont, LOGFONTW *aLogFont);
 
     /**
      * A fontentry only needs to have either of these. If it has both only
      * the IDWriteFont will be used.
      */
     nsRefPtr<IDWriteFont> mFont;
     nsRefPtr<IDWriteFontFile> mFontFile;
+
+    // font face corresponding to the mFont/mFontFile *without* any DWrite
+    // style simulations applied
+    nsRefPtr<IDWriteFontFace> mFontFace;
+
     DWRITE_FONT_FACE_TYPE mFaceType;
 
     int8_t mIsCJK;
     bool mForceGDIClassic;
 };
 
 // custom text renderer used to determine the fallback font for a given char
 class FontFallbackRenderer MOZ_FINAL : public IDWriteTextRenderer
--- a/gfx/thebes/gfxDWriteFonts.cpp
+++ b/gfx/thebes/gfxDWriteFonts.cpp
@@ -14,16 +14,17 @@
 
 #include "gfxDWriteTextAnalysis.h"
 
 #include "harfbuzz/hb.h"
 
 // Chosen this as to resemble DWrite's own oblique face style.
 #define OBLIQUE_SKEW_FACTOR 0.3
 
+using namespace mozilla;
 using namespace mozilla::gfx;
 
 // This is also in gfxGDIFont.cpp. Would be nice to put it somewhere common,
 // but we can't declare it in the gfxFont.h or gfxFontUtils.h headers
 // because those are exported, and the cairo headers aren't.
 static inline cairo_antialias_t
 GetCairoAntialiasOption(gfxFont::AntialiasOption anAntialiasOption)
 {
@@ -224,62 +225,51 @@ gfxDWriteFont::ComputeMetrics(AntialiasO
     mMetrics->emHeight = mAdjustedSize;
     mMetrics->emAscent = mMetrics->emHeight *
         mMetrics->maxAscent / mMetrics->maxHeight;
     mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent;
 
     mMetrics->maxAdvance = mAdjustedSize;
 
     // try to get the true maxAdvance value from 'hhea'
-    uint8_t *tableData;
-    uint32_t len;
-    void *tableContext = NULL;
-    BOOL exists;
-    HRESULT hr =
-        mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('h', 'h', 'e', 'a'),
-                                   (const void**)&tableData,
-                                   &len,
-                                   &tableContext,
-                                   &exists);
-    if (SUCCEEDED(hr)) {
-        if (exists && len >= sizeof(mozilla::HheaTable)) {
-            const mozilla::HheaTable* hhea =
-                reinterpret_cast<const mozilla::HheaTable*>(tableData);
+    gfxFontEntry::AutoTable hheaTable(GetFontEntry(),
+                                      TRUETYPE_TAG('h','h','e','a'));
+    if (hheaTable) {
+        uint32_t len;
+        const HheaTable* hhea =
+            reinterpret_cast<const HheaTable*>(hb_blob_get_data(hheaTable, &len));
+        if (len >= sizeof(HheaTable)) {
             mMetrics->maxAdvance =
                 uint16_t(hhea->advanceWidthMax) * mFUnitsConvFactor;
         }
-        mFontFace->ReleaseFontTable(tableContext);
     }
 
     mMetrics->internalLeading = std::max(mMetrics->maxHeight - mMetrics->emHeight, 0.0);
     mMetrics->externalLeading = ceil(fontMetrics.lineGap * mFUnitsConvFactor);
 
     UINT16 glyph = (uint16_t)GetSpaceGlyph();
     mMetrics->spaceWidth = MeasureGlyphWidth(glyph);
 
     // try to get aveCharWidth from the OS/2 table, fall back to measuring 'x'
     // if the table is not available or if using hinted/pixel-snapped widths
     if (mUseSubpixelPositions) {
         mMetrics->aveCharWidth = 0;
-        hr = mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('O', 'S', '/', '2'),
-                                        (const void**)&tableData,
-                                        &len,
-                                        &tableContext,
-                                        &exists);
-        if (SUCCEEDED(hr)) {
-            if (exists && len >= 4) {
+        gfxFontEntry::AutoTable os2Table(GetFontEntry(),
+                                         TRUETYPE_TAG('O','S','/','2'));
+        if (os2Table) {
+            uint32_t len;
+            const OS2Table* os2 =
+                reinterpret_cast<const OS2Table*>(hb_blob_get_data(os2Table, &len));
+            if (len >= 4) {
                 // Not checking against sizeof(mozilla::OS2Table) here because older
                 // versions of the table have different sizes; we only need the first
                 // two 16-bit fields here.
-                const mozilla::OS2Table* os2 =
-                    reinterpret_cast<const mozilla::OS2Table*>(tableData);
                 mMetrics->aveCharWidth =
                     int16_t(os2->xAvgCharWidth) * mFUnitsConvFactor;
             }
-            mFontFace->ReleaseFontTable(tableContext);
         }
     }
 
     UINT32 ucs;
     if (mMetrics->aveCharWidth < 1) {
         ucs = L'x';
         if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph))) {
             mMetrics->aveCharWidth = MeasureGlyphWidth(glyph);
@@ -596,70 +586,16 @@ gfxDWriteFont::Measure(gfxTextRun *aText
         metrics.mBoundingBox.width > 0) {
         metrics.mBoundingBox.x -= aTextRun->GetAppUnitsPerDevUnit();
         metrics.mBoundingBox.width += aTextRun->GetAppUnitsPerDevUnit() * 3;
     }
 
     return metrics;
 }
 
-// Access to font tables packaged in hb_blob_t form
-
-// object attached to the Harfbuzz blob, used to release
-// the table when the blob is destroyed
-class FontTableRec {
-public:
-    FontTableRec(IDWriteFontFace *aFontFace, void *aContext)
-        : mFontFace(aFontFace), mContext(aContext)
-    { }
-
-    ~FontTableRec() {
-        mFontFace->ReleaseFontTable(mContext);
-    }
-
-private:
-    IDWriteFontFace *mFontFace;
-    void            *mContext;
-};
-
-/*static*/ void
-gfxDWriteFont::DestroyBlobFunc(void* aUserData)
-{
-    FontTableRec *ftr = static_cast<FontTableRec*>(aUserData);
-    delete ftr;
-}
-
-hb_blob_t *
-gfxDWriteFont::GetFontTable(uint32_t aTag)
-{
-    const void *data;
-    UINT32      size;
-    void       *context;
-    BOOL        exists;
-    HRESULT hr = mFontFace->TryGetFontTable(mozilla::NativeEndian::swapToBigEndian(aTag),
-                                            &data, &size, &context, &exists);
-    if (SUCCEEDED(hr) && exists) {
-        FontTableRec *ftr = new FontTableRec(mFontFace, context);
-        return hb_blob_create(static_cast<const char*>(data), size,
-                              HB_MEMORY_MODE_READONLY,
-                              ftr, DestroyBlobFunc);
-    }
-
-    if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
-        // for downloaded fonts, there may be layout tables cached in the entry
-        // even though they're absent from the sanitized platform font
-        hb_blob_t *blob;
-        if (mFontEntry->GetExistingFontTable(aTag, &blob)) {
-            return blob;
-        }
-    }
-
-    return nullptr;
-}
-
 bool
 gfxDWriteFont::ProvidesGlyphWidths()
 {
     return !mUseSubpixelPositions ||
            (mFontFace->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD);
 }
 
 int32_t
--- a/gfx/thebes/gfxDWriteFonts.h
+++ b/gfx/thebes/gfxDWriteFonts.h
@@ -47,20 +47,16 @@ public:
 
     /* override Measure to add padding for antialiasing */
     virtual RunMetrics Measure(gfxTextRun *aTextRun,
                                uint32_t aStart, uint32_t aEnd,
                                BoundingBoxType aBoundingBoxType,
                                gfxContext *aContextForTightBoundingBox,
                                Spacing *aSpacing);
 
-    // override gfxFont table access function to bypass gfxFontEntry cache,
-    // use DWrite API to get direct access to system font data
-    virtual hb_blob_t *GetFontTable(uint32_t aTag);
-
     virtual bool ProvidesGlyphWidths();
 
     virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID);
 
     virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions> GetGlyphRenderingOptions();
 
     virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontCacheSizes*   aSizes) const;
@@ -83,18 +79,16 @@ protected:
     void ComputeMetrics(AntialiasOption anAAOption);
 
     bool HasBitmapStrikeForSize(uint32_t aSize);
 
     cairo_font_face_t *CairoFontFace();
 
     gfxFloat MeasureGlyphWidth(uint16_t aGlyph);
 
-    static void DestroyBlobFunc(void* userArg);
-
     DWRITE_MEASURING_MODE GetMeasuringMode();
     bool GetForceGDIClassic();
 
     nsRefPtr<IDWriteFontFace> mFontFace;
     cairo_font_face_t *mCairoFontFace;
 
     gfxFont::Metrics          *mMetrics;
 
--- a/gfx/thebes/gfxFT2FontBase.cpp
+++ b/gfx/thebes/gfxFT2FontBase.cpp
@@ -141,32 +141,16 @@ uint32_t
 gfxFT2FontBase::GetSpaceGlyph()
 {
     NS_ASSERTION(GetStyle()->size != 0,
                  "forgot to short-circuit a text run with zero-sized font?");
     GetMetrics();
     return mSpaceGlyph;
 }
 
-hb_blob_t *
-gfxFT2FontBase::GetFontTable(uint32_t aTag)
-{
-    hb_blob_t *blob;
-    if (mFontEntry->GetExistingFontTable(aTag, &blob))
-        return blob;
-
-    FallibleTArray<uint8_t> buffer;
-    bool haveTable = gfxFT2LockedFace(this).GetFontTable(aTag, buffer);
-
-    // Cache even when there is no table to save having to open the FT_Face
-    // again.
-    return mFontEntry->ShareFontTableAndGetBlob(aTag,
-                                                haveTable ? &buffer : nullptr);
-}
-
 uint32_t
 gfxFT2FontBase::GetGlyph(uint32_t unicode, uint32_t variation_selector)
 {
     if (variation_selector) {
         uint32_t id =
             gfxFT2LockedFace(this).GetUVSGlyph(unicode, variation_selector);
         if (id)
             return id;
--- a/gfx/thebes/gfxFT2FontBase.h
+++ b/gfx/thebes/gfxFT2FontBase.h
@@ -18,17 +18,16 @@ public:
                    const gfxFontStyle *aFontStyle);
     virtual ~gfxFT2FontBase();
 
     uint32_t GetGlyph(uint32_t aCharCode);
     void GetGlyphExtents(uint32_t aGlyph,
                          cairo_text_extents_t* aExtents);
     virtual const gfxFont::Metrics& GetMetrics();
     virtual uint32_t GetSpaceGlyph();
-    virtual hb_blob_t *GetFontTable(uint32_t aTag);
     virtual bool ProvidesGetGlyph() const { return true; }
     virtual uint32_t GetGlyph(uint32_t unicode, uint32_t variation_selector);
     virtual bool ProvidesGlyphWidths() { return true; }
     virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID);
 
     cairo_scaled_font_t *CairoScaledFont() { return mScaledFont; };
     virtual bool SetupCairoFont(gfxContext *aContext);
 
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -411,17 +411,17 @@ FT2FontEntry::ReadCMAP()
 {
     if (mCharacterMap) {
         return NS_OK;
     }
 
     nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
 
     AutoFallibleTArray<uint8_t,16384> buffer;
-    nsresult rv = GetFontTable(TTAG_cmap, buffer);
+    nsresult rv = CopyFontTable(TTAG_cmap, buffer);
     
     if (NS_SUCCEEDED(rv)) {
         bool unicodeFont;
         bool symbolFont;
         rv = gfxFontUtils::ReadCMAP(buffer.Elements(), buffer.Length(),
                                     *charmap, mUVSOffset,
                                     unicodeFont, symbolFont);
     }
@@ -433,18 +433,18 @@ FT2FontEntry::ReadCMAP()
     } else {
         // if error occurred, initialize to null cmap
         mCharacterMap = new gfxCharacterMap();
     }
     return rv;
 }
 
 nsresult
-FT2FontEntry::GetFontTable(uint32_t aTableTag,
-                           FallibleTArray<uint8_t>& aBuffer)
+FT2FontEntry::CopyFontTable(uint32_t aTableTag,
+                            FallibleTArray<uint8_t>& aBuffer)
 {
     AutoFTFace face(this);
     if (!face) {
         return NS_ERROR_FAILURE;
     }
 
     FT_Error status;
     FT_ULong len = 0;
--- a/gfx/thebes/gfxFT2FontList.h
+++ b/gfx/thebes/gfxFT2FontList.h
@@ -61,17 +61,19 @@ public:
 
     virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle,
                                         bool aNeedsBold);
 
     cairo_font_face_t *CairoFontFace();
     cairo_scaled_font_t *CreateScaledFont(const gfxFontStyle *aStyle);
 
     nsresult ReadCMAP();
-    nsresult GetFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer);
+
+    virtual nsresult CopyFontTable(uint32_t aTableTag,
+                                   FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
 
     // Check for various kinds of brokenness, and set flags on the entry
     // accordingly so that we avoid using bad font tables
     void CheckForBrokenFont(gfxFontFamily *aFamily);
 
     virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontListSizes*    aSizes) const;
     virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
--- a/gfx/thebes/gfxFT2Utils.cpp
+++ b/gfx/thebes/gfxFT2Utils.cpp
@@ -313,41 +313,16 @@ gfxFT2LockedFace::GetUVSGlyph(uint32_t a
     if (!mFace->charmap || mFace->charmap->encoding != FT_ENCODING_UNICODE) {
         FT_Select_Charmap(mFace, FT_ENCODING_UNICODE);
     }
 #endif
 
     return (*sGetCharVariantPtr)(mFace, aCharCode, aVariantSelector);
 }
 
-bool
-gfxFT2LockedFace::GetFontTable(uint32_t aTag, FallibleTArray<uint8_t>& aBuffer)
-{
-    if (!mFace || !FT_IS_SFNT(mFace))
-        return false;
-
-    FT_ULong length = 0;
-    // TRUETYPE_TAG is defined equivalent to FT_MAKE_TAG
-    FT_Error error = FT_Load_Sfnt_Table(mFace, aTag, 0, NULL, &length);
-    if (error != 0)
-        return false;
-
-    if (MOZ_UNLIKELY(length > static_cast<FallibleTArray<uint8_t>::size_type>(-1))
-        || MOZ_UNLIKELY(!aBuffer.SetLength(length)))
-        return false;
-        
-    error = FT_Load_Sfnt_Table(mFace, aTag, 0, aBuffer.Elements(), &length);
-    if (MOZ_UNLIKELY(error != 0)) {
-        aBuffer.Clear();
-        return false;
-    }
-
-    return true;
-}
-
 uint32_t
 gfxFT2LockedFace::GetCharExtents(char aChar, cairo_text_extents_t* aExtents)
 {
     NS_PRECONDITION(aExtents != NULL, "aExtents must not be NULL");
 
     if (!mFace)
         return 0;
 
--- a/gfx/thebes/gfxFT2Utils.h
+++ b/gfx/thebes/gfxFT2Utils.h
@@ -43,18 +43,16 @@ public:
     uint32_t GetGlyph(uint32_t aCharCode);
     /**
      * Returns 0 if there is no variation selector cmap subtable.
      */
     uint32_t GetUVSGlyph(uint32_t aCharCode, uint32_t aVariantSelector);
 
     void GetMetrics(gfxFont::Metrics* aMetrics, uint32_t* aSpaceGlyph);
 
-    bool GetFontTable(uint32_t aTag, FallibleTArray<uint8_t>& aBuffer);
-
     // A scale factor for use in converting horizontal metrics from font units
     // to pixels.
     gfxFloat XScale()
     {
         if (MOZ_UNLIKELY(!mFace))
             return 0.0;
 
         const FT_Size_Metrics& ftMetrics = mFace->size->metrics;
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -40,16 +40,17 @@
 #include "mozilla/Telemetry.h"
 #include "gfxSVGGlyphs.h"
 
 #include "cairo.h"
 #include "gfxFontTest.h"
 
 #include "harfbuzz/hb.h"
 #include "harfbuzz/hb-ot.h"
+#include "graphite2/Font.h"
 
 #include "nsCRT.h"
 #include "GeckoProfiler.h"
 
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
@@ -90,16 +91,22 @@ gfxCharacterMap::NotifyReleased()
 gfxFontEntry::~gfxFontEntry()
 {
     // For downloaded fonts, we need to tell the user font cache that this
     // entry is being deleted.
     if (!mIsProxy && IsUserFont() && !IsLocalUserFont()) {
         gfxUserFontSet::UserFontCache::ForgetFont(this);
     }
 
+    // By the time the entry is destroyed, all font instances that were
+    // using it should already have been deleted, and so the HB and/or Gr
+    // face objects should have been released.
+    MOZ_ASSERT(!mHBFace);
+    MOZ_ASSERT(!mGrFaceInitialized);
+
     if (mSVGGlyphs) {
         delete mSVGGlyphs;
     }
     delete mUserFontData;
 }
 
 bool gfxFontEntry::IsSymbolFont() 
 {
@@ -125,27 +132,29 @@ nsresult gfxFontEntry::InitializeUVSMap(
     }
 
     if (!mUVSOffset) {
         return NS_ERROR_FAILURE;
     }
 
     if (!mUVSData) {
         const uint32_t kCmapTag = TRUETYPE_TAG('c','m','a','p');
-        AutoFallibleTArray<uint8_t,16384> buffer;
-        if (GetFontTable(kCmapTag, buffer) != NS_OK) {
+        AutoTable cmapTable(this, kCmapTag);
+        if (!cmapTable) {
             mUVSOffset = 0; // don't bother to read the table again
             return NS_ERROR_FAILURE;
         }
 
         uint8_t* uvsData;
+        unsigned int cmapLen;
+        const char* cmapData = hb_blob_get_data(cmapTable, &cmapLen);
         nsresult rv = gfxFontUtils::ReadCMAPTableFormat14(
-                          buffer.Elements() + mUVSOffset,
-                          buffer.Length() - mUVSOffset,
-                          uvsData);
+                          (const uint8_t*)cmapData + mUVSOffset,
+                          cmapLen - mUVSOffset, uvsData);
+
         if (NS_FAILED(rv)) {
             mUVSOffset = 0; // don't bother to read the table again
             return rv;
         }
 
         mUVSData = uvsData;
     }
 
@@ -168,21 +177,20 @@ nsresult gfxFontEntry::ReadCMAP()
     NS_ASSERTION(false, "using default no-op implementation of ReadCMAP");
     mCharacterMap = new gfxCharacterMap();
     return NS_OK;
 }
 
 nsString
 gfxFontEntry::RealFaceName()
 {
-    FallibleTArray<uint8_t> nameTable;
-    nsresult rv = GetFontTable(TRUETYPE_TAG('n','a','m','e'), nameTable);
-    if (NS_SUCCEEDED(rv)) {
+    AutoTable nameTable(this, TRUETYPE_TAG('n','a','m','e'));
+    if (nameTable) {
         nsAutoString name;
-        rv = gfxFontUtils::GetFullNameFromTable(nameTable, name);
+        nsresult rv = gfxFontUtils::GetFullNameFromTable(nameTable, name);
         if (NS_SUCCEEDED(rv)) {
             return name;
         }
     }
     return Name();
 }
 
 already_AddRefed<gfxFont>
@@ -243,26 +251,32 @@ gfxFontEntry::TryGetSVGData()
 {
     if (!gfxPlatform::GetPlatform()->OpenTypeSVGEnabled()) {
         return false;
     }
 
     if (!mSVGInitialized) {
         mSVGInitialized = true;
 
-        FallibleTArray<uint8_t> svgTable;
-        nsresult rv = GetFontTable(TRUETYPE_TAG('S', 'V', 'G', ' '), svgTable);
-        if (NS_FAILED(rv)) {
+        // We don't use AutoTable here because we'll pass ownership of these
+        // blobs to the gfxSVGGlyphs, once we've confirmed the tables exist
+        hb_blob_t *svgTable = GetFontTable(TRUETYPE_TAG('S','V','G',' '));
+        if (!svgTable) {
             return false;
         }
 
-        FallibleTArray<uint8_t> cmapTable;
-        rv = GetFontTable(TRUETYPE_TAG('c', 'm', 'a', 'p'), cmapTable);
-        NS_ENSURE_SUCCESS(rv, false);
-
+        hb_blob_t *cmapTable = GetFontTable(TRUETYPE_TAG('c','m','a','p'));
+        if (!cmapTable) {
+            NS_NOTREACHED("using a font with no cmap!");
+            hb_blob_destroy(svgTable);
+            return false;
+        }
+
+        // gfxSVGGlyphs will hb_blob_destroy() the tables when it is finished
+        // with them.
         mSVGGlyphs = new gfxSVGGlyphs(svgTable, cmapTable);
     }
 
     return !!mSVGGlyphs;
 }
 
 /**
  * FontTableBlobData
@@ -422,22 +436,146 @@ gfxFontEntry::ShareFontTableAndGetBlob(u
         // ensure the entry is null
         entry->Clear();
         return nullptr;
     }
 
     return entry->ShareTableAndGetBlob(*aBuffer, &mFontTableCache);
 }
 
+hb_blob_t *
+gfxFontEntry::GetFontTable(uint32_t aTag)
+{
+    hb_blob_t *blob;
+    if (GetExistingFontTable(aTag, &blob)) {
+        return blob;
+    }
+
+    FallibleTArray<uint8_t> buffer;
+    bool haveTable = NS_SUCCEEDED(CopyFontTable(aTag, buffer));
+
+    return ShareFontTableAndGetBlob(aTag, haveTable ? &buffer : nullptr);
+}
+
+// callback for HarfBuzz to get a font table (in hb_blob_t form)
+// from the font entry (passed as aUserData)
+/*static*/ hb_blob_t *
+gfxFontEntry::HBGetTable(hb_face_t *face, uint32_t aTag, void *aUserData)
+{
+    gfxFontEntry *fontEntry = static_cast<gfxFontEntry*>(aUserData);
+
+    // bug 589682 - ignore the GDEF table in buggy fonts (applies to
+    // Italic and BoldItalic faces of Times New Roman)
+    if (aTag == TRUETYPE_TAG('G','D','E','F') &&
+        fontEntry->IgnoreGDEF()) {
+        return nullptr;
+    }
+
+    // bug 721719 - ignore the GSUB table in buggy fonts (applies to Roboto,
+    // at least on some Android ICS devices; set in gfxFT2FontList.cpp)
+    if (aTag == TRUETYPE_TAG('G','S','U','B') &&
+        fontEntry->IgnoreGSUB()) {
+        return nullptr;
+    }
+
+    return fontEntry->GetFontTable(aTag);
+}
+
+/*static*/ void
+gfxFontEntry::HBFaceDeletedCallback(void *aUserData)
+{
+    gfxFontEntry *fe = static_cast<gfxFontEntry*>(aUserData);
+    fe->ForgetHBFace();
+}
+
+void
+gfxFontEntry::ForgetHBFace()
+{
+    mHBFace = nullptr;
+}
+
+hb_face_t*
+gfxFontEntry::GetHBFace()
+{
+    if (!mHBFace) {
+        mHBFace = hb_face_create_for_tables(HBGetTable, this,
+                                            HBFaceDeletedCallback);
+        return mHBFace;
+    }
+    return hb_face_reference(mHBFace);
+}
+
+/*static*/ const void*
+gfxFontEntry::GrGetTable(const void *aAppFaceHandle, unsigned int aName,
+                         size_t *aLen)
+{
+    gfxFontEntry *fontEntry =
+        static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
+    hb_blob_t *blob = fontEntry->GetFontTable(aName);
+    if (blob) {
+        unsigned int blobLength;
+        const void *tableData = hb_blob_get_data(blob, &blobLength);
+        fontEntry->mGrTableMap->Put(tableData, blob);
+        *aLen = blobLength;
+        return tableData;
+    }
+    *aLen = 0;
+    return nullptr;
+}
+
+/*static*/ void
+gfxFontEntry::GrReleaseTable(const void *aAppFaceHandle,
+                             const void *aTableBuffer)
+{
+    gfxFontEntry *fontEntry =
+        static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
+    void *data;
+    if (fontEntry->mGrTableMap->Get(aTableBuffer, &data)) {
+        fontEntry->mGrTableMap->Remove(aTableBuffer);
+        hb_blob_destroy(static_cast<hb_blob_t*>(data));
+    }
+}
+
+gr_face*
+gfxFontEntry::GetGrFace()
+{
+    if (!mGrFaceInitialized) {
+        gr_face_ops faceOps = {
+            sizeof(gr_face_ops),
+            GrGetTable,
+            GrReleaseTable
+        };
+        mGrTableMap = new nsDataHashtable<nsPtrHashKey<const void>,void*>;
+        mGrTableMap->Init();
+        mGrFace = gr_make_face_with_ops(this, &faceOps, gr_face_default);
+        mGrFaceInitialized = true;
+    }
+    ++mGrFaceRefCnt;
+    return mGrFace;
+}
+
+void
+gfxFontEntry::ReleaseGrFace(gr_face *aFace)
+{
+    MOZ_ASSERT(aFace == mGrFace); // sanity-check
+    MOZ_ASSERT(mGrFaceRefCnt > 0);
+    if (--mGrFaceRefCnt == 0) {
+        gr_face_destroy(mGrFace);
+        mGrFace = nullptr;
+        mGrFaceInitialized = false;
+        delete mGrTableMap;
+        mGrTableMap = nullptr;
+    }
+}
+
 void
 gfxFontEntry::CheckForGraphiteTables()
 {
-    AutoFallibleTArray<uint8_t,16384> buffer;
-    mHasGraphiteTables =
-        NS_SUCCEEDED(GetFontTable(TRUETYPE_TAG('S','i','l','f'), buffer));
+    AutoTable silfTable(this, TRUETYPE_TAG('S','i','l','f'));
+    mHasGraphiteTables = silfTable && hb_blob_get_length(silfTable) > 0;
 }
 
 /* static */ size_t
 gfxFontEntry::FontTableHashEntry::SizeOfEntryExcludingThis
     (FontTableHashEntry *aEntry,
      nsMallocSizeOfFun   aMallocSizeOf,
      void*               aUserArg)
 {
@@ -879,21 +1017,21 @@ gfxFontFamily::SearchAllFontsForChar(Glo
             }
         }
     }
 }
 
 // returns true if other names were found, false otherwise
 bool
 gfxFontFamily::ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
-                                           FallibleTArray<uint8_t>& aNameTable,
-                                           bool useFullName)
-{
-    const uint8_t *nameData = aNameTable.Elements();
-    uint32_t dataLength = aNameTable.Length();
+                                           hb_blob_t           *aNameTable,
+                                           bool                 useFullName)
+{
+    uint32_t dataLength;
+    const char *nameData = hb_blob_get_data(aNameTable, &dataLength);
     const gfxFontUtils::NameHeader *nameHeader =
         reinterpret_cast<const gfxFontUtils::NameHeader*>(nameData);
 
     uint32_t nameCount = nameHeader->count;
     if (nameCount * sizeof(gfxFontUtils::NameRecord) > dataLength) {
         NS_WARNING("invalid font (name records)");
         return false;
     }
@@ -942,106 +1080,108 @@ gfxFontFamily::ReadOtherFamilyNames(gfxP
         return;
     mOtherFamilyNamesInitialized = true;
 
     FindStyleVariations();
 
     // read in other family names for the first face in the list
     uint32_t i, numFonts = mAvailableFonts.Length();
     const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
-    AutoFallibleTArray<uint8_t,8192> buffer;
 
     for (i = 0; i < numFonts; ++i) {
         gfxFontEntry *fe = mAvailableFonts[i];
-        if (!fe)
+        if (!fe) {
             continue;
-
-        if (fe->GetFontTable(kNAME, buffer) != NS_OK)
+        }
+        gfxFontEntry::AutoTable nameTable(fe, kNAME);
+        if (!nameTable) {
             continue;
-
+        }
         mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList,
-                                                           buffer);
+                                                           nameTable);
         break;
     }
 
     // read in other names for the first face in the list with the assumption
     // that if extra names don't exist in that face then they don't exist in
     // other faces for the same font
     if (!mHasOtherFamilyNames) 
         return;
 
     // read in names for all faces, needed to catch cases where fonts have
     // family names for individual weights (e.g. Hiragino Kaku Gothic Pro W6)
     for ( ; i < numFonts; i++) {
         gfxFontEntry *fe = mAvailableFonts[i];
-        if (!fe)
+        if (!fe) {
             continue;
-
-        if (fe->GetFontTable(kNAME, buffer) != NS_OK)
+        }
+        gfxFontEntry::AutoTable nameTable(fe, kNAME);
+        if (!nameTable) {
             continue;
-
-        ReadOtherFamilyNamesForFace(aPlatformFontList, buffer);
+        }
+        ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable);
     }
 }
 
 void
 gfxFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList, 
                              bool aNeedFullnamePostscriptNames)
 {
     // if all needed names have already been read, skip
     if (mOtherFamilyNamesInitialized &&
         (mFaceNamesInitialized || !aNeedFullnamePostscriptNames))
         return;
 
     FindStyleVariations();
 
     uint32_t i, numFonts = mAvailableFonts.Length();
     const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
-    AutoFallibleTArray<uint8_t,8192> buffer;
     nsAutoString fullname, psname;
 
     bool firstTime = true, readAllFaces = false;
     for (i = 0; i < numFonts; ++i) {
         gfxFontEntry *fe = mAvailableFonts[i];
-        if (!fe)
+        if (!fe) {
             continue;
-
-        if (fe->GetFontTable(kNAME, buffer) != NS_OK)
+        }
+        gfxFontEntry::AutoTable nameTable(fe, kNAME);
+        if (!nameTable) {
             continue;
-
+        }
         if (aNeedFullnamePostscriptNames) {
             if (gfxFontUtils::ReadCanonicalName(
-                    buffer, gfxFontUtils::NAME_ID_FULL, fullname) == NS_OK)
+                    nameTable, gfxFontUtils::NAME_ID_FULL, fullname) == NS_OK)
             {
                 aPlatformFontList->AddFullname(fe, fullname);
             }
 
             if (gfxFontUtils::ReadCanonicalName(
-                    buffer, gfxFontUtils::NAME_ID_POSTSCRIPT, psname) == NS_OK)
+                    nameTable, gfxFontUtils::NAME_ID_POSTSCRIPT, psname) == NS_OK)
             {
                 aPlatformFontList->AddPostscriptName(fe, psname);
             }
         }
 
-       if (!mOtherFamilyNamesInitialized && (firstTime || readAllFaces)) {
-           bool foundOtherName = ReadOtherFamilyNamesForFace(aPlatformFontList,
-                                                               buffer);
-
-           // if the first face has a different name, scan all faces, otherwise
-           // assume the family doesn't have other names
-           if (firstTime && foundOtherName) {
-               mHasOtherFamilyNames = true;
-               readAllFaces = true;
-           }
-           firstTime = false;
-       }
-
-       // if not reading in any more names, skip other faces
-       if (!readAllFaces && !aNeedFullnamePostscriptNames)
-           break;
+        if (!mOtherFamilyNamesInitialized && (firstTime || readAllFaces)) {
+            bool foundOtherName = ReadOtherFamilyNamesForFace(aPlatformFontList,
+                                                              nameTable);
+
+            // if the first face has a different name, scan all faces, otherwise
+            // assume the family doesn't have other names
+            if (firstTime && foundOtherName) {
+                mHasOtherFamilyNames = true;
+                readAllFaces = true;
+            }
+            firstTime = false;
+        }
+
+        // if not reading in any more names, skip other faces
+        if (!readAllFaces && !aNeedFullnamePostscriptNames) {
+            break;
+        }
     }
 
     mFaceNamesInitialized = true;
     mOtherFamilyNamesInitialized = true;
 }
 
 
 gfxFontEntry*
@@ -1362,27 +1502,121 @@ gfxFontCache::SizeOfExcludingThis(nsMall
 void
 gfxFontCache::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                   FontCacheSizes*   aSizes) const
 {
     aSizes->mFontInstances += aMallocSizeOf(this);
     SizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
 
+#define MAX_SSXX_VALUE 99
+#define MAX_CVXX_VALUE 99
+
+static void
+LookupAlternateValues(gfxFontFeatureValueSet *featureLookup,
+                      const nsAString& aFamily,
+                      const nsTArray<gfxAlternateValue>& altValue,
+                      nsTArray<gfxFontFeature>& aFontFeatures)
+{
+    uint32_t numAlternates = altValue.Length();
+    for (uint32_t i = 0; i < numAlternates; i++) {
+        const gfxAlternateValue& av = altValue.ElementAt(i);
+        nsAutoTArray<uint32_t,4> values;
+
+        // map <family, name, feature> ==> <values>
+        bool found =
+            featureLookup->GetFontFeatureValuesFor(aFamily, av.alternate,
+                                                   av.value, values);
+        uint32_t numValues = values.Length();
+
+        // nothing defined, skip
+        if (!found || numValues == 0) {
+            continue;
+        }
+
+        gfxFontFeature feature;
+        if (av.alternate == NS_FONT_VARIANT_ALTERNATES_CHARACTER_VARIANT) {
+            NS_ASSERTION(numValues <= 2,
+                         "too many values allowed for character-variant");
+            // character-variant(12 3) ==> 'cv12' = 3
+            uint32_t nn = values.ElementAt(0);
+            // ignore values greater than 99
+            if (nn == 0 || nn > MAX_CVXX_VALUE) {
+                continue;
+            }
+            feature.mValue = 1;
+            if (numValues > 1) {
+                feature.mValue = values.ElementAt(1);
+            }
+            feature.mTag = HB_TAG('c','v',('0' + nn / 10), ('0' + nn % 10));
+            aFontFeatures.AppendElement(feature);
+
+        } else if (av.alternate == NS_FONT_VARIANT_ALTERNATES_STYLESET) {
+            // styleset(1 2 7) ==> 'ss01' = 1, 'ss02' = 1, 'ss07' = 1
+            feature.mValue = 1;
+            for (uint32_t v = 0; v < numValues; v++) {
+                uint32_t nn = values.ElementAt(v);
+                if (nn == 0 || nn > MAX_SSXX_VALUE) {
+                    continue;
+                }
+                feature.mTag = HB_TAG('s','s',('0' + nn / 10), ('0' + nn % 10));
+                aFontFeatures.AppendElement(feature);
+            }
+
+        } else {
+            NS_ASSERTION(numValues == 1,
+                   "too many values for font-specific font-variant-alternates");
+            feature.mValue = values.ElementAt(0);
+
+            switch (av.alternate) {
+                case NS_FONT_VARIANT_ALTERNATES_STYLISTIC:  // salt
+                    feature.mTag = HB_TAG('s','a','l','t');
+                    break;
+                case NS_FONT_VARIANT_ALTERNATES_SWASH:  // swsh, cswh
+                    feature.mTag = HB_TAG('s','w','s','h');
+                    aFontFeatures.AppendElement(feature);
+                    feature.mTag = HB_TAG('c','s','w','h');
+                    break;
+                case NS_FONT_VARIANT_ALTERNATES_ORNAMENTS: // ornm
+                    feature.mTag = HB_TAG('o','r','n','m');
+                    break;
+                case NS_FONT_VARIANT_ALTERNATES_ANNOTATION: // nalt
+                    feature.mTag = HB_TAG('n','a','l','t');
+                    break;
+                default:
+                    feature.mTag = 0;
+                    break;
+            }
+
+            NS_ASSERTION(feature.mTag, "unsupported alternate type");
+            if (!feature.mTag) {
+                continue;
+            }
+            aFontFeatures.AppendElement(feature);
+        }
+    }
+}
+
 /* static */ bool
 gfxFontShaper::MergeFontFeatures(
-    const nsTArray<gfxFontFeature>& aStyleRuleFeatures,
+    const gfxFontStyle *aStyle,
     const nsTArray<gfxFontFeature>& aFontFeatures,
     bool aDisableLigatures,
+    const nsAString& aFamilyName,
     nsDataHashtable<nsUint32HashKey,uint32_t>& aMergedFeatures)
 {
+    uint32_t numAlts = aStyle->alternateValues.Length();
+    const nsTArray<gfxFontFeature>& styleRuleFeatures =
+        aStyle->featureSettings;
+
     // bail immediately if nothing to do
-    if (aStyleRuleFeatures.IsEmpty() &&
+    if (styleRuleFeatures.IsEmpty() &&
         aFontFeatures.IsEmpty() &&
-        !aDisableLigatures) {
+        !aDisableLigatures &&
+        numAlts == 0) {
         return false;
     }
 
     aMergedFeatures.Init();
 
     // Ligature features are enabled by default in the generic shaper,
     // so we explicitly turn them off if necessary (for letter-spacing)
     if (aDisableLigatures) {
@@ -1394,20 +1628,35 @@ gfxFontShaper::MergeFontFeatures(
     uint32_t i, count;
 
     count = aFontFeatures.Length();
     for (i = 0; i < count; i++) {
         const gfxFontFeature& feature = aFontFeatures.ElementAt(i);
         aMergedFeatures.Put(feature.mTag, feature.mValue);
     }
 
+    // add font-specific feature values from style rules
+    if (aStyle->featureValueLookup && numAlts > 0) {
+        nsAutoTArray<gfxFontFeature,4> featureList;
+
+        // insert list of alternate feature settings
+        LookupAlternateValues(aStyle->featureValueLookup, aFamilyName,
+                              aStyle->alternateValues, featureList);
+
+        count = featureList.Length();
+        for (i = 0; i < count; i++) {
+            const gfxFontFeature& feature = featureList.ElementAt(i);
+            aMergedFeatures.Put(feature.mTag, feature.mValue);
+        }
+    }
+
     // add feature values from style rules
-    count = aStyleRuleFeatures.Length();
+    count = styleRuleFeatures.Length();
     for (i = 0; i < count; i++) {
-        const gfxFontFeature& feature = aStyleRuleFeatures.ElementAt(i);
+        const gfxFontFeature& feature = styleRuleFeatures.ElementAt(i);
         aMergedFeatures.Put(feature.mTag, feature.mValue);
     }
 
     return aMergedFeatures.Count() != 0;
 }
 
 void
 gfxFont::RunMetrics::CombineWith(const RunMetrics& aOther, bool aOtherIsOnLeft)
@@ -1460,36 +1709,16 @@ gfxFont::AgeCacheEntry(CacheHashEntry *a
         return PL_DHASH_REMOVE;
     }
     if (aEntry->mShapedWord->IncrementAge() == kShapedWordCacheMaxAge) {
         return PL_DHASH_REMOVE;
     }
     return PL_DHASH_NEXT;
 }
 
-hb_blob_t *
-gfxFont::GetFontTable(uint32_t aTag) {
-    hb_blob_t *blob;
-    if (mFontEntry->GetExistingFontTable(aTag, &blob))
-        return blob;
-
-    FallibleTArray<uint8_t> buffer;
-    bool haveTable = NS_SUCCEEDED(mFontEntry->GetFontTable(aTag, buffer));
-
-    return mFontEntry->ShareFontTableAndGetBlob(aTag,
-                                                haveTable ? &buffer : nullptr);
-}
-
-static hb_blob_t *
-HBGetTable(hb_face_t *face, hb_tag_t aTag, void *aUserData)
-{
-    gfxFont* font = static_cast<gfxFont*>(aUserData);
-    return font->GetFontTable(aTag);
-}
-
 static bool
 HasLookupRuleWithGlyphByScript(hb_face_t *aFace, hb_tag_t aTableTag,
                                hb_tag_t aScript, uint16_t aGlyph)
 {
     hb_set_t *lookups = hb_set_create();
     hb_set_t *glyphs = hb_set_create();
     hb_tag_t scripts[2] = {0};
     scripts[0] = aScript;
@@ -1643,17 +1872,17 @@ nsDataHashtable<nsUint32HashKey, int32_t
 
 void
 gfxFont::CheckForFeaturesInvolvingSpace()
 {
     mFontEntry->mHasSpaceFeaturesInitialized = true;
 
     bool result = false;
 
-    hb_face_t *face = hb_face_create_for_tables(HBGetTable, this, nullptr);
+    hb_face_t *face = GetFontEntry()->GetHBFace();
 
     uint32_t i, len, offset;
     uint32_t spaceGlyph = GetSpaceGlyph();
     int32_t s;
 
     mFontEntry->mHasSpaceFeaturesSubDefault = false;
 
     // GSUB lookups - examine per script
@@ -3178,90 +3407,98 @@ gfxFont::SetupGlyphExtents(gfxContext *a
     aExtents->SetTightGlyphExtents(aGlyphID, bounds);
 }
 
 // Try to initialize font metrics by reading sfnt tables directly;
 // set mIsValid=TRUE and return TRUE on success.
 // Return FALSE if the gfxFontEntry subclass does not
 // implement GetFontTable(), or for non-sfnt fonts where tables are
 // not available.
+// If this returns TRUE without setting the mIsValid flag, then we -did-
+// apparently find an sfnt, but it was too broken to be used.
 bool
 gfxFont::InitMetricsFromSfntTables(Metrics& aMetrics)
 {
     mIsValid = false; // font is NOT valid in case of early return
 
     const uint32_t kHeadTableTag = TRUETYPE_TAG('h','e','a','d');
     const uint32_t kHheaTableTag = TRUETYPE_TAG('h','h','e','a');
     const uint32_t kPostTableTag = TRUETYPE_TAG('p','o','s','t');
     const uint32_t kOS_2TableTag = TRUETYPE_TAG('O','S','/','2');
 
+    uint32_t len;
+
     if (mFUnitsConvFactor == 0.0) {
         // If the conversion factor from FUnits is not yet set,
         // 'head' table is required; otherwise we cannot read any metrics
         // because we don't know unitsPerEm
-        AutoFallibleTArray<uint8_t,sizeof(HeadTable)> headData;
-        if (NS_FAILED(mFontEntry->GetFontTable(kHeadTableTag, headData)) ||
-            headData.Length() < sizeof(HeadTable)) {
-            return false; // no 'head' table -> not an sfnt
-        }
-        HeadTable *head = reinterpret_cast<HeadTable*>(headData.Elements());
+        gfxFontEntry::AutoTable headTable(mFontEntry, kHeadTableTag);
+        if (!headTable) {
+            return false;
+        }
+        const HeadTable* head =
+            reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable, &len));
+        if (len < sizeof(HeadTable)) {
+            return false;
+        }
         uint32_t unitsPerEm = head->unitsPerEm;
         if (!unitsPerEm) {
             return true; // is an sfnt, but not valid
         }
         mFUnitsConvFactor = mAdjustedSize / unitsPerEm;
     }
 
     // 'hhea' table is required to get vertical extents
-    AutoFallibleTArray<uint8_t,sizeof(HheaTable)> hheaData;
-    if (NS_FAILED(mFontEntry->GetFontTable(kHheaTableTag, hheaData)) ||
-        hheaData.Length() < sizeof(HheaTable)) {
+    gfxFontEntry::AutoTable hheaTable(mFontEntry, kHheaTableTag);
+    if (!hheaTable) {
         return false; // no 'hhea' table -> not an sfnt
     }
-    HheaTable *hhea = reinterpret_cast<HheaTable*>(hheaData.Elements());
+    const HheaTable* hhea =
+        reinterpret_cast<const HheaTable*>(hb_blob_get_data(hheaTable, &len));
+    if (len < sizeof(HheaTable)) {
+        return false;
+    }
 
 #define SET_UNSIGNED(field,src) aMetrics.field = uint16_t(src) * mFUnitsConvFactor
 #define SET_SIGNED(field,src)   aMetrics.field = int16_t(src) * mFUnitsConvFactor
 
     SET_UNSIGNED(maxAdvance, hhea->advanceWidthMax);
     SET_SIGNED(maxAscent, hhea->ascender);
     SET_SIGNED(maxDescent, -int16_t(hhea->descender));
     SET_SIGNED(externalLeading, hhea->lineGap);
 
     // 'post' table is required for underline metrics
-    AutoFallibleTArray<uint8_t,sizeof(PostTable)> postData;
-    if (NS_FAILED(mFontEntry->GetFontTable(kPostTableTag, postData))) {
+    gfxFontEntry::AutoTable postTable(mFontEntry, kPostTableTag);
+    if (!postTable) {
         return true; // no 'post' table -> sfnt is not valid
     }
-    if (postData.Length() <
-        offsetof(PostTable, underlineThickness) + sizeof(uint16_t)) {
+    const PostTable *post =
+        reinterpret_cast<const PostTable*>(hb_blob_get_data(postTable, &len));
+    if (len < offsetof(PostTable, underlineThickness) + sizeof(uint16_t)) {
         return true; // bad post table -> sfnt is not valid
     }
-    PostTable *post = reinterpret_cast<PostTable*>(postData.Elements());
 
     SET_SIGNED(underlineOffset, post->underlinePosition);
     SET_UNSIGNED(underlineSize, post->underlineThickness);
 
     // 'OS/2' table is optional, if not found we'll estimate xHeight
     // and aveCharWidth by measuring glyphs
-    AutoFallibleTArray<uint8_t,sizeof(OS2Table)> os2data;
-    if (NS_SUCCEEDED(mFontEntry->GetFontTable(kOS_2TableTag, os2data))) {
-        OS2Table *os2 = reinterpret_cast<OS2Table*>(os2data.Elements());
-
-        if (os2data.Length() >= offsetof(OS2Table, sxHeight) +
-                                sizeof(int16_t) &&
+    gfxFontEntry::AutoTable os2Table(mFontEntry, kOS_2TableTag);
+    if (os2Table) {
+        const OS2Table *os2 =
+            reinterpret_cast<const OS2Table*>(hb_blob_get_data(os2Table, &len));
+        if (len >= offsetof(OS2Table, sxHeight) + sizeof(int16_t) &&
             uint16_t(os2->version) >= 2) {
             // version 2 and later includes the x-height field
             SET_SIGNED(xHeight, os2->sxHeight);
             // Abs because of negative xHeight seen in Kokonor (Tibetan) font
             aMetrics.xHeight = Abs(aMetrics.xHeight);
         }
         // this should always be present
-        if (os2data.Length() >= offsetof(OS2Table, yStrikeoutPosition) +
-                                sizeof(int16_t)) {
+        if (len >= offsetof(OS2Table, yStrikeoutPosition) + sizeof(int16_t)) {
             SET_SIGNED(aveCharWidth, os2->xAvgCharWidth);
             SET_SIGNED(subscriptOffset, os2->ySubscriptYOffset);
             SET_SIGNED(superscriptOffset, os2->ySuperscriptYOffset);
             SET_SIGNED(strikeoutSize, os2->yStrikeoutSize);
             SET_SIGNED(strikeoutOffset, os2->yStrikeoutPosition);
         }
     }
 
@@ -4786,23 +5023,25 @@ gfxFontStyle::gfxFontStyle(uint8_t aStyl
     if (!language) {
         NS_WARNING("null language");
         language = nsGkAtoms::x_western;
     }
 }
 
 gfxFontStyle::gfxFontStyle(const gfxFontStyle& aStyle) :
     language(aStyle.language),
+    featureValueLookup(aStyle.featureValueLookup),
     size(aStyle.size), sizeAdjust(aStyle.sizeAdjust),
     languageOverride(aStyle.languageOverride),
     weight(aStyle.weight), stretch(aStyle.stretch),
     systemFont(aStyle.systemFont), printerFont(aStyle.printerFont),
     style(aStyle.style)
 {
     featureSettings.AppendElements(aStyle.featureSettings);
+    alternateValues.AppendElements(aStyle.alternateValues);
 }
 
 int8_t
 gfxFontStyle::ComputeWeight() const
 {
     int8_t baseWeight = (weight + 50) / 100;
 
     if (baseWeight < 0)
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -24,18 +24,20 @@
 #include "gfxPattern.h"
 #include "mozilla/HashFunctions.h"
 #include "nsIMemoryReporter.h"
 #include "gfxFontFeatures.h"
 #include "mozilla/gfx/Types.h"
 #include "mozilla/Attributes.h"
 #include <algorithm>
 #include "nsUnicodeProperties.h"
+#include "harfbuzz/hb.h"
 
 typedef struct _cairo_scaled_font cairo_scaled_font_t;
+typedef struct gr_face            gr_face;
 
 #ifdef DEBUG
 #include <stdio.h>
 #endif
 
 class gfxContext;
 class gfxTextRun;
 class gfxFont;
@@ -45,18 +47,16 @@ class gfxUserFontSet;
 class gfxUserFontData;
 class gfxShapedText;
 class gfxShapedWord;
 class gfxSVGGlyphs;
 class gfxTextObjectPaint;
 
 class nsILanguageAtomService;
 
-typedef struct hb_blob_t hb_blob_t;
-
 #define FONT_MAX_SIZE                  2000.0
 
 #define NO_FONT_LANGUAGE_OVERRIDE      0
 
 struct FontListSizes;
 struct gfxTextRunDrawCallbacks;
 
 struct THEBES_API gfxFontStyle {
@@ -68,19 +68,33 @@ struct THEBES_API gfxFontStyle {
                  const nsString& aLanguageOverride);
     gfxFontStyle(const gfxFontStyle& aStyle);
 
     // the language (may be an internal langGroup code rather than an actual
     // language code) specified in the document or element's lang property,
     // or inferred from the charset
     nsRefPtr<nsIAtom> language;
 
+    // Features are composed of (1) features from style rules (2) features
+    // from feature setttings rules and (3) family-specific features.  (1) and
+    // (3) are guaranteed to be mutually exclusive
+
     // custom opentype feature settings
     nsTArray<gfxFontFeature> featureSettings;
 
+    // Some font-variant property values require font-specific settings
+    // defined via @font-feature-values rules.  These are resolved after
+    // font matching occurs.
+
+    // -- list of value tags for specific alternate features
+    nsTArray<gfxAlternateValue> alternateValues;
+
+    // -- object used to look these up once the font is matched
+    nsRefPtr<gfxFontFeatureValueSet> featureValueLookup;
+
     // The logical size of the font, in pixels
     gfxFloat size;
 
     // The aspect-value (ie., the ratio actualsize:actualxheight) that any
     // actual physical font created from this font structure must have when
     // rendering or measuring a string. A value of 0 means no adjustment
     // needs to be done.
     float sizeAdjust;
@@ -139,17 +153,19 @@ struct THEBES_API gfxFontStyle {
             (systemFont == other.systemFont) &&
             (printerFont == other.printerFont) &&
             (weight == other.weight) &&
             (stretch == other.stretch) &&
             (language == other.language) &&
             (*reinterpret_cast<const uint32_t*>(&sizeAdjust) ==
              *reinterpret_cast<const uint32_t*>(&other.sizeAdjust)) &&
             (featureSettings == other.featureSettings) &&
-            (languageOverride == other.languageOverride);
+            (languageOverride == other.languageOverride) &&
+            (alternateValues == other.alternateValues) &&
+            (featureValueLookup == other.featureValueLookup);
     }
 
     static void ParseFontFeatureSettings(const nsString& aFeatureString,
                                          nsTArray<gfxFontFeature>& aFeatures);
 
     static uint32_t ParseFontLanguageOverride(const nsString& aLangTag);
 };
 
@@ -216,23 +232,27 @@ public:
         mIgnoreGDEF(false),
         mIgnoreGSUB(false),
         mSVGInitialized(false),
         mHasSpaceFeaturesInitialized(false),
         mHasSpaceFeatures(false),
         mHasSpaceFeaturesKerning(false),
         mHasSpaceFeaturesNonKerning(false),
         mHasSpaceFeaturesSubDefault(false),
-        mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
         mCheckedForGraphiteTables(false),
         mHasCmapTable(false),
+        mGrFaceInitialized(false),
+        mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
         mUVSOffset(0), mUVSData(nullptr),
         mUserFontData(nullptr),
         mSVGGlyphs(nullptr),
-        mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE)
+        mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
+        mHBFace(nullptr),
+        mGrFace(nullptr),
+        mGrFaceRefCnt(0)
     {
         memset(&mHasSpaceFeaturesSub, 0, sizeof(mHasSpaceFeaturesSub));
     }
 
     virtual ~gfxFontEntry();
 
     // unique name for the face, *not* the family; not necessarily the
     // "real" or user-friendly name, may be an internal identifier
@@ -301,19 +321,56 @@ public:
 
     virtual bool MatchesGenericFamily(const nsACString& aGeneric) const {
         return true;
     }
     virtual bool SupportsLangGroup(nsIAtom *aLangGroup) const {
         return true;
     }
 
-    virtual nsresult GetFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer) {
-        return NS_ERROR_FAILURE; // all platform subclasses should reimplement this!
-    }
+    // Access to raw font table data (needed for Harfbuzz):
+    // returns a pointer to data owned by the fontEntry or the OS,
+    // which will remain valid until the blob is destroyed.
+    // The data MUST be treated as read-only; we may be getting a
+    // reference to a shared system font cache.
+    //
+    // The default implementation uses CopyFontTable to get the data
+    // into a byte array, and maintains a cache of loaded tables.
+    //
+    // Subclasses should override this if they can provide more efficient
+    // access than copying table data into our own buffers.
+    //
+    // Get blob that encapsulates a specific font table, or NULL if
+    // the table doesn't exist in the font.
+    //
+    // Caller is responsible to call hb_blob_destroy() on the returned blob
+    // (if non-NULL) when no longer required. For transient access to a table,
+    // use of AutoTable (below) is generally preferred.
+    virtual hb_blob_t *GetFontTable(uint32_t aTag);
+
+    // Stack-based utility to return a specified table, automatically releasing
+    // the blob when the AutoTable goes out of scope.
+    class AutoTable {
+    public:
+        AutoTable(gfxFontEntry* aFontEntry, uint32_t aTag)
+        {
+            mBlob = aFontEntry->GetFontTable(aTag);
+        }
+        ~AutoTable() {
+            if (mBlob) {
+                hb_blob_destroy(mBlob);
+            }
+        }
+        operator hb_blob_t*() const { return mBlob; }
+    private:
+        hb_blob_t* mBlob;
+        // not implemented:
+        AutoTable(const AutoTable&) MOZ_DELETE;
+        AutoTable& operator=(const AutoTable&) MOZ_DELETE;
+    };
 
     already_AddRefed<gfxFont> FindOrMakeFont(const gfxFontStyle *aStyle,
                                              bool aNeedsBold);
 
     // Get an existing font table cache entry in aBlob if it has been
     // registered, or return false if not.  Callers must call
     // hb_blob_destroy on aBlob if true is returned.
     //
@@ -326,16 +383,31 @@ public:
     // reference is owned by the caller.  Removing the last reference
     // unregisters the table from the font entry.
     //
     // Pass NULL for aBuffer to indicate that the table is not present and
     // NULL will be returned.  Also returns NULL on OOM.
     hb_blob_t *ShareFontTableAndGetBlob(uint32_t aTag,
                                         FallibleTArray<uint8_t>* aTable);
 
+    // Shaper face accessors:
+    // NOTE that harfbuzz and graphite handle ownership/lifetime of the face
+    // object in completely different ways.
+
+    // Get HarfBuzz face corresponding to this font file.
+    // Caller must release with hb_face_destroy() when finished with it,
+    // and the font entry will be notified via ForgetHBFace.
+    hb_face_t* GetHBFace();
+    virtual void ForgetHBFace();
+
+    // Get Graphite face corresponding to this font file.
+    // Caller must call gfxFontEntry::ReleaseGrFace when finished with it.
+    gr_face* GetGrFace();
+    virtual void ReleaseGrFace(gr_face* aFace);
+    
     // For memory reporting
     virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontListSizes*    aSizes) const;
     virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontListSizes*    aSizes) const;
 
     nsString         mName;
     nsString         mFamilyName;
@@ -352,26 +424,27 @@ public:
     bool             mIgnoreGDEF  : 1;
     bool             mIgnoreGSUB  : 1;
     bool             mSVGInitialized : 1;
     bool             mHasSpaceFeaturesInitialized : 1;
     bool             mHasSpaceFeatures : 1;
     bool             mHasSpaceFeaturesKerning : 1;
     bool             mHasSpaceFeaturesNonKerning : 1;
     bool             mHasSpaceFeaturesSubDefault : 1;
+    bool             mHasGraphiteTables : 1;
+    bool             mCheckedForGraphiteTables : 1;
+    bool             mHasCmapTable : 1;
+    bool             mGrFaceInitialized : 1;
 
     // bitvector of substitution space features per script
     uint32_t         mHasSpaceFeaturesSub[(MOZ_NUM_SCRIPT_CODES + 31) / 32];
 
     uint16_t         mWeight;
     int16_t          mStretch;
 
-    bool             mHasGraphiteTables;
-    bool             mCheckedForGraphiteTables;
-    bool             mHasCmapTable;
     nsRefPtr<gfxCharacterMap> mCharacterMap;
     uint32_t         mUVSOffset;
     nsAutoArrayPtr<uint8_t> mUVSData;
     gfxUserFontData* mUserFontData;
     gfxSVGGlyphs    *mSVGGlyphs;
 
     nsTArray<gfxFontFeature> mFeatureSettings;
     uint32_t         mLanguageOverride;
@@ -394,34 +467,82 @@ protected:
         mIgnoreGDEF(false),
         mIgnoreGSUB(false),
         mSVGInitialized(false),
         mHasSpaceFeaturesInitialized(false),
         mHasSpaceFeatures(false),
         mHasSpaceFeaturesKerning(false),
         mHasSpaceFeaturesNonKerning(false),
         mHasSpaceFeaturesSubDefault(false),
-        mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
         mCheckedForGraphiteTables(false),
         mHasCmapTable(false),
+        mGrFaceInitialized(false),
+        mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
         mUVSOffset(0), mUVSData(nullptr),
         mUserFontData(nullptr),
         mSVGGlyphs(nullptr),
-        mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE)
+        mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
+        mHBFace(nullptr),
+        mGrFace(nullptr),
+        mGrFaceRefCnt(0)
     { }
 
     virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold) {
         NS_NOTREACHED("oops, somebody didn't override CreateFontInstance");
         return nullptr;
     }
 
     virtual void CheckForGraphiteTables();
 
+    // Copy a font table into aBuffer.
+    // The caller will be responsible for ownership of the data.
+    virtual nsresult CopyFontTable(uint32_t aTableTag,
+                                   FallibleTArray<uint8_t>& aBuffer) {
+        NS_NOTREACHED("forgot to override either GetFontTable or CopyFontTable?");
+        return NS_ERROR_FAILURE;
+    }
+
+protected:
+    // Shaper-specific face objects, shared by all instantiations of the same
+    // physical font, regardless of size.
+    // Usually, only one of these will actually be created for any given font
+    // entry, depending on the font tables that are present.
+
+    // hb_face_t is refcounted internally, so each shaper that's using it will
+    // bump the ref count when it acquires the face, and "destroy" (release) it
+    // in its destructor. The font entry has only this non-owning reference to
+    // the face; when the face is deleted, it will tell the font entry to forget
+    // it, so that a new face will be created next time it is needed.
+    hb_face_t* mHBFace;
+
+    static hb_blob_t* HBGetTable(hb_face_t *face, uint32_t aTag, void *aUserData);
+
+    // Callback that the hb_face will use to tell us when it is being deleted.
+    static void HBFaceDeletedCallback(void *aUserData);
+
+    // gr_face is -not- refcounted, so it will be owned directly by the font
+    // entry, and we'll keep a count of how many references we've handed out;
+    // each shaper is responsible to call ReleaseGrFace on its entry when
+    // finished with it, so that we know when it can be deleted.
+    gr_face*   mGrFace;
+
+    // hashtable to map raw table data ptr back to its owning blob, for use by
+    // graphite table-release callback
+    nsDataHashtable<nsPtrHashKey<const void>,void*>* mGrTableMap;
+
+    // number of current users of this entry's mGrFace
+    nsrefcnt mGrFaceRefCnt;
+
+    static const void* GrGetTable(const void *aAppFaceHandle,
+                                  unsigned int aName,
+                                  size_t *aLen);
+    static void GrReleaseTable(const void *aAppFaceHandle,
+                               const void *aTableBuffer);
+
 private:
-
     /**
      * Font table hashtable, to support GetFontTable for harfbuzz.
      *
      * The harfbuzz shaper (and potentially other clients) needs access to raw
      * font table data. This needs to be cached so that it can be used
      * repeatedly (each time we construct a text run; in some cases, for
      * each character/glyph within the run) without re-fetching large tables
      * every time.
@@ -671,18 +792,18 @@ public:
 
 protected:
     // fills in an array with weights of faces that match style,
     // returns whether any matching entries found
     virtual bool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[],
                                        bool anItalic, int16_t aStretch);
 
     bool ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
-                                       FallibleTArray<uint8_t>& aNameTable,
-                                       bool useFullName = false);
+                                     hb_blob_t           *aNameTable,
+                                     bool                 useFullName = false);
 
     // set whether this font family is in "bad" underline offset blacklist.
     void SetBadUnderlineFonts() {
         uint32_t i, numFonts = mAvailableFonts.Length();
         for (i = 0; i < numFonts; i++) {
             if (mAvailableFonts[i]) {
                 mAvailableFonts[i]->mIsBadUnderlineFont = true;
             }
@@ -1142,19 +1263,20 @@ public:
                            uint32_t         aLength,
                            int32_t          aScript,
                            gfxShapedText   *aShapedText) = 0;
 
     gfxFont *GetFont() const { return mFont; }
 
     // returns true if features exist in output, false otherwise
     static bool
-    MergeFontFeatures(const nsTArray<gfxFontFeature>& aStyleRuleFeatures,
+    MergeFontFeatures(const gfxFontStyle *aStyle,
                       const nsTArray<gfxFontFeature>& aFontFeatures,
                       bool aDisableLigatures,
+                      const nsAString& aFamilyName,
                       nsDataHashtable<nsUint32HashKey,uint32_t>& aMergedFeatures);
 
 protected:
     // the font this shaper is working with
     gfxFont * mFont;
 };
 
 /* a SPECIFIC single font family */
@@ -1285,31 +1407,16 @@ public:
         return mFontEntry->HasCmapTable();
     }
 
     // check whether this is an sfnt we can potentially use with Graphite
     bool FontCanSupportGraphite() {
         return mFontEntry->HasGraphiteTables();
     }
 
-    // Access to raw font table data (needed for Harfbuzz):
-    // returns a pointer to data owned by the fontEntry or the OS,
-    // which will remain valid until released.
-    //
-    // Default implementations forward to the font entry,
-    // and maintain a shared table.
-    //
-    // Subclasses should override this if they can provide more efficient
-    // access than getting tables with mFontEntry->GetFontTable() and sharing
-    // them via the entry.
-    //
-    // Get pointer to a specific font table, or NULL if
-    // the table doesn't exist in the font
-    virtual hb_blob_t *GetFontTable(uint32_t aTag);
-
     // Subclasses may choose to look up glyph ids for characters.
     // If they do not override this, gfxHarfBuzzShaper will fetch the cmap
     // table and use that.
     virtual bool ProvidesGetGlyph() const {
         return false;
     }
     // Map unicode character to glyph ID.
     // Only used if ProvidesGetGlyph() returns true.
@@ -1575,16 +1682,20 @@ public:
         FONT_TYPE_CAIRO
     } FontType;
 
     virtual FontType GetType() const = 0;
 
     virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont> GetScaledFont(mozilla::gfx::DrawTarget *aTarget)
     { return gfxPlatform::GetPlatform()->GetScaledFontForFont(aTarget, this); }
 
+    bool KerningDisabled() {
+        return mKerningSet && !mKerningEnabled;
+    }
+
 protected:
 
     bool HasSubstitutionRulesWithSpaceLookups(int32_t aRunScript) {
         NS_ASSERTION(GetFontEntry()->mHasSpaceFeaturesInitialized,
                      "need to initialize space lookup flags");
         NS_ASSERTION(aRunScript < MOZ_NUM_SCRIPT_CODES, "weird script code");
         if (aRunScript == MOZ_SCRIPT_INVALID ||
             aRunScript >= MOZ_NUM_SCRIPT_CODES) {
--- a/gfx/thebes/gfxFontConstants.h
+++ b/gfx/thebes/gfxFontConstants.h
@@ -25,9 +25,170 @@
 #define NS_FONT_STRETCH_CONDENSED       (-2)
 #define NS_FONT_STRETCH_SEMI_CONDENSED  (-1)
 #define NS_FONT_STRETCH_NORMAL          0
 #define NS_FONT_STRETCH_SEMI_EXPANDED   1
 #define NS_FONT_STRETCH_EXPANDED        2
 #define NS_FONT_STRETCH_EXTRA_EXPANDED  3
 #define NS_FONT_STRETCH_ULTRA_EXPANDED  4
 
+#define NS_FONT_KERNING_AUTO                        0
+#define NS_FONT_KERNING_NONE                        1
+#define NS_FONT_KERNING_NORMAL                      2
+
+#define NS_FONT_SYNTHESIS_WEIGHT                    0x1
+#define NS_FONT_SYNTHESIS_STYLE                     0x2
+
+enum {
+    eFeatureAlternates_historical,
+    eFeatureAlternates_stylistic,
+    eFeatureAlternates_styleset,
+    eFeatureAlternates_character_variant,
+    eFeatureAlternates_swash,
+    eFeatureAlternates_ornaments,
+    eFeatureAlternates_annotation,
+
+    eFeatureAlternates_numFeatures
+};
+
+// alternates - simple enumerated values
+#define NS_FONT_VARIANT_ALTERNATES_HISTORICAL        (1 << eFeatureAlternates_historical)
+
+// alternates - values that use functional syntax
+#define NS_FONT_VARIANT_ALTERNATES_STYLISTIC         (1 << eFeatureAlternates_stylistic)
+#define NS_FONT_VARIANT_ALTERNATES_STYLESET          (1 << eFeatureAlternates_styleset)
+#define NS_FONT_VARIANT_ALTERNATES_CHARACTER_VARIANT (1 << eFeatureAlternates_character_variant)
+#define NS_FONT_VARIANT_ALTERNATES_SWASH             (1 << eFeatureAlternates_swash)
+#define NS_FONT_VARIANT_ALTERNATES_ORNAMENTS         (1 << eFeatureAlternates_ornaments)
+#define NS_FONT_VARIANT_ALTERNATES_ANNOTATION        (1 << eFeatureAlternates_annotation)
+
+#define NS_FONT_VARIANT_ALTERNATES_ENUMERATED_MASK \
+    NS_FONT_VARIANT_ALTERNATES_HISTORICAL
+
+#define NS_FONT_VARIANT_ALTERNATES_FUNCTIONAL_MASK ( \
+    NS_FONT_VARIANT_ALTERNATES_STYLISTIC | \
+    NS_FONT_VARIANT_ALTERNATES_STYLESET | \
+    NS_FONT_VARIANT_ALTERNATES_CHARACTER_VARIANT | \
+    NS_FONT_VARIANT_ALTERNATES_SWASH | \
+    NS_FONT_VARIANT_ALTERNATES_ORNAMENTS | \
+    NS_FONT_VARIANT_ALTERNATES_ANNOTATION )
+
+#define NS_FONT_VARIANT_CAPS_NORMAL                 0
+#define NS_FONT_VARIANT_CAPS_SMALLCAPS              1
+#define NS_FONT_VARIANT_CAPS_ALLSMALL               2
+#define NS_FONT_VARIANT_CAPS_PETITECAPS             3
+#define NS_FONT_VARIANT_CAPS_ALLPETITE              4
+#define NS_FONT_VARIANT_CAPS_TITLING                5
+#define NS_FONT_VARIANT_CAPS_UNICASE                6
+
+enum {
+    eFeatureEastAsian_jis78,
+    eFeatureEastAsian_jis83,
+    eFeatureEastAsian_jis90,
+    eFeatureEastAsian_jis04,
+    eFeatureEastAsian_simplified,
+    eFeatureEastAsian_traditional,
+    eFeatureEastAsian_full_width,
+    eFeatureEastAsian_prop_width,
+    eFeatureEastAsian_ruby,
+
+    eFeatureEastAsian_numFeatures
+};
+
+#define NS_FONT_VARIANT_EAST_ASIAN_JIS78        (1 << eFeatureEastAsian_jis78)
+#define NS_FONT_VARIANT_EAST_ASIAN_JIS83        (1 << eFeatureEastAsian_jis83)
+#define NS_FONT_VARIANT_EAST_ASIAN_JIS90        (1 << eFeatureEastAsian_jis90)
+#define NS_FONT_VARIANT_EAST_ASIAN_JIS04        (1 << eFeatureEastAsian_jis04)
+#define NS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED   (1 << eFeatureEastAsian_simplified)
+#define NS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL  (1 << eFeatureEastAsian_traditional)
+#define NS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH   (1 << eFeatureEastAsian_full_width)
+#define NS_FONT_VARIANT_EAST_ASIAN_PROP_WIDTH   (1 << eFeatureEastAsian_prop_width)
+#define NS_FONT_VARIANT_EAST_ASIAN_RUBY         (1 << eFeatureEastAsian_ruby)
+
+#define NS_FONT_VARIANT_EAST_ASIAN_VARIANT_MASK ( \
+    NS_FONT_VARIANT_EAST_ASIAN_JIS78 | \
+    NS_FONT_VARIANT_EAST_ASIAN_JIS83 | \
+    NS_FONT_VARIANT_EAST_ASIAN_JIS90 | \
+    NS_FONT_VARIANT_EAST_ASIAN_JIS04 | \
+    NS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED | \
+    NS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL )
+
+#define NS_FONT_VARIANT_EAST_ASIAN_WIDTH_MASK ( \
+    NS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH | \
+    NS_FONT_VARIANT_EAST_ASIAN_PROP_WIDTH )
+
+enum {
+    eFeatureLigatures_common,
+    eFeatureLigatures_no_common,
+    eFeatureLigatures_discretionary,
+    eFeatureLigatures_no_discretionary,
+    eFeatureLigatures_historical,
+    eFeatureLigatures_no_historical,
+    eFeatureLigatures_contextual,
+    eFeatureLigatures_no_contextual,
+
+    eFeatureLigatures_numFeatures
+};
+
+#define NS_FONT_VARIANT_LIGATURES_COMMON            (1 << eFeatureLigatures_common)
+#define NS_FONT_VARIANT_LIGATURES_NO_COMMON         (1 << eFeatureLigatures_no_common)
+#define NS_FONT_VARIANT_LIGATURES_DISCRETIONARY     (1 << eFeatureLigatures_discretionary)
+#define NS_FONT_VARIANT_LIGATURES_NO_DISCRETIONARY  (1 << eFeatureLigatures_no_discretionary)
+#define NS_FONT_VARIANT_LIGATURES_HISTORICAL        (1 << eFeatureLigatures_historical)
+#define NS_FONT_VARIANT_LIGATURES_NO_HISTORICAL     (1 << eFeatureLigatures_no_historical)
+#define NS_FONT_VARIANT_LIGATURES_CONTEXTUAL        (1 << eFeatureLigatures_contextual)
+#define NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL     (1 << eFeatureLigatures_no_contextual)
+
+#define NS_FONT_VARIANT_LIGATURES_COMMON_MASK ( \
+    NS_FONT_VARIANT_LIGATURES_COMMON | \
+    NS_FONT_VARIANT_LIGATURES_NO_COMMON )
+
+#define NS_FONT_VARIANT_LIGATURES_DISCRETIONARY_MASK ( \
+    NS_FONT_VARIANT_LIGATURES_DISCRETIONARY | \
+    NS_FONT_VARIANT_LIGATURES_NO_DISCRETIONARY )
+
+#define NS_FONT_VARIANT_LIGATURES_HISTORICAL_MASK ( \
+    NS_FONT_VARIANT_LIGATURES_HISTORICAL | \
+    NS_FONT_VARIANT_LIGATURES_NO_HISTORICAL )
+
+#define NS_FONT_VARIANT_LIGATURES_CONTEXTUAL_MASK \
+    NS_FONT_VARIANT_LIGATURES_CONTEXTUAL | \
+    NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL
+
+enum {
+    eFeatureNumeric_lining,
+    eFeatureNumeric_oldstyle,
+    eFeatureNumeric_proportional,
+    eFeatureNumeric_tabular,
+    eFeatureNumeric_diagonal_fractions,
+    eFeatureNumeric_stacked_fractions,
+    eFeatureNumeric_slashedzero,
+    eFeatureNumeric_ordinal,
+
+    eFeatureNumeric_numFeatures
+};
+
+#define NS_FONT_VARIANT_NUMERIC_LINING              (1 << eFeatureNumeric_lining)
+#define NS_FONT_VARIANT_NUMERIC_OLDSTYLE            (1 << eFeatureNumeric_oldstyle)
+#define NS_FONT_VARIANT_NUMERIC_PROPORTIONAL        (1 << eFeatureNumeric_proportional)
+#define NS_FONT_VARIANT_NUMERIC_TABULAR             (1 << eFeatureNumeric_tabular)
+#define NS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS  (1 << eFeatureNumeric_diagonal_fractions)
+#define NS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS   (1 << eFeatureNumeric_stacked_fractions)
+#define NS_FONT_VARIANT_NUMERIC_SLASHZERO           (1 << eFeatureNumeric_slashedzero)
+#define NS_FONT_VARIANT_NUMERIC_ORDINAL             (1 << eFeatureNumeric_ordinal)
+
+#define NS_FONT_VARIANT_NUMERIC_FIGURE_MASK \
+    NS_FONT_VARIANT_NUMERIC_LINING | \
+    NS_FONT_VARIANT_NUMERIC_OLDSTYLE
+
+#define NS_FONT_VARIANT_NUMERIC_SPACING_MASK \
+    NS_FONT_VARIANT_NUMERIC_PROPORTIONAL | \
+    NS_FONT_VARIANT_NUMERIC_TABULAR
+
+#define NS_FONT_VARIANT_NUMERIC_FRACTION_MASK \
+    NS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS | \
+    NS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS
+
+#define NS_FONT_VARIANT_POSITION_NORMAL             0
+#define NS_FONT_VARIANT_POSITION_SUPER              1
+#define NS_FONT_VARIANT_POSITION_SUB                2
+
 #endif
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/gfxFontFeatures.cpp
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gfxFontFeatures.h"
+#include "nsUnicharUtils.h"
+#include "nsHashKeys.h"
+
+using namespace mozilla;
+
+gfxFontFeatureValueSet::gfxFontFeatureValueSet()
+{
+    mFontFeatureValues.Init(10);
+}
+
+bool
+gfxFontFeatureValueSet::GetFontFeatureValuesFor(const nsAString& aFamily,
+                                                uint32_t aVariantProperty,
+                                                const nsAString& aName,
+                                                nsTArray<uint32_t>& aValues)
+{
+    nsAutoString family(aFamily), name(aName);
+    ToLowerCase(family);
+    ToLowerCase(name);
+    FeatureValueHashKey key(family, aVariantProperty, name);
+
+    aValues.Clear();
+    FeatureValueHashEntry *entry = mFontFeatureValues.GetEntry(key);
+    if (entry) {
+        NS_ASSERTION(entry->mValues.Length() > 0,
+                     "null array of font feature values");
+        aValues.AppendElements(entry->mValues);
+        return true;
+    }
+
+    return false;
+}
+
+
+void
+gfxFontFeatureValueSet::AddFontFeatureValues(const nsAString& aFamily,
+                 const nsTArray<gfxFontFeatureValueSet::FeatureValues>& aValues)
+{
+    nsAutoString family(aFamily);
+    ToLowerCase(family);
+
+    uint32_t i, numFeatureValues = aValues.Length();
+    for (i = 0; i < numFeatureValues; i++) {
+        const FeatureValues& fv = aValues.ElementAt(i);
+        uint32_t alternate = fv.alternate;
+        uint32_t j, numValues = fv.valuelist.Length();
+        for (j = 0; j < numValues; j++) {
+            const ValueList& v = fv.valuelist.ElementAt(j);
+            nsAutoString name(v.name);
+            ToLowerCase(name);
+            FeatureValueHashKey key(family, alternate, name);
+            FeatureValueHashEntry *entry = mFontFeatureValues.PutEntry(key);
+            entry->mKey = key;
+            entry->mValues = v.featureSelectors;
+        }
+    }
+}
+
+bool
+gfxFontFeatureValueSet::FeatureValueHashEntry::KeyEquals(
+                                               const KeyTypePointer aKey) const
+{
+    return aKey->mPropVal == mKey.mPropVal &&
+           aKey->mFamily.Equals(mKey.mFamily) &&
+           aKey->mName.Equals(mKey.mName);
+}
+
+PLDHashNumber
+gfxFontFeatureValueSet::FeatureValueHashEntry::HashKey(
+                                                     const KeyTypePointer aKey)
+{
+    return HashString(aKey->mFamily) + HashString(aKey->mName) +
+           aKey->mPropVal * uint32_t(0xdeadbeef);
+}
+
--- a/gfx/thebes/gfxFontFeatures.h
+++ b/gfx/thebes/gfxFontFeatures.h
@@ -2,16 +2,21 @@
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_FONT_FEATURES_H
 #define GFX_FONT_FEATURES_H
 
+#include "gfxTypes.h"
+#include "nsTHashtable.h"
+#include "nsTArray.h"
+#include "nsString.h"
+
 // An OpenType feature tag and value pair
 struct gfxFontFeature {
     uint32_t mTag; // see http://www.microsoft.com/typography/otspec/featuretags.htm
     uint32_t mValue; // 0 = off, 1 = on, larger values may be used as parameters
                      // to features that select among multiple alternatives
 };
 
 inline bool
@@ -21,9 +26,100 @@ operator<(const gfxFontFeature& a, const
 }
 
 inline bool
 operator==(const gfxFontFeature& a, const gfxFontFeature& b)
 {
     return (a.mTag == b.mTag) && (a.mValue == b.mValue);
 }
 
+struct gfxAlternateValue {
+    uint32_t           alternate;  // constants in gfxFontConstants.h
+    nsString           value;      // string value to be looked up
+};
+
+inline bool
+operator<(const gfxAlternateValue& a, const gfxAlternateValue& b)
+{
+    return (a.alternate < b.alternate) ||
+        ((a.alternate == b.alternate) && (a.value < b.value));
+}
+
+inline bool
+operator==(const gfxAlternateValue& a, const gfxAlternateValue& b)
+{
+    return (a.alternate == b.alternate) && (a.value == b.value);
+}
+
+class THEBES_API gfxFontFeatureValueSet {
+public:
+    NS_INLINE_DECL_REFCOUNTING(gfxFontFeatureValueSet)
+
+    gfxFontFeatureValueSet();
+    virtual ~gfxFontFeatureValueSet() {}
+
+    struct ValueList {
+        ValueList(const nsAString& aName, const nsTArray<uint32_t>& aSelectors)
+          : name(aName), featureSelectors(aSelectors)
+        {}
+        nsString             name;
+        nsTArray<uint32_t>   featureSelectors;
+    };
+
+    struct FeatureValues {
+        uint32_t             alternate;
+        nsTArray<ValueList>  valuelist;
+    };
+
+    // returns true if found, false otherwise
+    bool
+    GetFontFeatureValuesFor(const nsAString& aFamily,
+                            uint32_t aVariantProperty,
+                            const nsAString& aName,
+                            nsTArray<uint32_t>& aValues);
+    void
+    AddFontFeatureValues(const nsAString& aFamily,
+                const nsTArray<gfxFontFeatureValueSet::FeatureValues>& aValues);
+
+protected:
+    struct FeatureValueHashKey {
+        nsString mFamily;
+        uint32_t mPropVal;
+        nsString mName;
+
+        FeatureValueHashKey()
+            : mPropVal(0)
+        { }
+        FeatureValueHashKey(const nsAString& aFamily,
+                            uint32_t aPropVal,
+                            const nsAString& aName)
+            : mFamily(aFamily), mPropVal(aPropVal), mName(aName)
+        { }
+        FeatureValueHashKey(const FeatureValueHashKey& aKey)
+            : mFamily(aKey.mFamily), mPropVal(aKey.mPropVal), mName(aKey.mName)
+        { }
+    };
+
+    class FeatureValueHashEntry : public PLDHashEntryHdr {
+    public:
+        typedef const FeatureValueHashKey &KeyType;
+        typedef const FeatureValueHashKey *KeyTypePointer;
+
+        FeatureValueHashEntry(KeyTypePointer aKey) { }
+        FeatureValueHashEntry(const FeatureValueHashEntry& toCopy)
+        {
+            NS_ERROR("Should not be called");
+        }
+        ~FeatureValueHashEntry() { }
+
+        bool KeyEquals(const KeyTypePointer aKey) const;
+        static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
+        static PLDHashNumber HashKey(const KeyTypePointer aKey);
+        enum { ALLOW_MEMMOVE = true };
+
+        FeatureValueHashKey mKey;
+        nsTArray<uint32_t>  mValues;
+    };
+
+    nsTHashtable<FeatureValueHashEntry> mFontFeatureValues;
+  };
+
 #endif
--- a/gfx/thebes/gfxFontUtils.cpp
+++ b/gfx/thebes/gfxFontUtils.cpp
@@ -15,16 +15,18 @@
 #include "nsServiceManagerUtils.h"
 
 #include "mozilla/Preferences.h"
 
 #include "nsIUUIDGenerator.h"
 #include "nsMemory.h"
 #include "nsICharsetConverterManager.h"
 
+#include "harfbuzz/hb.h"
+
 #include "plbase64.h"
 #include "prlog.h"
 
 #ifdef XP_MACOSX
 #include <CoreFoundation/CoreFoundation.h>
 #endif
 
 #ifdef PR_LOGGING
@@ -1210,27 +1212,28 @@ gfxFontUtils::GetFullNameFromSFNT(const 
     }
     
     // should never fail, as we're only called after font validation succeeded
     NS_ENSURE_TRUE(foundName, NS_ERROR_NOT_AVAILABLE);
 
     uint32_t len = dirEntry->length;
     NS_ENSURE_TRUE(aLength > len && aLength - len >= dirEntry->offset,
                    NS_ERROR_UNEXPECTED);
-    FallibleTArray<uint8_t> nameTable;
-    if (!nameTable.SetLength(len)) {
-        return NS_ERROR_OUT_OF_MEMORY;
-    }
-    memcpy(nameTable.Elements(), aFontData + dirEntry->offset, len);
 
-    return GetFullNameFromTable(nameTable, aFullName);
+    hb_blob_t *nameBlob =
+        hb_blob_create((const char*)aFontData + dirEntry->offset, len,
+                       HB_MEMORY_MODE_READONLY, nullptr, nullptr);
+    nsresult rv = GetFullNameFromTable(nameBlob, aFullName);
+    hb_blob_destroy(nameBlob);
+
+    return rv;
 }
 
 nsresult
-gfxFontUtils::GetFullNameFromTable(FallibleTArray<uint8_t>& aNameTable,
+gfxFontUtils::GetFullNameFromTable(hb_blob_t *aNameTable,
                                    nsAString& aFullName)
 {
     nsAutoString name;
     nsresult rv =
         gfxFontUtils::ReadCanonicalName(aNameTable,
                                         gfxFontUtils::NAME_ID_FULL,
                                         name);
     if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
@@ -1252,17 +1255,17 @@ gfxFontUtils::GetFullNameFromTable(Falli
         }
         return NS_OK;
     }
 
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 nsresult
-gfxFontUtils::GetFamilyNameFromTable(FallibleTArray<uint8_t>& aNameTable,
+gfxFontUtils::GetFamilyNameFromTable(hb_blob_t *aNameTable,
                                      nsAString& aFullName)
 {
     nsAutoString name;
     nsresult rv =
         gfxFontUtils::ReadCanonicalName(aNameTable,
                                         gfxFontUtils::NAME_ID_FAMILY,
                                         name);
     if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
@@ -1278,24 +1281,24 @@ enum {
     PLATFORM_ID       = gfxFontUtils::PLATFORM_ID_MAC
 #else
     CANONICAL_LANG_ID = gfxFontUtils::LANG_ID_MICROSOFT_EN_US,
     PLATFORM_ID       = gfxFontUtils::PLATFORM_ID_MICROSOFT
 #endif
 };    
 
 nsresult
-gfxFontUtils::ReadNames(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID, 
+gfxFontUtils::ReadNames(hb_blob_t *aNameTable, uint32_t aNameID, 
                         int32_t aPlatformID, nsTArray<nsString>& aNames)
 {
     return ReadNames(aNameTable, aNameID, LANG_ALL, aPlatformID, aNames);
 }
 
 nsresult
-gfxFontUtils::ReadCanonicalName(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID, 
+gfxFontUtils::ReadCanonicalName(hb_blob_t *aNameTable, uint32_t aNameID, 
                                 nsString& aName)
 {
     nsresult rv;
     
     nsTArray<nsString> names;
     
     // first, look for the English name (this will succeed 99% of the time)
     rv = ReadNames(aNameTable, aNameID, CANONICAL_LANG_ID, PLATFORM_ID, names);
@@ -1453,17 +1456,17 @@ gfxFontUtils::GetCharsetForFontName(uint
     }
 
     return nullptr;
 }
 
 // convert a raw name from the name table to an nsString, if possible;
 // return value indicates whether conversion succeeded
 bool
-gfxFontUtils::DecodeFontName(const uint8_t *aNameData, int32_t aByteLen, 
+gfxFontUtils::DecodeFontName(const char *aNameData, int32_t aByteLen, 
                              uint32_t aPlatformCode, uint32_t aScriptCode,
                              uint32_t aLangCode, nsAString& aName)
 {
     NS_ASSERTION(aByteLen > 0, "bad length for font name data");
 
     const char *csName = GetCharsetForFontName(aPlatformCode, aScriptCode, aLangCode);
 
     if (!csName) {
@@ -1503,47 +1506,47 @@ gfxFontUtils::DecodeFontName(const uint8
     nsCOMPtr<nsIUnicodeDecoder> decoder;
     rv = ccm->GetUnicodeDecoderRaw(csName, getter_AddRefs(decoder));
     if (NS_FAILED(rv)) {
         NS_WARNING("failed to get the decoder for a font name string");
         return false;
     }
 
     int32_t destLength;
-    rv = decoder->GetMaxLength(reinterpret_cast<const char*>(aNameData), aByteLen, &destLength);
+    rv = decoder->GetMaxLength(aNameData, aByteLen, &destLength);
     if (NS_FAILED(rv)) {
         NS_WARNING("decoder->GetMaxLength failed, invalid font name?");
         return false;
     }
 
     // make space for the converted string
     aName.SetLength(destLength);
-    rv = decoder->Convert(reinterpret_cast<const char*>(aNameData), &aByteLen,
+    rv = decoder->Convert(aNameData, &aByteLen,
                           aName.BeginWriting(), &destLength);
     if (NS_FAILED(rv)) {
         NS_WARNING("decoder->Convert failed, invalid font name?");
         return false;
     }
     aName.Truncate(destLength); // set the actual length
 
     return true;
 }
 
 nsresult
-gfxFontUtils::ReadNames(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID, 
+gfxFontUtils::ReadNames(hb_blob_t *aNameTable, uint32_t aNameID, 
                         int32_t aLangID, int32_t aPlatformID,
                         nsTArray<nsString>& aNames)
 {
-    uint32_t nameTableLen = aNameTable.Length();
+    uint32_t nameTableLen;
+    const char *nameTable = hb_blob_get_data(aNameTable, &nameTableLen);
     NS_ASSERTION(nameTableLen != 0, "null name table");
 
-    if (nameTableLen == 0)
+    if (!nameTableLen) {
         return NS_ERROR_FAILURE;
-
-    uint8_t *nameTable = aNameTable.Elements();
+    }
 
     // -- name table data
     const NameHeader *nameHeader = reinterpret_cast<const NameHeader*>(nameTable);
 
     uint32_t nameCount = nameHeader->count;
 
     // -- sanity check the number of name records
     if (uint64_t(nameCount) * sizeof(NameRecord) > nameTableLen) {
--- a/gfx/thebes/gfxFontUtils.h
+++ b/gfx/thebes/gfxFontUtils.h
@@ -28,16 +28,18 @@
 #include <algorithm>
 
 /* Bug 341128 - w32api defines min/max which causes problems with <bitset> */
 #ifdef __MINGW32__
 #undef min
 #undef max
 #endif
 
+typedef struct hb_blob_t hb_blob_t;
+
 class gfxSparseBitSet {
 private:
     enum { BLOCK_SIZE = 32 };   // ==> 256 codepoints per block
     enum { BLOCK_SIZE_BITS = BLOCK_SIZE * 8 };
     enum { BLOCK_INDEX_SHIFT = 8 };
 
     struct Block {
         Block(const Block& aBlock) { memcpy(mBits, aBlock.mBits, sizeof(mBits)); }
@@ -824,46 +826,46 @@ public:
     // so it should always succeed in finding the name table.
     static nsresult
     GetFullNameFromSFNT(const uint8_t* aFontData, uint32_t aLength,
                         nsAString& aFullName);
 
     // helper to get fullname from name table, constructing from family+style
     // if no explicit fullname is present
     static nsresult
-    GetFullNameFromTable(FallibleTArray<uint8_t>& aNameTable,
+    GetFullNameFromTable(hb_blob_t *aNameTable,
                          nsAString& aFullName);
 
     // helper to get family name from name table
     static nsresult
-    GetFamilyNameFromTable(FallibleTArray<uint8_t>& aNameTable,
+    GetFamilyNameFromTable(hb_blob_t *aNameTable,
                            nsAString& aFamilyName);
 
     // create a new name table and build a new font with that name table
     // appended on the end, returns true on success
     static nsresult
     RenameFont(const nsAString& aName, const uint8_t *aFontData, 
                uint32_t aFontDataLength, FallibleTArray<uint8_t> *aNewFont);
     
     // read all names matching aNameID, returning in aNames array
     static nsresult
-    ReadNames(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID, 
+    ReadNames(hb_blob_t *aNameTable, uint32_t aNameID, 
               int32_t aPlatformID, nsTArray<nsString>& aNames);
       
     // reads English or first name matching aNameID, returning in aName
     // platform based on OS
     static nsresult
-    ReadCanonicalName(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID, 
+    ReadCanonicalName(hb_blob_t *aNameTable, uint32_t aNameID, 
                       nsString& aName);
       
     // convert a name from the raw name table data into an nsString,
     // provided we know how; return true if successful, or false
     // if we can't handle the encoding
     static bool
-    DecodeFontName(const uint8_t *aBuf, int32_t aLength, 
+    DecodeFontName(const char *aBuf, int32_t aLength, 
                    uint32_t aPlatformCode, uint32_t aScriptCode,
                    uint32_t aLangCode, nsAString& dest);
 
     static inline bool IsJoinCauser(uint32_t ch) {
         return (ch == 0x200D);
     }
 
     static inline bool IsJoinControl(uint32_t ch) {
@@ -929,17 +931,17 @@ public:
     static void GetPrefsFontList(const char *aPrefName, 
                                  nsTArray<nsString>& aFontList);
 
     // generate a unique font name
     static nsresult MakeUniqueUserFontName(nsAString& aName);
 
 protected:
     static nsresult
-    ReadNames(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID, 
+    ReadNames(hb_blob_t *aNameTable, uint32_t aNameID, 
               int32_t aLangID, int32_t aPlatformID, nsTArray<nsString>& aNames);
 
     // convert opentype name-table platform/encoding/language values to a charset name
     // we can use to convert the name data to unicode, or "" if data is UTF16BE
     static const char*
     GetCharsetForFontName(uint16_t aPlatform, uint16_t aScript, uint16_t aLanguage);
 
     struct MacFontNameCharsetMapping {
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -194,17 +194,17 @@ GDIFontEntry::ReadCMAP()
     }
 
     nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
 
     uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
     nsresult rv;
 
     AutoFallibleTArray<uint8_t,16384> cmap;
-    rv = GetFontTable(kCMAP, cmap);
+    rv = CopyFontTable(kCMAP, cmap);
 
     bool unicodeFont = false, symbolFont = false; // currently ignored
 
     if (NS_SUCCEEDED(rv)) {
         rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
                                     *charmap, mUVSOffset,
                                     unicodeFont, symbolFont);
     }
@@ -258,18 +258,18 @@ GDIFontEntry::CreateFontInstance(const g
           gfxWindowsPlatform::GetPlatform()->UseClearTypeForDownloadableFonts()));
 
     return new gfxGDIFont(this, aFontStyle, aNeedsBold, 
                           (useClearType ? gfxFont::kAntialiasSubpixel
                                         : gfxFont::kAntialiasDefault));
 }
 
 nsresult
-GDIFontEntry::GetFontTable(uint32_t aTableTag,
-                           FallibleTArray<uint8_t>& aBuffer)
+GDIFontEntry::CopyFontTable(uint32_t aTableTag,
+                            FallibleTArray<uint8_t>& aBuffer)
 {
     if (!IsTrueType()) {
         return NS_ERROR_FAILURE;
     }
 
     AutoDC dc;
     AutoSelectFont font(dc.GetDC(), &mLogFont);
     if (font.IsValid()) {
--- a/gfx/thebes/gfxGDIFontList.h
+++ b/gfx/thebes/gfxGDIFontList.h
@@ -275,18 +275,18 @@ protected:
     GDIFontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType,
                  bool aItalic, uint16_t aWeight, int16_t aStretch,
                  gfxUserFontData *aUserFontData, bool aFamilyHasItalicFace);
 
     void InitLogFont(const nsAString& aName, gfxWindowsFontType aFontType);
 
     virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold);
 
-    virtual nsresult GetFontTable(uint32_t aTableTag,
-                                  FallibleTArray<uint8_t>& aBuffer);
+    virtual nsresult CopyFontTable(uint32_t aTableTag,
+                                   FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
 
     LOGFONTW mLogFont;
 };
 
 // a single font family, referencing one or more faces
 class GDIFontFamily : public gfxFontFamily
 {
 public:
--- a/gfx/thebes/gfxGraphiteShaper.cpp
+++ b/gfx/thebes/gfxGraphiteShaper.cpp
@@ -35,79 +35,36 @@
 using namespace mozilla; // for AutoSwap_* types
 
 /*
  * Creation and destruction; on deletion, release any font tables we're holding
  */
 
 gfxGraphiteShaper::gfxGraphiteShaper(gfxFont *aFont)
     : gfxFontShaper(aFont),
-      mGrFace(nullptr),
+      mGrFace(mFont->GetFontEntry()->GetGrFace()),
       mGrFont(nullptr)
 {
-    mTables.Init();
     mCallbackData.mFont = aFont;
     mCallbackData.mShaper = this;
 }
 
-PLDHashOperator
-ReleaseTableFunc(const uint32_t& /* aKey */,
-                 gfxGraphiteShaper::TableRec& aData,
-                 void* /* aUserArg */)
-{
-    hb_blob_destroy(aData.mBlob);
-    return PL_DHASH_REMOVE;
-}
-
 gfxGraphiteShaper::~gfxGraphiteShaper()
 {
     if (mGrFont) {
         gr_font_destroy(mGrFont);
     }
-    if (mGrFace) {
-        gr_face_destroy(mGrFace);
-    }
-    mTables.Enumerate(ReleaseTableFunc, nullptr);
-}
-
-static const void*
-GrGetTable(const void* appFaceHandle, unsigned int name, size_t *len)
-{
-    const gfxGraphiteShaper::CallbackData *cb =
-        static_cast<const gfxGraphiteShaper::CallbackData*>(appFaceHandle);
-    return cb->mShaper->GetTable(name, len);
+    mFont->GetFontEntry()->ReleaseGrFace(mGrFace);
 }
 
-const void*
-gfxGraphiteShaper::GetTable(uint32_t aTag, size_t *aLength)
+/*static*/ float
+gfxGraphiteShaper::GrGetAdvance(const void* appFontHandle, uint16_t glyphid)
 {
-    TableRec tableRec;
-
-    if (!mTables.Get(aTag, &tableRec)) {
-        hb_blob_t *blob = mFont->GetFontTable(aTag);
-        if (blob) {
-            // mFont->GetFontTable() gives us a reference to the blob.
-            // We will destroy (release) it in our destructor.
-            tableRec.mBlob = blob;
-            tableRec.mData = hb_blob_get_data(blob, &tableRec.mLength);
-            mTables.Put(aTag, tableRec);
-        } else {
-            return nullptr;
-        }
-    }
-
-    *aLength = tableRec.mLength;
-    return tableRec.mData;
-}
-
-static float
-GrGetAdvance(const void* appFontHandle, gr_uint16 glyphid)
-{
-    const gfxGraphiteShaper::CallbackData *cb =
-        static_cast<const gfxGraphiteShaper::CallbackData*>(appFontHandle);
+    const CallbackData *cb =
+        static_cast<const CallbackData*>(appFontHandle);
     return FixedToFloat(cb->mFont->GetGlyphWidth(cb->mContext, glyphid));
 }
 
 static inline uint32_t
 MakeGraphiteLangTag(uint32_t aTag)
 {
     uint32_t grLangTag = aTag;
     // replace trailing space-padding with NULs for graphite
@@ -147,17 +104,16 @@ gfxGraphiteShaper::ShapeText(gfxContext 
     // some font back-ends require this in order to get proper hinted metrics
     if (!mFont->SetupCairoFont(aContext)) {
         return false;
     }
 
     mCallbackData.mContext = aContext;
 
     if (!mGrFont) {
-        mGrFace = gr_make_face(&mCallbackData, GrGetTable, gr_face_default);
         if (!mGrFace) {
             return false;
         }
 
         if (mFont->ProvidesGlyphWidths()) {
             gr_font_ops ops = {
                 sizeof(gr_font_ops),
                 &GrGetAdvance,
@@ -165,18 +121,16 @@ gfxGraphiteShaper::ShapeText(gfxContext 
             };
             mGrFont = gr_make_font_with_ops(mFont->GetAdjustedSize(),
                                             &mCallbackData, &ops, mGrFace);
         } else {
             mGrFont = gr_make_font(mFont->GetAdjustedSize(), mGrFace);
         }
 
         if (!mGrFont) {
-            gr_face_destroy(mGrFace);
-            mGrFace = nullptr;
             return false;
         }
     }
 
     gfxFontEntry *entry = mFont->GetFontEntry();
     const gfxFontStyle *style = mFont->GetStyle();
     uint32_t grLang = 0;
     if (style->languageOverride) {
@@ -187,18 +141,23 @@ gfxGraphiteShaper::ShapeText(gfxContext 
         nsAutoCString langString;
         style->language->ToUTF8String(langString);
         grLang = GetGraphiteTagForLang(langString);
     }
     gr_feature_val *grFeatures = gr_face_featureval_for_lang(mGrFace, grLang);
 
     nsDataHashtable<nsUint32HashKey,uint32_t> mergedFeatures;
 
-    if (MergeFontFeatures(style->featureSettings, entry->mFeatureSettings,
-                          aShapedText->DisableLigatures(), mergedFeatures)) {
+    // if style contains font-specific features
+    if (MergeFontFeatures(style,
+                          mFont->GetFontEntry()->mFeatureSettings,
+                          aShapedText->DisableLigatures(),
+                          mFont->GetFontEntry()->FamilyName(),
+                          mergedFeatures))
+    {
         // enumerate result and insert into Graphite feature list
         GrFontFeatures f = {mGrFace, grFeatures};
         mergedFeatures.Enumerate(AddFeature, &f);
     }
 
     size_t numChars = gr_count_unicode_characters(gr_utf16,
                                                   aText, aText + aLength,
                                                   nullptr);
--- a/gfx/thebes/gfxGraphiteShaper.h
+++ b/gfx/thebes/gfxGraphiteShaper.h
@@ -22,45 +22,38 @@ public:
 
     virtual bool ShapeText(gfxContext      *aContext,
                            const PRUnichar *aText,
                            uint32_t         aOffset,
                            uint32_t         aLength,
                            int32_t          aScript,
                            gfxShapedText   *aShapedText);
 
-    const void* GetTable(uint32_t aTag, size_t *aLength);
-
     static void Shutdown();
 
-    struct CallbackData {
-        gfxFont           *mFont;
-        gfxGraphiteShaper *mShaper;
-        gfxContext        *mContext;
-    };
-
-    struct TableRec {
-        hb_blob_t  *mBlob;
-        const void *mData;
-        uint32_t    mLength;
-    };
-
 protected:
     nsresult SetGlyphsFromSegment(gfxContext      *aContext,
                                   gfxShapedText   *aShapedText,
                                   uint32_t         aOffset,
                                   uint32_t         aLength,
                                   const PRUnichar *aText,
                                   gr_segment      *aSegment);
 
-    gr_face *mGrFace;
-    gr_font *mGrFont;
+    static float GrGetAdvance(const void* appFontHandle, uint16_t glyphid);
+
+    gr_face *mGrFace; // owned by the font entry; shaper must call
+                      // gfxFontEntry::ReleaseGrFace when finished with it
+    gr_font *mGrFont; // owned by the shaper itself
+
+    struct CallbackData {
+        gfxFont           *mFont;
+        gfxGraphiteShaper *mShaper;
+        gfxContext        *mContext;
+    };
 
     CallbackData mCallbackData;
 
-    nsDataHashtable<nsUint32HashKey,TableRec> mTables;
-
     // Convert HTML 'lang' (BCP47) to Graphite language code
     static uint32_t GetGraphiteTagForLang(const nsCString& aLang);
     static nsTHashtable<nsUint32HashKey> sLanguageTags;
 };
 
 #endif /* GFX_GRAPHITESHAPER_H */
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -38,80 +38,50 @@ using namespace mozilla; // for AutoSwap
 using namespace mozilla::unicode; // for Unicode property lookup
 
 /*
  * Creation and destruction; on deletion, release any font tables we're holding
  */
 
 gfxHarfBuzzShaper::gfxHarfBuzzShaper(gfxFont *aFont)
     : gfxFontShaper(aFont),
-      mHBFace(nullptr),
+      mHBFace(aFont->GetFontEntry()->GetHBFace()),
+      mHBFont(nullptr),
       mKernTable(nullptr),
       mHmtxTable(nullptr),
       mNumLongMetrics(0),
       mCmapTable(nullptr),
       mCmapFormat(-1),
       mSubtableOffset(0),
       mUVSTableOffset(0),
       mUseFontGetGlyph(aFont->ProvidesGetGlyph()),
-      mUseFontGlyphWidths(false)
+      mUseFontGlyphWidths(false),
+      mInitialized(false)
 {
 }
 
 gfxHarfBuzzShaper::~gfxHarfBuzzShaper()
 {
-    hb_blob_destroy(mCmapTable);
-    hb_blob_destroy(mHmtxTable);
-    hb_blob_destroy(mKernTable);
-    hb_face_destroy(mHBFace);
-}
-
-/*
- * HarfBuzz callback access to font table data
- */
-
-// callback for HarfBuzz to get a font table (in hb_blob_t form)
-// from the shaper (passed as aUserData)
-static hb_blob_t *
-HBGetTable(hb_face_t *face, hb_tag_t aTag, void *aUserData)
-{
-    gfxHarfBuzzShaper *shaper = static_cast<gfxHarfBuzzShaper*>(aUserData);
-    gfxFont *font = shaper->GetFont();
-
-    // bug 589682 - ignore the GDEF table in buggy fonts (applies to
-    // Italic and BoldItalic faces of Times New Roman)
-    if (aTag == TRUETYPE_TAG('G','D','E','F') &&
-        font->GetFontEntry()->IgnoreGDEF()) {
-        return nullptr;
+    if (mCmapTable) {
+        hb_blob_destroy(mCmapTable);
+    }
+    if (mHmtxTable) {
+        hb_blob_destroy(mHmtxTable);
     }
-
-    // bug 721719 - ignore the GSUB table in buggy fonts (applies to Roboto,
-    // at least on some Android ICS devices; set in gfxFT2FontList.cpp)
-    if (aTag == TRUETYPE_TAG('G','S','U','B') &&
-        font->GetFontEntry()->IgnoreGSUB()) {
-        return nullptr;
+    if (mKernTable) {
+        hb_blob_destroy(mKernTable);
     }
-
-    return font->GetFontTable(aTag);
+    if (mHBFont) {
+        hb_font_destroy(mHBFont);
+    }
+    if (mHBFace) {
+        hb_face_destroy(mHBFace);
+    }
 }
 
-/*
- * HarfBuzz font callback functions; font_data is a ptr to a
- * FontCallbackData struct
- */
-
-struct FontCallbackData {
-    FontCallbackData(gfxHarfBuzzShaper *aShaper, gfxContext *aContext)
-        : mShaper(aShaper), mContext(aContext)
-    { }
-
-    gfxHarfBuzzShaper *mShaper;
-    gfxContext        *mContext;
-};
-
 #define UNICODE_BMP_LIMIT 0x10000
 
 hb_codepoint_t
 gfxHarfBuzzShaper::GetGlyph(hb_codepoint_t unicode,
                             hb_codepoint_t variation_selector) const
 {
     hb_codepoint_t gid;
 
@@ -168,18 +138,18 @@ gfxHarfBuzzShaper::GetGlyph(hb_codepoint
 }
 
 static hb_bool_t
 HBGetGlyph(hb_font_t *font, void *font_data,
            hb_codepoint_t unicode, hb_codepoint_t variation_selector,
            hb_codepoint_t *glyph,
            void *user_data)
 {
-    const FontCallbackData *fcd =
-        static_cast<const FontCallbackData*>(font_data);
+    const gfxHarfBuzzShaper::FontCallbackData *fcd =
+        static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
     *glyph = fcd->mShaper->GetGlyph(unicode, variation_selector);
     return *glyph != 0;
 }
 
 struct HMetricsHeader {
     AutoSwap_PRUint32    tableVersionNumber;
     AutoSwap_PRInt16     ascender;
     AutoSwap_PRInt16     descender;
@@ -233,18 +203,18 @@ gfxHarfBuzzShaper::GetGlyphHAdvance(gfxC
     return FloatToFixed(mFont->FUnitsToDevUnitsFactor() *
                         uint16_t(hmtx->metrics[glyph].advanceWidth));
 }
 
 static hb_position_t
 HBGetGlyphHAdvance(hb_font_t *font, void *font_data,
                    hb_codepoint_t glyph, void *user_data)
 {
-    const FontCallbackData *fcd =
-        static_cast<const FontCallbackData*>(font_data);
+    const gfxHarfBuzzShaper::FontCallbackData *fcd =
+        static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
     return fcd->mShaper->GetGlyphHAdvance(fcd->mContext, glyph);
 }
 
 static hb_bool_t
 HBGetContourPoint(hb_font_t *font, void *font_data,
                   unsigned int point_index, hb_codepoint_t glyph,
                   hb_position_t *x, hb_position_t *y,
                   void *user_data)
@@ -493,17 +463,17 @@ gfxHarfBuzzShaper::GetHKerning(uint16_t 
     // handling words in isolation, the only space characters seen here are
     // the ones artificially added by the textRun code.
     uint32_t spaceGlyph = mFont->GetSpaceGlyph();
     if (aFirstGlyph == spaceGlyph || aSecondGlyph == spaceGlyph) {
         return 0;
     }
 
     if (!mKernTable) {
-        mKernTable = mFont->GetFontTable(TRUETYPE_TAG('k','e','r','n'));
+        mKernTable = mFont->GetFontEntry()->GetFontTable(TRUETYPE_TAG('k','e','r','n'));
         if (!mKernTable) {
             mKernTable = hb_blob_get_empty();
         }
     }
 
     uint32_t len;
     const char* base = hb_blob_get_data(mKernTable, &len);
     if (len < sizeof(KernTableVersion0)) {
@@ -637,18 +607,18 @@ gfxHarfBuzzShaper::GetHKerning(uint16_t 
     return 0;
 }
 
 static hb_position_t
 HBGetHKerning(hb_font_t *font, void *font_data,
               hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
               void *user_data)
 {
-    const FontCallbackData *fcd =
-        static_cast<const FontCallbackData*>(font_data);
+    const gfxHarfBuzzShaper::FontCallbackData *fcd =
+        static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
     return fcd->mShaper->GetHKerning(first_glyph, second_glyph);
 }
 
 /*
  * HarfBuzz unicode property callbacks
  */
 
 static hb_codepoint_t
@@ -846,22 +816,25 @@ gfxHarfBuzzShaper::ShapeText(gfxContext 
                              int32_t          aScript,
                              gfxShapedText   *aShapedText)
 {
     // some font back-ends require this in order to get proper hinted metrics
     if (!mFont->SetupCairoFont(aContext)) {
         return false;
     }
 
-    if (!mHBFace) {
+    mCallbackData.mContext = aContext;
+    gfxFontEntry *entry = mFont->GetFontEntry();
+
+    if (!mInitialized) {
+        mInitialized = true;
+        mCallbackData.mShaper = this;
 
         mUseFontGlyphWidths = mFont->ProvidesGlyphWidths();
 
-        // set up the harfbuzz face etc the first time we use the font
-
         if (!sHBFontFuncs) {
             // static function callback pointers, initialized by the first
             // harfbuzz shaper used
             sHBFontFuncs = hb_font_funcs_create();
             hb_font_funcs_set_glyph_func(sHBFontFuncs, HBGetGlyph,
                                          nullptr, nullptr);
             hb_font_funcs_set_glyph_h_advance_func(sHBFontFuncs,
                                                    HBGetGlyphHAdvance,
@@ -892,21 +865,19 @@ gfxHarfBuzzShaper::ShapeText(gfxContext 
             hb_unicode_funcs_set_compose_func(sHBUnicodeFuncs,
                                               HBUnicodeCompose,
                                               nullptr, nullptr);
             hb_unicode_funcs_set_decompose_func(sHBUnicodeFuncs,
                                                 HBUnicodeDecompose,
                                                 nullptr, nullptr);
         }
 
-        mHBFace = hb_face_create_for_tables(HBGetTable, this, nullptr);
-
         if (!mUseFontGetGlyph) {
             // get the cmap table and find offset to our subtable
-            mCmapTable = mFont->GetFontTable(TRUETYPE_TAG('c','m','a','p'));
+            mCmapTable = entry->GetFontTable(TRUETYPE_TAG('c','m','a','p'));
             if (!mCmapTable) {
                 NS_WARNING("failed to load cmap, glyphs will be missing");
                 return false;
             }
             uint32_t len;
             const uint8_t* data = (const uint8_t*)hb_blob_get_data(mCmapTable, &len);
             bool symbol;
             mCmapFormat = gfxFontUtils::
@@ -915,69 +886,67 @@ gfxHarfBuzzShaper::ShapeText(gfxContext 
                                       &symbol);
         }
 
         if (!mUseFontGlyphWidths) {
             // if font doesn't implement GetGlyphWidth, we will be reading
             // the hmtx table directly;
             // read mNumLongMetrics from hhea table without caching its blob,
             // and preload/cache the hmtx table
-            hb_blob_t *hheaTable =
-                mFont->GetFontTable(TRUETYPE_TAG('h','h','e','a'));
+            gfxFontEntry::AutoTable hheaTable(entry, TRUETYPE_TAG('h','h','e','a'));
             if (hheaTable) {
                 uint32_t len;
                 const HMetricsHeader* hhea =
                     reinterpret_cast<const HMetricsHeader*>
                         (hb_blob_get_data(hheaTable, &len));
                 if (len >= sizeof(HMetricsHeader)) {
                     mNumLongMetrics = hhea->numberOfHMetrics;
                     if (mNumLongMetrics > 0 &&
                         int16_t(hhea->metricDataFormat) == 0) {
                         // no point reading hmtx if number of entries is zero!
                         // in that case, we won't be able to use this font
                         // (this method will return FALSE below if mHmtx is null)
                         mHmtxTable =
-                            mFont->GetFontTable(TRUETYPE_TAG('h','m','t','x'));
+                            entry->GetFontTable(TRUETYPE_TAG('h','m','t','x'));
                         if (hb_blob_get_length(mHmtxTable) <
                             mNumLongMetrics * sizeof(HLongMetric)) {
                             // hmtx table is not large enough for the claimed
                             // number of entries: invalid, do not use.
                             hb_blob_destroy(mHmtxTable);
                             mHmtxTable = nullptr;
                         }
                     }
                 }
             }
-            hb_blob_destroy(hheaTable);
         }
+
+        mHBFont = hb_font_create(mHBFace);
+        hb_font_set_funcs(mHBFont, sHBFontFuncs, &mCallbackData, nullptr);
+        hb_font_set_ppem(mHBFont, mFont->GetAdjustedSize(), mFont->GetAdjustedSize());
+        uint32_t scale = FloatToFixed(mFont->GetAdjustedSize()); // 16.16 fixed-point
+        hb_font_set_scale(mHBFont, scale, scale);
     }
 
     if ((!mUseFontGetGlyph && mCmapFormat <= 0) ||
         (!mUseFontGlyphWidths && !mHmtxTable)) {
         // unable to shape with this font
         return false;
     }
 
-    FontCallbackData fcd(this, aContext);
-    hb_font_t *font = hb_font_create(mHBFace);
-    hb_font_set_funcs(font, sHBFontFuncs, &fcd, nullptr);
-    hb_font_set_ppem(font, mFont->GetAdjustedSize(), mFont->GetAdjustedSize());
-    uint32_t scale = FloatToFixed(mFont->GetAdjustedSize()); // 16.16 fixed-point
-    hb_font_set_scale(font, scale, scale);
+    const gfxFontStyle *style = mFont->GetStyle();
 
     nsAutoTArray<hb_feature_t,20> features;
-
-    gfxFontEntry *entry = mFont->GetFontEntry();
-    const gfxFontStyle *style = mFont->GetStyle();
-
     nsDataHashtable<nsUint32HashKey,uint32_t> mergedFeatures;
 
-    if (MergeFontFeatures(style->featureSettings,
-                      mFont->GetFontEntry()->mFeatureSettings,
-                      aShapedText->DisableLigatures(), mergedFeatures)) {
+    if (MergeFontFeatures(style,
+                          entry->mFeatureSettings,
+                          aShapedText->DisableLigatures(),
+                          entry->FamilyName(),
+                          mergedFeatures))
+    {
         // enumerate result and insert into hb_feature array
         mergedFeatures.Enumerate(AddFeature, &features);
     }
 
     bool isRightToLeft = aShapedText->IsRightToLeft();
     hb_buffer_t *buffer = hb_buffer_create();
     hb_buffer_set_unicode_funcs(buffer, sHBUnicodeFuncs);
     hb_buffer_set_direction(buffer, isRightToLeft ? HB_DIRECTION_RTL :
@@ -1003,28 +972,27 @@ gfxHarfBuzzShaper::ShapeText(gfxContext 
     }
     hb_buffer_set_language(buffer, language);
 
     uint32_t length = aLength;
     hb_buffer_add_utf16(buffer,
                         reinterpret_cast<const uint16_t*>(aText),
                         length, 0, length);
 
-    hb_shape(font, buffer, features.Elements(), features.Length());
+    hb_shape(mHBFont, buffer, features.Elements(), features.Length());
 
     if (isRightToLeft) {
         hb_buffer_reverse(buffer);
     }
 
     nsresult rv = SetGlyphsFromRun(aContext, aShapedText, aOffset, aLength,
                                    aText, buffer);
 
     NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "failed to store glyphs into gfxShapedWord");
     hb_buffer_destroy(buffer);
-    hb_font_destroy(font);
 
     return NS_SUCCEEDED(rv);
 }
 
 #define SMALL_GLYPH_RUN 128 // some testing indicates that 90%+ of text runs
                             // will fit without requiring separate allocation
                             // for charToGlyphArray
 
--- a/gfx/thebes/gfxHarfBuzzShaper.h
+++ b/gfx/thebes/gfxHarfBuzzShaper.h
@@ -13,16 +13,25 @@
 
 #include "harfbuzz/hb.h"
 
 class gfxHarfBuzzShaper : public gfxFontShaper {
 public:
     gfxHarfBuzzShaper(gfxFont *aFont);
     virtual ~gfxHarfBuzzShaper();
 
+    /*
+     * For HarfBuzz font callback functions, font_data is a ptr to a
+     * FontCallbackData struct
+     */
+    struct FontCallbackData {
+        gfxHarfBuzzShaper *mShaper;
+        gfxContext        *mContext;
+    };
+
     virtual bool ShapeText(gfxContext      *aContext,
                            const PRUnichar *aText,
                            uint32_t         aOffset,
                            uint32_t         aLength,
                            int32_t          aScript,
                            gfxShapedText   *aShapedText);
 
     // get a given font table in harfbuzz blob form
@@ -49,19 +58,25 @@ protected:
 
     // retrieve glyph positions, applying advance adjustments and attachments
     // returns results in appUnits
     nscoord GetGlyphPositions(gfxContext *aContext,
                               hb_buffer_t *aBuffer,
                               nsTArray<nsPoint>& aPositions,
                               uint32_t aAppUnitsPerDevUnit);
 
-    // harfbuzz face object, created on first use (caches font tables)
+    // harfbuzz face object: we acquire a reference from the font entry
+    // on shaper creation, and release it in our destructor
     hb_face_t         *mHBFace;
 
+    // size-specific font object, owned by the gfxHarfBuzzShaper
+    hb_font_t         *mHBFont;
+
+    FontCallbackData   mCallbackData;
+
     // Following table references etc are declared "mutable" because the
     // harfbuzz callback functions take a const ptr to the shaper, but
     // wish to cache tables here to avoid repeatedly looking them up
     // in the font.
 
     // Old-style TrueType kern table, if we're not doing GPOS kerning
     mutable hb_blob_t *mKernTable;
 
@@ -82,11 +97,13 @@ protected:
     mutable uint32_t   mUVSTableOffset;
 
     // Whether the font implements GetGlyph, or we should read tables
     // directly
     bool mUseFontGetGlyph;
     // Whether the font implements GetGlyphWidth, or we should read tables
     // directly to get ideal widths
     bool mUseFontGlyphWidths;
+
+    bool mInitialized;
 };
 
 #endif /* GFX_HARFBUZZSHAPER_H */
--- a/gfx/thebes/gfxMacFont.cpp
+++ b/gfx/thebes/gfxMacFont.cpp
@@ -184,23 +184,27 @@ gfxMacFont::InitMetrics()
 
     uint32_t upem = 0;
 
     // try to get unitsPerEm from sfnt head table, to avoid calling CGFont
     // if possible (bug 574368) and because CGFontGetUnitsPerEm does not
     // return the true value for OpenType/CFF fonts (it normalizes to 1000,
     // which then leads to metrics errors when we read the 'hmtx' table to
     // get glyph advances for HarfBuzz, see bug 580863)
-    const uint32_t kHeadTableTag = TRUETYPE_TAG('h','e','a','d');
-    AutoFallibleTArray<uint8_t,sizeof(HeadTable)> headData;
-    if (NS_SUCCEEDED(mFontEntry->GetFontTable(kHeadTableTag, headData)) &&
-        headData.Length() >= sizeof(HeadTable)) {
-        HeadTable *head = reinterpret_cast<HeadTable*>(headData.Elements());
-        upem = head->unitsPerEm;
-    } else {
+    CFDataRef headData =
+        ::CGFontCopyTableForTag(mCGFont, TRUETYPE_TAG('h','e','a','d'));
+    if (headData) {
+        if (size_t(::CFDataGetLength(headData)) >= sizeof(HeadTable)) {
+            const HeadTable *head =
+                reinterpret_cast<const HeadTable*>(::CFDataGetBytePtr(headData));
+            upem = head->unitsPerEm;
+        }
+        ::CFRelease(headData);
+    }
+    if (!upem) {
         upem = ::CGFontGetUnitsPerEm(mCGFont);
     }
 
     if (upem < 16 || upem > 16384) {
         // See http://www.microsoft.com/typography/otspec/head.htm
 #ifdef DEBUG
         char warnBuf[1024];
         sprintf(warnBuf, "Bad font metrics for: %s (invalid unitsPerEm value)",
@@ -343,45 +347,16 @@ gfxMacFont::GetCharWidth(CFDataRef aCmap
         if (::CGFontGetGlyphAdvances(mCGFont, &glyph, 1, &advance)) {
             return advance * aConvFactor;
         }
     }
 
     return 0;
 }
 
-/*static*/ void
-gfxMacFont::DestroyBlobFunc(void* aUserData)
-{
-    ::CFRelease((CFDataRef)aUserData);
-}
-
-hb_blob_t *
-gfxMacFont::GetFontTable(uint32_t aTag)
-{
-    CFDataRef dataRef = ::CGFontCopyTableForTag(mCGFont, aTag);
-    if (dataRef) {
-        return hb_blob_create((const char*)::CFDataGetBytePtr(dataRef),
-                              ::CFDataGetLength(dataRef),
-                              HB_MEMORY_MODE_READONLY,
-                              (void*)dataRef, DestroyBlobFunc);
-    }
-
-    if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
-        // for downloaded fonts, there may be layout tables cached in the entry
-        // even though they're absent from the sanitized platform font
-        hb_blob_t *blob;
-        if (mFontEntry->GetExistingFontTable(aTag, &blob)) {
-            return blob;
-        }
-    }
-
-    return nullptr;
-}
-
 // Try to initialize font metrics via platform APIs (CG/CT),
 // and set mIsValid = TRUE on success.
 // We ONLY call this for local (platform) fonts that are not sfnt format;
 // for sfnts, including ALL downloadable fonts, we prefer to use
 // InitMetricsFromSfntTables and avoid platform APIs.
 void
 gfxMacFont::InitMetricsFromPlatform()
 {
--- a/gfx/thebes/gfxMacFont.h
+++ b/gfx/thebes/gfxMacFont.h
@@ -35,20 +35,16 @@ public:
 
     /* override Measure to add padding for antialiasing */
     virtual RunMetrics Measure(gfxTextRun *aTextRun,
                                uint32_t aStart, uint32_t aEnd,
                                BoundingBoxType aBoundingBoxType,
                                gfxContext *aContextForTightBoundingBox,
                                Spacing *aSpacing);
 
-    // override gfxFont table access function to bypass gfxFontEntry cache,
-    // use CGFontRef API to get direct access to system font data
-    virtual hb_blob_t *GetFontTable(uint32_t aTag);
-
     virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont> GetScaledFont(mozilla::gfx::DrawTarget *aTarget);
 
     virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontCacheSizes*   aSizes) const;
     virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontCacheSizes*   aSizes) const;
 
     virtual FontType GetType() const { return FONT_TYPE_MAC; }
@@ -68,18 +64,16 @@ protected:
     void InitMetrics();
     void InitMetricsFromPlatform();
 
     // Get width and glyph ID for a character; uses aConvFactor
     // to convert font units as returned by CG to actual dimensions
     gfxFloat GetCharWidth(CFDataRef aCmap, PRUnichar aUniChar,
                           uint32_t *aGlyphID, gfxFloat aConvFactor);
 
-    static void DestroyBlobFunc(void* aUserData);
-
     // a weak reference to the CoreGraphics font: this is owned by the
     // MacOSFontEntry, it is not retained or released by gfxMacFont
     CGFontRef             mCGFont;
 
     cairo_font_face_t    *mFontFace;
 
     Metrics               mMetrics;
     uint32_t              mSpaceGlyph;
--- a/gfx/thebes/gfxMacPlatformFontList.h
+++ b/gfx/thebes/gfxMacPlatformFontList.h
@@ -35,33 +35,36 @@ public:
                    bool aIsUserFont, bool aIsLocal);
 
     virtual ~MacOSFontEntry() {
         ::CGFontRelease(mFontRef);
     }
 
     virtual CGFontRef GetFontRef();
 
-    virtual nsresult GetFontTable(uint32_t aTableTag,
-                                  FallibleTArray<uint8_t>& aBuffer);
+    // override gfxFontEntry table access function to bypass table cache,
+    // use CGFontRef API to get direct access to system font data
+    virtual hb_blob_t *GetFontTable(uint32_t aTag) MOZ_OVERRIDE;
 
     virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
                                      FontListSizes*    aSizes) const;
 
     nsresult ReadCMAP();
 
     bool RequiresAATLayout() const { return mRequiresAAT; }
 
     bool IsCFF();
 
 protected:
     virtual gfxFont* CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold);
 
     virtual bool HasFontTable(uint32_t aTableTag);
 
+    static void DestroyBlobFunc(void* aUserData);
+
     CGFontRef mFontRef; // owning reference to the CGFont, released on destruction
 
     bool mFontRefInitialized;
     bool mRequiresAAT;
     bool mIsCFF;
     bool mIsCFFInitialized;
 };
 
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -196,77 +196,58 @@ static const ScriptRange sComplexScripts
                         TRUETYPE_TAG('m','y','m','2'), 0 } },
     { 0x1780, 0x17ff, { TRUETYPE_TAG('k','h','m','r'), 0, 0 } },
     // Khmer Symbols (19e0..19ff) don't seem to need any special shaping
     { 0xaa60, 0xaa7f, { TRUETYPE_TAG('m','y','m','r'),
                         TRUETYPE_TAG('m','y','m','2'), 0 } },
     // Thai seems to be "renderable" without AAT morphing tables
 };
 
-static void
-DestroyBlobFunc(void* aUserData)
-{
-    FallibleTArray<uint8_t>* data = static_cast<FallibleTArray<uint8_t>*>(aUserData);
-    delete data;
-}
-
-// This is only used via MacOSFontEntry::ReadCMAP when checking for layout
-// support; it does not respect the mIgnore* flags on font entries, as those
-// are not relevant here at present.
-static hb_blob_t *
-GetTableForHarfBuzz(hb_face_t *aFace, hb_tag_t aTag, void *aUserData)
-{
-    gfxFontEntry *fe = static_cast<gfxFontEntry*>(aUserData);
-    FallibleTArray<uint8_t>* table = new FallibleTArray<uint8_t>;
-    nsresult rv = fe->GetFontTable(aTag, *table);
-    if (NS_SUCCEEDED(rv)) {
-        return hb_blob_create((const char*)table->Elements(), table->Length(),
-                              HB_MEMORY_MODE_READONLY, table, DestroyBlobFunc);
-    }
-    delete table;
-    return hb_blob_get_empty();
-}
-
 static bool
 SupportsScriptInGSUB(gfxFontEntry* aFontEntry, const hb_tag_t* aScriptTags)
 {
-    hb_face_t *face = hb_face_create_for_tables(GetTableForHarfBuzz,
-                                                aFontEntry, nullptr);
+    hb_face_t *face = aFontEntry->GetHBFace();
+    if (!face) {
+        return false;
+    }
+
     unsigned int index;
     hb_tag_t     chosenScript;
     bool found =
         hb_ot_layout_table_choose_script(face, TRUETYPE_TAG('G','S','U','B'),
                                          aScriptTags, &index, &chosenScript);
     hb_face_destroy(face);
+
     return found && chosenScript != TRUETYPE_TAG('D','F','L','T');
 }
 
 nsresult
 MacOSFontEntry::ReadCMAP()
 {
     // attempt this once, if errors occur leave a blank cmap
     if (mCharacterMap) {
         return NS_OK;
     }
 
     nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
 
     uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
-    nsresult rv;
 
-    AutoFallibleTArray<uint8_t,16384> cmap;
-    rv = GetFontTable(kCMAP, cmap);
+    AutoTable cmapTable(this, kCMAP);
+    if (!cmapTable) {
+        return NS_OK; // leave it empty
+    }
 
     bool unicodeFont = false, symbolFont = false; // currently ignored
 
-    if (NS_SUCCEEDED(rv)) {
-        rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
-                                    *charmap, mUVSOffset,
-                                    unicodeFont, symbolFont);
-    }
+    uint32_t cmapLen;
+    const char* cmapData = hb_blob_get_data(cmapTable, &cmapLen);
+    nsresult rv = gfxFontUtils::ReadCMAP((const uint8_t*)cmapData, cmapLen,
+                                         *charmap, mUVSOffset,
+                                         unicodeFont, symbolFont);
   
     if (NS_SUCCEEDED(rv) && !HasGraphiteTables()) {
         // We assume a Graphite font knows what it's doing,
         // and provides whatever shaping is needed for the
         // characters it supports, so only check/clear the
         // complex-script ranges for non-Graphite fonts
 
         // for layout support, check for the presence of mort/morx and/or
@@ -390,43 +371,39 @@ MacOSFontEntry::GetFontRef()
     if (!mFontRefInitialized) {
         mFontRefInitialized = true;
         NSString *psname = GetNSStringForString(mName);
         mFontRef = ::CGFontCreateWithFontName(CFStringRef(psname));
     }
     return mFontRef;
 }
 
-nsresult
-MacOSFontEntry::GetFontTable(uint32_t aTableTag,
-                             FallibleTArray<uint8_t>& aBuffer)
+/*static*/ void
+MacOSFontEntry::DestroyBlobFunc(void* aUserData)
 {
-    nsAutoreleasePool localPool;
+    ::CFRelease((CFDataRef)aUserData);
+}
 
+hb_blob_t *
+MacOSFontEntry::GetFontTable(uint32_t aTag)
+{
     CGFontRef fontRef = GetFontRef();
     if (!fontRef) {
-        return NS_ERROR_FAILURE;
+        return nullptr;
     }
 
-    CFDataRef tableData = ::CGFontCopyTableForTag(fontRef, aTableTag);
-    if (!tableData) {
-        return NS_ERROR_FAILURE;
+    CFDataRef dataRef = ::CGFontCopyTableForTag(fontRef, aTag);
+    if (dataRef) {
+        return hb_blob_create((const char*)::CFDataGetBytePtr(dataRef),
+                              ::CFDataGetLength(dataRef),
+                              HB_MEMORY_MODE_READONLY,
+                              (void*)dataRef, DestroyBlobFunc);
     }
 
-    nsresult rval = NS_OK;
-    CFIndex dataLength = ::CFDataGetLength(tableData);
-    if (aBuffer.AppendElements(dataLength)) {
-        ::CFDataGetBytes(tableData, ::CFRangeMake(0, dataLength),
-                         aBuffer.Elements());
-    } else {
-        rval = NS_ERROR_OUT_OF_MEMORY;
-    }
-    ::CFRelease(tableData);
-
-    return rval;
+    return nullptr;
 }
 
 bool
 MacOSFontEntry::HasFontTable(uint32_t aTableTag)
 {
     nsAutoreleasePool localPool;
 
     CGFontRef fontRef = GetFontRef();
@@ -635,32 +612,36 @@ gfxSingleFaceMacFontFamily::LocalizedNam
 
     // failed to get localized name, just use the canonical one
     aLocalizedName = mName;
 }
 
 void
 gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList)
 {
-    if (mOtherFamilyNamesInitialized)
+    if (mOtherFamilyNamesInitialized) {
         return;
+    }
 
     gfxFontEntry *fe = mAvailableFonts[0];
-    if (!fe)
+    if (!fe) {
         return;
+    }
 
     const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
-    AutoFallibleTArray<uint8_t,8192> buffer;
 
-    if (fe->GetFontTable(kNAME, buffer) != NS_OK)
+    gfxFontEntry::AutoTable nameTable(fe, kNAME);
+    if (!nameTable) {
         return;
+    }
 
     mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList,
-                                                       buffer,
+                                                       nameTable,
                                                        true);
+
     mOtherFamilyNamesInitialized = true;
 }
 
 
 /* gfxMacPlatformFontList */
 #pragma mark-
 
 gfxMacPlatformFontList::gfxMacPlatformFontList() :
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -310,17 +310,18 @@ gfxFcFontEntry::ShouldUseHarfBuzz(int32_
 
 class gfxSystemFcFontEntry : public gfxFcFontEntry {
 public:
     // For memory efficiency, aFontPattern should be a font pattern,
     // not a fully resolved pattern.
     gfxSystemFcFontEntry(cairo_font_face_t *aFontFace,
                          FcPattern *aFontPattern,
                          const nsAString& aName)
-        : gfxFcFontEntry(aName), mFontFace(aFontFace)
+        : gfxFcFontEntry(aName), mFontFace(aFontFace),
+          mFTFace(nullptr), mFTFaceInitialized(false)
     {
         cairo_font_face_reference(mFontFace);
         cairo_font_face_set_user_data(mFontFace, &sFontEntryKey, this, NULL);
         mPatterns.AppendElement();
         // mPatterns is an nsAutoTArray with 1 space always available, so the
         // AppendElement always succeeds.
         mPatterns[0] = aFontPattern;
 
@@ -331,20 +332,99 @@ public:
         }
     }
 
     ~gfxSystemFcFontEntry()
     {
         cairo_font_face_set_user_data(mFontFace, &sFontEntryKey, NULL, NULL);
         cairo_font_face_destroy(mFontFace);
     }
+
+    virtual void ForgetHBFace();
+    virtual void ReleaseGrFace(gr_face* aFace);
+
+protected:
+    virtual nsresult
+    CopyFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
+
+    void MaybeReleaseFTFace();
+
 private:
     cairo_font_face_t *mFontFace;
+    FT_Face            mFTFace;
+    bool               mFTFaceInitialized;
 };
 
+nsresult
+gfxSystemFcFontEntry::CopyFontTable(uint32_t aTableTag,
+                                    FallibleTArray<uint8_t>& aBuffer)
+{
+    if (!mFTFaceInitialized) {
+        mFTFaceInitialized = true;
+        FcChar8 *filename;
+        if (FcPatternGetString(mPatterns[0], FC_FILE, 0, &filename) != FcResultMatch) {
+            return NS_ERROR_FAILURE;
+        }
+        int index;
+        if (FcPatternGetInteger(mPatterns[0], FC_INDEX, 0, &index) != FcResultMatch) {
+            index = 0; // default to 0 if not found in pattern
+        }
+        if (FT_New_Face(gfxPangoFontGroup::GetFTLibrary(),
+                        (const char*)filename, index, &mFTFace) != 0) {
+            return NS_ERROR_FAILURE;
+        }
+    }
+
+    if (!mFTFace) {
+        return NS_ERROR_NOT_AVAILABLE;
+    }
+
+    FT_ULong length = 0;
+    if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, nullptr, &length) != 0) {
+        return NS_ERROR_NOT_AVAILABLE;
+    }
+    if (!aBuffer.SetLength(length)) {
+        return NS_ERROR_OUT_OF_MEMORY;
+    }
+    if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, aBuffer.Elements(), &length) != 0) {
+        aBuffer.Clear();
+        return NS_ERROR_FAILURE;
+    }
+
+    return NS_OK;
+}
+
+void
+gfxSystemFcFontEntry::MaybeReleaseFTFace()
+{
+    // don't release if either HB or Gr face still exists
+    if (mHBFace || mGrFace) {
+        return;
+    }
+    if (mFTFace) {
+        FT_Done_Face(mFTFace);
+        mFTFace = nullptr;
+    }
+    mFTFaceInitialized = false;
+}
+
+void
+gfxSystemFcFontEntry::ForgetHBFace()
+{
+    gfxFontEntry::ForgetHBFace();
+    MaybeReleaseFTFace();        
+}
+
+void
+gfxSystemFcFontEntry::ReleaseGrFace(gr_face* aFace)
+{
+    gfxFontEntry::ReleaseGrFace(aFace);
+    MaybeReleaseFTFace();        
+}
+
 // A namespace for @font-face family names in FcPatterns so that fontconfig
 // aliases do not pick up families from @font-face rules and so that
 // fontconfig rules can distinguish between web fonts and platform fonts.
 // http://lists.freedesktop.org/archives/fontconfig/2008-November/003037.html
 #define FONT_FACE_FAMILY_PREFIX "@font-face:"
 
 /**
  * gfxUserFcFontEntry:
@@ -509,18 +589,17 @@ public:
     // Returns true on success
     bool SetCairoFace(cairo_font_face_t *aFace);
 
     // Returns a PangoCoverage owned by the FontEntry.  The caller must add a
     // reference if it wishes to keep the PangoCoverage longer than the
     // lifetime of the FontEntry.
     PangoCoverage *GetPangoCoverage();
 
-    virtual nsresult
-    GetFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
+    virtual hb_blob_t* GetFontTable(uint32_t aTableTag) MOZ_OVERRIDE;
 
 protected:
     void InitPattern();
 
     // mFontData holds the data used to instantiate the FT_Face;
     // this has to persist until we are finished with the face,
     // then be released with NS_Free().
     const uint8_t* mFontData;
@@ -727,37 +806,43 @@ gfxDownloadedFcFontEntry::GetPangoCovera
     NS_ASSERTION(mPatterns.Length() != 0,
                  "Can't get coverage without a pattern!");
     if (!mPangoCoverage) {
         mPangoCoverage.own(NewPangoCoverage(mPatterns[0]));
     }
     return mPangoCoverage;
 }
 
-nsresult
-gfxDownloadedFcFontEntry::GetFontTable(uint32_t aTableTag,
-                                       FallibleTArray<uint8_t>& aBuffer)
+static int
+DirEntryCmp(const void* aKey, const void* aItem)
+{
+    int32_t tag = *static_cast<const int32_t*>(aKey);
+    const TableDirEntry* entry = static_cast<const TableDirEntry*>(aItem);
+    return tag - int32_t(entry->tag);
+}
+
+hb_blob_t *
+gfxDownloadedFcFontEntry::GetFontTable(uint32_t aTableTag)
 {
-    FT_ULong length = 0;
-    FT_Error error = FT_Load_Sfnt_Table(mFace, aTableTag, 0, nullptr, &length);
-    if (error) {
-        return NS_ERROR_NOT_AVAILABLE;
+    // The entry already owns the (sanitized) sfnt data in mFontData,
+    // so we can just return a blob that "wraps" the appropriate chunk of it.
+    // The blob should not attempt to free its data, as the entire sfnt data
+    // will be freed when the font entry is deleted.
+    const SFNTHeader* header = reinterpret_cast<const SFNTHeader*>(mFontData);
+    const TableDirEntry* dir = reinterpret_cast<const TableDirEntry*>(header + 1);
+    dir = static_cast<const TableDirEntry*>
+        (bsearch(&aTableTag, dir, header->numTables, sizeof(TableDirEntry),
+                 DirEntryCmp));
+    if (dir) {
+        return hb_blob_create(reinterpret_cast<const char*>(mFontData) +
+                                  dir->offset, dir->length,
+                              HB_MEMORY_MODE_READONLY, nullptr, nullptr);
+
     }
-
-    if (!aBuffer.SetLength(length)) {
-        return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    error = FT_Load_Sfnt_Table(mFace, aTableTag, 0, aBuffer.Elements(), &length);
-    if (error) {
-        aBuffer.Clear();
-        return NS_ERROR_FAILURE;
-    }
-
-    return NS_OK;
+    return nullptr;
 }
 
 /*
  * gfxFcFont
  *
  * This is a gfxFont implementation using a CAIRO_FONT_TYPE_FT
  * cairo_scaled_font created from an FcPattern.
  */
--- a/gfx/thebes/gfxPangoFonts.h
+++ b/gfx/thebes/gfxPangoFonts.h
@@ -90,12 +90,13 @@ private:
 
     gfxFloat GetSizeAdjustFactor()
     {
         if (mFontSets.Length() == 0)
             GetBaseFontSet();
         return mSizeAdjustFactor;
     }
 
+    friend class gfxSystemFcFontEntry;
     static FT_Library GetFTLibrary();
 };
 
 #endif /* GFX_PANGOFONTS_H */
--- a/gfx/thebes/gfxSVGGlyphs.cpp
+++ b/gfx/thebes/gfxSVGGlyphs.cpp
@@ -55,54 +55,46 @@
 #include "nsXMLContentSink.h"
 #include "nsNetUtil.h"
 #include "nsIInputStream.h"
 #include "nsStringStream.h"
 #include "nsStreamUtils.h"
 #include "nsIPrincipal.h"
 #include "Element.h"
 #include "nsSVGUtils.h"
+#include "harfbuzz/hb.h"
 
 #define SVG_CONTENT_TYPE NS_LITERAL_CSTRING("image/svg+xml")
 #define UTF8_CHARSET NS_LITERAL_CSTRING("utf-8")
 
 typedef mozilla::dom::Element Element;
 
 mozilla::gfx::UserDataKey gfxTextObjectPaint::sUserDataKey;
 
 const float gfxSVGGlyphs::SVG_UNITS_PER_EM = 1000.0f;
 
 const gfxRGBA SimpleTextObjectPaint::sZero = gfxRGBA(0.0f, 0.0f, 0.0f, 0.0f);
 
-gfxSVGGlyphs::gfxSVGGlyphs(FallibleTArray<uint8_t>& aSVGTable,
-                           const FallibleTArray<uint8_t>& aCmapTable)
+gfxSVGGlyphs::gfxSVGGlyphs(hb_blob_t *aSVGTable, hb_blob_t *aCmapTable)
 {
-    mSVGData.SwapElements(aSVGTable);
+    mSVGData = aSVGTable;
 
-    mHeader = reinterpret_cast<Header*>(mSVGData.Elements());
-    UnmangleHeaders();
+    const char* svgData = hb_blob_get_data(mSVGData, nullptr);
+    mHeader = reinterpret_cast<const Header*>(svgData);
+    mIndex = reinterpret_cast<const IndexEntry*>(svgData + sizeof(Header));
 
     mGlyphDocs.Init();
     mGlyphIdMap.Init();
     mCmapData = aCmapTable;
 }
 
-void
-gfxSVGGlyphs::UnmangleHeaders()
+gfxSVGGlyphs::~gfxSVGGlyphs()
 {
-    mHeader->mIndexLength = mozilla::NativeEndian::swapFromBigEndian(mHeader->mIndexLength);
-
-    mIndex = reinterpret_cast<IndexEntry*>(mSVGData.Elements() + sizeof(Header));
-
-    for (uint16_t i = 0; i < mHeader->mIndexLength; i++) {
-        mIndex[i].mStartGlyph = mozilla::NativeEndian::swapFromBigEndian(mIndex[i].mStartGlyph);
-        mIndex[i].mEndGlyph = mozilla::NativeEndian::swapFromBigEndian(mIndex[i].mEndGlyph);
-        mIndex[i].mDocOffset = mozilla::NativeEndian::swapFromBigEndian(mIndex[i].mDocOffset);
-        mIndex[i].mDocLength = mozilla::NativeEndian::swapFromBigEndian(mIndex[i].mDocLength);
-    }
+    hb_blob_destroy(mSVGData);
+    hb_blob_destroy(mCmapData);
 }
 
 /*
  * Comparison operator for finding a range containing a given glyph ID. Simply
  *   checks whether |key| is less (greater) than every element of |range|, in
  *   which case return |key| < |range| (|key| > |range|). Otherwise |key| is in
  *   |range|, in which case return equality.
  * The total ordering here is guaranteed by
@@ -112,36 +104,37 @@ gfxSVGGlyphs::UnmangleHeaders()
  *        sets intersecting of size > 1 -- so... don't do that)
  */
 /* static */ int
 gfxSVGGlyphs::CompareIndexEntries(const void *_key, const void *_entry)
 {
     const uint32_t key = *(uint32_t*)_key;
     const IndexEntry *entry = (const IndexEntry*)_entry;
 
-    if (key < entry->mStartGlyph) return -1;
-    if (key >= entry->mEndGlyph) return 1;
+    if (key < uint16_t(entry->mStartGlyph)) return -1;
+    if (key >= uint16_t(entry->mEndGlyph)) return 1;
     return 0;
 }
 
 gfxSVGGlyphsDocument *
 gfxSVGGlyphs::FindOrCreateGlyphsDocument(uint32_t aGlyphId)
 {
     IndexEntry *entry = (IndexEntry*)bsearch(&aGlyphId, mIndex,
-                                             mHeader->mIndexLength,
+                                             uint16_t(mHeader->mIndexLength),
                                              sizeof(IndexEntry),
                                              CompareIndexEntries);
     if (!entry) {
         return nullptr;
     }
 
     gfxSVGGlyphsDocument *result = mGlyphDocs.Get(entry->mDocOffset);
 
     if (!result) {
-        result = new gfxSVGGlyphsDocument(mSVGData.Elements() + entry->mDocOffset,
+        const uint8_t *data = (const uint8_t*)hb_blob_get_data(mSVGData, nullptr);
+        result = new gfxSVGGlyphsDocument(data + entry->mDocOffset,
                                           entry->mDocLength, mCmapData);
         mGlyphDocs.Put(entry->mDocOffset, result);
     }
 
     return result;
 }
 
 nsresult
@@ -188,18 +181,17 @@ gfxSVGGlyphsDocument::SetupPresentation(
 
 /**
  * Walk the DOM tree to find all glyph elements and insert them into the lookup
  * table
  * @param aElem The element to search from
  * @param aCmapTable Buffer containing the raw cmap table data
  */
 void
-gfxSVGGlyphsDocument::FindGlyphElements(Element *aElem,
-                                        const FallibleTArray<uint8_t> &aCmapTable)
+gfxSVGGlyphsDocument::FindGlyphElements(Element *aElem, hb_blob_t *aCmapTable)
 {
     for (nsIContent *child = aElem->GetLastChild(); child;
             child = child->GetPreviousSibling()) {
         if (!child->IsElement()) {
             continue;
         }
         FindGlyphElements(child->AsElement(), aCmapTable);
     }
@@ -265,18 +257,18 @@ gfxSVGGlyphs::HasSVGGlyph(uint32_t aGlyp
 }
 
 Element *
 gfxSVGGlyphsDocument::GetGlyphElement(uint32_t aGlyphId)
 {
     return mGlyphIdMap.Get(aGlyphId);
 }
 
-gfxSVGGlyphsDocument::gfxSVGGlyphsDocument(uint8_t *aBuffer, uint32_t aBufLen,
-                                           const FallibleTArray<uint8_t>& aCmapTable)
+gfxSVGGlyphsDocument::gfxSVGGlyphsDocument(const uint8_t *aBuffer, uint32_t aBufLen,
+                                           hb_blob_t *aCmapTable)
 {
     mGlyphIdMap.Init();
     ParseDocument(aBuffer, aBufLen);
     if (!mDocument) {
         NS_WARNING("Could not parse SVG glyphs document");
         return;
     }
 
@@ -291,17 +283,17 @@ gfxSVGGlyphsDocument::gfxSVGGlyphsDocume
         NS_WARNING("Couldn't setup presentation for SVG glyphs document");
         return;
     }
 
     FindGlyphElements(root, aCmapTable);
 }
 
 static nsresult
-CreateBufferedStream(uint8_t *aBuffer, uint32_t aBufLen,
+CreateBufferedStream(const uint8_t *aBuffer, uint32_t aBufLen,
                      nsCOMPtr<nsIInputStream> &aResult)
 {
     nsCOMPtr<nsIInputStream> stream;
     nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream),
                                         reinterpret_cast<const char *>(aBuffer),
                                         aBufLen, NS_ASSIGNMENT_DEPEND);
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -313,17 +305,17 @@ CreateBufferedStream(uint8_t *aBuffer, u
     }
 
     aResult = stream;
 
     return NS_OK;
 }
 
 nsresult
-gfxSVGGlyphsDocument::ParseDocument(uint8_t *aBuffer, uint32_t aBufLen)
+gfxSVGGlyphsDocument::ParseDocument(const uint8_t *aBuffer, uint32_t aBufLen)
 {
     // Mostly pulled from nsDOMParser::ParseFromStream
 
     nsCOMPtr<nsIInputStream> stream;
     nsresult rv = CreateBufferedStream(aBuffer, aBufLen, stream);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIPrincipal> principal =
@@ -407,26 +399,27 @@ gfxSVGGlyphsDocument::InsertGlyphId(Elem
     if (NS_FAILED(rv)) {
         return;
     }
 
     mGlyphIdMap.Put(glyphId, aGlyphElement);
 }
 
 void
-gfxSVGGlyphsDocument::InsertGlyphChar(Element *aGlyphElement,
-                                      const FallibleTArray<uint8_t> &aCmapTable)
+gfxSVGGlyphsDocument::InsertGlyphChar(Element *aGlyphElement, hb_blob_t *aCmapTable)
 {
     nsAutoString glyphChar;
     if (!aGlyphElement->GetAttr(kNameSpaceID_None, nsGkAtoms::glyphchar, glyphChar)) {
         return;
     }
 
     uint32_t varSelector;
 
+    // XXX jfkthame
+    // This will not handle surrogate pairs properly!
     switch (glyphChar.Length()) {
         case 0:
             NS_WARNING("glyphchar is empty");
             return;
         case 1:
             varSelector = 0;
             break;
         case 2:
@@ -434,18 +427,19 @@ gfxSVGGlyphsDocument::InsertGlyphChar(El
                 varSelector = glyphChar.CharAt(1);
                 break;
             }
         default:
             NS_WARNING("glyphchar contains more than one character");
             return;
     }
 
-    uint32_t glyphId = gfxFontUtils::MapCharToGlyph(aCmapTable.Elements(),
-                                                    aCmapTable.Length(),
+    uint32_t len;
+    const uint8_t *data = (const uint8_t*)hb_blob_get_data(aCmapTable, &len);
+    uint32_t glyphId = gfxFontUtils::MapCharToGlyph(data, len,
                                                     glyphChar.CharAt(0),
                                                     varSelector);
 
     if (glyphId) {
         mGlyphIdMap.Put(glyphId, aGlyphElement);
     }
 }
 
--- a/gfx/thebes/gfxSVGGlyphs.h
+++ b/gfx/thebes/gfxSVGGlyphs.h
@@ -60,38 +60,36 @@
  *   mappings to be drawn by gfxSVGGlyphs
  */
 class gfxSVGGlyphsDocument
 {
     typedef mozilla::dom::Element Element;
     typedef gfxFont::DrawMode DrawMode;
 
 public:
-    gfxSVGGlyphsDocument(uint8_t *aBuffer, uint32_t aBufLen,
-                         const FallibleTArray<uint8_t>& aCmapTable);
+    gfxSVGGlyphsDocument(const uint8_t *aBuffer, uint32_t aBufLen,
+                         hb_blob_t *aCmapTable);
 
     Element *GetGlyphElement(uint32_t aGlyphId);
 
     ~gfxSVGGlyphsDocument() {
         if (mViewer) {
             mViewer->Destroy();
         }
     }
 
 private:
-    nsresult ParseDocument(uint8_t *aBuffer, uint32_t aBufLen);
+    nsresult ParseDocument(const uint8_t *aBuffer, uint32_t aBufLen);
 
     nsresult SetupPresentation();
 
-    void FindGlyphElements(Element *aElement,
-                           const FallibleTArray<uint8_t> &aCmapTable);
+    void FindGlyphElements(Element *aElement, hb_blob_t *aCmapTable);
 
     void InsertGlyphId(Element *aGlyphElement);
-    void InsertGlyphChar(Element *aGlyphElement,
-                         const FallibleTArray<uint8_t> &aCmapTable);
+    void InsertGlyphChar(Element *aGlyphElement, hb_blob_t *aCmapTable);
 
     nsCOMPtr<nsIDocument> mDocument;
     nsCOMPtr<nsIContentViewer> mViewer;
     nsCOMPtr<nsIPresShell> mPresShell;
 
     nsBaseHashtable<nsUint32HashKey, Element*, Element*> mGlyphIdMap;
 };
 
@@ -108,24 +106,27 @@ private:
     typedef gfxFont::DrawMode DrawMode;
 
 public:
     static const float SVG_UNITS_PER_EM;
 
     /**
      * @param aSVGTable The SVG table from the OpenType font
      * @param aCmapTable The CMAP table from the OpenType font
+     *
+     * The gfxSVGGlyphs object takes over ownership of the blob references
+     * that are passed in, and will hb_blob_destroy() them when finished;
+     * the caller should -not- destroy these references.
      */
-    gfxSVGGlyphs(FallibleTArray<uint8_t>& aSVGTable,
-                 const FallibleTArray<uint8_t>& aCmapTable);
+    gfxSVGGlyphs(hb_blob_t *aSVGTable, hb_blob_t *aCmapTable);
 
     /**
-     * Big- to little-endian conversion for headers
+     * Releases our references to the SVG and cmap tables.
      */
-    void UnmangleHeaders();
+    ~gfxSVGGlyphs();
 
     /**
      * Find the |gfxSVGGlyphsDocument| containing an SVG glyph for |aGlyphId|.
      * If |aGlyphId| does not map to an SVG document, return null.
      * If a |gfxSVGGlyphsDocument| has not been created for the document, create one.
      */
     gfxSVGGlyphsDocument *FindOrCreateGlyphsDocument(uint32_t aGlyphId);
 
@@ -152,29 +153,29 @@ public:
                          gfxRect *aResult);
 
 private:
     Element *GetGlyphElement(uint32_t aGlyphId);
 
     nsClassHashtable<nsUint32HashKey, gfxSVGGlyphsDocument> mGlyphDocs;
     nsBaseHashtable<nsUint32HashKey, Element*, Element*> mGlyphIdMap;
 
-    FallibleTArray<uint8_t> mSVGData;
-    FallibleTArray<uint8_t> mCmapData;
+    hb_blob_t *mSVGData;
+    hb_blob_t *mCmapData;
 
-    struct Header {
-        uint16_t mVersion;
-        uint16_t mIndexLength;
+    const struct Header {
+        mozilla::AutoSwap_PRUint16 mVersion;
+        mozilla::AutoSwap_PRUint16 mIndexLength;
     } *mHeader;
 
-    struct IndexEntry {
-        uint16_t mStartGlyph;
-        uint16_t mEndGlyph;
-        uint32_t mDocOffset;
-        uint32_t mDocLength;
+    const struct IndexEntry {
+        mozilla::AutoSwap_PRUint16 mStartGlyph;
+        mozilla::AutoSwap_PRUint16 mEndGlyph;
+        mozilla::AutoSwap_PRUint32 mDocOffset;
+        mozilla::AutoSwap_PRUint32 mDocLength;
     } *mIndex;
 
     static int CompareIndexEntries(const void *_a, const void *_b);
 };
 
 /**
  * Used for trickling down paint information through to SVG glyphs.
  * Will be extended in later patch.
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -1021,19 +1021,18 @@ XPCShellEnvironment::Init()
                                               principal, 0,
                                               JS::SystemZone,
                                               getter_AddRefs(holder));
     if (NS_FAILED(rv)) {
         NS_ERROR("InitClassesWithNewWrappedGlobal failed!");
         return false;
     }
 
-    JS::Rooted<JSObject*> globalObj(cx);
-    rv = holder->GetJSObject(globalObj.address());
-    if (NS_FAILED(rv)) {
+    JS::Rooted<JSObject*> globalObj(cx, holder->GetJSObject());
+    if (!globalObj) {
         NS_ERROR("Failed to get global JSObject!");
         return false;
     }
 
     backstagePass->SetGlobalObject(globalObj);
 
     {
         JSAutoRequest ar(cx);
--- a/js/xpconnect/idl/nsIXPConnect.idl
+++ b/js/xpconnect/idl/nsIXPConnect.idl
@@ -58,20 +58,20 @@ interface nsIXPCSecurityManager;
 interface nsIPrincipal;
 
 %{C++
 class nsCycleCollectionTraversalCallback;
 class nsScriptObjectTracer;
 %}
 
 /***************************************************************************/
-[uuid(8916a320-d118-11d3-8f3a-0010a4e73d9a)]
+[uuid(909e8641-7c54-4dff-9b94-ba631f057b33)]
 interface nsIXPConnectJSObjectHolder : nsISupports
 {
-    readonly attribute JSObjectPtr      JSObject;
+    [notxpcom, nostdcall] JSObjectPtr GetJSObject();
 };
 
 [uuid(92e98688-0154-4b65-971b-0d4afe8fd7cb)]
 interface nsIXPConnectWrappedNative : nsIXPConnectJSObjectHolder
 {
     /* attribute 'JSObject' inherited from nsIXPConnectJSObjectHolder */
     readonly attribute nsISupports      Native;
     readonly attribute JSObjectPtr      JSObjectPrototype;
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -541,50 +541,48 @@ mozJSComponentLoader::LoadModule(FileLoc
     nsCOMPtr<nsIComponentManager> cm;
     rv = NS_GetComponentManager(getter_AddRefs(cm));
     if (NS_FAILED(rv))
         return NULL;
 
     JSCLContextHelper cx(mContext);
     JSAutoCompartment ac(cx, entry->obj);
 
-    JSObject* cm_jsobj;
     nsCOMPtr<nsIXPConnectJSObjectHolder> cm_holder;
     rv = xpc->WrapNative(cx, entry->obj, cm,
                          NS_GET_IID(nsIComponentManager),
                          getter_AddRefs(cm_holder));
 
     if (NS_FAILED(rv)) {
 #ifdef DEBUG_shaver
         fprintf(stderr, "WrapNative(%p,%p,nsIComponentManager) failed: %x\n",
                 (void *)(JSContext*)cx, (void *)mCompMgr, rv);
 #endif
         return NULL;
     }
 
-    rv = cm_holder->GetJSObject(&cm_jsobj);
-    if (NS_FAILED(rv)) {
+    JSObject* cm_jsobj = cm_holder->GetJSObject();
+    if (!cm_jsobj) {
 #ifdef DEBUG_shaver
         fprintf(stderr, "GetJSObject of ComponentManager failed\n");
 #endif
         return NULL;
     }
 
-    JSObject* file_jsobj;
     nsCOMPtr<nsIXPConnectJSObjectHolder> file_holder;
     rv = xpc->WrapNative(cx, entry->obj, file,
                          NS_GET_IID(nsIFile),
                          getter_AddRefs(file_holder));
 
     if (NS_FAILED(rv)) {
         return NULL;
     }
 
-    rv = file_holder->GetJSObject(&file_jsobj);
-    if (NS_FAILED(rv)) {
+    JSObject* file_jsobj = file_holder->GetJSObject();
+    if (!file_jsobj) {
         return NULL;
     }
 
     JSCLAutoErrorReporterSetter aers(cx, mozJSLoaderErrorReporter);
 
     RootedValue NSGetFactory_val(cx);
     if (!JS_GetProperty(cx, entry->obj, "NSGetFactory", NSGetFactory_val.address()) ||
         JSVAL_IS_VOID(NSGetFactory_val)) {
@@ -657,17 +655,17 @@ mozJSComponentLoader::FindTargetObject(J
         nsAXPCNativeCallContext *cc = nullptr;
         rv = xpc->GetCurrentNativeCallContext(&cc);
         NS_ENSURE_SUCCESS(rv, rv);
 
         nsCOMPtr<nsIXPConnectWrappedNative> wn;
         rv = cc->GetCalleeWrapper(getter_AddRefs(wn));
         NS_ENSURE_SUCCESS(rv, rv);
 
-        wn->GetJSObject(targetObject.address());
+        targetObject = wn->GetJSObject();
         if (!targetObject) {
             NS_ERROR("null calling object");
             return NS_ERROR_FAILURE;
         }
 
         targetObject = JS_GetGlobalForObject(aCx, targetObject);
     }
 
@@ -740,36 +738,34 @@ mozJSComponentLoader::PrepareObjectForLo
         rv = xpc->InitClassesWithNewWrappedGlobal(aCx,
                                                   static_cast<nsIGlobalObject *>(backstagePass),
                                                   mSystemPrincipal,
                                                   0,
                                                   JS::SystemZone,
                                                   getter_AddRefs(holder));
         NS_ENSURE_SUCCESS(rv, nullptr);
 
-        RootedObject global(aCx);
-        rv = holder->GetJSObject(global.address());
-        NS_ENSURE_SUCCESS(rv, nullptr);
+        RootedObject global(aCx, holder->GetJSObject());
+        NS_ENSURE_TRUE(global, nullptr);
 
         backstagePass->SetGlobalObject(global);
 
         JSAutoCompartment ac(aCx, global);
         if (!JS_DefineFunctions(aCx, global, gGlobalFun) ||
             !JS_DefineProfilingFunctions(aCx, global)) {
             return nullptr;
         }
 
         if (aReuseLoaderGlobal) {
             mLoaderGlobal = holder;
         }
     }
 
-    RootedObject obj(aCx);
-    rv = holder->GetJSObject(obj.address());
-    NS_ENSURE_SUCCESS(rv, nullptr);
+    RootedObject obj(aCx, holder->GetJSObject());
+    NS_ENSURE_TRUE(obj, nullptr);
 
     JSAutoCompartment ac(aCx, obj);
 
     if (aReuseLoaderGlobal) {
         // If we're reusing the loader global, we don't actually use the
         // global, but rather we use a different object as the 'this' object.
         obj = JS_NewObject(aCx, &kFakeBackstagePassJSClass, nullptr, nullptr);
         NS_ENSURE_TRUE(obj, nullptr);
@@ -790,19 +786,18 @@ mozJSComponentLoader::PrepareObjectForLo
         *aRealFile = true;
 
         nsCOMPtr<nsIXPConnectJSObjectHolder> locationHolder;
         rv = xpc->WrapNative(aCx, obj, aComponentFile,
                              NS_GET_IID(nsIFile),
                              getter_AddRefs(locationHolder));
         NS_ENSURE_SUCCESS(rv, nullptr);
 
-        RootedObject locationObj(aCx);
-        rv = locationHolder->GetJSObject(locationObj.address());
-        NS_ENSURE_SUCCESS(rv, nullptr);
+        RootedObject locationObj(aCx, locationHolder->GetJSObject());
+        NS_ENSURE_TRUE(locationObj, nullptr);
 
         if (!JS_DefineProperty(aCx, obj, "__LOCATION__",
                                JS::ObjectValue(*locationObj),
                                nullptr, nullptr, 0)) {
             return nullptr;
         }
     }
 
@@ -1135,18 +1130,18 @@ mozJSComponentLoader::ClearModules(const
 void
 mozJSComponentLoader::UnloadModules()
 {
     mInitialized = false;
 
     if (mLoaderGlobal) {
         MOZ_ASSERT(mReuseLoaderGlobal, "How did this happen?");
 
-        RootedObject global(mContext);
-        if (NS_SUCCEEDED(mLoaderGlobal->GetJSObject(global.address()))) {
+        RootedObject global(mContext, mLoaderGlobal->GetJSObject());
+        if (global) {
             JSAutoRequest ar(mContext);
             JS_SetAllNonReservedSlotsToUndefined(mContext, global);
         } else {
             NS_WARNING("Going to leak!");
         }
 
         mLoaderGlobal = nullptr;
     }
--- a/js/xpconnect/public/nsTArrayHelpers.h
+++ b/js/xpconnect/public/nsTArrayHelpers.h
@@ -8,35 +8,37 @@
 template <class T>
 inline nsresult
 nsTArrayToJSArray(JSContext* aCx, const nsTArray<T>& aSourceArray,
                   JSObject** aResultArray)
 {
   MOZ_ASSERT(aCx);
   JSAutoRequest ar(aCx);
 
-  JSObject* arrayObj = JS_NewArrayObject(aCx, aSourceArray.Length(), nullptr);
+  JS::Rooted<JSObject*> arrayObj(aCx,
+    JS_NewArrayObject(aCx, aSourceArray.Length(), nullptr));
   if (!arrayObj) {
     NS_WARNING("JS_NewArrayObject failed!");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForScopeChain(aCx));
   MOZ_ASSERT(global);
 
   for (uint32_t index = 0; index < aSourceArray.Length(); index++) {
     nsCOMPtr<nsISupports> obj;
     nsresult rv = aSourceArray[index]->QueryInterface(NS_GET_IID(nsISupports), getter_AddRefs(obj));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    jsval wrappedVal;
-    rv = nsContentUtils::WrapNative(aCx, global, obj, &wrappedVal, nullptr, true);
+    JS::Rooted<JS::Value> wrappedVal(aCx);
+    rv = nsContentUtils::WrapNative(aCx, global, obj, wrappedVal.address(),
+                                    nullptr, true);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    if (!JS_SetElement(aCx, arrayObj, index, &wrappedVal)) {
+    if (!JS_SetElement(aCx, arrayObj, index, wrappedVal.address())) {
       NS_WARNING("JS_SetElement failed!");
       return NS_ERROR_FAILURE;
     }
   }
 
   if (!JS_FreezeObject(aCx, arrayObj)) {
     NS_WARNING("JS_FreezeObject failed!");
     return NS_ERROR_FAILURE;
@@ -50,34 +52,35 @@ template <>
 inline nsresult
 nsTArrayToJSArray<nsString>(JSContext* aCx,
                             const nsTArray<nsString>& aSourceArray,
                             JSObject** aResultArray)
 {
   MOZ_ASSERT(aCx);
   JSAutoRequest ar(aCx);
 
-  JSObject* arrayObj = JS_NewArrayObject(aCx, aSourceArray.Length(), nullptr);
+  JS::Rooted<JSObject*> arrayObj(aCx,
+    JS_NewArrayObject(aCx, aSourceArray.Length(), nullptr));
   if (!arrayObj) {
     NS_WARNING("JS_NewArrayObject failed!");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   for (uint32_t index = 0; index < aSourceArray.Length(); index++) {
     JSString* s = JS_NewUCStringCopyN(aCx, aSourceArray[index].BeginReading(),
                                       aSourceArray[index].Length());
 
     if(!s) {
       NS_WARNING("Memory allocation error!");
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
-    jsval wrappedVal = STRING_TO_JSVAL(s);
+    JS::Rooted<JS::Value> wrappedVal(aCx, STRING_TO_JSVAL(s));
 
-    if (!JS_SetElement(aCx, arrayObj, index, &wrappedVal)) {
+    if (!JS_SetElement(aCx, arrayObj, index, wrappedVal.address())) {
       NS_WARNING("JS_SetElement failed!");
       return NS_ERROR_FAILURE;
     }
   }
 
   if (!JS_FreezeObject(aCx, arrayObj)) {
     NS_WARNING("JS_FreezeObject failed!");
     return NS_ERROR_FAILURE;
--- a/js/xpconnect/shell/xpcshell.cpp
+++ b/js/xpconnect/shell/xpcshell.cpp
@@ -199,30 +199,29 @@ GetLocationProperty(JSContext *cx, JSHan
             absolutePath.Append(filenameString);
 
             rv = NS_NewLocalFile(absolutePath,
                                  false, getter_AddRefs(location));
         }
 
         if (location) {
             nsCOMPtr<nsIXPConnectJSObjectHolder> locationHolder;
-            JS::Rooted<JSObject*> locationObj(cx, nullptr);
 
             bool symlink;
             // don't normalize symlinks, because that's kind of confusing
             if (NS_SUCCEEDED(location->IsSymlink(&symlink)) &&
                 !symlink)
                 location->Normalize();
             rv = xpc->WrapNative(cx, obj, location,
                                  NS_GET_IID(nsIFile),
                                  getter_AddRefs(locationHolder));
 
             if (NS_SUCCEEDED(rv) &&
-                NS_SUCCEEDED(locationHolder->GetJSObject(locationObj.address()))) {
-                vp.set(OBJECT_TO_JSVAL(locationObj));
+                locationHolder->GetJSObject()) {
+                vp.set(OBJECT_TO_JSVAL(locationHolder->GetJSObject()));
             }
         }
     }
 
     return true;
 #endif
 }
 
@@ -1687,17 +1686,16 @@ static JSSecurityCallbacks shellSecurity
 int
 main(int argc, char **argv, char **envp)
 {
 #ifdef XP_MACOSX
     InitAutoreleasePool();
 #endif
     JSRuntime *rt;
     JSContext *cx;
-    JSObject *glob, *envobj;
     int result;
     nsresult rv;
 
 #ifdef HAVE_SETBUF
     // unbuffer stdout so that output is in the correct order; note that stderr
     // is unbuffered by default
     setbuf(stdout, 0);
 #endif
@@ -1815,16 +1813,19 @@ main(int argc, char **argv, char **envp)
         gOldJSContextCallback = JS_SetContextCallback(rt, ContextCallback);
 
         cx = JS_NewContext(rt, 8192);
         if (!cx) {
             printf("JS_NewContext failed!\n");
             return 1;
         }
 
+        JS::Rooted<JSObject*> glob(cx);
+        JS::Rooted<JSObject*> envobj(cx);
+
         argc--;
         argv++;
         ProcessArgsForCompartment(cx, argv, argc);
 
         nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
         if (!xpc) {
             printf("failed to get nsXPConnect service!\n");
             return 1;
@@ -1888,19 +1889,18 @@ main(int argc, char **argv, char **envp)
                                                   static_cast<nsIGlobalObject *>(backstagePass),
                                                   systemprincipal,
                                                   0,
                                                   JS::SystemZone,
                                                   getter_AddRefs(holder));
         if (NS_FAILED(rv))
             return 1;
 
-        rv = holder->GetJSObject(&glob);
-        if (NS_FAILED(rv)) {
-            NS_ASSERTION(glob == nullptr, "bad GetJSObject?");
+        glob = holder->GetJSObject();
+        if (!glob) {
             return 1;
         }
 
         backstagePass->SetGlobalObject(glob);
 
         JS_BeginRequest(cx);
         {
             JSAutoCompartment ac(cx, glob);
@@ -1926,18 +1926,17 @@ main(int argc, char **argv, char **envp)
 
             nsAutoString workingDirectory;
             if (GetCurrentWorkingDirectory(workingDirectory))
                 gWorkingDirectory = &workingDirectory;
 
             JS_DefineProperty(cx, glob, "__LOCATION__", JSVAL_VOID,
                               GetLocationProperty, NULL, 0);
 
-            JS::Rooted<JSObject*> rootedGlob(cx, glob);
-            result = ProcessArgs(cx, rootedGlob, argv, argc, &dirprovider);
+            result = ProcessArgs(cx, glob, argv, argc, &dirprovider);
 
             JS_DropPrincipals(rt, gJSPrincipals);
             JS_SetAllNonReservedSlotsToUndefined(cx, glob);
             JS_GC(rt);
             xpc::danger::PopJSContext();
             JS_GC(rt);
         } //this scopes the JSAutoCrossCompartmentCall
         JS_EndRequest(cx);
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -328,17 +328,19 @@ nsXPCComponents_Interfaces::NewResolve(n
             wrapper->GetXPConnect(getter_AddRefs(xpc));
             if (xpc) {
                 nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
                 if (NS_SUCCEEDED(xpc->WrapNative(cx, obj,
                                                  static_cast<nsIJSIID*>(nsid),
                                                  NS_GET_IID(nsIJSIID),
                                                  getter_AddRefs(holder)))) {
                     RootedObject idobj(cx);
-                    if (holder && NS_SUCCEEDED(holder->GetJSObject(idobj.address()))) {
+                    if (holder &&
+                        // Assign, not compare
+                        (idobj = holder->GetJSObject())) {
                         *objp = obj;
                         *_retval = JS_DefinePropertyById(cx, obj, id,
                                                          OBJECT_TO_JSVAL(idobj),
                                                          nullptr, nullptr,
                                                          JSPROP_ENUMERATE |
                                                          JSPROP_READONLY |
                                                          JSPROP_PERMANENT);
                     }
@@ -618,17 +620,19 @@ nsXPCComponents_InterfacesByID::NewResol
         wrapper->GetXPConnect(getter_AddRefs(xpc));
         if (xpc) {
             nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
             if (NS_SUCCEEDED(xpc->WrapNative(cx, obj,
                                              static_cast<nsIJSIID*>(nsid),
                                              NS_GET_IID(nsIJSIID),
                                              getter_AddRefs(holder)))) {
                 RootedObject idobj(cx);
-                if (holder && NS_SUCCEEDED(holder->GetJSObject(idobj.address()))) {
+                if (holder &&
+                    // Assign, not compare
+                    (idobj = holder->GetJSObject())) {
                     *objp = obj;
                     *_retval =
                         JS_DefinePropertyById(cx, obj, id,
                                               OBJECT_TO_JSVAL(idobj),
                                               nullptr, nullptr,
                                               JSPROP_ENUMERATE |
                                               JSPROP_READONLY |
                                               JSPROP_PERMANENT);
@@ -898,17 +902,19 @@ nsXPCComponents_Classes::NewResolve(nsIX
             wrapper->GetXPConnect(getter_AddRefs(xpc));
             if (xpc) {
                 nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
                 if (NS_SUCCEEDED(xpc->WrapNative(cx, obj,
                                                  static_cast<nsIJSCID*>(nsid),
                                                  NS_GET_IID(nsIJSCID),
                                                  getter_AddRefs(holder)))) {
                     RootedObject idobj(cx);
-                    if (holder && NS_SUCCEEDED(holder->GetJSObject(idobj.address()))) {
+                    if (holder &&
+                        // Assign, not compare
+                        (idobj = holder->GetJSObject())) {
                         *objp = obj;
                         *_retval = JS_DefinePropertyById(cx, obj, id,
                                                          OBJECT_TO_JSVAL(idobj),
                                                          nullptr, nullptr,
                                                          JSPROP_ENUMERATE |
                                                          JSPROP_READONLY |
                                                          JSPROP_PERMANENT);
                     }
@@ -1160,17 +1166,19 @@ nsXPCComponents_ClassesByID::NewResolve(
             wrapper->GetXPConnect(getter_AddRefs(xpc));
             if (xpc) {
                 nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
                 if (NS_SUCCEEDED(xpc->WrapNative(cx, obj,
                                                  static_cast<nsIJSCID*>(nsid),
                                                  NS_GET_IID(nsIJSCID),
                                                  getter_AddRefs(holder)))) {
                     RootedObject idobj(cx);
-                    if (holder && NS_SUCCEEDED(holder->GetJSObject(idobj.address()))) {
+                    if (holder &&
+                        // Assign, not compare
+                        (idobj = holder->GetJSObject())) {
                         *objp = obj;
                         *_retval = JS_DefinePropertyById(cx, obj, id,
                                                          ObjectValue(*idobj),
                                                          nullptr, nullptr,
                                                          JSPROP_ENUMERATE |
                                                          JSPROP_READONLY |
                                                          JSPROP_PERMANENT);
                     }
@@ -1974,17 +1982,18 @@ nsXPCComponents_Exception::CallOrConstru
     if (!e)
         return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
 
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
     RootedObject newObj(cx);
 
     if (NS_FAILED(xpc->WrapNative(cx, obj, e, NS_GET_IID(nsIXPCException),
                                   getter_AddRefs(holder))) || !holder ||
-        NS_FAILED(holder->GetJSObject(newObj.address())) || !newObj) {
+        // Assign, not compare
+        !(newObj = holder->GetJSObject())) {
         return ThrowAndFail(NS_ERROR_XPC_CANT_CREATE_WN, cx, _retval);
     }
 
     args.rval().setObject(*newObj);
     return NS_OK;
 }
 
 /* bool hasInstance (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval val, out bool bp); */
@@ -2231,20 +2240,22 @@ nsXPCConstructor::CallOrConstruct(nsIXPC
 
     nsCOMPtr<nsIXPConnectJSObjectHolder> cidHolder;
     nsCOMPtr<nsIXPConnectJSObjectHolder> iidHolder;
     RootedObject cidObj(cx);
     RootedObject iidObj(cx);
 
     if (NS_FAILED(xpc->WrapNative(cx, obj, mClassID, NS_GET_IID(nsIJSCID),
                                   getter_AddRefs(cidHolder))) || !cidHolder ||
-        NS_FAILED(cidHolder->GetJSObject(cidObj.address())) || !cidObj ||
+        // Assign, not compare
+        !(cidObj = cidHolder->GetJSObject()) ||
         NS_FAILED(xpc->WrapNative(cx, obj, mInterfaceID, NS_GET_IID(nsIJSIID),
                                   getter_AddRefs(iidHolder))) || !iidHolder ||
-        NS_FAILED(iidHolder->GetJSObject(iidObj.address())) || !iidObj) {
+        // Assign, not compare
+        !(iidObj = iidHolder->GetJSObject())) {
         return ThrowAndFail(NS_ERROR_XPC_CANT_CREATE_WN, cx, _retval);
     }
 
     Value argv[1] = {ObjectValue(*iidObj)};
     RootedValue rval(cx);
     if (!JS_CallFunctionName(cx, cidObj, "createInstance", 1, argv, rval.address()) ||
         rval.isPrimitive()) {
         // createInstance will have thrown an exception
@@ -2498,17 +2509,18 @@ nsXPCComponents_Constructor::CallOrConst
         // we do the lookup by asking the Components.interfaces object
         // for the property with this name - i.e. we let its caching of these
         // nsIJSIID objects work for us.
 
         if (NS_FAILED(comp->GetInterfaces(getter_AddRefs(ifaces))) ||
             NS_FAILED(xpc->WrapNative(cx, obj, ifaces,
                                       NS_GET_IID(nsIXPCComponents_Interfaces),
                                       getter_AddRefs(holder))) || !holder ||
-            NS_FAILED(holder->GetJSObject(ifacesObj.address())) || !ifacesObj) {
+            // Assign, not compare
+            !(ifacesObj = holder->GetJSObject())) {
             return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
         }
 
         RootedString str(cx, JS_ValueToString(cx, args[1]));
         RootedId id(cx);
         if (!str || !JS_ValueToId(cx, StringValue(str), id.address()))
             return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
 
@@ -2546,17 +2558,18 @@ nsXPCComponents_Constructor::CallOrConst
         nsCOMPtr<nsIXPCComponents_Classes> classes;
         nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
         RootedObject classesObj(cx);
 
         if (NS_FAILED(comp->GetClasses(getter_AddRefs(classes))) ||
             NS_FAILED(xpc->WrapNative(cx, obj, classes,
                                       NS_GET_IID(nsIXPCComponents_Classes),
                                       getter_AddRefs(holder))) || !holder ||
-            NS_FAILED(holder->GetJSObject(classesObj.address())) || !classesObj) {
+            // Assign, not compare
+            !(classesObj = holder->GetJSObject())) {
             return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
         }
 
         RootedString str(cx, JS_ValueToString(cx, args[0]));
         RootedId id(cx);
         if (!str || !JS_ValueToId(cx, StringValue(str), id.address()))
             return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
 
@@ -2578,17 +2591,18 @@ nsXPCComponents_Constructor::CallOrConst
     if (!ctor)
         return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
 
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder2;
     RootedObject newObj(cx);
 
     if (NS_FAILED(xpc->WrapNative(cx, obj, ctor, NS_GET_IID(nsIXPCConstructor),
                                   getter_AddRefs(holder2))) || !holder2 ||
-        NS_FAILED(holder2->GetJSObject(newObj.address())) || !newObj) {
+        // Assign, not compare
+        !(newObj = holder2->GetJSObject())) {
         return ThrowAndFail(NS_ERROR_XPC_CANT_CREATE_WN, cx, _retval);
     }
 
     args.rval().setObject(*newObj);
     return NS_OK;
 }
 
 /* bool hasInstance (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval val, out bool bp); */
--- a/js/xpconnect/src/XPCJSID.cpp
+++ b/js/xpconnect/src/XPCJSID.cpp
@@ -720,17 +720,17 @@ GetWrapperObject(MutableHandleObject obj
 
     nsAXPCNativeCallContext *ccxp = NULL;
     xpc->GetCurrentNativeCallContext(&ccxp);
     if (!ccxp)
         return;
 
     nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
     ccxp->GetCalleeWrapper(getter_AddRefs(wrapper));
-    wrapper->GetJSObject(obj.address());
+    obj.set(wrapper->GetJSObject());
 }
 
 /* nsISupports createInstance (); */
 NS_IMETHODIMP
 nsJSCID::CreateInstance(const JS::Value& iidval, JSContext* cx,
                         uint8_t optionalArgc, JS::Value* retval)
 {
     if (!mDetails.IsValid())
@@ -814,17 +814,19 @@ nsJSCID::GetService(const JS::Value& iid
     rv = svcMgr->GetService(mDetails.ID(), *iid, getter_AddRefs(srvc));
     NS_ASSERTION(NS_FAILED(rv) || srvc, "service manager returned success, but service is null!");
     if (NS_FAILED(rv) || !srvc)
         return NS_ERROR_XPC_GS_RETURNED_FAILURE;
 
     RootedObject instJSObj(cx);
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
     rv = nsXPConnect::GetXPConnect()->WrapNative(cx, obj, srvc, *iid, getter_AddRefs(holder));
-    if (NS_FAILED(rv) || !holder || NS_FAILED(holder->GetJSObject(instJSObj.address())))
+    if (NS_FAILED(rv) || !holder ||
+        // Assign, not compare
+        !(instJSObj = holder->GetJSObject()))
         return NS_ERROR_XPC_CANT_CREATE_WN;
 
     *retval = OBJECT_TO_JSVAL(instJSObj);
     return NS_OK;
 }
 
 /* bool construct (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in uint32_t argc, in JSValPtr argv, in JSValPtr vp); */
 NS_IMETHODIMP
@@ -896,17 +898,17 @@ xpc_NewIDObject(JSContext *cx, HandleObj
         nsXPConnect* xpc = nsXPConnect::GetXPConnect();
         if (xpc) {
             nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
             nsresult rv = xpc->WrapNative(cx, jsobj,
                                           static_cast<nsISupports*>(iid),
                                           NS_GET_IID(nsIJSID),
                                           getter_AddRefs(holder));
             if (NS_SUCCEEDED(rv) && holder) {
-                holder->GetJSObject(obj.address());
+                obj = holder->GetJSObject();
             }
         }
     }
     return obj;
 }
 
 // note: returned pointer is only valid while |obj| remains alive!
 const nsID*
--- a/js/xpconnect/src/XPCJSWeakReference.cpp
+++ b/js/xpconnect/src/XPCJSWeakReference.cpp
@@ -73,18 +73,17 @@ xpcJSWeakReference::Get(JSContext* aCx, 
         // We have a generic XPCOM object that supports weak references here.
         // Wrap it and pass it out.
         JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForScopeChain(aCx));
         return nsContentUtils::WrapNative(aCx, global,
                                           supports, &NS_GET_IID(nsISupports),
                                           aRetval);
     }
 
-    JS::RootedObject obj(aCx);
-    wrappedObj->GetJSObject(obj.address());
+    JS::RootedObject obj(aCx, wrappedObj->GetJSObject());
     if (!obj) {
         return NS_OK;
     }
 
     // Most users of XPCWrappedJS don't need to worry about
     // re-wrapping because things are implicitly rewrapped by
     // xpcconvert. However, because we're doing this directly
     // through the native call context, we need to call
--- a/js/xpconnect/src/XPCThrower.cpp
+++ b/js/xpconnect/src/XPCThrower.cpp
@@ -246,18 +246,18 @@ XPCThrower::ThrowExceptionObject(JSConte
             if (!glob)
                 return false;
 
             nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
             nsresult rv = xpc->WrapNative(cx, glob, e,
                                           NS_GET_IID(nsIException),
                                           getter_AddRefs(holder));
             if (NS_SUCCEEDED(rv) && holder) {
-                JS::RootedObject obj(cx);
-                if (NS_SUCCEEDED(holder->GetJSObject(obj.address()))) {
+                JS::RootedObject obj(cx, holder->GetJSObject());
+                if (obj) {
                     JS_SetPendingException(cx, OBJECT_TO_JSVAL(obj));
                     success = true;
                 }
             }
         }
     }
     return success;
 }
--- a/js/xpconnect/src/XPCWrappedJS.cpp
+++ b/js/xpconnect/src/XPCWrappedJS.cpp
@@ -231,25 +231,20 @@ NS_IMETHODIMP
 nsXPCWrappedJS::GetWeakReference(nsIWeakReference** aInstancePtr)
 {
     if (mRoot != this)
         return mRoot->GetWeakReference(aInstancePtr);
 
     return nsSupportsWeakReference::GetWeakReference(aInstancePtr);
 }
 
-NS_IMETHODIMP
-nsXPCWrappedJS::GetJSObject(JSObject** aJSObj)
+JSObject*
+nsXPCWrappedJS::GetJSObject()
 {
-    NS_PRECONDITION(aJSObj, "bad param");
-    NS_PRECONDITION(IsValid(), "bad wrapper");
-
-    if (!(*aJSObj = GetJSObject()))
-        return NS_ERROR_OUT_OF_MEMORY;
-    return NS_OK;
+    return xpc_UnmarkGrayObject(mJSObj);
 }
 
 static bool
 CheckMainThreadOnly(nsXPCWrappedJS *aWrapper)
 {
     if(aWrapper->IsMainThreadOnly())
         return NS_IsMainThread();
 
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -558,19 +558,17 @@ XPCWrappedNative::GetNewOrUsed(XPCCallCo
             return NS_OK;
         }
     } else {
         ac.construct(ccx, parent);
 
         nsISupports *Object = helper.Object();
         if (nsXPCWrappedJSClass::IsWrappedJS(Object)) {
             nsCOMPtr<nsIXPConnectWrappedJS> wrappedjs(do_QueryInterface(Object));
-            RootedObject obj(ccx);
-            wrappedjs->GetJSObject(obj.address());
-            if (xpc::AccessCheck::isChrome(js::GetObjectCompartment(obj)) &&
+            if (xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrappedjs->GetJSObject())) &&
                 !xpc::AccessCheck::isChrome(js::GetObjectCompartment(Scope->GetGlobalJSObject()))) {
                 needsCOW = true;
             }
         }
     }
 
     AutoMarkingWrappedNativeProtoPtr proto(ccx);
 
@@ -1913,19 +1911,18 @@ XPCWrappedNative::InitTearOff(XPCCallCon
         // into an infinite loop.
         // see: http://bugzilla.mozilla.org/show_bug.cgi?id=96725
 
         // The code in this block also does a check for the double wrapped
         // nsIPropertyBag case.
 
         nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS(do_QueryInterface(obj));
         if (wrappedJS) {
-            RootedObject jso(ccx);
-            if (NS_SUCCEEDED(wrappedJS->GetJSObject(jso.address())) &&
-                jso == mFlatJSObject) {
+            RootedObject jso(ccx, wrappedJS->GetJSObject());
+            if (jso == mFlatJSObject) {
                 // The implementing JSObject is the same as ours! Just say OK
                 // without actually extending the set.
                 //
                 // XXX It is a little cheesy to have FindTearOff return an
                 // 'empty' tearoff. But this is the centralized place to do the
                 // QI activities on the underlying object. *And* most caller to
                 // FindTearOff only look for a non-null result and ignore the
                 // actual tearoff returned. The only callers that do use the
@@ -2938,21 +2935,21 @@ CallMethodHelper::Invoke()
     nsXPTCVariant* argv = mDispatchParams.Elements();
 
     return NS_InvokeByIndex(mCallee, mVTableIndex, argc, argv);
 }
 
 /***************************************************************************/
 // interface methods
 
-/* readonly attribute JSObjectPtr JSObject; */
-NS_IMETHODIMP XPCWrappedNative::GetJSObject(JSObject * *aJSObject)
+/* JSObjectPtr GetJSObject(); */
+JSObject*
+XPCWrappedNative::GetJSObject()
 {
-    *aJSObject = GetFlatJSObject();
-    return NS_OK;
+    return GetFlatJSObject();
 }
 
 /* readonly attribute nsISupports Native; */
 NS_IMETHODIMP XPCWrappedNative::GetNative(nsISupports * *aNative)
 {
     // No need to QI here, we already have the correct nsISupports
     // vtable.
     *aNative = mIdentity;
@@ -3544,23 +3541,21 @@ void DEBUG_ReportShadowedMembers(XPCNati
             }
         }
     }
 }
 #endif
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(XPCJSObjectHolder, nsIXPConnectJSObjectHolder)
 
-NS_IMETHODIMP
-XPCJSObjectHolder::GetJSObject(JSObject** aJSObj)
+JSObject*
+XPCJSObjectHolder::GetJSObject()
 {
-    NS_PRECONDITION(aJSObj, "bad param");
     NS_PRECONDITION(mJSObj, "bad object state");
-    *aJSObj = mJSObj;
-    return NS_OK;
+    return mJSObj;
 }
 
 XPCJSObjectHolder::XPCJSObjectHolder(XPCCallContext& ccx, JSObject* obj)
     : mJSObj(obj)
 {
     ccx.GetRuntime()->AddObjectHolderRoot(this);
 }
 
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -141,18 +141,18 @@ XPC_WN_Shared_ToSource(JSContext *cx, un
 
 static JSObject*
 GetDoubleWrappedJSObject(XPCCallContext& ccx, XPCWrappedNative* wrapper)
 {
     RootedObject obj(ccx);
     nsCOMPtr<nsIXPConnectWrappedJS>
         underware = do_QueryInterface(wrapper->GetIdentityObject());
     if (underware) {
-        RootedObject mainObj(ccx);
-        if (NS_SUCCEEDED(underware->GetJSObject(mainObj.address())) && mainObj) {
+        RootedObject mainObj(ccx, underware->GetJSObject());
+        if (mainObj) {
             RootedId id(ccx, ccx.GetRuntime()->
                             GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT));
 
             JSAutoCompartment ac(ccx, mainObj);
 
             RootedValue val(ccx);
             if (JS_GetPropertyById(ccx, mainObj, id, val.address()) &&
                 !JSVAL_IS_PRIMITIVE(val)) {
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -3142,22 +3142,16 @@ public:
                  JSObject* aJSObj,
                  REFNSIID aIID,
                  nsISupports* aOuter,
                  nsXPCWrappedJS** wrapper);
 
     nsISomeInterface* GetXPTCStub() { return mXPTCStub; }
 
     /**
-     * This getter clears the gray bit before handing out the JSObject which
-     * means that the object is guaranteed to be kept alive past the next CC.
-     */
-    JSObject* GetJSObject() const {return xpc_UnmarkGrayObject(mJSObj);}
-
-    /**
      * This getter does not change the color of the JSObject meaning that the
      * object returned is not guaranteed to be kept alive past the next CC.
      *
      * This should only be called if you are certain that the return value won't
      * be passed into a JS API function and that it won't be stored without
      * being rooted (or otherwise signaling the stored value to the CC).
      */
     JSObject* GetJSObjectPreserveColor() const {return mJSObj;}
--- a/layout/media/symbols.def.in
+++ b/layout/media/symbols.def.in
@@ -528,16 +528,17 @@ hb_buffer_get_glyph_infos
 hb_buffer_get_glyph_positions
 hb_buffer_reverse
 hb_buffer_set_direction
 hb_buffer_set_language
 hb_buffer_set_script
 hb_buffer_set_unicode_funcs
 hb_face_create_for_tables
 hb_face_destroy
+hb_face_reference
 hb_font_create
 hb_font_destroy
 hb_font_funcs_create
 hb_font_funcs_set_glyph_contour_point_func
 hb_font_funcs_set_glyph_func
 hb_font_funcs_set_glyph_h_advance_func
 hb_font_funcs_set_glyph_h_kerning_func
 hb_font_set_funcs
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/alternates-order-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style type="text/css">
+@font-face {
+  font-family: libertine;
+  src: url(../fonts/LinLibertine_Re-4.7.5.woff) format("woff");
+}
+body {
+  font-family: libertine, sans-serif;
+  font-size: 800%;
+  line-height: 1.2em;
+}
+
+div { margin: 0 20px; }
+span {
+  -moz-font-feature-settings: "ss05"; /* crossed W */
+}
+
+</style>
+</head>
+<body lang="en">
+<div><span id="test1">W</span> <span id="test2">W</span> <span id="test3">W</span></div>
+<div><span id="test4">W</span> <span id="test5">W</span> <span id="test6">W</span></div>
+<div><span id="test7">W</span> <span id="test8">W</span> <span id="test9">W</span></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/alternates-order.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style type="text/css">
+@font-face {
+  font-family: libertine;
+  src: url(../fonts/LinLibertine_Re-4.7.5.woff) format("woff");
+}
+
+@font-face {
+  font-family: fontA;
+  src: url(../fonts/LinLibertine_Re-4.7.5.woff) format("woff");
+  -moz-font-feature-settings: "ss05" on;
+}
+
+@font-face {
+  font-family: fontB;
+  src: url(../fonts/LinLibertine_Re-4.7.5.woff) format("woff");
+  -moz-font-feature-settings: "ss05" off;
+}
+
+@font-feature-values libertine {
+  @styleset { 
+    crossed-doubleu: 5;
+    somethingElse: 4;
+  }
+}
+
+@font-feature-values fontA {
+  @styleset { aLtW: 5; }
+}
+
+@font-feature-values fontB {
+  @styleset { crossedW: 5; several: 1 3 5; }
+  @styleset { altW: 4; }
+}
+
+@font-feature-values fontB {
+  @styleset {
+    AlTw: 5;
+    defined-for-fontB: 5;
+    scriptJ: 3;
+  }
+}
+
+body {
+  font-family: libertine, sans-serif;
+  font-size: 800%;
+  line-height: 1.2em;
+}
+
+/* -moz-font-feature-settings: "ss05"; crossed W */
+
+div { margin: 0 20px; }
+
+#test1 {
+  font-variant-alternates: styleset(crossed-doubleu);
+}
+
+#test2 {
+  /* testing case-insensitivity of styleset name */
+  font-family: fontB;
+  font-variant-alternates: styleset(altW);
+}
+
+#test3 {
+  /* testing case-insensitivity of styleset name */
+  font-family: fontB;
+  font-variant-alternates: styleset(ALTW);
+}
+
+#test4 {
+  /* testing escapes in styleset name */
+  font-family: fontB;
+  font-variant-alternates: styleset(\41 ltW);
+}
+
+#test5 {
+  /* testing font-specificity of feature value rule */
+  font-family: fontA;
+  font-variant-alternates: styleset(defined-for-fontB);
+}
+
+#test6 {
+  /* testing one feature doesn't affect another */
+  font-variant-alternates: styleset(somethingElse);
+  -moz-font-feature-settings: "ss05" on;
+}
+
+#test7 {
+  /* testing font-specificity of feature value rule */
+  font-family: fontA;
+  font-variant-alternates: styleset(scriptJ);
+  -moz-font-feature-settings: "ss06";
+}
+
+#test8 {
+  /* testing that an undefined value doesn't affect the results */
+  font-family: fontB;
+  font-variant-alternates: styleset(scriptJ, somethingUndefined, defined-for-fontB);
+}
+
+#test9 {
+  /* testing matching of font name with escape */
+  font-family: font\62 ;
+  font-variant-alternates: styleset(defined-for-fontB);
+}
+
+</style>
+</head>
+<body lang="en">
+<div><span id="test1">W</span> <span id="test2">W</span> <span id="test3">W</span></div>
+<div><span id="test4">W</span> <span id="test5">W</span> <span id="test6">W</span></div>
+<div><span id="test7">W</span> <span id="test8">W</span> <span id="test9">W</span></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/annotations-ref.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Annotations test</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+<style type="text/css">
+
+body {
+  margin: 20px;
+  font-size: 800%;
+  font-family: Hiragino Maru Gothic ProN, Meiryo;
+}
+
+/* for platforms without these fonts the default glyphs will show */
+
+@font-face {
+  font-family: testMeiryo-circled;
+  src: local(Meiryo);
+  -moz-font-feature-settings: "nalt" 4;
+}
+
+@font-face {
+  font-family: testMeiryo-black-circled;
+  src: local(Meiryo);
+  -moz-font-feature-settings: "nalt" 5;
+}
+
+@font-face {
+  font-family: testMeiryo-rounded-box;
+  src: local(Meiryo);
+  -moz-font-feature-settings: "nalt" 9;
+}
+
+@font-face {
+  font-family: testHiraginoMaru-circled;
+  src: local(HiraMaruProN-W4), local(Hiragino Maru Gothic ProN W4);
+  -moz-font-feature-settings: "nalt" 1;
+}
+
+@font-face {
+  font-family: testHiraginoMaru-black-circled;
+  src: local(HiraMaruProN-W4), local(Hiragino Maru Gothic ProN W4);
+  -moz-font-feature-settings: "nalt" 4;
+}
+
+@font-face {
+  font-family: testHiraginoMaru-rounded-box;
+  src: local(HiraMaruProN-W4), local(Hiragino Maru Gothic ProN W4);
+  -moz-font-feature-settings: "nalt" 10;
+}
+
+#test1 {
+  font-family: testHiraginoMaru-circled, testMeiryo-circled;
+}
+
+#test2 {
+  font-family: testHiraginoMaru-black-circled, testMeiryo-black-circled;
+}
+
+#test3 {
+  font-family: testHiraginoMaru-rounded-box, testMeiryo-rounded-box;
+}
+
+</style>
+
+</head>
+<body>
+<div><span id="test1">1</span> <span id="test2">2</span> <span id="test3">3</span></div>
+</body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/annotations.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Annotations test</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+<style type="text/css">
+
+body {
+  margin: 20px;
+  font-size: 800%;
+  font-family: Hiragino Maru Gothic ProN, Meiryo;
+}
+
+/* for platforms without these fonts the default glyphs will show */
+
+@font-feature-values Hiragino Maru Gothic ProN {
+  @annotation { circled: 1; }
+  @annotation { black-circled: 4; }
+  @annotation { black-box: 8; }
+  @annotation { black-rounded-box: 10; }
+}
+
+@font-feature-values Meiryo {
+  @annotation { 
+    circled: 4;
+    black-circled: 5;
+    black-box: 7;
+    black-rounded-box: 9;
+  }
+}
+
+#test1 {
+  font-variant-alternates: annotation(circled);
+}
+
+#test2 {
+  font-variant-alternates: annotation(black-circled);
+}
+
+#test3 {
+  font-variant-alternates: annotation(black-rounded-box);
+}
+
+</style>
+
+</head>
+<body>
+<div><span id="test1">1</span> <span id="test2">2</span> <span id="test3">3</span></div>
+</body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-features-order-3.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style type="text/css">
+@font-face {
+  font-family: libertine;
+  src: url(../fonts/LinLibertine_Re-4.7.5.woff) format("woff");
+  -moz-font-feature-settings: "liga" on, "hlig" on;
+}
+body {
+  font-family: libertine, sans-serif;
+  font-size: 400%;
+  line-height: 2em;
+  /* font feature settings property should override font setting */
+  -moz-font-feature-settings: "liga" off, "hlig" off;
+}
+</style>
+</head>
+<body lang="en">
+fastest firefox
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-features-order-4.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style type="text/css">
+@font-face {
+  font-family: libertine;
+  src: url(../fonts/LinLibertine_Re-4.7.5.woff) format("woff");
+  font-feature-settings: "liga" on, "hlig" on;
+}
+body {
+  font-family: libertine, sans-serif;
+  font-size: 400%;
+  line-height: 2em;
+  /* font variant property should override font setting */
+  font-variant-ligatures: no-common-ligatures no-historical-ligatures;
+}
+</style>
+</head>
+<body lang="en">
+fastest firefox
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-features-order-5.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style type="text/css">
+@font-face {
+  font-family: libertine;
+  src: url(../fonts/LinLibertine_Re-4.7.5.woff) format("woff");
+  font-feature-settings: "liga" on, "hlig" on;
+}
+body {
+  font-family: libertine, sans-serif;
+  font-size: 400%;
+  line-height: 2em;
+  /* font variant property should override font setting but font feature
+     settings property should override that */
+  font-variant-ligatures: no-common-ligatures no-historical-ligatures;
+  font-feature-settings: "liga" on, "hlig" on;
+}
+</style>
+</head>
+<body lang="en">
+fastest firefox
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-kerning-1.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style type="text/css">
+@font-face {
+  font-family: libertine;
+  src: url(../fonts/LinLibertine_Re-4.7.5.woff) format("woff");
+}
+body {
+  margin: 10px;
+  font-family: libertine, sans-serif;
+  font-size: 600%;
+  line-height: 1.2em;
+  /* font-feature-settings should take precedence over font-kerning,
+     so kerning should be DISabled here */
+  font-feature-settings: "kern" off;
+  font-kerning: normal;
+}
+</style>
+</head>
+<body lang="en">
+<div>Ta To</div>
+<div>AVA</div>
+<div>AWAY</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-kerning-2.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style type="text/css">
+@font-face {
+  font-family: libertine;
+  src: url(../fonts/LinLibertine_Re-4.7.5.woff) format("woff");
+}
+body {
+  margin: 10px;
+  font-family: libertine, sans-serif;
+  font-size: 600%;
+  line-height: 1.2em;
+  /* font-feature-settings should take precedence over font-kerning,
+     so kerning should be ENabled here. */
+  font-feature-settings: "kern" on;
+  font-kerning: none;
+}
+</style>
+</head>
+<body lang="en">
+<div>Ta To</div>
+<div>AVA</div>
+<div>AWAY</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-kerning-3.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style type="text/css">
+@font-face {
+  font-family: libertine;
+  src: url(../fonts/LinLibertine_Re-4.7.5.woff) format("woff");
+  font-feature-settings: "kern" off;
+}
+body {
+  margin: 10px;
+  font-family: libertine, sans-serif;
+  font-size: 600%;
+  line-height: 1.2em;
+}
+</style>
+</head>
+<body lang="en">
+<div>Ta To</div>
+<div>AVA</div>
+<div>AWAY</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-kerning-auto.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style type="text/css">
+@font-face {
+  font-family: libertine;
+  src: url(../fonts/LinLibertine_Re-4.7.5.woff) format("woff");
+}
+body {
+  margin: 10px;
+  font-family: libertine, sans-serif;
+  font-size: 600%;
+  line-height: 1.2em;
+  font-kerning: auto;
+}
+</style>
+</head>
+<body lang="en">
+<div>Ta To</div>
+<div>AVA</div>
+<div>AWAY</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-kerning-kern.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style type="text/css">
+@font-face {
+  font-family: libertine;
+  src: url(../fonts/LinLibertine_Re-4.7.5.woff) format("woff");
+}
+body {
+  margin: 10px;
+  font-family: libertine, sans-serif;
+  font-size: 600%;
+  line-height: 1.2em;
+  font-feature-settings: "kern" on;
+}
+</style>
+</head>
+<body lang="en">
+<div>Ta To</div>
+<div>AVA</div>
+<div>AWAY</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-kerning-nokern.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style type="text/css">
+@font-face {
+  font-family: libertine;
+  src: url(../fonts/LinLibertine_Re-4.7.5.woff) format("woff");
+}
+body {
+  margin: 10px;
+  font-family: libertine, sans-serif;
+  font-size: 600%;
+  line-height: 1.2em;
+  font-feature-settings: "kern" off;
+}
+</style>
+</head>
+<body lang="en">
+<div>Ta To</div>
+<div>AVA</div>
+<div>AWAY</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-kerning-none.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style type="text/css">
+@font-face {
+  font-family: libertine;
+  src: url(../fonts/LinLibertine_Re-4.7.5.woff) format("woff");
+}
+body {
+  margin: 10px;
+  font-family: libertine, sans-serif;
+  font-size: 600%;
+  line-height: 1.2em;
+  font-kerning: none;
+}
+</style>
+</head>
+<body lang="en">
+<div>Ta To</div>
+<div>AVA</div>
+<div>AWAY</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-kerning-normal.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style type="text/css">
+@font-face {
+  font-family: libertine;
+  src: url(../fonts/LinLibertine_Re-4.7.5.woff) format("woff");
+}
+body {
+  margin: 10px;
+  font-family: libertine, sans-serif;
+  font-size: 600%;
+  line-height: 1.2em;
+  font-kerning: normal;
+}
+</style>
+</head>
+<body lang="en">
+<div>Ta To</div>
+<div>AVA</div>
+<div>AWAY</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-kerning-table-none.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style type="text/css">
+@font-face {
+  font-family: gentium;
+  /* font that has an old-style 'kern' table rather than GPOS 'kern' feature */
+  src: url(../fonts/sil/GenR102.ttf);
+}
+body {
+  margin: 10px;
+  font-family: gentium;
+  font-size: 600%;
+  line-height: 1.2em;
+  font-kerning: none;
+}
+</style>
+</head>
+<body lang="en">
+<div>Ta To</div>
+<div>AVA</div>
+<div>AWAY</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-kerning-table-normal.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style type="text/css">
+@font-face {
+  font-family: gentium;
+  src: url(../fonts/sil/GenR102.ttf);
+}
+body {
+  margin: 10px;
+  font-family: gentium;
+  font-size: 600%;
+  line-height: 1.2em;
+  font-kerning: normal;
+}
+</style>
+</head>
+<body lang="en">
+<div>Ta To</div>
+<div>AVA</div>
+<div>AWAY</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-variant-alternates-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+<title>font-variant-alternates test</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript" src="../fonts/gsubtest/gsubtest-features.js"></script>
+<script type="text/javascript" src="font-variant-features.js"></script>
+<link rel="stylesheet" href="font-variant-features.css" type="text/css"/>
+
+<style type="text/css">
+</style>
+
+</head>
+<body>
+<div id="content"></div>
+<script type="text/javascript">
+  document.getElementById("content").appendChild(createFeatureTestTable(gPropertyData, "font-variant-alternates", true, false));
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-variant-alternates.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+<title>font-variant-alternates test</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript" src="../fonts/gsubtest/gsubtest-features.js"></script>
+<script type="text/javascript" src="font-variant-features.js"></script>
+<link rel="stylesheet" href="font-variant-features.css" type="text/css"/>
+
+<style type="text/css">
+</style>
+
+</head>
+<body>
+<div id="content"></div>
+<script type="text/javascript">
+  document.getElementById("content").appendChild(createFeatureTestTable(gPropertyData, "font-variant-alternates", false, false));
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-variant-caps-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+<title>font-variant-caps test</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript" src="../fonts/gsubtest/gsubtest-features.js"></script>
+<script type="text/javascript" src="font-variant-features.js"></script>
+<link rel="stylesheet" href="font-variant-features.css" type="text/css"/>
+</head>
+<body>
+<div id="content"></div>
+<script type="text/javascript">
+  document.getElementById("content").appendChild(createFeatureTestTable(gPropertyData, "font-variant-caps", true, false));
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-variant-caps.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+<title>font-variant-caps test</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript" src="../fonts/gsubtest/gsubtest-features.js"></script>
+<script type="text/javascript" src="font-variant-features.js"></script>
+<link rel="stylesheet" href="font-variant-features.css" type="text/css"/>
+</head>
+<body>
+<div id="content"></div>
+<script type="text/javascript">
+  document.getElementById("content").appendChild(createFeatureTestTable(gPropertyData, "font-variant-caps", false, false));
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-variant-debug.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+<title>font-variant test</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript" src="../fonts/gsubtest/gsubtest-features.js"></script>
+<script type="text/javascript" src="font-variant-features.js"></script>
+<link rel="stylesheet" href="font-variant-features.css" type="text/css"/>
+</head>
+<body>
+<div id="content"></div>
+<script type="text/javascript">
+  document.getElementById("content").appendChild(createFeatureTestTable(gPropertyData, "all", false, true));
+</script>
+</body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-variant-east-asian-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+<title>font-variant-east-asian test</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript" src="../fonts/gsubtest/gsubtest-features.js"></script>
+<script type="text/javascript" src="font-variant-features.js"></script>
+<link rel="stylesheet" href="font-variant-features.css" type="text/css"/>
+</head>
+<body>
+<div id="content"></div>
+<script type="text/javascript">
+  document.getElementById("content").appendChild(createFeatureTestTable(gPropertyData, "font-variant-east-asian", true, false));
+</script>
+</body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-variant-east-asian.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+<title>font-variant-east-asian test</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript" src="../fonts/gsubtest/gsubtest-features.js"></script>
+<script type="text/javascript" src="font-variant-features.js"></script>
+<link rel="stylesheet" href="font-variant-features.css" type="text/css"/>
+</head>
+<body>
+<div id="content"></div>
+<script type="text/javascript">
+  document.getElementById("content").appendChild(createFeatureTestTable(gPropertyData, "font-variant-east-asian", false, false));
+</script>
+</body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-variant-features.css
@@ -0,0 +1,63 @@
+body { margin: 10px; }
+
+@font-face {
+  font-family: gsub-test;
+  src: url(../fonts/gsubtest/gsubtest-lookup3.otf);