Merge m-c to b2ginbound, a=merge
authorWes Kocher <wkocher@mozilla.com>
Tue, 15 Sep 2015 17:20:50 -0700
changeset 295412 9891fadcb68e558ae2b947c4b2c4d4ede6ee6b32
parent 295411 6500e08b83d6c68a1fc417682cbaddbc20d4f315 (current diff)
parent 295237 df10a3f6060f208bc3f5f0e1d9965e083076a952 (diff)
child 295413 41d01b15bf69873a98c3333b3d5fec0fb0a29f16
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone43.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 m-c to b2ginbound, a=merge
testing/web-platform/meta/service-workers/cache-storage/window/cache-add.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/window/cache-delete.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/window/cache-storage-keys.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/window/cache-storage.https.html.ini
testing/web-platform/meta/service-workers/cache-storage/window/sandboxed-iframes.https.html.ini
--- a/accessible/base/AccEvent.cpp
+++ b/accessible/base/AccEvent.cpp
@@ -99,18 +99,19 @@ AccReorderEvent::IsShowHideEventTarget(c
   return 0;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccHideEvent
 ////////////////////////////////////////////////////////////////////////////////
 
 AccHideEvent::
-  AccHideEvent(Accessible* aTarget, nsINode* aTargetNode) :
-  AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget, aTargetNode)
+  AccHideEvent(Accessible* aTarget, nsINode* aTargetNode, bool aNeedsShutdown) :
+  AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget, aTargetNode),
+  mNeedsShutdown(aNeedsShutdown)
 {
   mNextSibling = mAccessible->NextSibling();
   mPrevSibling = mAccessible->PrevSibling();
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccShowEvent
--- a/accessible/base/AccEvent.h
+++ b/accessible/base/AccEvent.h
@@ -245,31 +245,34 @@ protected:
 
 
 /**
  * Accessible hide event.
  */
 class AccHideEvent: public AccMutationEvent
 {
 public:
-  AccHideEvent(Accessible* aTarget, nsINode* aTargetNode);
+  AccHideEvent(Accessible* aTarget, nsINode* aTargetNode,
+               bool aNeedsShutdown = true);
 
   // Event
   static const EventGroup kEventGroup = eHideEvent;
   virtual unsigned int GetEventGroups() const override
   {
     return AccMutationEvent::GetEventGroups() | (1U << eHideEvent);
   }
 
   // AccHideEvent
   Accessible* TargetParent() const { return mParent; }
   Accessible* TargetNextSibling() const { return mNextSibling; }
   Accessible* TargetPrevSibling() const { return mPrevSibling; }
+  bool NeedsShutdown() const { return mNeedsShutdown; }
 
 protected:
+  bool mNeedsShutdown;
   nsRefPtr<Accessible> mNextSibling;
   nsRefPtr<Accessible> mPrevSibling;
 
   friend class EventQueue;
 };
 
 
 /**
--- a/accessible/base/EventQueue.cpp
+++ b/accessible/base/EventQueue.cpp
@@ -541,15 +541,17 @@ EventQueue::ProcessEventQueue()
       // Fire text change events.
       AccMutationEvent* mutationEvent = downcast_accEvent(event);
       if (mutationEvent) {
         if (mutationEvent->mTextChangeEvent)
           nsEventShell::FireEvent(mutationEvent->mTextChangeEvent);
       }
     }
 
-    if (event->mEventType == nsIAccessibleEvent::EVENT_HIDE)
+    AccHideEvent* hideEvent = downcast_accEvent(event);
+    if (hideEvent && hideEvent->NeedsShutdown()) {
       mDocument->ShutdownChildrenInSubtree(event->mAccessible);
+    }
 
     if (!mDocument)
       return;
   }
 }
--- a/accessible/base/NotificationController.cpp
+++ b/accessible/base/NotificationController.cpp
@@ -104,30 +104,30 @@ NotificationController::ScheduleContentI
   nsRefPtr<ContentInsertion> insertion = new ContentInsertion(mDocument,
                                                               aContainer);
   if (insertion && insertion->InitChildList(aStartChildNode, aEndChildNode) &&
       mContentInsertions.AppendElement(insertion)) {
     ScheduleProcessing();
   }
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// NotificationCollector: protected
-
 void
 NotificationController::ScheduleProcessing()
 {
   // If notification flush isn't planed yet start notification flush
   // asynchronously (after style and layout).
   if (mObservingState == eNotObservingRefresh) {
     if (mPresShell->AddRefreshObserver(this, Flush_Display))
       mObservingState = eRefreshObserving;
   }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// NotificationCollector: protected
+
 bool
 NotificationController::IsUpdatePending()
 {
   return mPresShell->IsLayoutFlushObserver() ||
     mObservingState == eRefreshProcessingForUpdate ||
     mContentInsertions.Length() != 0 || mNotifications.Length() != 0 ||
     mTextHash.Count() != 0 ||
     !mDocument->HasLoadState(DocAccessible::eTreeConstructed);
--- a/accessible/base/NotificationController.h
+++ b/accessible/base/NotificationController.h
@@ -3,16 +3,18 @@
  * 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 mozilla_a11y_NotificationController_h_
 #define mozilla_a11y_NotificationController_h_
 
 #include "EventQueue.h"
 
+#include "mozilla/IndexSequence.h"
+#include "mozilla/Tuple.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsRefreshDriver.h"
 
 #ifdef A11Y_LOG
 #include "Logging.h"
 #endif
 
 namespace mozilla {
@@ -49,42 +51,42 @@ private:
 
 /**
  * Template class for generic notification.
  *
  * @note  Instance is kept as a weak ref, the caller must guarantee it exists
  *        longer than the document accessible owning the notification controller
  *        that this notification is processed by.
  */
-template<class Class, class Arg>
+template<class Class, class ... Args>
 class TNotification : public Notification
 {
 public:
-  typedef void (Class::*Callback)(Arg*);
+  typedef void (Class::*Callback)(Args* ...);
 
-  TNotification(Class* aInstance, Callback aCallback, Arg* aArg) :
-    mInstance(aInstance), mCallback(aCallback), mArg(aArg) { }
+  TNotification(Class* aInstance, Callback aCallback, Args* ... aArgs) :
+    mInstance(aInstance), mCallback(aCallback), mArgs(aArgs...) { }
   virtual ~TNotification() { mInstance = nullptr; }
 
   virtual void Process() override
-  {
-    (mInstance->*mCallback)(mArg);
-
-    mInstance = nullptr;
-    mCallback = nullptr;
-    mArg = nullptr;
-  }
+    { ProcessHelper(typename IndexSequenceFor<Args...>::Type()); }
 
 private:
   TNotification(const TNotification&);
   TNotification& operator = (const TNotification&);
 
+  template <size_t... Indices>
+    void ProcessHelper(IndexSequence<Indices...>)
+  {
+     (mInstance->*mCallback)(Get<Indices>(mArgs)...);
+  }
+
   Class* mInstance;
   Callback mCallback;
-  nsRefPtr<Arg> mArg;
+  Tuple<nsRefPtr<Args> ...> mArgs;
 };
 
 /**
  * Used to process notifications from core for the document accessible.
  */
 class NotificationController final : public EventQueue,
                                      public nsARefreshObserver
 {
@@ -127,16 +129,22 @@ public:
   /**
    * Pend accessible tree update for content insertion.
    */
   void ScheduleContentInsertion(Accessible* aContainer,
                                 nsIContent* aStartChildNode,
                                 nsIContent* aEndChildNode);
 
   /**
+   * Start to observe refresh to make notifications and events processing after
+   * layout.
+   */
+  void ScheduleProcessing();
+
+  /**
    * Process the generic notification synchronously if there are no pending
    * layout changes and no notifications are pending or being processed right
    * now. Otherwise, queue it up to process asynchronously.
    *
    * @note  The caller must guarantee that the given instance still exists when
    *        the notification is processed.
    */
   template<class Class, class Arg>
@@ -160,45 +168,38 @@ public:
   }
 
   /**
    * Schedule the generic notification to process asynchronously.
    *
    * @note  The caller must guarantee that the given instance still exists when
    *        the notification is processed.
    */
-  template<class Class, class Arg>
+  template<class Class>
   inline void ScheduleNotification(Class* aInstance,
-                                   typename TNotification<Class, Arg>::Callback aMethod,
-                                   Arg* aArg)
+                                   typename TNotification<Class>::Callback aMethod)
   {
     nsRefPtr<Notification> notification =
-      new TNotification<Class, Arg>(aInstance, aMethod, aArg);
+      new TNotification<Class>(aInstance, aMethod);
     if (notification && mNotifications.AppendElement(notification))
       ScheduleProcessing();
   }
 
 #ifdef DEBUG
   bool IsUpdating() const
     { return mObservingState == eRefreshProcessingForUpdate; }
 #endif
 
 protected:
   virtual ~NotificationController();
 
   nsCycleCollectingAutoRefCnt mRefCnt;
   NS_DECL_OWNINGTHREAD
 
   /**
-   * Start to observe refresh to make notifications and events processing after
-   * layout.
-   */
-  void ScheduleProcessing();
-
-  /**
    * Return true if the accessible tree state update is pending.
    */
   bool IsUpdatePending();
 
 private:
   NotificationController(const NotificationController&);
   NotificationController& operator = (const NotificationController&);
 
--- a/accessible/base/TreeWalker.cpp
+++ b/accessible/base/TreeWalker.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "TreeWalker.h"
 
 #include "Accessible.h"
+#include "AccIterator.h"
 #include "nsAccessibilityService.h"
 #include "DocAccessible.h"
 
 #include "mozilla/dom/ChildIterator.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
@@ -45,30 +46,26 @@ TreeWalker::~TreeWalker()
 // TreeWalker: private
 
 Accessible*
 TreeWalker::NextChild()
 {
   if (mStateStack.IsEmpty())
     return nullptr;
 
-  dom::AllChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
+  ChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
   while (top) {
-    while (nsIContent* childNode = top->GetNextChild()) {
-      bool isSubtreeHidden = false;
-      Accessible* accessible = mFlags & eWalkCache ?
-        mDoc->GetAccessible(childNode) :
-        GetAccService()->GetOrCreateAccessible(childNode, mContext,
-                                               &isSubtreeHidden);
-
-      if (accessible)
-        return accessible;
+    Accessible* child = nullptr;
+    bool skipSubtree = false;
+    while (nsIContent* childNode = Next(top, &child, &skipSubtree)) {
+      if (child)
+        return child;
 
       // Walk down into subtree to find accessibles.
-      if (!isSubtreeHidden && childNode->IsElement())
+      if (!skipSubtree && childNode->IsElement())
         top = PushState(childNode);
     }
 
     top = PopState();
   }
 
   // If we traversed the whole subtree of the anchor node. Move to next node
   // relative anchor node within the context subtree if possible.
@@ -77,34 +74,73 @@ TreeWalker::NextChild()
 
   nsINode* contextNode = mContext->GetNode();
   while (mAnchorNode != contextNode) {
     nsINode* parentNode = mAnchorNode->GetFlattenedTreeParent();
     if (!parentNode || !parentNode->IsElement())
       return nullptr;
 
     nsIContent* parent = parentNode->AsElement();
-    top = mStateStack.AppendElement(dom::AllChildrenIterator(parent,
-                                                             mChildFilter));
-    while (nsIContent* childNode = top->GetNextChild()) {
+    top = PushState(parent);
+    while (nsIContent* childNode = Next(top)) {
       if (childNode == mAnchorNode) {
         mAnchorNode = parent;
         return NextChild();
       }
     }
 
     // XXX We really should never get here, it means we're trying to find an
     // accessible for a dom node where iterating over its parent's children
     // doesn't return it. However this sometimes happens when we're asked for
     // the nearest accessible to place holder content which we ignore.
     mAnchorNode = parent;
   }
 
   return nullptr;
 }
 
-dom::AllChildrenIterator*
+nsIContent*
+TreeWalker::Next(ChildrenIterator* aIter, Accessible** aAccesible,
+                 bool* aSkipSubtree)
+{
+  nsIContent* childEl = aIter->mDOMIter.GetNextChild();
+  if (!aAccesible)
+    return childEl;
+
+  *aAccesible = nullptr;
+  *aSkipSubtree = false;
+
+  if (childEl) {
+    Accessible* accessible = mFlags & eWalkCache ?
+      mDoc->GetAccessible(childEl) :
+      GetAccService()->GetOrCreateAccessible(childEl, mContext, aSkipSubtree);
+
+    // Ignore the accessible and its subtree if it was repositioned by means of
+    // aria-owns.
+    if (accessible) {
+      if (accessible->IsRepositioned()) {
+        *aSkipSubtree = true;
+      } else {
+        *aAccesible = accessible;
+      }
+    }
+    return childEl;
+  }
+
+  // At last iterate over ARIA owned children.
+  Accessible* parent = mDoc->GetAccessible(aIter->mDOMIter.Parent());
+  if (parent) {
+    Accessible* child = mDoc->ARIAOwnedAt(parent, aIter->mARIAOwnsIdx++);
+    if (child) {
+      *aAccesible = child;
+      return child->GetContent();
+    }
+  }
+  return nullptr;
+}
+
+TreeWalker::ChildrenIterator*
 TreeWalker::PopState()
 {
   size_t length = mStateStack.Length();
   mStateStack.RemoveElementAt(length - 1);
   return mStateStack.IsEmpty() ? nullptr : &mStateStack[mStateStack.Length() - 1];
 }
--- a/accessible/base/TreeWalker.h
+++ b/accessible/base/TreeWalker.h
@@ -52,37 +52,47 @@ public:
    */
   Accessible* NextChild();
 
 private:
   TreeWalker();
   TreeWalker(const TreeWalker&);
   TreeWalker& operator =(const TreeWalker&);
 
+  struct ChildrenIterator {
+    ChildrenIterator(nsIContent* aNode, uint32_t aFilter) :
+      mDOMIter(aNode, aFilter), mARIAOwnsIdx(0) { }
+
+    dom::AllChildrenIterator mDOMIter;
+    uint32_t mARIAOwnsIdx;
+  };
+
+  nsIContent* Next(ChildrenIterator* aIter, Accessible** aAccessible = nullptr,
+                   bool* aSkipSubtree = nullptr);
+
   /**
    * Create new state for the given node and push it on top of stack.
    *
    * @note State stack is used to navigate up/down the DOM subtree during
    *        accessible children search.
    */
-  dom::AllChildrenIterator* PushState(nsIContent* aContent)
+  ChildrenIterator* PushState(nsIContent* aContent)
   {
-    return mStateStack.AppendElement(dom::AllChildrenIterator(aContent,
-                                                              mChildFilter));
+    return mStateStack.AppendElement(ChildrenIterator(aContent, mChildFilter));
   }
 
   /**
    * Pop state from stack.
    */
-  dom::AllChildrenIterator* PopState();
+  ChildrenIterator* PopState();
 
   DocAccessible* mDoc;
   Accessible* mContext;
   nsIContent* mAnchorNode;
-  nsAutoTArray<dom::AllChildrenIterator, 20> mStateStack;
+  nsAutoTArray<ChildrenIterator, 20> mStateStack;
   int32_t mChildFilter;
   uint32_t mFlags;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_TreeWalker_h_
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -1969,18 +1969,18 @@ Accessible::NativeName(nsString& aName)
 void
 Accessible::BindToParent(Accessible* aParent, uint32_t aIndexInParent)
 {
   NS_PRECONDITION(aParent, "This method isn't used to set null parent!");
 
   if (mParent) {
     if (mParent != aParent) {
       NS_ERROR("Adopting child!");
+      mParent->InvalidateChildrenGroupInfo();
       mParent->RemoveChild(this);
-      mParent->InvalidateChildrenGroupInfo();
     } else {
       NS_ERROR("Binding to the same parent!");
       return;
     }
   }
 
   mParent = aParent;
   mIndexInParent = aIndexInParent;
--- a/accessible/generic/Accessible.h
+++ b/accessible/generic/Accessible.h
@@ -155,16 +155,18 @@ public:
    */
   virtual nsINode* GetNode() const;
   inline already_AddRefed<nsIDOMNode> DOMNode() const
   {
     nsCOMPtr<nsIDOMNode> DOMNode = do_QueryInterface(GetNode());
     return DOMNode.forget();
   }
   nsIContent* GetContent() const { return mContent; }
+  mozilla::dom::Element* Elm() const
+    { return mContent && mContent->IsElement() ? mContent->AsElement() : nullptr; }
 
   /**
    * Return node type information of DOM node associated with the accessible.
    */
   bool IsContent() const
     { return GetNode() && GetNode()->IsNodeOfType(nsINode::eCONTENT); }
 
   /**
@@ -895,31 +897,43 @@ public:
   {
     if (aIsSurviving)
       mStateFlags |= eSurvivingInUpdate;
     else
       mStateFlags &= ~eSurvivingInUpdate;
   }
 
   /**
+   * Get/set repositioned bit indicating that the accessible was moved in
+   * the accessible tree, i.e. the accessible tree structure differs from DOM.
+   */
+  bool IsRepositioned() const { return mStateFlags & eRepositioned; }
+  void SetRepositioned(bool aRepositioned)
+  {
+    if (aRepositioned)
+      mStateFlags |= eRepositioned;
+    else
+      mStateFlags &= ~eRepositioned;
+  }
+
+  /**
    * Return true if this accessible has a parent whose name depends on this
    * accessible.
    */
   bool HasNameDependentParent() const
     { return mContextFlags & eHasNameDependentParent; }
 
   /**
    * Return true if aria-hidden="true" is applied to the accessible or inherited
    * from the parent.
    */
   bool IsARIAHidden() const { return mContextFlags & eARIAHidden; }
   void SetARIAHidden(bool aIsDefined);
 
 protected:
-
   virtual ~Accessible();
 
   /**
    * Return the accessible name provided by native markup. It doesn't take
    * into account ARIA markup used to specify the name.
    */
   virtual mozilla::a11y::ENameValueFlag NativeName(nsString& aName);
 
@@ -985,18 +999,19 @@ protected:
     eIsNotInDocument = 1 << 1, // accessible is not in document
     eSharedNode = 1 << 2, // accessible shares DOM node from another accessible
     eNotNodeMapEntry = 1 << 3, // accessible shouldn't be in document node map
     eHasNumericValue = 1 << 4, // accessible has a numeric value
     eGroupInfoDirty = 1 << 5, // accessible needs to update group info
     eSubtreeMutating = 1 << 6, // subtree is being mutated
     eIgnoreDOMUIEvent = 1 << 7, // don't process DOM UI events for a11y events
     eSurvivingInUpdate = 1 << 8, // parent drops children to recollect them
+    eRepositioned = 1 << 9, // accessible was moved in tree
 
-    eLastStateFlag = eSurvivingInUpdate
+    eLastStateFlag = eRepositioned
   };
 
   /**
    * Flags used for contextual information about the accessible.
    */
   enum ContextFlags {
     eHasNameDependentParent = 1 << 0, // Parent's name depends on this accessible.
     eARIAHidden = 1 << 1,
@@ -1101,17 +1116,17 @@ protected:
   nsCOMPtr<nsIContent> mContent;
   DocAccessible* mDoc;
 
   nsRefPtr<Accessible> mParent;
   nsTArray<nsRefPtr<Accessible> > mChildren;
   int32_t mIndexInParent;
 
   static const uint8_t kChildrenFlagsBits = 2;
-  static const uint8_t kStateFlagsBits = 9;
+  static const uint8_t kStateFlagsBits = 10;
   static const uint8_t kContextFlagsBits = 2;
   static const uint8_t kTypeBits = 6;
   static const uint8_t kGenericTypesBits = 14;
 
   /**
    * Keep in sync with ChildrenFlags, StateFlags, ContextFlags, and AccTypes.
    */
   uint32_t mChildrenFlags : kChildrenFlagsBits;
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -702,17 +702,17 @@ DocAccessible::AttributeWillChange(nsIDo
 
     accessible = this;
   }
 
   // Update dependent IDs cache. Take care of elements that are accessible
   // because dependent IDs cache doesn't contain IDs from non accessible
   // elements.
   if (aModType != nsIDOMMutationEvent::ADDITION)
-    RemoveDependentIDsFor(aElement, aAttribute);
+    RemoveDependentIDsFor(accessible, aAttribute);
 
   // Store the ARIA attribute old value so that it can be used after
   // attribute change. Note, we assume there's no nested ARIA attribute
   // changes. If this happens then we should end up with keeping a stack of
   // old values.
 
   // XXX TODO: bugs 472142, 472143.
   // Here we will want to cache whatever attribute values we are interested
@@ -764,17 +764,17 @@ DocAccessible::AttributeChanged(nsIDocum
 
   // Update dependent IDs cache. Take care of accessible elements because no
   // accessible element means either the element is not accessible at all or
   // its accessible will be created later. It doesn't make sense to keep
   // dependent IDs for non accessible elements. For the second case we'll update
   // dependent IDs cache when its accessible is created.
   if (aModType == nsIDOMMutationEvent::MODIFICATION ||
       aModType == nsIDOMMutationEvent::ADDITION) {
-    AddDependentIDsFor(aElement, aAttribute);
+    AddDependentIDsFor(accessible, aAttribute);
   }
 }
 
 // DocAccessible protected member
 void
 DocAccessible::AttributeChangedImpl(Accessible* aAccessible,
                                     int32_t aNameSpaceID, nsIAtom* aAttribute)
 {
@@ -1236,19 +1236,17 @@ DocAccessible::BindToDocument(Accessible
   if (aAccessible->IsNodeMapEntry())
     mNodeToAccessibleMap.Put(aAccessible->GetNode(), aAccessible);
 
   // Put into unique ID cache.
   mAccessibleCache.Put(aAccessible->UniqueID(), aAccessible);
 
   aAccessible->SetRoleMapEntry(aRoleMapEntry);
 
-  nsIContent* content = aAccessible->GetContent();
-  if (content && content->IsElement())
-    AddDependentIDsFor(content->AsElement());
+  AddDependentIDsFor(aAccessible);
 }
 
 void
 DocAccessible::UnbindFromDocument(Accessible* aAccessible)
 {
   NS_ASSERTION(mAccessibleCache.GetWeak(aAccessible->UniqueID()),
                "Unbinding the unbound accessible!");
 
@@ -1333,16 +1331,59 @@ DocAccessible::ProcessInvalidationList()
     if (!HasAccessible(content)) {
       Accessible* container = GetContainerAccessible(content);
       if (container)
         UpdateTreeOnInsertion(container);
     }
   }
 
   mInvalidationList.Clear();
+
+  // Alter the tree according to aria-owns (seize the trees).
+  for (uint32_t idx = 0; idx < mARIAOwnsInvalidationList.Length(); idx++) {
+    Accessible* owner = mARIAOwnsInvalidationList[idx].mOwner;
+    Accessible* child = GetAccessible(mARIAOwnsInvalidationList[idx].mChild);
+    if (!child) {
+      continue;
+    }
+
+    // XXX: update context flags
+    {
+      Accessible* oldParent = child->Parent();
+      nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(oldParent);
+      nsRefPtr<AccMutationEvent> hideEvent =
+        new AccHideEvent(child, child->GetContent(), false);
+      FireDelayedEvent(hideEvent);
+      reorderEvent->AddSubMutationEvent(hideEvent);
+
+      AutoTreeMutation mut(oldParent);
+      oldParent->RemoveChild(child);
+
+      MaybeNotifyOfValueChange(oldParent);
+      FireDelayedEvent(reorderEvent);
+    }
+
+    {
+      nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(owner);
+      nsRefPtr<AccMutationEvent> showEvent =
+        new AccShowEvent(child, child->GetContent());
+      FireDelayedEvent(showEvent);
+      reorderEvent->AddSubMutationEvent(showEvent);
+
+      AutoTreeMutation mut(owner);
+      owner->AppendChild(child);
+
+      MaybeNotifyOfValueChange(owner);
+      FireDelayedEvent(reorderEvent);
+    }
+
+    child->SetRepositioned(true);
+  }
+
+  mARIAOwnsInvalidationList.Clear();
 }
 
 Accessible*
 DocAccessible::GetAccessibleEvenIfNotInMap(nsINode* aNode) const
 {
 if (!aNode->IsContent() || !aNode->AsContent()->IsHTMLElement(nsGkAtoms::area))
     return GetAccessible(aNode);
 
@@ -1491,104 +1532,207 @@ DocAccessible::ProcessLoad()
 
   // Fire busy state change event.
   nsRefPtr<AccEvent> stateEvent =
     new AccStateChangeEvent(this, states::BUSY, false);
   FireDelayedEvent(stateEvent);
 }
 
 void
-DocAccessible::AddDependentIDsFor(dom::Element* aRelProviderElm,
-                                  nsIAtom* aRelAttr)
+DocAccessible::AddDependentIDsFor(Accessible* aRelProvider, nsIAtom* aRelAttr)
 {
+  dom::Element* relProviderEl = aRelProvider->Elm();
+  if (!relProviderEl)
+    return;
+
   for (uint32_t idx = 0; idx < kRelationAttrsLen; idx++) {
     nsIAtom* relAttr = *kRelationAttrs[idx];
     if (aRelAttr && aRelAttr != relAttr)
       continue;
 
     if (relAttr == nsGkAtoms::_for) {
-      if (!aRelProviderElm->IsAnyOfHTMLElements(nsGkAtoms::label,
-                                                nsGkAtoms::output))
+      if (!relProviderEl->IsAnyOfHTMLElements(nsGkAtoms::label,
+                                               nsGkAtoms::output))
         continue;
 
     } else if (relAttr == nsGkAtoms::control) {
-      if (!aRelProviderElm->IsAnyOfXULElements(nsGkAtoms::label,
-                                               nsGkAtoms::description))
+      if (!relProviderEl->IsAnyOfXULElements(nsGkAtoms::label,
+                                              nsGkAtoms::description))
         continue;
     }
 
-    IDRefsIterator iter(this, aRelProviderElm, relAttr);
+    IDRefsIterator iter(this, relProviderEl, relAttr);
     while (true) {
       const nsDependentSubstring id = iter.NextID();
       if (id.IsEmpty())
         break;
 
       AttrRelProviderArray* providers = mDependentIDsHash.Get(id);
       if (!providers) {
         providers = new AttrRelProviderArray();
         if (providers) {
           mDependentIDsHash.Put(id, providers);
         }
       }
 
       if (providers) {
         AttrRelProvider* provider =
-          new AttrRelProvider(relAttr, aRelProviderElm);
+          new AttrRelProvider(relAttr, relProviderEl);
         if (provider) {
           providers->AppendElement(provider);
 
           // We've got here during the children caching. If the referenced
           // content is not accessible then store it to pend its container
           // children invalidation (this happens immediately after the caching
           // is finished).
           nsIContent* dependentContent = iter.GetElem(id);
-          if (dependentContent && !HasAccessible(dependentContent)) {
-            mInvalidationList.AppendElement(dependentContent);
+          if (dependentContent) {
+            if (!HasAccessible(dependentContent)) {
+              mInvalidationList.AppendElement(dependentContent);
+            }
+
+            if (relAttr == nsGkAtoms::aria_owns) {
+              // Dependent content cannot point to other aria-owns content or
+              // their parents. Ignore it if so.
+              // XXX: note, this alg may make invalid the scenario when X owns Y
+              // and Y owns Z, we should have something smarter to handle that.
+              bool isvalid = true;
+              for (auto it = mARIAOwnsHash.Iter(); !it.Done(); it.Next()) {
+                Accessible* owner = it.Key();
+                nsIContent* parentEl = owner->GetContent();
+                while (parentEl && parentEl != dependentContent) {
+                  parentEl = parentEl->GetParent();
+                }
+                if (parentEl) {
+                  isvalid = false;
+                  break;
+                }
+              }
+              if (isvalid) {
+                // ARIA owns also cannot refer to itself or a parent.
+                nsIContent* parentEl = relProviderEl;
+                while (parentEl && parentEl != dependentContent) {
+                  parentEl = parentEl->GetParent();
+                }
+                if (parentEl) {
+                  isvalid = false;
+                }
+
+                if (isvalid) {
+                  nsTArray<nsIContent*>* list =
+                    mARIAOwnsHash.LookupOrAdd(aRelProvider);
+                  list->AppendElement(dependentContent);
+
+                  mARIAOwnsInvalidationList.AppendElement(
+                    ARIAOwnsPair(aRelProvider, dependentContent));
+                }
+              }
+            }
           }
         }
       }
     }
 
     // If the relation attribute is given then we don't have anything else to
     // check.
     if (aRelAttr)
       break;
   }
+
+  // Make sure to schedule the tree update if needed.
+  mNotificationController->ScheduleProcessing();
 }
 
 void
-DocAccessible::RemoveDependentIDsFor(dom::Element* aRelProviderElm,
+DocAccessible::RemoveDependentIDsFor(Accessible* aRelProvider,
                                      nsIAtom* aRelAttr)
 {
+  dom::Element* relProviderElm = aRelProvider->Elm();
+  if (!relProviderElm)
+    return;
+
   for (uint32_t idx = 0; idx < kRelationAttrsLen; idx++) {
     nsIAtom* relAttr = *kRelationAttrs[idx];
     if (aRelAttr && aRelAttr != *kRelationAttrs[idx])
       continue;
 
-    IDRefsIterator iter(this, aRelProviderElm, relAttr);
+    IDRefsIterator iter(this, relProviderElm, relAttr);
     while (true) {
       const nsDependentSubstring id = iter.NextID();
       if (id.IsEmpty())
         break;
 
       AttrRelProviderArray* providers = mDependentIDsHash.Get(id);
       if (providers) {
         for (uint32_t jdx = 0; jdx < providers->Length(); ) {
           AttrRelProvider* provider = (*providers)[jdx];
           if (provider->mRelAttr == relAttr &&
-              provider->mContent == aRelProviderElm)
+              provider->mContent == relProviderElm)
             providers->RemoveElement(provider);
           else
             jdx++;
         }
         if (providers->Length() == 0)
           mDependentIDsHash.Remove(id);
       }
     }
 
+    // aria-owns has gone, put the children back.
+    if (relAttr == nsGkAtoms::aria_owns) {
+      nsTArray<nsIContent*>* children = mARIAOwnsHash.Get(aRelProvider);
+      if (children) {
+        nsTArray<Accessible*> containers;
+
+        // Remove ARIA owned elements from where they belonged.
+        nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aRelProvider);
+        {
+          AutoTreeMutation mut(aRelProvider);
+          for (uint32_t idx = 0; idx < children->Length(); idx++) {
+            nsIContent* childEl = children->ElementAt(idx);
+            Accessible* child = GetAccessible(childEl);
+            if (child && child->IsRepositioned()) {
+              {
+                nsRefPtr<AccMutationEvent> hideEvent =
+                  new AccHideEvent(child, childEl, false);
+                FireDelayedEvent(hideEvent);
+                reorderEvent->AddSubMutationEvent(hideEvent);
+
+                aRelProvider->RemoveChild(child);
+              }
+
+              // Collect DOM-order containers to update their trees.
+              child->SetRepositioned(false);
+              Accessible* container = GetContainerAccessible(childEl);
+              if (!containers.Contains(container)) {
+                containers.AppendElement(container);
+              }
+            }
+          }
+        }
+
+        mARIAOwnsHash.Remove(aRelProvider);
+        for (uint32_t idx = 0; idx < mARIAOwnsInvalidationList.Length();) {
+          if (mARIAOwnsInvalidationList[idx].mOwner == aRelProvider) {
+            mARIAOwnsInvalidationList.RemoveElementAt(idx);
+            continue;
+          }
+          idx++;
+        }
+
+        MaybeNotifyOfValueChange(aRelProvider);
+        FireDelayedEvent(reorderEvent);
+
+        // Reinserted previously ARIA owned elements into the tree
+        // (restore a DOM-like order).
+        for (uint32_t idx = 0; idx < containers.Length(); idx++) {
+          UpdateTreeOnInsertion(containers[idx]);
+        }
+      }
+    }
+
     // If the relation attribute is given then we don't have anything else to
     // check.
     if (aRelAttr)
       break;
   }
 }
 
 bool
@@ -1801,16 +1945,21 @@ DocAccessible::UpdateTreeOnRemoval(Acces
       if (childNode != containerNode) {
         updateFlags |= UpdateTreeInternal(child, false, reorderEvent);
       } else {
         idx++;
       }
     }
   }
 
+  // We may not have an integral DOM tree to remove all aria-owns relations
+  // from the tree. Validate all relations after timeout to workaround that.
+  mNotificationController->ScheduleNotification<DocAccessible>
+    (this, &DocAccessible::ValidateARIAOwned);
+
   // Content insertion/removal is not cause of accessible tree change.
   if (updateFlags == eNoAccessible)
     return;
 
   MaybeNotifyOfValueChange(aContainer);
   FireDelayedEvent(reorderEvent);
 }
 
@@ -1885,16 +2034,31 @@ DocAccessible::UpdateTreeInternal(Access
     FocusMgr()->DispatchFocusEvent(this, focusedAcc);
     SelectionMgr()->SetControlSelectionListener(focusedAcc->GetNode()->AsElement());
   }
 
   return updateFlags;
 }
 
 void
+DocAccessible::ValidateARIAOwned()
+{
+  for (auto it = mARIAOwnsHash.Iter(); !it.Done(); it.Next()) {
+    nsTArray<nsIContent*>* childEls = it.UserData();
+    for (uint32_t idx = 0; idx < childEls->Length(); idx++) {
+      nsIContent* childEl = childEls->ElementAt(idx);
+      Accessible* child = GetAccessible(childEl);
+      if (child && !child->GetFrame()) {
+        UpdateTreeOnRemoval(child->Parent(), childEl);
+      }
+    }
+  }
+}
+
+void
 DocAccessible::CacheChildrenInSubtree(Accessible* aRoot,
                                       Accessible** aFocusedAcc)
 {
   // If the accessible is focused then report a focus event after all related
   // mutation events.
   if (aFocusedAcc && !*aFocusedAcc &&
       FocusMgr()->HasDOMFocus(aRoot->GetContent()))
     *aFocusedAcc = aRoot;
@@ -1921,20 +2085,17 @@ DocAccessible::CacheChildrenInSubtree(Ac
       FireDelayedEvent(nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE, aRoot);
   }
 }
 
 void
 DocAccessible::UncacheChildrenInSubtree(Accessible* aRoot)
 {
   aRoot->mStateFlags |= eIsNotInDocument;
-
-  nsIContent* rootContent = aRoot->GetContent();
-  if (rootContent && rootContent->IsElement())
-    RemoveDependentIDsFor(rootContent->AsElement());
+  RemoveDependentIDsFor(aRoot);
 
   uint32_t count = aRoot->ContentChildCount();
   for (uint32_t idx = 0; idx < count; idx++)
     UncacheChildrenInSubtree(aRoot->ContentChildAt(idx));
 
   if (aRoot->IsNodeMapEntry() &&
       mNodeToAccessibleMap.Get(aRoot->GetNode()) == aRoot)
     mNodeToAccessibleMap.Remove(aRoot->GetNode());
--- a/accessible/generic/DocAccessible.h
+++ b/accessible/generic/DocAccessible.h
@@ -27,17 +27,17 @@ const uint32_t kDefaultCacheLength = 128
 
 namespace mozilla {
 namespace a11y {
 
 class DocManager;
 class NotificationController;
 class DocAccessibleChild;
 class RelatedAccIterator;
-template<class Class, class Arg>
+template<class Class, class ... Args>
 class TNotification;
 
 class DocAccessible : public HyperTextAccessibleWrap,
                       public nsIDocumentObserver,
                       public nsIObserver,
                       public nsIScrollPositionListener,
                       public nsSupportsWeakReference,
                       public nsIAccessiblePivotObserver
@@ -277,16 +277,32 @@ public:
   }
 
   /**
    * Return an accessible for the given node or its first accessible descendant.
    */
   Accessible* GetAccessibleOrDescendant(nsINode* aNode) const;
 
   /**
+   * Returns aria-owns seized child at the given index.
+   */
+  Accessible* ARIAOwnedAt(Accessible* aParent, uint32_t aIndex) const
+  {
+    nsTArray<nsIContent*>* childrenEl = mARIAOwnsHash.Get(aParent);
+    if (childrenEl) {
+      nsIContent* childEl = childrenEl->SafeElementAt(aIndex);
+      Accessible* child = GetAccessible(childEl);
+      if (child && child->IsRepositioned()) {
+        return child;
+      }
+    }
+    return nullptr;
+  }
+
+  /**
    * Return true if the given ID is referred by relation attribute.
    *
    * @note Different elements may share the same ID if they are hosted inside
    *       XBL bindings. Be careful the result of this method may be  senseless
    *       while it's called for XUL elements (where XBL is used widely).
    */
   bool IsDependentID(const nsAString& aID) const
     { return mDependentIDsHash.Get(aID, nullptr); }
@@ -401,28 +417,28 @@ protected:
   /**
    * Add dependent IDs pointed by accessible element by relation attribute to
    * cache. If the relation attribute is missed then all relation attributes
    * are checked.
    *
    * @param aRelProvider [in] accessible that element has relation attribute
    * @param aRelAttr     [in, optional] relation attribute
    */
-  void AddDependentIDsFor(dom::Element* aRelProviderElm,
+  void AddDependentIDsFor(Accessible* aRelProvider,
                           nsIAtom* aRelAttr = nullptr);
 
   /**
    * Remove dependent IDs pointed by accessible element by relation attribute
    * from cache. If the relation attribute is absent then all relation
    * attributes are checked.
    *
    * @param aRelProvider [in] accessible that element has relation attribute
    * @param aRelAttr     [in, optional] relation attribute
    */
-  void RemoveDependentIDsFor(dom::Element* aRelProviderElm,
+  void RemoveDependentIDsFor(Accessible* aRelProvider,
                              nsIAtom* aRelAttr = nullptr);
 
   /**
    * Update or recreate an accessible depending on a changed attribute.
    *
    * @param aElement   [in] the element the attribute was changed on
    * @param aAttribute [in] the changed attribute
    * @return            true if an action was taken on the attribute change
@@ -487,16 +503,21 @@ protected:
     eAccessible = 1,
     eAlertAccessible = 2
   };
 
   uint32_t UpdateTreeInternal(Accessible* aChild, bool aIsInsert,
                               AccReorderEvent* aReorderEvent);
 
   /**
+   * Validates all aria-owns connections and updates the tree accordingly.
+   */
+  void ValidateARIAOwned();
+
+  /**
    * Create accessible tree.
    *
    * @param aRoot       [in] a root of subtree to create
    * @param aFocusedAcc [in, optional] a focused accessible under created
    *                      subtree if any
    */
   void CacheChildrenInSubtree(Accessible* aRoot,
                               Accessible** aFocusedAcc = nullptr);
@@ -642,16 +663,35 @@ protected:
    * Used for our caching algorithm. We store the list of nodes that should be
    * invalidated.
    *
    * @see ProcessInvalidationList
    */
   nsTArray<nsIContent*> mInvalidationList;
 
   /**
+   * Holds a list of aria-owns relations.
+   */
+  nsClassHashtable<nsPtrHashKey<Accessible>, nsTArray<nsIContent*> >
+    mARIAOwnsHash;
+
+  struct ARIAOwnsPair {
+    ARIAOwnsPair(Accessible* aOwner, nsIContent* aChild) :
+      mOwner(aOwner), mChild(aChild) { }
+    ARIAOwnsPair(const ARIAOwnsPair& aPair) :
+      mOwner(aPair.mOwner), mChild(aPair.mChild) { }
+    ARIAOwnsPair& operator =(const ARIAOwnsPair& aPair)
+      { mOwner = aPair.mOwner; mChild = aPair.mChild; return *this; }
+
+    Accessible* mOwner;
+    nsIContent* mChild;
+  };
+  nsTArray<ARIAOwnsPair> mARIAOwnsInvalidationList;
+
+  /**
    * Used to process notification from core and accessible events.
    */
   nsRefPtr<NotificationController> mNotificationController;
   friend class EventQueue;
   friend class NotificationController;
 
 private:
 
--- a/accessible/tests/mochitest/common.js
+++ b/accessible/tests/mochitest/common.js
@@ -447,36 +447,49 @@ function testAccessibleTree(aAccOrElmOrI
     }
   }
 
   // Test children.
   if ("children" in accTree && accTree["children"] instanceof Array) {
     var children = acc.children;
     var childCount = children.length;
 
-
     if (accTree.children.length != childCount) {
       for (var i = 0; i < Math.max(accTree.children.length, childCount); i++) {
         var accChild;
         try {
           accChild = children.queryElementAt(i, nsIAccessible);
-          if (!accTree.children[i]) {
+
+          testChild = accTree.children[i];
+          if (!testChild) {
             ok(false, prettyName(acc) + " has an extra child at index " + i +
               " : " + prettyName(accChild));
+            continue;
           }
-          if (accChild.role !== accTree.children[i].role) {
+
+          var key = Object.keys(testChild)[0];
+          var roleName = "ROLE_" + key;
+          if (roleName in nsIAccessibleRole) {
+            testChild = {
+              role: nsIAccessibleRole[roleName],
+              children: testChild[key]
+            };
+          }
+
+          if (accChild.role !== testChild.role) {
             ok(false, prettyName(accTree) + " and " + prettyName(acc) +
               " have different children at index " + i + " : " +
-              prettyName(accTree.children[i]) + ", " + prettyName(accChild));
+              prettyName(testChild) + ", " + prettyName(accChild));
           }
           info("Matching " + prettyName(accTree) + " and " + prettyName(acc) +
                " child at index " + i + " : " + prettyName(accChild));
         } catch (e) {
           ok(false, prettyName(accTree) + " has an extra child at index " + i +
-             " : " + prettyName(accTree.children[i]));
+             " : " + prettyName(testChild) + ", " + e);
+          throw e;
         }
       }
     } else {
       if (aFlags & kSkipTreeFullCheck) {
         for (var i = 0; i < childCount; i++) {
           var child = children.queryElementAt(i, nsIAccessible);
           testAccessibleTree(child, accTree.children[i], aFlags);
         }
--- a/accessible/tests/mochitest/tree/test_aria_presentation.html
+++ b/accessible/tests/mochitest/tree/test_aria_presentation.html
@@ -82,29 +82,26 @@
       ] };
     testAccessibleTree("list_cnt", tree);
 
     // Has ARIA globals or referred by ARIA relationship, role='presentation'
     // and role='none' are ignored.
     tree =
       { SECTION: [ // container
         { LABEL: [ // label, has aria-owns
-          { TEXT_LEAF: [ ] }
-        ] },
-        { TEXT_LEAF: [ ] },
-        { LABEL: [ // label, referenced by aria-owns
-          { TEXT_LEAF: [ ] }
+          { TEXT_LEAF: [ ] },
+          { LABEL: [ // label, referenced by aria-owns
+            { TEXT_LEAF: [ ] }
+          ] },
         ] },
-        { TEXT_LEAF: [ ] },
         { LABEL: [ // label, has aria-owns
-          { TEXT_LEAF: [ ] }
-        ] },
-        { TEXT_LEAF: [ ] },
-        { LABEL: [ // label, referenced by aria-owns
-          { TEXT_LEAF: [ ] }
+          { TEXT_LEAF: [ ] },
+          { LABEL: [ // label, referenced by aria-owns
+            { TEXT_LEAF: [ ] }
+          ] }
         ] }
       ] };
     testAccessibleTree("airaglobalprop_cnt", tree);
 
     SimpleTest.finish();
   }
 
   SimpleTest.waitForExplicitFinish();
@@ -167,17 +164,16 @@
     <ul role="presentation">
       <li>item</li>
     </ul>
     <ul role="none">
       <li>item</li>
     </ul>
   </div>
 
-  <div id="airaglobalprop_cnt">
-    <label role="presentation" aria-owns="ariaowned">has aria-owns</label>
-    <label role="presentation" id="ariaowned">referred by aria-owns</label>
-    <label role="none" aria-owns="ariaowned2">has aria-owns</label>
-    <label role="none" id="ariaowned2">referred by aria-owns</label>
-  </div>
+  <div id="airaglobalprop_cnt"><label
+    role="presentation" aria-owns="ariaowned">has aria-owns</label><label
+    role="presentation" id="ariaowned">referred by aria-owns</label><label
+    role="none" aria-owns="ariaowned2">has aria-owns</label><label
+    role="none" id="ariaowned2">referred by aria-owns</label></div>
 
 </body>
 </html>
--- a/accessible/tests/mochitest/treeupdate/a11y.ini
+++ b/accessible/tests/mochitest/treeupdate/a11y.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 
 [test_ariadialog.html]
+[test_ariaowns.html]
 [test_bug852150.xhtml]
 [test_bug883708.xhtml]
 [test_bug884251.xhtml]
 [test_bug895082.html]
 [test_bug1040735.html]
 [test_bug1100602.html]
 [test_bug1175913.html]
 [test_bug1189277.html]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_ariaowns.html
@@ -0,0 +1,234 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <title>@aria-owns attribute testing</title>
+
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../role.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+
+  <script type="application/javascript">
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Invokers
+    ////////////////////////////////////////////////////////////////////////////
+
+    function removeARIAOwns()
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_HIDE, getNode("t2_checkbox")),
+        new invokerChecker(EVENT_HIDE, getNode("t2_button")),
+        new invokerChecker(EVENT_SHOW, getNode("t2_button")),
+        new invokerChecker(EVENT_SHOW, getNode("t2_checkbox")),
+        new invokerChecker(EVENT_REORDER, getNode("container2"))
+      ];
+
+      this.invoke = function removeARIAOwns_invoke()
+      {
+        // children are swapped
+        var tree =
+          { SECTION: [
+              { CHECKBUTTON: [
+                { SECTION: [] }
+              ] },
+              { PUSHBUTTON: [ ] }
+          ] };
+        testAccessibleTree("container2", tree);
+
+        getNode("container2").removeAttribute("aria-owns");
+      }
+
+      this.finalCheck = function removeARIAOwns_finalCheck()
+      {
+        // children follow the DOM order
+        var tree =
+          { SECTION: [
+              { PUSHBUTTON: [ ] },
+              { CHECKBUTTON: [
+                  { SECTION: [] }
+              ] }
+          ] };
+        testAccessibleTree("container2", tree);
+      }
+
+      this.getID = function removeARIAOwns_getID()
+      {
+        return "Remove @aria-owns attribute";
+      }
+    }
+
+    function setARIAOwns()
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_HIDE, getNode("t2_button")),
+        new invokerChecker(EVENT_SHOW, getNode("t2_button")),
+        new invokerChecker(EVENT_HIDE, getNode("t2_subdiv")),
+        new invokerChecker(EVENT_SHOW, getNode("t2_subdiv")),
+        new invokerChecker(EVENT_REORDER, getNode("container2"))
+      ];
+
+      this.invoke = function setARIAOwns_invoke()
+      {
+        getNode("container2").setAttribute("aria-owns", "t2_button t2_subdiv");
+      }
+
+      this.finalCheck = function setARIAOwns_finalCheck()
+      {
+        // children are swapped again, button and subdiv are appended to
+        // the children.
+        var tree =
+          { SECTION: [
+              { CHECKBUTTON: [ ] }, // div
+              { PUSHBUTTON: [ ] }, // button
+              { SECTION: [ ] } // subdiv
+          ] };
+        testAccessibleTree("container2", tree);
+      }
+
+      this.getID = function setARIAOwns_getID()
+      {
+        return "Set @aria-owns attribute";
+      }
+    }
+
+    function appendEl()
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_SHOW, getNode, "child3"),
+        new invokerChecker(EVENT_REORDER, getNode("container2"))
+      ];
+
+      this.invoke = function appendEl_invoke()
+      {
+        var div = document.createElement("div");
+        div.setAttribute("id", "child3");
+        div.setAttribute("role", "radio")
+        getNode("container2").appendChild(div);
+      }
+
+      this.finalCheck = function appendEl_finalCheck()
+      {
+        // children are invalidated, they includes aria-owns swapped kids and
+        // newly inserted child.
+        var tree =
+          { SECTION: [
+              { CHECKBUTTON: [ ] },
+              { RADIOBUTTON: [ ] },
+              { PUSHBUTTON: [ ] }, // ARIA owned
+              { SECTION: [ ] } // ARIA owned
+          ] };
+        testAccessibleTree("container2", tree);
+      }
+
+      this.getID = function appendEl_getID()
+      {
+        return "Append child under @aria-owns element";
+      }
+    }
+
+    function removeEl()
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_HIDE, getNode, "t2_checkbox"),
+        new invokerChecker(EVENT_SHOW, getNode, "t2_checkbox"),
+        new invokerChecker(EVENT_REORDER, getNode("container2"))
+      ];
+
+      this.invoke = function removeEl_invoke()
+      {
+        // remove a container of t2_subdiv
+        getNode("t2_span").parentNode.removeChild(getNode("t2_span"));
+      }
+
+      this.finalCheck = function removeEl_finalCheck()
+      {
+        // subdiv should go away
+        var tree =
+          { SECTION: [
+              { CHECKBUTTON: [ ] },
+              { RADIOBUTTON: [ ] },
+              { PUSHBUTTON: [ ] } // ARIA owned
+          ] };
+        testAccessibleTree("container2", tree);
+      }
+
+      this.getID = function removeEl_getID()
+      {
+        return "Remove a container of ARIA ownded element";
+      }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Test
+    ////////////////////////////////////////////////////////////////////////////
+
+    gA11yEventDumpToConsole = true;
+    enableLogging("tree"); // debug stuff
+
+    var gQueue = null;
+
+    function doTest()
+    {
+      // nested and recursive aria-owns
+      var tree =
+        { SECTION: [ // container
+          { SECTION: [ // child
+            { SECTION: [ // mid div
+              { SECTION: [] } // grandchild
+            ] }
+          ] }
+        ] };
+      testAccessibleTree("container", tree);
+
+      // dynamic tests
+      gQueue = new eventQueue();
+
+      gQueue.push(new removeARIAOwns());
+      gQueue.push(new setARIAOwns());
+      gQueue.push(new appendEl());
+      gQueue.push(new removeEl());
+
+      gQueue.invoke(); // SimpleTest.finish() will be called in the end
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+
+  </script>
+</head>
+
+<body>
+
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <div id="container" aria-owns="child" aria-label="container"></div>
+  <div id="child" aria-label="child">
+    <div aria-owns="grandchild" aria-label="midchild"></div>
+  </div>
+  <div id="grandchild" aria-owns="container" aria-label="grandchild"></div>
+
+  <div id="container2" aria-owns="t2_checkbox t2_button">
+    <div role="button" id="t2_button"></div>
+    <div role="checkbox" id="t2_checkbox">
+      <span id="t2_span">
+        <div id="t2_subdiv"></div>
+      </span>
+    </div>
+  </div>
+
+</body>
+
+</html>
--- a/browser/base/content/test/general/browser_devices_get_user_media_in_frame.js
+++ b/browser/base/content/test/general/browser_devices_get_user_media_in_frame.js
@@ -264,26 +264,33 @@ let gTests = [
       info("requesting devices");
       global.requestDevice(true, true);
     });
     expectObserverCalled("getUserMedia:request");
     checkDeviceSelectors(true, true);
 
     let indicator = promiseIndicatorWindow();
     yield promiseMessage("ok", () => {
-      PopupNotifications.panel.firstChild.button.click();
+      activateSecondaryAction(kActionAlways);
     });
     expectObserverCalled("getUserMedia:response:allow");
     expectObserverCalled("recording-device-events");
     is(getMediaCaptureState(), "CameraAndMicrophone",
        "expected camera and microphone to be shared");
 
     yield indicator;
     yield checkSharingUI({video: true, audio: true});
 
+    let Perms = Services.perms;
+    let uri = Services.io.newURI("https://example.com/", null, null);
+    is(Perms.testExactPermission(uri, "microphone"), Perms.ALLOW_ACTION,
+                                 "microphone persistently allowed");
+    is(Perms.testExactPermission(uri, "camera"), Perms.ALLOW_ACTION,
+                                 "camera persistently allowed");
+
     yield promiseNotificationShown(PopupNotifications.getNotification("webRTC-sharingDevices"));
     activateSecondaryAction(kActionDeny);
 
     yield promiseObserverCalled("recording-device-events");
     expectObserverCalled("getUserMedia:revoke");
 
     yield promiseNoPopupNotification("webRTC-sharingDevices");
     expectObserverCalled("recording-window-ended");
@@ -291,16 +298,22 @@ let gTests = [
     if (gObservedTopics["recording-device-events"] == 1) {
       todo(false, "Got the 'recording-device-events' notification twice, likely because of bug 962719");
       gObservedTopics["recording-device-events"] = 0;
     }
 
     expectNoObserverCalled();
     yield checkNotSharing();
 
+    // The persistent permissions for the frame should have been removed.
+    is(Perms.testExactPermission(uri, "microphone"), Perms.UNKNOWN_ACTION,
+                                 "microphone not persistently allowed");
+    is(Perms.testExactPermission(uri, "camera"), Perms.UNKNOWN_ACTION,
+                                 "camera not persistently allowed");
+
     // the stream is already closed, but this will do some cleanup anyway
     yield closeStream(global, true);
   }
 },
 
 {
   desc: "getUserMedia audio+video: reloading the frame removes all sharing UI",
   run: function checkReloading() {
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -34,22 +34,22 @@ file, You can obtain one at http://mozil
                   class="textbox-input-box urlbar-input-box"
                   flex="1" xbl:inherits="tooltiptext=inputtooltiptext">
           <children/>
           <html:input anonid="input"
                       class="autocomplete-textbox urlbar-input textbox-input uri-element-right-align"
                       allowevents="true"
                       xbl:inherits="tooltiptext=inputtooltiptext,value,type,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey"/>
         </xul:hbox>
+        <xul:dropmarker anonid="historydropmarker"
+                        class="autocomplete-history-dropmarker urlbar-history-dropmarker"
+                        allowevents="true"
+                        xbl:inherits="open,enablehistory,parentfocused=focused"/>
         <children includes="hbox"/>
       </xul:hbox>
-      <xul:dropmarker anonid="historydropmarker"
-                      class="autocomplete-history-dropmarker urlbar-history-dropmarker"
-                      allowevents="true"
-                      xbl:inherits="open,enablehistory,parentfocused=focused"/>
       <xul:popupset anonid="popupset"
                     class="autocomplete-result-popupset"/>
       <children includes="toolbarbutton"/>
     </content>
 
     <implementation implements="nsIObserver, nsIDOMEventListener">
       <field name="AppConstants" readonly="true">
         (Components.utils.import("resource://gre/modules/AppConstants.jsm", {})).AppConstants;
--- a/browser/components/search/content/search.xml
+++ b/browser/components/search/content/search.xml
@@ -63,24 +63,21 @@
 
     <implementation implements="nsIObserver">
       <constructor><![CDATA[
         if (this.parentNode.parentNode.localName == "toolbarpaletteitem")
           return;
         // Make sure we rebuild the popup in onpopupshowing
         this._needToBuildPopup = true;
 
-        var os =
-               Components.classes["@mozilla.org/observer-service;1"]
-                         .getService(Components.interfaces.nsIObserverService);
-        os.addObserver(this, "browser-search-engine-modified", false);
+        Services.obs.addObserver(this, "browser-search-engine-modified", false);
 
         this._initialized = true;
 
-        this.searchService.init((function search_init_cb(aStatus) {
+        Services.search.init((function search_init_cb(aStatus) {
           // Bail out if the binding's been destroyed
           if (!this._initialized)
             return;
 
           if (Components.isSuccessCode(aStatus)) {
             // Refresh the display (updating icon, etc)
             this.updateDisplay();
           } else {
@@ -93,19 +90,17 @@
         this.destroy();
       ]]></destructor>
 
       <method name="destroy">
         <body><![CDATA[
         if (this._initialized) {
           this._initialized = false;
 
-          var os = Components.classes["@mozilla.org/observer-service;1"]
-                             .getService(Components.interfaces.nsIObserverService);
-          os.removeObserver(this, "browser-search-engine-modified");
+          Services.obs.removeObserver(this, "browser-search-engine-modified");
         }
 
         // Make sure to break the cycle from _textbox to us. Otherwise we leak
         // the world. But make sure it's actually pointing to us.
         // Also make sure the textbox has ever been constructed, otherwise the
         // _textbox getter will cause the textbox constructor to run, add an
         // observer, and leak the world too.
         if (this._textboxInitialized && this._textbox.mController.input == this)
@@ -115,63 +110,50 @@
 
       <field name="_ignoreFocus">false</field>
       <field name="_clickClosedPopup">false</field>
       <field name="_stringBundle">document.getAnonymousElementByAttribute(this,
           "anonid", "searchbar-stringbundle");</field>
       <field name="_textboxInitialized">false</field>
       <field name="_textbox">document.getAnonymousElementByAttribute(this,
           "anonid", "searchbar-textbox");</field>
-      <field name="_ss">null</field>
       <field name="_engines">null</field>
       <field name="FormHistory" readonly="true">
         (Components.utils.import("resource://gre/modules/FormHistory.jsm", {})).FormHistory;
       </field>
       <field name="PlacesUtils" readonly="true">
         (Components.utils.import("resource://gre/modules/PlacesUtils.jsm", {})).PlacesUtils;
       </field>
 
       <property name="engines" readonly="true">
         <getter><![CDATA[
           if (!this._engines)
-            this._engines = this.searchService.getVisibleEngines();
+            this._engines = Services.search.getVisibleEngines();
           return this._engines;
         ]]></getter>
       </property>
 
       <property name="currentEngine">
         <setter><![CDATA[
-          let ss = this.searchService;
+          let ss = Services.search;
           ss.defaultEngine = ss.currentEngine = val;
           return val;
         ]]></setter>
         <getter><![CDATA[
-          var currentEngine = this.searchService.currentEngine;
+          var currentEngine = Services.search.currentEngine;
           // Return a dummy engine if there is no currentEngine
           return currentEngine || {name: "", uri: null};
         ]]></getter>
       </property>
 
       <!-- textbox is used by sanitize.js to clear the undo history when
            clearing form information. -->
       <property name="textbox" readonly="true"
                 onget="return this._textbox;"/>
 
-      <property name="searchService" readonly="true">
-        <getter><![CDATA[
-          if (!this._ss) {
-            const nsIBSS = Components.interfaces.nsIBrowserSearchService;
-            this._ss =
-                 Components.classes["@mozilla.org/browser/search-service;1"]
-                           .getService(nsIBSS);
-          }
-          return this._ss;
-        ]]></getter>
-      </property>
-
       <property name="value" onget="return this._textbox.value;"
                              onset="return this._textbox.value = val;"/>
 
       <method name="focus">
         <body><![CDATA[
           this._textbox.focus();
         ]]></body>
       </method>
@@ -361,17 +343,17 @@
 
           // Open ctrl/cmd clicks on one-off buttons in a new background tab.
           if (aEvent && aEvent.originalTarget.getAttribute("anonid") == "search-go-button") {
             if (aEvent.button == 2)
               return;
             where = whereToOpenLink(aEvent, false, true);
           }
           else {
-            var newTabPref = textBox._prefBranch.getBoolPref("browser.search.openintab");
+            var newTabPref = Services.prefs.getBoolPref("browser.search.openintab");
             if (((aEvent instanceof KeyboardEvent) && aEvent.altKey) ^ newTabPref)
               where = "tab";
             if ((aEvent instanceof MouseEvent) &&
                 (aEvent.button == 1 || aEvent.getModifierState("Accel"))) {
               where = "tab-background";
             }
           }
 
@@ -451,28 +433,25 @@
     </implementation>
 
     <handlers>
       <handler event="command"><![CDATA[
         const target = event.originalTarget;
         if (target.engine) {
           this.currentEngine = target.engine;
         } else if (target.classList.contains("addengine-item")) {
-          var searchService =
-            Components.classes["@mozilla.org/browser/search-service;1"]
-                      .getService(Components.interfaces.nsIBrowserSearchService);
           // We only detect OpenSearch files
-          var type = Components.interfaces.nsISearchEngine.DATA_XML;
+          var type = Ci.nsISearchEngine.DATA_XML;
           // Select the installed engine if the installation succeeds
           var installCallback = {
             onSuccess: engine => this.currentEngine = engine
           }
-          searchService.addEngine(target.getAttribute("uri"), type,
-                                  target.getAttribute("src"), false,
-                                  installCallback);
+          Services.search.addEngine(target.getAttribute("uri"), type,
+                                    target.getAttribute("src"), false,
+                                    installCallback);
         }
         else
           return;
 
         this.focus();
         this.select();
       ]]></handler>
 
@@ -554,23 +533,20 @@
           "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
         if (document.getBindingParent(this).parentNode.parentNode.localName ==
             "toolbarpaletteitem")
           return;
 
         // Initialize fields
         this._stringBundle = document.getBindingParent(this)._stringBundle;
-        this._prefBranch =
-                  Components.classes["@mozilla.org/preferences-service;1"]
-                            .getService(Components.interfaces.nsIPrefBranch);
         this._suggestEnabled =
-            this._prefBranch.getBoolPref("browser.search.suggest.enabled");
+          Services.prefs.getBoolPref("browser.search.suggest.enabled");
 
-        if (this._prefBranch.getBoolPref("browser.urlbar.clickSelectsAll"))
+        if (Services.prefs.getBoolPref("browser.urlbar.clickSelectsAll"))
           this.setAttribute("clickSelectsAll", true);
 
         // Add items to context menu and attach controller to handle them
         var textBox = document.getAnonymousElementByAttribute(this,
                                               "anonid", "textbox-input-box");
         var cxmenu = document.getAnonymousElementByAttribute(textBox,
                                           "anonid", "input-box-contextmenu");
         var pasteAndSearch;
@@ -632,35 +608,30 @@
           if (navigator.platform.startsWith("Mac") && aEvent.keyCode == KeyEvent.VK_F4)
             this.openSearch()
         }, true);
 
         this.controllers.appendController(this.searchbarController);
         document.getBindingParent(this)._textboxInitialized = true;
 
         // Add observer for suggest preference
-        var prefs = Components.classes["@mozilla.org/preferences-service;1"]
-                            .getService(Components.interfaces.nsIPrefBranch);
-        prefs.addObserver("browser.search.suggest.enabled", this, false);
+        Services.prefs.addObserver("browser.search.suggest.enabled", this, false);
       ]]></constructor>
 
       <destructor><![CDATA[
-          var prefs = Components.classes["@mozilla.org/preferences-service;1"]
-                              .getService(Components.interfaces.nsIPrefBranch);
-          prefs.removeObserver("browser.search.suggest.enabled", this);
+        Services.prefs.removeObserver("browser.search.suggest.enabled", this);
 
         // Because XBL and the customize toolbar code interacts poorly,
         // there may not be anything to remove here
         try {
           this.controllers.removeController(this.searchbarController);
         } catch (ex) { }
       ]]></destructor>
 
       <field name="_stringBundle"/>
-      <field name="_prefBranch"/>
       <field name="_suggestMenuItem"/>
       <field name="_suggestEnabled"/>
 
       <!--
         This overrides the searchParam property in autocomplete.xml.  We're
         hijacking this property as a vehicle for delivering the privacy
         information about the window into the guts of nsSearchSuggestions.
 
@@ -693,17 +664,17 @@
             popup.hidden = false;
 
             // Don't roll up on mouse click in the anchor for the search UI.
             if (popup.id == "PopupSearchAutoComplete") {
               popup.setAttribute("norolluponanchor", "true");
             }
 
             popup.mInput = this;
-            popup.view = this.controller.QueryInterface(Components.interfaces.nsITreeView);
+            popup.view = this.controller.QueryInterface(Ci.nsITreeView);
             popup.invalidate();
 
             popup.showCommentColumn = this.showCommentColumn;
             popup.showImageColumn = this.showImageColumn;
 
             document.popupNode = null;
 
             const isRTL = getComputedStyle(this, "").direction == "rtl";
@@ -725,17 +696,17 @@
 
       <method name="observe">
         <parameter name="aSubject"/>
         <parameter name="aTopic"/>
         <parameter name="aData"/>
         <body><![CDATA[
           if (aTopic == "nsPref:changed") {
             this._suggestEnabled =
-              this._prefBranch.getBoolPref("browser.search.suggest.enabled");
+              Services.prefs.getBoolPref("browser.search.suggest.enabled");
             this._suggestMenuItem.setAttribute("checked", this._suggestEnabled);
           }
         ]]></body>
       </method>
 
       <method name="openSearch">
         <body>
           <![CDATA[
@@ -751,17 +722,17 @@
       <!-- override |onTextEntered| in autocomplete.xml -->
       <method name="onTextEntered">
         <parameter name="aEvent"/>
         <body><![CDATA[
           var evt = aEvent || this.mEnterEvent;
 
           let engine;
           let oneOff = this.selectedButton;
-          if (oneOff) {
+          if (oneOff && !this.selectionFromMouseOver) {
             if (!oneOff.engine) {
               oneOff.doCommand();
               this.mEnterEvent = null;
               return;
             }
             engine = oneOff.engine;
           }
           if (this.mEnterEvent && this._selectionDetails &&
@@ -773,16 +744,19 @@
 
           this.mEnterEvent = null;
         ]]></body>
       </method>
 
       <field name="_selectedButton"/>
       <property name="selectedButton" onget="return this._selectedButton;">
         <setter><![CDATA[
+          // Set to true from the mouseover handler right after this setter call.
+          this.selectionFromMouseOver = false;
+
           if (this._selectedButton)
             this._selectedButton.removeAttribute("selected");
 
           let textbox = document.getBindingParent(this).textbox;
           let header =
             document.getAnonymousElementByAttribute(this.popup, "anonid",
                                                     "search-panel-one-offs-header");
           // Avoid selecting dummy buttons.
@@ -969,18 +943,18 @@
               let searchBar = this._self.parentNode;
 
               BrowserSearch.searchBar.FormHistory.update({ op : "remove", fieldname : param }, null);
               this._self.value = "";
               break;
             case "cmd_togglesuggest":
               // The pref observer will update _suggestEnabled and the menu
               // checkmark.
-              this._self._prefBranch.setBoolPref("browser.search.suggest.enabled",
-                                                 !this._self._suggestEnabled);
+              Services.prefs.setBoolPref("browser.search.suggest.enabled",
+                                         !this._self._suggestEnabled);
               break;
             default:
               // do nothing with unrecognized command
           }
         }
       })]]></field>
     </implementation>
 
@@ -1164,16 +1138,20 @@
         let textbox = searchbar.textbox;
         let self = this;
         let inputHandler = function() {
           headerSearchText.setAttribute("value", textbox.value);
           let groupText;
           let isOneOffSelected =
             this.selectedButton &&
             this.selectedButton.classList.contains("searchbar-engine-one-off-item");
+          // Typing de-selects the settings or opensearch buttons at the bottom
+          // of the search panel, as typing shows the user intends to search.
+          if (this.selectedButton && !isOneOffSelected)
+            this.selectedButton = null;
           if (textbox.value) {
             self.removeAttribute("showonlysettings");
             groupText = headerSearchText.previousSibling.value +
                         '"' + headerSearchText.value + '"' +
                         headerSearchText.nextSibling.value;
             if (!isOneOffSelected)
               headerPanel.selectedIndex = 1;
           }
@@ -1227,20 +1205,16 @@
             addEngineList.appendChild(button);
           }
         }
 
         // Finally, build the list of one-off buttons.
         while (list.firstChild)
           list.firstChild.remove();
 
-        // Avoid setting the selection based on mouse events before
-        // the 'popupshown' event has fired.
-        this._ignoreMouseEvents = true;
-
         let Preferences =
           Cu.import("resource://gre/modules/Preferences.jsm", {}).Preferences;
         let pref = Preferences.get("browser.search.hiddenOneOffs");
         let hiddenList = pref ? pref.split(",") : [];
 
         let currentEngineName = Services.search.currentEngine.name;
         let engines = Services.search.getVisibleEngines()
                               .filter(e => e.name != currentEngineName &&
@@ -1322,41 +1296,34 @@
 
           if (!--dummyItems)
             button.classList.add("last-of-row");
 
           list.appendChild(button);
         }
       ]]></handler>
 
-      <handler event="popupshown"><![CDATA[
-        this._ignoreMouseEvents = false;
-      ]]></handler>
-
       <handler event="mousedown"><![CDATA[
         // Required to receive click events from the buttons on Linux.
         event.preventDefault();
       ]]></handler>
 
       <handler event="mouseover"><![CDATA[
         let target = event.originalTarget;
         if (target.localName != "button")
           return;
 
-        // We ignore mouse events between the popupshowing and popupshown
-        // events to avoid selecting the button that happens to be under the
-        // mouse when the panel opens.
-        if (this._ignoreMouseEvents)
-          return;
-
         if ((target.classList.contains("searchbar-engine-one-off-item") &&
              !target.classList.contains("dummy")) ||
             target.classList.contains("addengine-item") ||
-            target.classList.contains("search-setting-button"))
-          document.getElementById("searchbar").textbox.selectedButton = target;
+            target.classList.contains("search-setting-button")) {
+          let textbox = document.getElementById("searchbar").textbox;
+          textbox.selectedButton = target;
+          textbox.selectionFromMouseOver = true;
+        }
       ]]></handler>
 
       <handler event="mouseout"><![CDATA[
         let target = event.originalTarget;
         if (target.localName != "button")
           return;
 
         let textbox = document.getElementById("searchbar").textbox;
--- a/browser/components/search/test/browser_oneOffHeader.js
+++ b/browser/components/search/test/browser_oneOffHeader.js
@@ -133,9 +133,12 @@ add_task(function* test_text() {
      "Header has the correct index selected when search terms have been entered and the Change Search Settings button is selected.");
   is(getHeaderText(), "Search for foo with:",
      "Header has the correct text when search terms have been entered and the Change Search Settings button is selected.");
 
   promise = promiseEvent(searchPopup, "popuphidden");
   info("Closing search panel");
   EventUtils.synthesizeKey("VK_ESCAPE", {});
   yield promise;
+
+  // Move the cursor out of the panel area to avoid messing with other tests.
+  yield synthesizeNativeMouseMove(searchbar);
 });
--- a/browser/components/search/test/browser_searchbar_keyboard_navigation.js
+++ b/browser/components/search/test/browser_searchbar_keyboard_navigation.js
@@ -147,16 +147,33 @@ add_task(function* test_arrows() {
     EventUtils.synthesizeKey("VK_UP", {});
   }
 
   is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
   is(textbox.value, kUserValue,
      "the textfield value should be back to initial value");
 });
 
+add_task(function* test_typing_clears_button_selection() {
+  is(Services.focus.focusedElement, textbox.inputField,
+     "the search bar should be focused"); // from the previous test.
+  ok(!textbox.selectedButton, "no button should be selected");
+
+  EventUtils.synthesizeKey("VK_UP", {});
+  is(textbox.selectedButton.getAttribute("anonid"), "search-settings",
+     "the settings item should be selected");
+
+  // Type a character.
+  EventUtils.synthesizeKey("a", {});
+  ok(!textbox.selectedButton, "the settings item should be de-selected");
+
+  // Remove the character.
+  EventUtils.synthesizeKey("VK_BACK_SPACE", {});
+});
+
 add_task(function* test_tab() {
   is(Services.focus.focusedElement, textbox.inputField,
      "the search bar should be focused"); // from the previous test.
 
   let oneOffs = getOneOffs();
   ok(!textbox.selectedButton, "no one-off button should be selected");
 
   // Pressing tab should select the first one-off without selecting suggestions.
--- a/browser/devtools/netmonitor/netmonitor-controller.js
+++ b/browser/devtools/netmonitor/netmonitor-controller.js
@@ -333,19 +333,26 @@ let NetMonitorController = {
   inspectRequest: function(requestId) {
     // Look for the request in the existing ones or wait for it to appear, if
     // the network monitor is still loading.
     let deferred = promise.defer();
     let request = null;
     let inspector = function() {
       let predicate = i => i.value === requestId;
       request = NetMonitorView.RequestsMenu.getItemForPredicate(predicate);
+      if (!request) {
+        // Reset filters so that the request is visible.
+        NetMonitorView.RequestsMenu.filterOn("all");
+        request = NetMonitorView.RequestsMenu.getItemForPredicate(predicate);
+      }
+
+      // If the request was found, select it. Otherwise this function will be
+      // called again once new requests arrive.
       if (request) {
         window.off(EVENTS.REQUEST_ADDED, inspector);
-        NetMonitorView.RequestsMenu.filterOn("all");
         NetMonitorView.RequestsMenu.selectedItem = request;
         deferred.resolve();
       }
     }
 
     inspector();
     if (!request) {
       window.on(EVENTS.REQUEST_ADDED, inspector);
--- a/browser/devtools/webconsole/test/browser.ini
+++ b/browser/devtools/webconsole/test/browser.ini
@@ -323,16 +323,17 @@ skip-if = buildapp == 'mulet' || e10s # 
 [browser_webconsole_inspect-parsed-documents.js]
 [browser_webconsole_js_input_expansion.js]
 [browser_webconsole_jsterm.js]
 skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout)
 [browser_webconsole_live_filtering_of_message_types.js]
 [browser_webconsole_live_filtering_on_search_strings.js]
 [browser_webconsole_message_node_id.js]
 [browser_webconsole_netlogging.js]
+[browser_webconsole_netlogging_reset_filter.js]
 [browser_webconsole_notifications.js]
 [browser_webconsole_open-links-without-callback.js]
 [browser_webconsole_promise.js]
 [browser_webconsole_output_copy_newlines.js]
 [browser_webconsole_output_order.js]
 [browser_webconsole_property_provider.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_scratchpad_panel_link.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_netlogging_reset_filter.js
@@ -0,0 +1,91 @@
+/* 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/. */
+
+// Tests that network log messages bring up the network panel and select the
+// right request even if it was previously filtered off.
+
+"use strict";
+
+const TEST_FILE_URI = "http://example.com/browser/browser/" +
+                      "devtools/webconsole/test/test-network.html";
+const TEST_URI = "data:text/html;charset=utf8,<p>test file URI";
+
+let hud;
+
+let test = asyncTest(function* () {
+  let requests = [];
+  let { browser } = yield loadTab(TEST_URI);
+
+  yield pushPrefEnv();
+  hud = yield openConsole();
+  hud.jsterm.clearOutput();
+
+  HUDService.lastFinishedRequest.callback = request => requests.push(request);
+
+  let loaded = loadBrowser(browser);
+  content.location = TEST_FILE_URI;
+  yield loaded;
+
+  yield testMessages();
+  let htmlRequest = requests.find(e => e.request.url.endsWith("html"));
+  ok(htmlRequest, "htmlRequest was a html");
+
+  yield hud.ui.openNetworkPanel(htmlRequest.actor);
+  let toolbox = gDevTools.getToolbox(hud.target);
+  is(toolbox.currentToolId, "netmonitor", "Network panel was opened");
+
+  let panel = toolbox.getCurrentPanel();
+  let selected = panel.panelWin.NetMonitorView.RequestsMenu.selectedItem;
+  is(selected.attachment.method, htmlRequest.request.method,
+     "The correct request is selected");
+  is(selected.attachment.url, htmlRequest.request.url,
+     "The correct request is definitely selected");
+
+  // Filter out the HTML request.
+  panel.panelWin.NetMonitorView.RequestsMenu.filterOn("js");
+
+  yield toolbox.selectTool("webconsole");
+  is(toolbox.currentToolId, "webconsole", "Web console was selected");
+  yield hud.ui.openNetworkPanel(htmlRequest.actor);
+
+  panel.panelWin.NetMonitorView.RequestsMenu.selectedItem;
+  is(selected.attachment.method, htmlRequest.request.method,
+     "The correct request is selected");
+  is(selected.attachment.url, htmlRequest.request.url,
+     "The correct request is definitely selected");
+
+  // All tests are done. Shutdown.
+  HUDService.lastFinishedRequest.callback = null;
+  htmlRequest = browser = requests = hud = null;
+});
+
+function testMessages() {
+  return waitForMessages({
+    webconsole: hud,
+    messages: [{
+      text: "running network console logging tests",
+      category: CATEGORY_WEBDEV,
+      severity: SEVERITY_LOG,
+    },
+    {
+      text: "test-network.html",
+      category: CATEGORY_NETWORK,
+      severity: SEVERITY_LOG,
+    },
+    {
+      text: "testscript.js",
+      category: CATEGORY_NETWORK,
+      severity: SEVERITY_LOG,
+    }],
+  });
+}
+
+function pushPrefEnv() {
+  let deferred = promise.defer();
+  let options = {
+    set: [["devtools.webconsole.filter.networkinfo", true]]
+  };
+  SpecialPowers.pushPrefEnv(options, deferred.resolve);
+  return deferred.promise;
+}
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -388,17 +388,26 @@ function prompt(aBrowser, aRequest) {
         // and will grant audio access immediately.
         if ((!audioDevices.length || micPerm) && (!videoDevices.length || camPerm)) {
           // All permissions we were about to request are already persistently set.
           let allowedDevices = [];
           if (videoDevices.length && camPerm == perms.ALLOW_ACTION)
             allowedDevices.push(videoDevices[0].deviceIndex);
           if (audioDevices.length && micPerm == perms.ALLOW_ACTION)
             allowedDevices.push(audioDevices[0].deviceIndex);
-          let mm = this.browser.messageManager;
+
+          // Remember on which URIs we found persistent permissions so that we
+          // can remove them if the user clicks 'Stop Sharing'. There's no
+          // other way for the stop sharing code to know the hostnames of frames
+          // using devices until bug 1066082 is fixed.
+          let browser = this.browser;
+          browser._devicePermissionURIs = browser._devicePermissionURIs || [];
+          browser._devicePermissionURIs.push(uri);
+
+          let mm = browser.messageManager;
           mm.sendAsyncMessage("webrtc:Allow", {callID: aRequest.callID,
                                                windowID: aRequest.windowID,
                                                devices: allowedDevices});
           this.remove();
           return true;
         }
       }
 
@@ -529,16 +538,23 @@ function prompt(aBrowser, aRequest) {
           }
         }
 
         if (!allowedDevices.length) {
           denyRequest(notification.browser, aRequest);
           return;
         }
 
+        if (aRemember) {
+          // Remember on which URIs we set persistent permissions so that we
+          // can remove them if the user clicks 'Stop Sharing'.
+          aBrowser._devicePermissionURIs = aBrowser._devicePermissionURIs || [];
+          aBrowser._devicePermissionURIs.push(uri);
+        }
+
         let mm = notification.browser.messageManager;
         mm.sendAsyncMessage("webrtc:Allow", {callID: aRequest.callID,
                                              windowID: aRequest.windowID,
                                              devices: allowedDevices});
       };
       return false;
     }
   };
@@ -857,25 +873,27 @@ function updateBrowserSpecificIndicator(
     accessKey: stringBundle.getString("getUserMedia.continueSharing.accesskey"),
     callback: function () {},
     dismiss: true
   };
   let secondaryActions = [{
     label: stringBundle.getString("getUserMedia.stopSharing.label"),
     accessKey: stringBundle.getString("getUserMedia.stopSharing.accesskey"),
     callback: function () {
-      let uri = Services.io.newURI(aState.documentURI, null, null);
+      let uris = aBrowser._devicePermissionURIs || [];
+      uris = uris.concat(Services.io.newURI(aState.documentURI, null, null));
       let perms = Services.perms;
-      if (aState.camera &&
-          perms.testExactPermission(uri, "camera") == perms.ALLOW_ACTION)
-        perms.remove(uri, "camera");
-      if (aState.microphone &&
-          perms.testExactPermission(uri, "microphone") == perms.ALLOW_ACTION)
-        perms.remove(uri, "microphone");
-
+      for (let uri of uris) {
+        if (aState.camera &&
+            perms.testExactPermission(uri, "camera") == perms.ALLOW_ACTION)
+          perms.remove(uri, "camera");
+        if (aState.microphone &&
+            perms.testExactPermission(uri, "microphone") == perms.ALLOW_ACTION)
+          perms.remove(uri, "microphone");
+      }
       let mm = notification.browser.messageManager;
       mm.sendAsyncMessage("webrtc:StopSharing", windowId);
     }
   }];
   let options = {
     hideNotNow: true,
     dismissed: true,
     eventCallback: function(aTopic, aNewBrowser) {
@@ -897,22 +915,23 @@ function updateBrowserSpecificIndicator(
     let anchorId = captureState == "Microphone" ? "webRTC-sharingMicrophone-notification-icon"
                                                 : "webRTC-sharingDevices-notification-icon";
     let message = stringBundle.getString("getUserMedia.sharing" + captureState + ".message2");
     notification =
       chromeWin.PopupNotifications.show(aBrowser, "webRTC-sharingDevices", message,
                                         anchorId, mainAction, secondaryActions, options);
   }
   else {
-    removeBrowserNotification(aBrowser,"webRTC-sharingDevices");
+    removeBrowserNotification(aBrowser, "webRTC-sharingDevices");
+    aBrowser._devicePermissionURIs = null;
   }
 
   // Now handle the screen sharing indicator.
   if (!aState.screen) {
-    removeBrowserNotification(aBrowser,"webRTC-sharingScreen");
+    removeBrowserNotification(aBrowser, "webRTC-sharingScreen");
     return;
   }
 
   let screenSharingNotif; // Used by action callbacks.
   let isBrowserSharing = aState.screen == "Browser";
   options = {
     hideNotNow: !isBrowserSharing,
     dismissed: true,
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -885,16 +885,21 @@ toolbarbutton[constrain-size="true"][cui
 }
 
 .urlbar-input-box {
   -moz-margin-start: 0;
 }
 
 .urlbar-history-dropmarker {
   -moz-appearance: toolbarbutton-dropdown;
+  transition: opacity 0.15s ease;
+}
+
+#urlbar:not(:hover) > .urlbar-textbox-container > .urlbar-history-dropmarker {
+  opacity: 0;
 }
 
 #urlbar-container {
   -moz-box-align: center;
 }
 
 @conditionalForwardWithUrlbar@ > #urlbar {
   -moz-border-start: none;
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -1694,16 +1694,21 @@ toolbarbutton[constrain-size="true"][cui
   -moz-margin-start: 0;
   padding: 3px 0 2px;
 }
 
 .urlbar-history-dropmarker {
   padding: 0 3px;
   list-style-image: var(--urlbar-dropmarker-url);
   -moz-image-region: var(--urlbar-dropmarker-region);
+  transition: opacity 0.15s ease;
+}
+
+#urlbar:not(:hover) > .urlbar-textbox-container > .urlbar-history-dropmarker {
+  opacity: 0;
 }
 
 .urlbar-history-dropmarker[open="true"],
 .urlbar-history-dropmarker:hover:active {
   -moz-image-region: var(--urlbar-dropmarker-active-region);
 }
 
 @media (min-resolution: 2dppx) {
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -1471,16 +1471,21 @@ html|*.urlbar-input:-moz-lwtheme::-moz-p
 .urlbar-history-dropmarker {
   -moz-appearance: none;
   padding: 0 3px;
   background-color: transparent;
   border: none;
   width: auto;
   list-style-image: var(--urlbar-dropmarker-url);
   -moz-image-region: var(--urlbar-dropmarker-region);
+  transition: opacity 0.15s ease;
+}
+
+#urlbar:not(:hover) > .urlbar-textbox-container > .urlbar-history-dropmarker {
+  opacity: 0;
 }
 
 .urlbar-history-dropmarker:hover {
   -moz-image-region: var(--urlbar-dropmarker-hover-region);
 }
 
 .urlbar-history-dropmarker:hover:active,
 .urlbar-history-dropmarker[open="true"] {
--- a/build/upload.py
+++ b/build/upload.py
@@ -10,16 +10,20 @@
 # UPLOAD_USER    : username on that host
 #  and one of the following:
 # UPLOAD_PATH    : path on that host to put the files in
 # UPLOAD_TO_TEMP : upload files to a new temporary directory
 #
 # If UPLOAD_HOST and UPLOAD_USER are not set, this script will simply write out
 # the properties file.
 #
+# If UPLOAD_HOST is "localhost", then files are simply copied to UPLOAD_PATH.
+# In this case, UPLOAD_TO_TEMP and POST_UPLOAD_CMD are not supported, and no
+# properties are written out.
+#
 # And will use the following optional environment variables if set:
 # UPLOAD_SSH_KEY : path to a ssh private key to use
 # UPLOAD_PORT    : port to use for ssh
 # POST_UPLOAD_CMD: a commandline to run on the remote host after uploading.
 #                  UPLOAD_PATH and the full paths of all files uploaded will
 #                  be appended to the commandline.
 #
 # All files to be uploaded should be passed as commandline arguments to this
@@ -27,16 +31,17 @@
 # to indicate that files should be uploaded including their paths relative
 # to the base path.
 
 import sys, os
 import re
 import json
 import errno
 import hashlib
+import shutil
 from optparse import OptionParser
 from subprocess import check_call, check_output, STDOUT
 import redo
 
 def OptionalEnvironmentVariable(v):
     """Return the value of the environment variable named v, or None
     if it's unset (or empty)."""
     if v in os.environ and os.environ[v] != "":
@@ -101,17 +106,17 @@ def DoSCPFile(file, remote_path, user, h
     cmdline.extend([WindowsPathToMsysPath(file),
                     "%s@%s:%s" % (user, host, remote_path)])
     with redo.retrying(check_call, sleeptime=10) as f:
         f(cmdline)
         return
 
     raise Exception("Command %s returned non-zero exit code" % cmdline)
 
-def GetRemotePath(path, local_file, base_path):
+def GetBaseRelativePath(path, local_file, base_path):
     """Given a remote path to upload to, a full path to a local file, and an
     optional full path that is a base path of the local file, construct the
     full remote path to place the file in. If base_path is not None, include
     the relative path from base_path to file."""
     if base_path is None or not local_file.startswith(base_path):
         return path
     dir = os.path.dirname(local_file)
     # strip base_path + extra slash and make it unixy
@@ -209,17 +214,17 @@ def UploadFiles(user, host, path, files,
     remote_files = []
     properties = {}
     try:
         for file in files:
             file = os.path.abspath(file)
             if not os.path.isfile(file):
                 raise IOError("File not found: %s" % file)
             # first ensure that path exists remotely
-            remote_path = GetRemotePath(path, file, base_path)
+            remote_path = GetBaseRelativePath(path, file, base_path)
             DoSSHCommand("mkdir -p " + remote_path, user, host, port=port, ssh_key=ssh_key)
             if verbose:
                 print "Uploading " + file
             DoSCPFile(file, remote_path, user, host, port=port, ssh_key=ssh_key)
             remote_files.append(remote_path + '/' + os.path.basename(file))
         if post_upload_command is not None:
             if verbose:
                 print "Running post-upload command: " + post_upload_command
@@ -231,16 +236,35 @@ def UploadFiles(user, host, path, files,
     finally:
         if upload_to_temp_dir:
             DoSSHCommand("rm -rf %s" % path, user, host, port=port,
                          ssh_key=ssh_key)
     if verbose:
         print "Upload complete"
     return properties
 
+def CopyFilesLocally(path, files, verbose=False, base_path=None, package=None):
+    """Copy each file in the list of files to `path`.  The `base_path` argument is treated
+    as it is by UploadFiles."""
+    if not path.endswith("/"):
+        path += "/"
+    if base_path is not None:
+        base_path = os.path.abspath(base_path)
+    for file in files:
+        file = os.path.abspath(file)
+        if not os.path.isfile(file):
+            raise IOError("File not found: %s" % file)
+        # first ensure that path exists remotely
+        target_path = GetBaseRelativePath(path, file, base_path)
+        if not os.path.exists(target_path):
+            os.makedirs(target_path)
+        if verbose:
+            print "Copying " + file + " to " + target_path
+        shutil.copy(file, target_path)
+
 def WriteProperties(files, properties_file, url_properties, package):
     properties = url_properties
     for file in files:
         if file.endswith('.complete.mar'):
             properties.update(GetMarProperties(file))
     with open(properties_file, 'w') as outfile:
         properties['packageFilename'] = package
         properties['uploadFiles'] = [os.path.abspath(f) for f in files]
@@ -275,21 +299,35 @@ if __name__ == '__main__':
                       help="Name of the main package.")
     (options, args) = parser.parse_args()
     if len(args) < 1:
         print "You must specify at least one file to upload"
         sys.exit(1)
     if not options.properties_file:
         print "You must specify a --properties-file"
         sys.exit(1)
+
+    if host == "localhost":
+        if upload_to_temp_dir:
+            print "Cannot use UPLOAD_TO_TEMP with UPLOAD_HOST=localhost"
+            sys.exit(1)
+        if post_upload_command:
+            # POST_UPLOAD_COMMAND is difficult to extract from the mozharness
+            # scripts, so just ignore it until it's no longer used anywhere
+            print "Ignoring POST_UPLOAD_COMMAND with UPLOAD_HOST=localhost"
+
     try:
-        url_properties = UploadFiles(user, host, path, args, base_path=options.base_path,
-                                     port=port, ssh_key=key, upload_to_temp_dir=upload_to_temp_dir,
-                                     post_upload_command=post_upload_command,
-                                     package=options.package,
-                                     verbose=True)
-        WriteProperties(args, options.properties_file, url_properties, options.package)
+        if host == "localhost":
+            CopyFilesLocally(path, args, base_path=options.base_path,
+                             package=options.package,
+                             verbose=True)
+        else:
+
+            url_properties = UploadFiles(user, host, path, args,
+                                         base_path=options.base_path, port=port, ssh_key=key,
+                                         upload_to_temp_dir=upload_to_temp_dir,
+                                         post_upload_command=post_upload_command,
+                                         package=options.package, verbose=True)
+
+            WriteProperties(args, options.properties_file, url_properties, options.package)
     except IOError, (strerror):
         print strerror
         sys.exit(1)
-    except Exception, (err):
-        print err
-        sys.exit(2)
--- a/dom/base/ChildIterator.h
+++ b/dom/base/ChildIterator.h
@@ -195,16 +195,17 @@ public:
 #endif
       {}
 
 #ifdef DEBUG
   ~AllChildrenIterator() { MOZ_ASSERT(!mMutationGuard.Mutated(0)); }
 #endif
 
   nsIContent* GetNextChild();
+  nsIContent* Parent() const { return mOriginalContent; }
 
 private:
   enum IteratorPhase
   {
     eNeedBeforeKid,
     eNeedExplicitKids,
     eNeedAnonKids,
     eNeedAfterKid,
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -131,17 +131,17 @@ static const int64_t LOW_DATA_THRESHOLD_
 // LOW_DATA_THRESHOLD_USECS needs to be greater than AMPLE_AUDIO_USECS, otherwise
 // the skip-to-keyframe logic can activate when we're running low on data.
 static_assert(LOW_DATA_THRESHOLD_USECS > AMPLE_AUDIO_USECS,
               "LOW_DATA_THRESHOLD_USECS is too small");
 
 } // namespace detail
 
 // Amount of excess usecs of data to add in to the "should we buffer" calculation.
-static const uint32_t EXHAUSTED_DATA_MARGIN_USECS = 60000;
+static const uint32_t EXHAUSTED_DATA_MARGIN_USECS = 100000;
 
 // If we enter buffering within QUICK_BUFFER_THRESHOLD_USECS seconds of starting
 // decoding, we'll enter "quick buffering" mode, which exits a lot sooner than
 // normal buffering mode. This exists so that if the decode-ahead exhausts the
 // downloaded data while decode/playback is just starting up (for example
 // after a seek while the media is still playing, or when playing a media
 // as soon as it's load started), we won't necessarily stop for 30s and wait
 // for buffering. We may actually be able to playback in this case, so exit
@@ -694,26 +694,28 @@ MediaDecoderStateMachine::PushFront(Medi
 void
 MediaDecoderStateMachine::OnAudioPopped(const nsRefPtr<MediaData>& aSample)
 {
   MOZ_ASSERT(OnTaskQueue());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   mPlaybackOffset = std::max(mPlaybackOffset.Ref(), aSample->mOffset);
   UpdateNextFrameStatus();
   DispatchAudioDecodeTaskIfNeeded();
+  MaybeStartBuffering();
 }
 
 void
 MediaDecoderStateMachine::OnVideoPopped(const nsRefPtr<MediaData>& aSample)
 {
   MOZ_ASSERT(OnTaskQueue());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   mPlaybackOffset = std::max(mPlaybackOffset.Ref(), aSample->mOffset);
   UpdateNextFrameStatus();
   DispatchVideoDecodeTaskIfNeeded();
+  MaybeStartBuffering();
 }
 
 void
 MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
                                        MediaDecoderReader::NotDecodedReason aReason)
 {
   MOZ_ASSERT(OnTaskQueue());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
@@ -1092,16 +1094,44 @@ void MediaDecoderStateMachine::MaybeStar
   if (!IsPlaying()) {
     mMediaSink->SetPlaying(true);
     MOZ_ASSERT(IsPlaying());
   }
 
   DispatchDecodeTasksIfNeeded();
 }
 
+void
+MediaDecoderStateMachine::MaybeStartBuffering()
+{
+  MOZ_ASSERT(OnTaskQueue());
+  AssertCurrentThreadInMonitor();
+
+  if (mState == DECODER_STATE_DECODING &&
+      mPlayState == MediaDecoder::PLAY_STATE_PLAYING &&
+      mResource->IsExpectingMoreData()) {
+    bool shouldBuffer;
+    if (mReader->UseBufferingHeuristics()) {
+      shouldBuffer = HasLowDecodedData(EXHAUSTED_DATA_MARGIN_USECS) &&
+                     (JustExitedQuickBuffering() || HasLowUndecodedData());
+    } else {
+      MOZ_ASSERT(mReader->IsWaitForDataSupported());
+      shouldBuffer = (OutOfDecodedAudio() && mAudioWaitRequest.Exists()) ||
+                     (OutOfDecodedVideo() && mVideoWaitRequest.Exists());
+    }
+    if (shouldBuffer) {
+      StartBuffering();
+      // Don't go straight back to the state machine loop since that might
+      // cause us to start decoding again and we could flip-flop between
+      // decoding and quick-buffering.
+      ScheduleStateMachineIn(USECS_PER_S);
+    }
+  }
+}
+
 void MediaDecoderStateMachine::UpdatePlaybackPositionInternal(int64_t aTime)
 {
   MOZ_ASSERT(OnTaskQueue());
   SAMPLE_LOG("UpdatePlaybackPositionInternal(%lld)", aTime);
   AssertCurrentThreadInMonitor();
 
   mCurrentPosition = aTime;
   NS_ASSERTION(mCurrentPosition >= 0, "CurrentTime should be positive!");
@@ -2607,40 +2637,16 @@ void MediaDecoderStateMachine::UpdateRen
       mVideoFrameEndTime = currentFrame->GetEndTime();
       MediaDecoder::FrameStatistics& frameStats = mDecoder->GetFrameStatistics();
       frameStats.NotifyPresentedFrame();
     }
   }
 
   RenderVideoFrames(sVideoQueueSendToCompositorSize, clockTime, nowTime);
 
-  // Check to see if we don't have enough data to play up to the next frame.
-  // If we don't, switch to buffering mode.
-  if (mState == DECODER_STATE_DECODING &&
-      mPlayState == MediaDecoder::PLAY_STATE_PLAYING &&
-      mResource->IsExpectingMoreData()) {
-    bool shouldBuffer;
-    if (mReader->UseBufferingHeuristics()) {
-      shouldBuffer = HasLowDecodedData(remainingTime + EXHAUSTED_DATA_MARGIN_USECS) &&
-                     (JustExitedQuickBuffering() || HasLowUndecodedData());
-    } else {
-      MOZ_ASSERT(mReader->IsWaitForDataSupported());
-      shouldBuffer = (OutOfDecodedAudio() && mAudioWaitRequest.Exists()) ||
-                     (OutOfDecodedVideo() && mVideoWaitRequest.Exists());
-    }
-    if (shouldBuffer) {
-      StartBuffering();
-      // Don't go straight back to the state machine loop since that might
-      // cause us to start decoding again and we could flip-flop between
-      // decoding and quick-buffering.
-      ScheduleStateMachineIn(USECS_PER_S);
-      return;
-    }
-  }
-
   // Cap the current time to the larger of the audio and video end time.
   // This ensures that if we're running off the system clock, we don't
   // advance the clock to after the media end time.
   if (mVideoFrameEndTime != -1 || AudioEndTime() != -1) {
     // These will be non -1 if we've displayed a video frame, or played an audio frame.
     int64_t t = std::min(clockTime, std::max(mVideoFrameEndTime, AudioEndTime()));
     // FIXME: Bug 1091422 - chained ogg files hit this assertion.
     //MOZ_ASSERT(t >= GetMediaTime());
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -517,16 +517,20 @@ protected:
   // The decoder monitor must be held.
   void StopPlayback();
 
   // If the conditions are right, sets internal state which causes playback
   // of media to begin or resume.
   // Must be called with the decode monitor held.
   void MaybeStartPlayback();
 
+  // Check to see if we don't have enough data to play up to the next frame.
+  // If we don't, switch to buffering mode.
+  void MaybeStartBuffering();
+
   // Moves the decoder into decoding state. Called on the state machine
   // thread. The decoder monitor must be held.
   void StartDecoding();
 
   // Moves the decoder into the shutdown state, and dispatches an error
   // event to the media element. This begins shutting down the decoder.
   // The decoder monitor must be held. This is only called on the
   // decode thread.
--- a/dom/tests/mochitest/fetch/mochitest.ini
+++ b/dom/tests/mochitest/fetch/mochitest.ini
@@ -22,20 +22,20 @@ support-files =
 skip-if = buildapp == 'b2g' # Bug 1137683
 [test_headers_mainthread.html]
 [test_fetch_app_protocol.html]
 [test_fetch_basic.html]
 [test_fetch_basic_sw_reroute.html]
 skip-if = buildapp == 'b2g' # Bug 1137683
 [test_fetch_basic_http.html]
 [test_fetch_basic_http_sw_reroute.html]
-skip-if = e10s || buildapp == 'b2g' || buildapp == 'mulet' # Bug 1093357 for e10s, bug 1137683 for b2g, bug 1174872 for mulet
+skip-if = buildapp == 'b2g' || buildapp == 'mulet' # Bug 1137683 for b2g, bug 1174872 for mulet
 [test_fetch_cors.html]
 [test_fetch_cors_sw_reroute.html]
-skip-if = e10s || buildapp == 'b2g' # Bug 1093357 for e10s, bug 1137683 for b2g
+skip-if = buildapp == 'b2g' # Bug 1137683 for b2g
 [test_formdataparsing.html]
 [test_formdataparsing_sw_reroute.html]
 skip-if = buildapp == 'b2g' # Bug 1137683
 [test_request.html]
 [test_request_context.html]
 [test_request_sw_reroute.html]
 skip-if = buildapp == 'b2g' # Bug 1137683
 [test_response.html]
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -3862,16 +3862,92 @@ private:
       }
 
       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
     }
     return true;
   }
 };
 
+namespace {
+
+class ContinueDispatchFetchEventRunnable : public nsRunnable
+{
+  WorkerPrivate* mWorkerPrivate;
+  nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
+  nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
+  nsAutoPtr<ServiceWorkerClientInfo> mClientInfo;
+  bool mIsReload;
+public:
+  ContinueDispatchFetchEventRunnable(WorkerPrivate* aWorkerPrivate,
+                                     nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
+                                     nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
+                                     nsAutoPtr<ServiceWorkerClientInfo>& aClientInfo,
+                                     bool aIsReload)
+    : mWorkerPrivate(aWorkerPrivate)
+    , mChannel(aChannel)
+    , mServiceWorker(aServiceWorker)
+    , mClientInfo(aClientInfo)
+    , mIsReload(aIsReload)
+  {
+  }
+
+  void
+  HandleError()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    NS_WARNING("Unexpected error while dispatching fetch event!");
+    DebugOnly<nsresult> rv = mChannel->ResetInterception();
+    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to resume intercepted network request");
+  }
+
+  NS_IMETHOD
+  Run() override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsCOMPtr<nsIChannel> channel;
+    nsresult rv = mChannel->GetChannel(getter_AddRefs(channel));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      HandleError();
+      return NS_OK;
+    }
+
+    // The channel might have encountered an unexpected error while ensuring
+    // the upload stream is cloneable.  Check here and reset the interception
+    // if that happens.
+    nsresult status;
+    rv = channel->GetStatus(&status);
+    if (NS_WARN_IF(NS_FAILED(rv) || NS_FAILED(status))) {
+      HandleError();
+      return NS_OK;
+    }
+
+    nsRefPtr<FetchEventRunnable> event =
+      new FetchEventRunnable(mWorkerPrivate, mChannel, mServiceWorker,
+                             mClientInfo, mIsReload);
+    rv = event->Init();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      HandleError();
+      return NS_OK;
+    }
+
+    AutoJSAPI jsapi;
+    jsapi.Init();
+    if (NS_WARN_IF(!event->Dispatch(jsapi.cx()))) {
+      HandleError();
+      return NS_OK;
+    }
+
+    return NS_OK;
+  }
+};
+
+} // anonymous namespace
+
 NS_IMPL_ISUPPORTS_INHERITED(FetchEventRunnable, WorkerRunnable, nsIHttpHeaderVisitor)
 
 void
 ServiceWorkerManager::DispatchFetchEvent(const OriginAttributes& aOriginAttributes,
                                          nsIDocument* aDoc,
                                          nsIInterceptedChannel* aChannel,
                                          bool aIsReload,
                                          ErrorResult& aRv)
@@ -3935,31 +4011,38 @@ ServiceWorkerManager::DispatchFetchEvent
 
   nsMainThreadPtrHandle<nsIInterceptedChannel> handle(
     new nsMainThreadPtrHolder<nsIInterceptedChannel>(aChannel, false));
 
   nsRefPtr<ServiceWorker> sw = static_cast<ServiceWorker*>(serviceWorker.get());
   nsMainThreadPtrHandle<ServiceWorker> serviceWorkerHandle(
     new nsMainThreadPtrHolder<ServiceWorker>(sw));
 
-  // clientInfo is null if we don't have a controlled document
-  nsRefPtr<FetchEventRunnable> event =
-    new FetchEventRunnable(sw->GetWorkerPrivate(), handle, serviceWorkerHandle,
-                           clientInfo, aIsReload);
-  aRv = event->Init();
+  nsCOMPtr<nsIRunnable> continueRunnable =
+    new ContinueDispatchFetchEventRunnable(sw->GetWorkerPrivate(), handle,
+                                           serviceWorkerHandle, clientInfo,
+                                           aIsReload);
+
+  nsCOMPtr<nsIChannel> innerChannel;
+  aRv = aChannel->GetChannel(getter_AddRefs(innerChannel));
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
-  AutoJSAPI api;
-  api.Init();
-  if (NS_WARN_IF(!event->Dispatch(api.cx()))) {
-    aRv.Throw(NS_ERROR_FAILURE);
+  nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(innerChannel);
+
+  // If there is no upload stream, then continue immediately
+  if (!uploadChannel) {
+    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(continueRunnable->Run()));
     return;
   }
+
+  // Otherwise, ensure the upload stream can be cloned directly.  This may
+  // require some async copying, so provide a callback.
+  aRv = uploadChannel->EnsureUploadStreamIsCloneable(continueRunnable);
 }
 
 bool
 ServiceWorkerManager::IsAvailable(const OriginAttributes& aOriginAttributes,
                                   nsIURI* aURI)
 {
   MOZ_ASSERT(aURI);
 
--- a/dom/workers/test/serviceworkers/mochitest.ini
+++ b/dom/workers/test/serviceworkers/mochitest.ini
@@ -155,16 +155,18 @@ support-files =
   opaque_intercept_worker.js
   notify_loaded.js
   test_request_context.js
   fetch_event_client.js
   sw_clients/dummy.html
   fetch/plugin/worker.js
   fetch/plugin/plugins.html
   eventsource/*
+  sw_clients/file_blob_upload_frame.html
+  redirect_post.sjs
 
 [test_app_protocol.html]
 skip-if = release_build
 [test_bug1151916.html]
 [test_claim.html]
 [test_claim_fetch.html]
 [test_claim_oninstall.html]
 [test_close.html]
@@ -246,8 +248,9 @@ skip-if = toolkit == "android" || toolki
 [test_workerUnregister.html]
 [test_workerUpdate.html]
 [test_workerupdatefoundevent.html]
 [test_opaque_intercept.html]
 [test_fetch_event_client_postmessage.html]
 [test_escapedSlashes.html]
 [test_eventsource_intercept.html]
 [test_not_intercept_plugin.html]
+[test_file_blob_upload.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/redirect_post.sjs
@@ -0,0 +1,35 @@
+const CC = Components.Constructor;
+const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
+                             "nsIBinaryInputStream",
+                             "setInputStream");
+
+function handleRequest(request, response)
+{
+  var query = {};
+  request.queryString.split('&').forEach(function (val) {
+    var [name, value] = val.split('=');
+    query[name] = unescape(value);
+  });
+
+  var bodyStream = new BinaryInputStream(request.bodyInputStream);
+  var bodyBytes = [];
+  while ((bodyAvail = bodyStream.available()) > 0)
+    Array.prototype.push.apply(bodyBytes, bodyStream.readByteArray(bodyAvail));
+
+  var body = decodeURIComponent(
+    escape(String.fromCharCode.apply(null, bodyBytes)));
+
+  var currentHop = query.hop ? parseInt(query.hop) : 0;
+
+  var obj = JSON.parse(body);
+  if (currentHop < obj.hops) {
+    var newURL = '/tests/dom/workers/test/serviceworkers/redirect_post.sjs?hop=' +
+                 (1 + currentHop);
+    response.setStatusLine(null, 307, 'redirect');
+    response.setHeader('Location', newURL);
+    return;
+  }
+
+  response.setHeader('Content-Type', 'application/json');
+  response.write(body);
+}
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/sw_clients/file_blob_upload_frame.html
@@ -0,0 +1,77 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>test file blob upload with SW interception</title>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+
+if (!parent) {
+  dump("sw_clients/file_blob_upload_frame.html shouldn't be launched directly!");
+}
+
+function makeFileBlob(obj) {
+  return new Promise(function(resolve, reject) {
+
+    var request = indexedDB.open(window.location.pathname, 1);
+    request.onerror = reject;
+    request.onupgradeneeded = function(evt) {
+      var db = evt.target.result;
+      db.onerror = reject;
+
+      var objectStore = db.createObjectStore('test', { autoIncrement: true });
+      var index = objectStore.createIndex('test', 'index');
+    };
+
+    request.onsuccess = function(evt) {
+      var db = evt.target.result;
+      db.onerror = reject;
+
+      var blob = new Blob([JSON.stringify(obj)],
+                          { type: 'application/json' });
+      var data = { blob: blob, index: 5 };
+
+      objectStore = db.transaction('test', 'readwrite').objectStore('test');
+      objectStore.add(data).onsuccess = function(evt) {
+        var key = evt.target.result;
+        objectStore = db.transaction('test').objectStore('test');
+        objectStore.get(key).onsuccess = function(evt) {
+          resolve(evt.target.result.blob);
+        };
+      };
+    };
+  });
+}
+
+navigator.serviceWorker.ready.then(function() {
+  parent.postMessage({ status: 'READY' }, '*');
+});
+
+var URL = '/tests/dom/workers/test/serviceworkers/redirect_post.sjs';
+
+addEventListener('message', function(evt) {
+  if (evt.data.type = 'TEST') {
+    makeFileBlob(evt.data.body).then(function(blob) {
+      return fetch(URL, { method: 'POST', body: blob });
+    }).then(function(response) {
+      return response.json();
+    }).then(function(result) {
+      parent.postMessage({ status: 'OK', result: result }, '*');
+    }).catch(function(e) {
+      parent.postMessage({ status: 'ERROR', result: e.toString() }, '*');
+    });
+  }
+});
+
+</script>
+</pre>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_file_blob_upload.html
@@ -0,0 +1,146 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 1203680 - Test interception of file blob uploads</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+  var registration;
+  var iframe;
+  function start() {
+    return navigator.serviceWorker.register("empty.js",
+                                            { scope: "./sw_clients/" })
+      .then((swr) => registration = swr);
+  }
+
+  function unregister() {
+    if (iframe) {
+      iframe.remove();
+      iframe = null;
+    }
+
+    return registration.unregister().then(function(result) {
+      ok(result, "Unregister should return true.");
+    }, function(e) {
+      ok(false, "Unregistering the SW failed with " + e + "\n");
+    });
+  }
+
+  function withFrame() {
+    var content = document.getElementById("content");
+    ok(content, "Parent exists.");
+
+    iframe = document.createElement("iframe");
+    iframe.setAttribute('src', "sw_clients/file_blob_upload_frame.html");
+    content.appendChild(iframe);
+
+    return new Promise(function(resolve, reject) {
+      window.addEventListener('message', function readyCallback(evt) {
+        window.removeEventListener('message', readyCallback);
+        if (evt.data.status === 'READY') {
+          resolve();
+        } else {
+          reject(evt.data.result);
+        }
+      });
+    });
+  }
+
+  function postBlob(body) {
+    return new Promise(function(resolve, reject) {
+      window.addEventListener('message', function postBlobCallback(evt) {
+        window.removeEventListener('message', postBlobCallback);
+        if (evt.data.status === 'OK') {
+          is(JSON.stringify(body), JSON.stringify(evt.data.result),
+             'body echoed back correctly');
+          resolve();
+        } else {
+          reject(evt.data.result);
+        }
+      });
+
+      iframe.contentWindow.postMessage({ type: 'TEST', body: body }, '*');
+    });
+  }
+
+  function generateMessage(length) {
+
+    var lorem =
+      'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis egestas '
+      'vehicula tortor eget ultrices. Sed et luctus est. Nunc eu orci ligula. '
+      'In vel ornare eros, eget lacinia diam. Praesent vel metus mattis, '
+      'cursus nulla sit amet, rhoncus diam. Aliquam nulla tortor, aliquet et '
+      'viverra non, dignissim vel tellus. Praesent sed ex in dolor aliquet '
+      'aliquet. In at facilisis sem, et aliquet eros. Maecenas feugiat nisl '
+      'quis elit blandit posuere. Duis viverra odio sed eros consectetur, '
+      'viverra mattis ligula volutpat.';
+
+    var result = '';
+
+    while (result.length < length) {
+      var remaining = length - result.length;
+      if (remaining < lorem.length) {
+        result += lorem.slice(0, remaining);
+      } else {
+        result += lorem;
+      }
+    }
+
+    return result;
+  }
+
+  var smallBody = generateMessage(64);
+  var mediumBody = generateMessage(1024);
+
+  // TODO: Test large bodies over the default pipe size.  Currently stalls
+  //       due to bug 1134372.
+  //var largeBody = generateMessage(100 * 1024);
+
+  function runTest() {
+    start()
+      .then(withFrame)
+      .then(function() {
+        return postBlob({ hops: 0, message: smallBody });
+      })
+      .then(function() {
+        return postBlob({ hops: 1, message: smallBody });
+      })
+      .then(function() {
+        return postBlob({ hops: 10, message: smallBody });
+      })
+      .then(function() {
+        return postBlob({ hops: 0, message: mediumBody });
+      })
+      .then(function() {
+        return postBlob({ hops: 1, message: mediumBody });
+      })
+      .then(function() {
+        return postBlob({ hops: 10, message: mediumBody });
+      })
+      .then(unregister)
+      .catch(function(e) {
+        ok(false, "Some test failed with error " + e);
+      }).then(SimpleTest.finish);
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  SpecialPowers.pushPrefEnv({"set": [
+    ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+    ["dom.serviceWorkers.interception.enabled", true],
+    ["dom.serviceWorkers.enabled", true],
+    ["dom.serviceWorkers.testing.enabled", true]
+  ]}, runTest);
+</script>
+</pre>
+</body>
+</html>
+
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -143,17 +143,17 @@ BasicCompositor::CreateDataTextureSource
 {
   RefPtr<DataTextureSource> result = new DataTextureSourceBasic();
   return result.forget();
 }
 
 bool
 BasicCompositor::SupportsEffect(EffectTypes aEffect)
 {
-  return static_cast<EffectTypes>(aEffect) != EffectTypes::YCBCR;
+  return aEffect != EffectTypes::YCBCR && aEffect != EffectTypes::COMPONENT_ALPHA;
 }
 
 static void
 DrawSurfaceWithTextureCoords(DrawTarget *aDest,
                              const gfx::Rect& aDestRect,
                              SourceSurface *aSource,
                              const gfx::Rect& aTextureCoords,
                              gfx::Filter aFilter,
--- a/gfx/layers/composite/ImageHost.cpp
+++ b/gfx/layers/composite/ImageHost.cpp
@@ -307,16 +307,20 @@ ImageHost::Composite(LayerComposite* aLa
     RefPtr<TexturedEffect> effect =
         CreateTexturedEffect(img->mFrontBuffer->GetFormat(),
             img->mTextureSource.get(), aFilter, isAlphaPremultiplied,
             GetRenderState());
     if (!effect) {
       return;
     }
 
+    if (!GetCompositor()->SupportsEffect(effect->mType)) {
+      return;
+    }
+
     if (mLastFrameID != img->mFrameID || mLastProducerID != img->mProducerID) {
       if (mImageContainer) {
         aLayer->GetLayerManager()->
             AppendImageCompositeNotification(ImageCompositeNotification(
                 mImageContainer, nullptr,
                 img->mTimeStamp, GetCompositor()->GetCompositionTime(),
                 img->mFrameID, img->mProducerID));
       }
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -41,37 +41,47 @@ static const GUID sDeviceAttachmentsD3D1
 // {88041664-C835-4AA8-ACB8-7EC832357ED8}
 static const GUID sLayerManagerCount =
 { 0x88041664, 0xc835, 0x4aa8, { 0xac, 0xb8, 0x7e, 0xc8, 0x32, 0x35, 0x7e, 0xd8 } };
 
 const FLOAT sBlendFactor[] = { 0, 0, 0, 0 };
 
 struct DeviceAttachmentsD3D11
 {
+  DeviceAttachmentsD3D11(ID3D11Device* device)
+   : mDevice(device),
+     mInitOkay(true)
+  {}
+
+  bool CreateShaders();
+
   typedef EnumeratedArray<MaskType, MaskType::NumMaskTypes, RefPtr<ID3D11VertexShader>>
           VertexShaderArray;
   typedef EnumeratedArray<MaskType, MaskType::NumMaskTypes, RefPtr<ID3D11PixelShader>>
           PixelShaderArray;
 
   RefPtr<ID3D11InputLayout> mInputLayout;
   RefPtr<ID3D11Buffer> mVertexBuffer;
 
   VertexShaderArray mVSQuadShader;
   PixelShaderArray mSolidColorShader;
   PixelShaderArray mRGBAShader;
+  PixelShaderArray mRGBAShaderPremul;
   PixelShaderArray mRGBShader;
   PixelShaderArray mYCbCrShader;
   PixelShaderArray mComponentAlphaShader;
   RefPtr<ID3D11Buffer> mPSConstantBuffer;
   RefPtr<ID3D11Buffer> mVSConstantBuffer;
   RefPtr<ID3D11RasterizerState> mRasterizerState;
   RefPtr<ID3D11SamplerState> mLinearSamplerState;
   RefPtr<ID3D11SamplerState> mPointSamplerState;
   RefPtr<ID3D11BlendState> mPremulBlendState;
   RefPtr<ID3D11BlendState> mNonPremulBlendState;
+  RefPtr<ID3D11BlendState> mPremulBlendMultiplyState;
+  RefPtr<ID3D11BlendState> mPremulBlendScreenState;
   RefPtr<ID3D11BlendState> mComponentBlendState;
   RefPtr<ID3D11BlendState> mDisabledBlendState;
   RefPtr<IDXGIResource> mSyncTexture;
 
   //
   // VR pieces
   //
   typedef EnumeratedArray<VRHMDType, VRHMDType::NumHMDTypes, RefPtr<ID3D11InputLayout>>
@@ -88,16 +98,44 @@ struct DeviceAttachmentsD3D11
   RefPtr<ID3D11Buffer> mVRDistortionConstants;
 
   // These will be created/filled in as needed during rendering whenever the configuration
   // changes.
   VRHMDConfiguration mVRConfiguration;
   RefPtr<ID3D11Buffer> mVRDistortionVertices[2]; // one for each eye
   RefPtr<ID3D11Buffer> mVRDistortionIndices[2];
   uint32_t mVRDistortionIndexCount[2];
+
+private:
+  void InitVertexShader(const ShaderBytes& aShader, VertexShaderArray& aArray, MaskType aMaskType) {
+    InitVertexShader(aShader, byRef(aArray[aMaskType]));
+  }
+  void InitPixelShader(const ShaderBytes& aShader, PixelShaderArray& aArray, MaskType aMaskType) {
+    InitPixelShader(aShader, byRef(aArray[aMaskType]));
+  }
+  void InitVertexShader(const ShaderBytes& aShader, ID3D11VertexShader** aOut) {
+    if (!mInitOkay) {
+      return;
+    }
+    if (FAILED(mDevice->CreateVertexShader(aShader.mData, aShader.mLength, nullptr, aOut))) {
+      mInitOkay = false;
+    }
+  }
+  void InitPixelShader(const ShaderBytes& aShader, ID3D11PixelShader** aOut) {
+    if (!mInitOkay) {
+      return;
+    }
+    if (FAILED(mDevice->CreatePixelShader(aShader.mData, aShader.mLength, nullptr, aOut))) {
+      mInitOkay = false;
+    }
+  }
+
+  // Only used during initialization.
+  RefPtr<ID3D11Device> mDevice;
+  bool mInitOkay;
 };
 
 CompositorD3D11::CompositorD3D11(nsIWidget* aWidget)
   : mAttachments(nullptr)
   , mWidget(aWidget)
   , mHwnd(nullptr)
   , mDisableSequenceForNextFrame(false)
 {
@@ -166,17 +204,17 @@ CompositorD3D11::Initialize()
   mDevice->SetPrivateData(sLayerManagerCount,
                           sizeof(referenceCount),
                           &referenceCount);
 
   size = sizeof(DeviceAttachmentsD3D11*);
   if (FAILED(mDevice->GetPrivateData(sDeviceAttachmentsD3D11,
                                      &size,
                                      &mAttachments))) {
-    mAttachments = new DeviceAttachmentsD3D11;
+    mAttachments = new DeviceAttachmentsD3D11(mDevice);
     mDevice->SetPrivateData(sDeviceAttachmentsD3D11,
                             sizeof(mAttachments),
                             &mAttachments);
 
     D3D11_INPUT_ELEMENT_DESC layout[] =
     {
       { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
     };
@@ -197,17 +235,17 @@ CompositorD3D11::Initialize()
     data.pSysMem = (void*)vertices;
 
     hr = mDevice->CreateBuffer(&bufferDesc, &data, byRef(mAttachments->mVertexBuffer));
 
     if (FAILED(hr)) {
       return false;
     }
 
-    if (!CreateShaders()) {
+    if (!mAttachments->CreateShaders()) {
       return false;
     }
 
     CD3D11_BUFFER_DESC cBufferDesc(sizeof(VertexShaderConstants),
                                    D3D11_BIND_CONSTANT_BUFFER,
                                    D3D11_USAGE_DYNAMIC,
                                    D3D11_CPU_ACCESS_WRITE);
 
@@ -251,16 +289,40 @@ CompositorD3D11::Initialize()
       D3D11_COLOR_WRITE_ENABLE_ALL
     };
     blendDesc.RenderTarget[0] = rtBlendPremul;
     hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mPremulBlendState));
     if (FAILED(hr)) {
       return false;
     }
 
+    D3D11_RENDER_TARGET_BLEND_DESC rtBlendMultiplyPremul = {
+      TRUE,
+      D3D11_BLEND_DEST_COLOR, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
+      D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
+      D3D11_COLOR_WRITE_ENABLE_ALL
+    };
+    blendDesc.RenderTarget[0] = rtBlendMultiplyPremul;
+    hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mPremulBlendMultiplyState));
+    if (FAILED(hr)) {
+      return false;
+    }
+
+    D3D11_RENDER_TARGET_BLEND_DESC rtBlendScreenPremul = {
+      TRUE,
+      D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_COLOR, D3D11_BLEND_OP_ADD,
+      D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
+      D3D11_COLOR_WRITE_ENABLE_ALL
+    };
+    blendDesc.RenderTarget[0] = rtBlendScreenPremul;
+    hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mPremulBlendScreenState));
+    if (FAILED(hr)) {
+      return false;
+    }
+
     D3D11_RENDER_TARGET_BLEND_DESC rtBlendNonPremul = {
       TRUE,
       D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
       D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
       D3D11_COLOR_WRITE_ENABLE_ALL
     };
     blendDesc.RenderTarget[0] = rtBlendNonPremul;
     hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mNonPremulBlendState));
@@ -415,16 +477,18 @@ CompositorD3D11::GetTextureFactoryIdenti
   if (mAttachments->mSyncTexture) {
     HRESULT hr = mAttachments->mSyncTexture->GetSharedHandle(&ident.mSyncHandle);
     if (FAILED(hr) || !ident.mSyncHandle) {
       gfxCriticalError() << "Failed to get SharedHandle for sync texture. Result: "
                          << hexa(hr);
       MOZ_CRASH();
     }
   }
+  ident.mSupportedBlendModes += gfx::CompositionOp::OP_SCREEN;
+  ident.mSupportedBlendModes += gfx::CompositionOp::OP_MULTIPLY;
   return ident;
 }
 
 bool
 CompositorD3D11::CanUseCanvasLayerForSize(const gfx::IntSize& aSize)
 {
   int32_t maxTextureSize = GetMaxTextureSize();
 
@@ -556,31 +620,24 @@ CompositorD3D11::SetRenderTarget(Composi
 
 void
 CompositorD3D11::SetPSForEffect(Effect* aEffect, MaskType aMaskType, gfx::SurfaceFormat aFormat)
 {
   switch (aEffect->mType) {
   case EffectTypes::SOLID_COLOR:
     mContext->PSSetShader(mAttachments->mSolidColorShader[aMaskType], nullptr, 0);
     return;
-  case EffectTypes::RENDER_TARGET:
-    mContext->PSSetShader(mAttachments->mRGBAShader[aMaskType], nullptr, 0);
-    return;
-  case EffectTypes::RGB:
-    mContext->PSSetShader((aFormat == SurfaceFormat::B8G8R8A8 || aFormat == SurfaceFormat::R8G8B8A8)
-                          ? mAttachments->mRGBAShader[aMaskType]
-                          : mAttachments->mRGBShader[aMaskType], nullptr, 0);
-    return;
   case EffectTypes::YCBCR:
     mContext->PSSetShader(mAttachments->mYCbCrShader[aMaskType], nullptr, 0);
     return;
   case EffectTypes::COMPONENT_ALPHA:
     mContext->PSSetShader(mAttachments->mComponentAlphaShader[aMaskType], nullptr, 0);
     return;
   default:
+    // Note: the RGB and RENDER_TARGET cases are handled in-line in DrawQuad().
     NS_WARNING("No shader to load");
     return;
   }
 }
 
 void
 CompositorD3D11::ClearRect(const gfx::Rect& aRect)
 {
@@ -837,26 +894,33 @@ CompositorD3D11::DrawQuad(const gfx::Rec
   scissor.bottom = clipRect.YMost();
 
   mContext->RSSetScissorRects(1, &scissor);
   mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
   mContext->VSSetShader(mAttachments->mVSQuadShader[maskType], nullptr, 0);
 
   const Rect* pTexCoordRect = nullptr;
 
+  gfx::CompositionOp blendMode = gfx::CompositionOp::OP_OVER;
+  if (Effect* effect = aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get()) {
+    blendMode = static_cast<EffectBlendMode*>(effect)->mBlendMode;
+  }
+
   switch (aEffectChain.mPrimaryEffect->mType) {
   case EffectTypes::SOLID_COLOR: {
       SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, SurfaceFormat::UNKNOWN);
 
       Color color =
         static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get())->mColor;
       mPSConstants.layerColor[0] = color.r * color.a * aOpacity;
       mPSConstants.layerColor[1] = color.g * color.a * aOpacity;
       mPSConstants.layerColor[2] = color.b * color.a * aOpacity;
       mPSConstants.layerColor[3] = color.a * aOpacity;
+
+      restoreBlendMode = SetBlendMode(blendMode);
     }
     break;
   case EffectTypes::RGB:
   case EffectTypes::RENDER_TARGET:
     {
       TexturedEffect* texturedEffect =
         static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
 
@@ -864,25 +928,37 @@ CompositorD3D11::DrawQuad(const gfx::Rec
 
       TextureSourceD3D11* source = texturedEffect->mTexture->AsSourceD3D11();
 
       if (!source) {
         NS_WARNING("Missing texture source!");
         return;
       }
 
-      SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, texturedEffect->mTexture->GetFormat());
+      SurfaceFormat format = texturedEffect->mTexture->GetFormat();
+      bool useRGBAShader = (format == SurfaceFormat::B8G8R8A8 || format == SurfaceFormat::R8G8B8A8) ||
+                           (texturedEffect->mType == EffectTypes::RENDER_TARGET);
+
+      bool premultiplied = texturedEffect->mPremultiplied;
+      if (!premultiplied && useRGBAShader &&
+          (blendMode == CompositionOp::OP_MULTIPLY ||
+           blendMode == CompositionOp::OP_SCREEN))
+      {
+        mContext->PSSetShader(mAttachments->mRGBAShaderPremul[maskType], nullptr, 0);
+        premultiplied = true;
+      } else if (useRGBAShader) {
+        mContext->PSSetShader(mAttachments->mRGBAShader[maskType], nullptr, 0);
+      } else {
+        mContext->PSSetShader(mAttachments->mRGBShader[maskType], nullptr, 0);
+      }
 
       ID3D11ShaderResourceView* srView = source->GetShaderResourceView();
       mContext->PSSetShaderResources(0, 1, &srView);
 
-      if (!texturedEffect->mPremultiplied) {
-        mContext->OMSetBlendState(mAttachments->mNonPremulBlendState, sBlendFactor, 0xFFFFFFFF);
-        restoreBlendMode = true;
-      }
+      restoreBlendMode = SetBlendMode(blendMode, premultiplied);
 
       SetSamplerForFilter(texturedEffect->mFilter);
     }
     break;
   case EffectTypes::YCBCR: {
       EffectYCbCr* ycbcrEffect =
         static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());
 
@@ -909,16 +985,18 @@ CompositorD3D11::DrawQuad(const gfx::Rec
       TextureSourceD3D11* sourceY  = source->GetSubSource(Y)->AsSourceD3D11();
       TextureSourceD3D11* sourceCb = source->GetSubSource(Cb)->AsSourceD3D11();
       TextureSourceD3D11* sourceCr = source->GetSubSource(Cr)->AsSourceD3D11();
 
       ID3D11ShaderResourceView* srViews[3] = { sourceY->GetShaderResourceView(),
                                                sourceCb->GetShaderResourceView(),
                                                sourceCr->GetShaderResourceView() };
       mContext->PSSetShaderResources(0, 3, srViews);
+
+      restoreBlendMode = SetBlendMode(blendMode);
     }
     break;
   case EffectTypes::COMPONENT_ALPHA:
     {
       MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled());
       MOZ_ASSERT(mAttachments->mComponentBlendState);
       EffectComponentAlpha* effectComponentAlpha =
         static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
@@ -936,16 +1014,17 @@ CompositorD3D11::DrawQuad(const gfx::Rec
       SetSamplerForFilter(effectComponentAlpha->mFilter);
 
       pTexCoordRect = &effectComponentAlpha->mTextureCoords;
 
       ID3D11ShaderResourceView* srViews[2] = { sourceOnBlack->GetShaderResourceView(),
                                                sourceOnWhite->GetShaderResourceView() };
       mContext->PSSetShaderResources(0, 2, srViews);
 
+      // Note: component alpha is never used in blend containers.
       mContext->OMSetBlendState(mAttachments->mComponentBlendState, sBlendFactor, 0xFFFFFFFF);
       restoreBlendMode = true;
     }
     break;
   default:
     NS_WARNING("Unknown shader type");
     return;
   }
@@ -977,16 +1056,49 @@ CompositorD3D11::DrawQuad(const gfx::Rec
     }
   }
 
   if (restoreBlendMode) {
     mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor, 0xFFFFFFFF);
   }
 }
 
+bool
+CompositorD3D11::SetBlendMode(gfx::CompositionOp aOp, bool aPremultiplied)
+{
+  if (aOp == gfx::CompositionOp::OP_OVER && aPremultiplied) {
+    return false;
+  }
+
+  ID3D11BlendState* blendState = nullptr;
+
+  switch (aOp) {
+    case gfx::CompositionOp::OP_OVER:
+      MOZ_ASSERT(!aPremultiplied);
+      blendState = mAttachments->mNonPremulBlendState;
+      break;
+    case gfx::CompositionOp::OP_MULTIPLY:
+      // Premultiplication is handled in the shader.
+      MOZ_ASSERT(aPremultiplied);
+      blendState = mAttachments->mPremulBlendMultiplyState;
+      break;
+    case gfx::CompositionOp::OP_SCREEN:
+      // Premultiplication is handled in the shader.
+      MOZ_ASSERT(aPremultiplied);
+      blendState = mAttachments->mPremulBlendScreenState;
+      break;
+    default:
+      MOZ_ASSERT_UNREACHABLE("Unsupported blend mode!");
+      return false;
+  }
+
+  mContext->OMSetBlendState(blendState, sBlendFactor, 0xFFFFFFFF);
+  return true;
+}
+
 void
 CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion,
                             const Rect* aClipRectIn,
                             const Rect& aRenderBounds,
                             Rect* aClipRectOut,
                             Rect* aRenderBoundsOut)
 {
   // Don't composite if we are minimised. Other than for the sake of efficency,
@@ -1231,96 +1343,47 @@ CompositorD3D11::UpdateRenderTarget()
     return;
   }
 
   mDefaultRT = new CompositingRenderTargetD3D11(backBuf, IntPoint(0, 0));
   mDefaultRT->SetSize(mSize);
 }
 
 bool
-CompositorD3D11::CreateShaders()
+DeviceAttachmentsD3D11::CreateShaders()
 {
-  HRESULT hr;
-
-  hr = mDevice->CreateVertexShader(LayerQuadVS,
-                                   sizeof(LayerQuadVS),
-                                   nullptr,
-                                   byRef(mAttachments->mVSQuadShader[MaskType::MaskNone]));
-  if (FAILED(hr)) {
-    return false;
-  }
+  InitVertexShader(sLayerQuadVS, mVSQuadShader, MaskType::MaskNone);
+  InitVertexShader(sLayerQuadMaskVS, mVSQuadShader, MaskType::Mask2d);
+  InitVertexShader(sLayerQuadMask3DVS, mVSQuadShader, MaskType::Mask3d);
 
-  hr = mDevice->CreateVertexShader(LayerQuadMaskVS,
-                                   sizeof(LayerQuadMaskVS),
-                                   nullptr,
-                                   byRef(mAttachments->mVSQuadShader[MaskType::Mask2d]));
-  if (FAILED(hr)) {
-    return false;
-  }
-
-  hr = mDevice->CreateVertexShader(LayerQuadMask3DVS,
-                                   sizeof(LayerQuadMask3DVS),
-                                   nullptr,
-                                   byRef(mAttachments->mVSQuadShader[MaskType::Mask3d]));
-  if (FAILED(hr)) {
-    return false;
-  }
-
-#define LOAD_PIXEL_SHADER(x) hr = mDevice->CreatePixelShader(x, sizeof(x), nullptr, byRef(mAttachments->m##x[MaskType::MaskNone])); \
-  if (FAILED(hr)) { \
-    return false; \
-  } \
-  hr = mDevice->CreatePixelShader(x##Mask, sizeof(x##Mask), nullptr, byRef(mAttachments->m##x[MaskType::Mask2d])); \
-  if (FAILED(hr)) { \
-    return false; \
+  InitPixelShader(sSolidColorShader, mSolidColorShader, MaskType::MaskNone);
+  InitPixelShader(sSolidColorShaderMask, mSolidColorShader, MaskType::Mask2d);
+  InitPixelShader(sRGBShader, mRGBShader, MaskType::MaskNone);
+  InitPixelShader(sRGBShaderMask, mRGBShader, MaskType::Mask2d);
+  InitPixelShader(sRGBAShader, mRGBAShader, MaskType::MaskNone);
+  InitPixelShader(sRGBAShaderMask, mRGBAShader, MaskType::Mask2d);
+  InitPixelShader(sRGBAShaderMask3D, mRGBAShader, MaskType::Mask3d);
+  InitPixelShader(sRGBAShaderPremul, mRGBAShaderPremul, MaskType::MaskNone);
+  InitPixelShader(sRGBAShaderMaskPremul, mRGBAShaderPremul, MaskType::Mask2d);
+  InitPixelShader(sRGBAShaderMask3DPremul, mRGBAShaderPremul, MaskType::Mask3d);
+  InitPixelShader(sYCbCrShader, mYCbCrShader, MaskType::MaskNone);
+  InitPixelShader(sYCbCrShaderMask, mYCbCrShader, MaskType::Mask2d);
+  if (gfxPrefs::ComponentAlphaEnabled()) {
+    InitPixelShader(sComponentAlphaShader, mComponentAlphaShader, MaskType::MaskNone);
+    InitPixelShader(sComponentAlphaShaderMask, mComponentAlphaShader, MaskType::Mask2d);
   }
 
-  LOAD_PIXEL_SHADER(SolidColorShader);
-  LOAD_PIXEL_SHADER(RGBShader);
-  LOAD_PIXEL_SHADER(RGBAShader);
-  LOAD_PIXEL_SHADER(YCbCrShader);
-  if (gfxPrefs::ComponentAlphaEnabled()) {
-    LOAD_PIXEL_SHADER(ComponentAlphaShader);
-  }
-
-#undef LOAD_PIXEL_SHADER
-
-  hr = mDevice->CreatePixelShader(RGBAShaderMask3D,
-                                  sizeof(RGBAShaderMask3D),
-                                  nullptr,
-                                  byRef(mAttachments->mRGBAShader[MaskType::Mask3d]));
-  if (FAILED(hr)) {
-    return false;
-  }
-
-
-  /* VR stuff */
-
-  hr = mDevice->CreateVertexShader(Oculus050VRDistortionVS,
-                                   sizeof(Oculus050VRDistortionVS),
-                                   nullptr,
-                                   byRef(mAttachments->mVRDistortionVS[VRHMDType::Oculus050]));
-  if (FAILED(hr)) {
-    return false;
-  }
-
-  hr = mDevice->CreatePixelShader(Oculus050VRDistortionPS,
-                                  sizeof(Oculus050VRDistortionPS),
-                                  nullptr,
-                                  byRef(mAttachments->mVRDistortionPS[VRHMDType::Oculus050]));
-  if (FAILED(hr)) {
-    return false;
-  }
+  InitVertexShader(sOculus050VRDistortionVS, byRef(mVRDistortionVS[VRHMDType::Oculus050]));
+  InitPixelShader(sOculus050VRDistortionPS, byRef(mVRDistortionPS[VRHMDType::Oculus050]));
 
   // These are shared
   // XXX rename Oculus050 shaders to something more generic
-  mAttachments->mVRDistortionVS[VRHMDType::Cardboard] = mAttachments->mVRDistortionVS[VRHMDType::Oculus050];
-  mAttachments->mVRDistortionPS[VRHMDType::Cardboard] = mAttachments->mVRDistortionPS[VRHMDType::Oculus050];
-
-  return true;
+  mVRDistortionVS[VRHMDType::Cardboard] = mVRDistortionVS[VRHMDType::Oculus050];
+  mVRDistortionPS[VRHMDType::Cardboard] = mVRDistortionPS[VRHMDType::Oculus050];
+  return mInitOkay;
 }
 
 bool
 CompositorD3D11::UpdateConstantBuffers()
 {
   HRESULT hr;
   D3D11_MAPPED_SUBRESOURCE resource;
   resource.pData = nullptr;
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -159,21 +159,21 @@ private:
   void HandleError(HRESULT hr, Severity aSeverity = DebugAssert);
   bool Failed(HRESULT hr, Severity aSeverity = DebugAssert);
   bool Succeeded(HRESULT hr, Severity aSeverity = DebugAssert);
 
   // ensure mSize is up to date with respect to mWidget
   void EnsureSize();
   bool VerifyBufferSize();
   void UpdateRenderTarget();
-  bool CreateShaders();
   bool UpdateConstantBuffers();
   void SetSamplerForFilter(gfx::Filter aFilter);
   void SetPSForEffect(Effect *aEffect, MaskType aMaskType, gfx::SurfaceFormat aFormat);
   void PaintToTarget();
+  bool SetBlendMode(gfx::CompositionOp aOp, bool aPremultipled = true);
 
   virtual gfx::IntSize GetWidgetSize() const override { return mSize; }
 
   RefPtr<ID3D11DeviceContext> mContext;
   RefPtr<ID3D11Device> mDevice;
   RefPtr<IDXGISwapChain> mSwapChain;
   RefPtr<CompositingRenderTargetD3D11> mDefaultRT;
   RefPtr<CompositingRenderTargetD3D11> mCurrentRT;
--- a/gfx/layers/d3d11/CompositorD3D11.hlsl
+++ b/gfx/layers/d3d11/CompositorD3D11.hlsl
@@ -158,23 +158,37 @@ VS_MASK_3D_OUTPUT LayerQuadMask3DVS(cons
 
 float4 RGBAShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target
 {
   float2 maskCoords = aVertex.vMaskCoords;
   float mask = tMask.Sample(sSampler, maskCoords).r;
   return tRGB.Sample(sSampler, aVertex.vTexCoords) * fLayerOpacity * mask;
 }
 
+float4 RGBAShaderMaskPremul(const VS_MASK_OUTPUT aVertex) : SV_Target
+{
+  float4 result = RGBAShaderMask(aVertex);
+  result.rgb *= result.a;
+  return result;
+}
+
 float4 RGBAShaderMask3D(const VS_MASK_3D_OUTPUT aVertex) : SV_Target
 {
   float2 maskCoords = aVertex.vMaskCoords.xy / aVertex.vMaskCoords.z;
   float mask = tMask.Sample(LayerTextureSamplerLinear, maskCoords).r;
   return tRGB.Sample(sSampler, aVertex.vTexCoords) * fLayerOpacity * mask;
 }
 
+float4 RGBAShaderMask3DPremul(const VS_MASK_3D_OUTPUT aVertex) : SV_Target
+{
+  float4 result = RGBAShaderMask3D(aVertex);
+  result.rgb *= result.a;
+  return result;
+}
+
 float4 RGBShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target
 {
   float4 result;
   result = tRGB.Sample(sSampler, aVertex.vTexCoords) * fLayerOpacity;
   result.a = fLayerOpacity;
 
   float2 maskCoords = aVertex.vMaskCoords;
   float mask = tMask.Sample(sSampler, maskCoords).r;
@@ -243,16 +257,23 @@ float4 SolidColorShaderMask(const VS_MAS
  *  Un-masked versions
  *************************************************************
  */
 float4 RGBAShader(const VS_OUTPUT aVertex) : SV_Target
 {
   return tRGB.Sample(sSampler, aVertex.vTexCoords) * fLayerOpacity;
 }
 
+float4 RGBAShaderPremul(const VS_OUTPUT aVertex) : SV_Target
+{
+  float4 result = RGBAShader(aVertex);
+  result.rgb *= result.a;
+  return result;
+}
+
 float4 RGBShader(const VS_OUTPUT aVertex) : SV_Target
 {
   float4 result;
   result = tRGB.Sample(sSampler, aVertex.vTexCoords) * fLayerOpacity;
   result.a = fLayerOpacity;
   return result;
 }
 
--- a/gfx/layers/d3d11/CompositorD3D11Shaders.h
+++ b/gfx/layers/d3d11/CompositorD3D11Shaders.h
@@ -1,15 +1,12 @@
+struct ShaderBytes { const void* mData; size_t mLength; };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
-//
-//
-//   fxc -nologo -Tvs_4_0_level_9_3 CompositorD3D11.hlsl -ELayerQuadVS
-//    -VnLayerQuadVS -FhtmpShaderHeader
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4x4 mLayerTransform;          // Offset:    0 Size:    64
@@ -29,27 +26,27 @@
 // Name                                 Type  Format         Dim Slot Elements
 // ------------------------------ ---------- ------- ----------- ---- --------
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// POSITION                 0   xy          0     NONE  float   xy  
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// POSITION                 0   xy          0     NONE   float   xy  
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Position              0   xyzw        0      POS  float   xyzw
-// TEXCOORD                 0   xy          1     NONE  float   xy  
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float   xyzw
+// TEXCOORD                 0   xy          1     NONE   float   xy  
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c1         cb0             0         2  ( FLT, FLT, FLT, FLT)
 // c3         cb0             3         8  ( FLT, FLT, FLT, FLT)
@@ -102,20 +99,20 @@ mad r1.xyzw, cb0[6].xyzw, r0.zzzz, r1.xy
 mad o0.xyzw, cb0[7].xyzw, r0.wwww, r1.xyzw
 mad o1.xy, v0.xyxx, cb0[9].zwzz, cb0[9].xyxx
 ret 
 // Approximately 13 instruction slots used
 #endif
 
 const BYTE LayerQuadVS[] =
 {
-     68,  88,  66,  67,  26, 156, 
-     32, 249,  73, 220,  32,  91, 
-     64, 185, 136, 143, 133, 249, 
-    140, 206,   1,   0,   0,   0, 
+     68,  88,  66,  67, 200, 251, 
+     64, 251, 166, 240, 101, 137, 
+    191, 140,  75, 217,   9, 168, 
+     61, 163,   1,   0,   0,   0, 
     180,   6,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     152,   1,   0,   0, 160,   3, 
       0,   0,  28,   4,   0,   0, 
      40,   6,   0,   0,  92,   6, 
       0,   0,  65, 111, 110,  57, 
      88,   1,   0,   0,  88,   1, 
       0,   0,   0,   2, 254, 255, 
@@ -260,27 +257,27 @@ const BYTE LayerQuadVS[] =
     230, 138,  32,   0,   0,   0, 
       0,   0,   9,   0,   0,   0, 
      70, 128,  32,   0,   0,   0, 
       0,   0,   9,   0,   0,   0, 
      62,   0,   0,   1,  83,  84, 
      65,  84, 116,   0,   0,   0, 
      13,   0,   0,   0,   2,   0, 
       0,   0,   0,   0,   0,   0, 
-      3,   0,   0,   0,   6,   0, 
+      3,   0,   0,   0,  12,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   1,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,  82,  68,  69,  70, 
       4,   2,   0,   0,   1,   0, 
@@ -361,20 +358,20 @@ const BYTE LayerQuadVS[] =
       0, 171,   0,   0,   3,   0, 
       1,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
      77, 105,  99, 114, 111, 115, 
     111, 102, 116,  32,  40,  82, 
      41,  32,  72,  76,  83,  76, 
      32,  83, 104,  97, 100, 101, 
     114,  32,  67, 111, 109, 112, 
-    105, 108, 101, 114,  32,  57, 
-     46,  50,  57,  46,  57,  53, 
-     50,  46,  51,  49,  49,  49, 
-      0, 171, 171, 171,  73,  83, 
+    105, 108, 101, 114,  32,  54, 
+     46,  51,  46,  57,  54,  48, 
+     48,  46,  49,  54,  51,  56, 
+     52,   0, 171, 171,  73,  83, 
      71,  78,  44,   0,   0,   0, 
       1,   0,   0,   0,   8,   0, 
       0,   0,  32,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,   3,   3, 
       0,   0,  80,  79,  83,  73, 
      84,  73,  79,  78,   0, 171, 
@@ -389,23 +386,20 @@ const BYTE LayerQuadVS[] =
       0,   0,   0,   0,   0,   0, 
       3,   0,   0,   0,   1,   0, 
       0,   0,   3,  12,   0,   0, 
      83,  86,  95,  80, 111, 115, 
     105, 116, 105, 111, 110,   0, 
      84,  69,  88,  67,  79,  79, 
      82,  68,   0, 171, 171, 171
 };
+ShaderBytes sLayerQuadVS = { LayerQuadVS, sizeof(LayerQuadVS) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
-//
-//
-//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ESolidColorShader
-//    -VnSolidColorShader -FhtmpShaderHeader
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16
@@ -425,27 +419,27 @@ const BYTE LayerQuadVS[] =
 // Name                                 Type  Format         Dim Slot Elements
 // ------------------------------ ---------- ------- ----------- ---- --------
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Position              0   xyzw        0      POS  float       
-// TEXCOORD                 0   xy          1     NONE  float       
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float       
+// TEXCOORD                 0   xy          1     NONE   float       
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Target                0   xyzw        0   TARGET  float   xyzw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target                0   xyzw        0   TARGET   float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             0         1  ( FLT, FLT, FLT, FLT)
 //
@@ -461,20 +455,20 @@ dcl_constantbuffer cb0[1], immediateInde
 dcl_output o0.xyzw
 mov o0.xyzw, cb0[0].xyzw
 ret 
 // Approximately 2 instruction slots used
 #endif
 
 const BYTE SolidColorShader[] =
 {
-     68,  88,  66,  67, 204,   8, 
-      5, 100,  51,  20, 107, 176, 
-    111, 165, 149, 245, 134, 187, 
-     83,  96,   1,   0,   0,   0, 
+     68,  88,  66,  67,  30, 148, 
+    104, 202, 165,  39,  58, 182, 
+    100, 205,  95, 195,  52, 137, 
+    197, 241,   1,   0,   0,   0, 
     224,   3,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     132,   0,   0,   0, 204,   0, 
       0,   0,  72,   1,   0,   0, 
      84,   3,   0,   0, 172,   3, 
       0,   0,  65, 111, 110,  57, 
      68,   0,   0,   0,  68,   0, 
       0,   0,   0,   2, 255, 255, 
@@ -600,19 +594,19 @@ const BYTE SolidColorShader[] =
      81, 117,  97, 100,   0, 118, 
      77,  97, 115, 107,  81, 117, 
      97, 100,   0,  77, 105,  99, 
     114, 111, 115, 111, 102, 116, 
      32,  40,  82,  41,  32,  72, 
      76,  83,  76,  32,  83, 104, 
      97, 100, 101, 114,  32,  67, 
     111, 109, 112, 105, 108, 101, 
-    114,  32,  57,  46,  50,  57, 
-     46,  57,  53,  50,  46,  51, 
-     49,  49,  49,   0, 171, 171, 
+    114,  32,  54,  46,  51,  46, 
+     57,  54,  48,  48,  46,  49, 
+     54,  51,  56,  52,   0, 171, 
      73,  83,  71,  78,  80,   0, 
       0,   0,   2,   0,   0,   0, 
       8,   0,   0,   0,  56,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
      15,   0,   0,   0,  68,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -628,23 +622,20 @@ const BYTE SolidColorShader[] =
       0,   0,  32,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  83,  86,  95,  84, 
      97, 114, 103, 101, 116,   0, 
     171, 171
 };
+ShaderBytes sSolidColorShader = { SolidColorShader, sizeof(SolidColorShader) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
-//
-//
-//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ERGBShader
-//    -VnRGBShader -FhtmpShaderHeader
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -666,27 +657,27 @@ const BYTE SolidColorShader[] =
 // sSampler                          sampler      NA          NA    0        1
 // tRGB                              texture  float4          2d    0        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Position              0   xyzw        0      POS  float       
-// TEXCOORD                 0   xy          1     NONE  float   xy  
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float       
+// TEXCOORD                 0   xy          1     NONE   float   xy  
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Target                0   xyzw        0   TARGET  float   xyzw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target                0   xyzw        0   TARGET   float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -720,20 +711,20 @@ sample r0.xyzw, v1.xyxx, t0.xyzw, s0
 mul o0.xyz, r0.xyzx, cb0[1].xxxx
 mov o0.w, cb0[1].x
 ret 
 // Approximately 4 instruction slots used
 #endif
 
 const BYTE RGBShader[] =
 {
-     68,  88,  66,  67,  20, 109, 
-    176, 198,  26, 112, 108, 185, 
-    246, 240, 143,  18,  57, 236, 
-    126,  68,   1,   0,   0,   0, 
+     68,  88,  66,  67, 239, 198, 
+     87, 206,  69,  92, 245,  30, 
+    125, 195, 239,  77,  37, 241, 
+    175, 187,   1,   0,   0,   0, 
     232,   4,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     204,   0,   0,   0, 136,   1, 
       0,   0,   4,   2,   0,   0, 
      92,   4,   0,   0, 180,   4, 
       0,   0,  65, 111, 110,  57, 
     140,   0,   0,   0, 140,   0, 
       0,   0,   0,   2, 255, 255, 
@@ -903,19 +894,19 @@ const BYTE RGBShader[] =
      81, 117,  97, 100,   0, 118, 
      77,  97, 115, 107,  81, 117, 
      97, 100,   0,  77, 105,  99, 
     114, 111, 115, 111, 102, 116, 
      32,  40,  82,  41,  32,  72, 
      76,  83,  76,  32,  83, 104, 
      97, 100, 101, 114,  32,  67, 
     111, 109, 112, 105, 108, 101, 
-    114,  32,  57,  46,  50,  57, 
-     46,  57,  53,  50,  46,  51, 
-     49,  49,  49,   0, 171, 171, 
+    114,  32,  54,  46,  51,  46, 
+     57,  54,  48,  48,  46,  49, 
+     54,  51,  56,  52,   0, 171, 
      73,  83,  71,  78,  80,   0, 
       0,   0,   2,   0,   0,   0, 
       8,   0,   0,   0,  56,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
      15,   0,   0,   0,  68,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -931,23 +922,20 @@ const BYTE RGBShader[] =
       0,   0,  32,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  83,  86,  95,  84, 
      97, 114, 103, 101, 116,   0, 
     171, 171
 };
+ShaderBytes sRGBShader = { RGBShader, sizeof(RGBShader) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
-//
-//
-//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ERGBAShader
-//    -VnRGBAShader -FhtmpShaderHeader
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -969,27 +957,27 @@ const BYTE RGBShader[] =
 // sSampler                          sampler      NA          NA    0        1
 // tRGB                              texture  float4          2d    0        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Position              0   xyzw        0      POS  float       
-// TEXCOORD                 0   xy          1     NONE  float   xy  
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float       
+// TEXCOORD                 0   xy          1     NONE   float   xy  
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Target                0   xyzw        0   TARGET  float   xyzw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target                0   xyzw        0   TARGET   float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -1021,20 +1009,20 @@ dcl_temps 1
 sample r0.xyzw, v1.xyxx, t0.xyzw, s0
 mul o0.xyzw, r0.xyzw, cb0[1].xxxx
 ret 
 // Approximately 3 instruction slots used
 #endif
 
 const BYTE RGBAShader[] =
 {
-     68,  88,  66,  67, 214,  26, 
-    168, 112,  65, 151,  75,  99, 
-    196,  63, 136, 104, 158, 202, 
-    217,   7,   1,   0,   0,   0, 
+     68,  88,  66,  67, 230,  59, 
+     90,  23,  60,  77,  18, 113, 
+     14, 129, 183, 152, 233,  55, 
+    111,  42,   1,   0,   0,   0, 
     196,   4,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     192,   0,   0,   0, 100,   1, 
       0,   0, 224,   1,   0,   0, 
      56,   4,   0,   0, 144,   4, 
       0,   0,  65, 111, 110,  57, 
     128,   0,   0,   0, 128,   0, 
       0,   0,   0,   2, 255, 255, 
@@ -1198,19 +1186,19 @@ const BYTE RGBAShader[] =
      81, 117,  97, 100,   0, 118, 
      77,  97, 115, 107,  81, 117, 
      97, 100,   0,  77, 105,  99, 
     114, 111, 115, 111, 102, 116, 
      32,  40,  82,  41,  32,  72, 
      76,  83,  76,  32,  83, 104, 
      97, 100, 101, 114,  32,  67, 
     111, 109, 112, 105, 108, 101, 
-    114,  32,  57,  46,  50,  57, 
-     46,  57,  53,  50,  46,  51, 
-     49,  49,  49,   0, 171, 171, 
+    114,  32,  54,  46,  51,  46, 
+     57,  54,  48,  48,  46,  49, 
+     54,  51,  56,  52,   0, 171, 
      73,  83,  71,  78,  80,   0, 
       0,   0,   2,   0,   0,   0, 
       8,   0,   0,   0,  56,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
      15,   0,   0,   0,  68,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -1226,23 +1214,325 @@ const BYTE RGBAShader[] =
       0,   0,  32,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  83,  86,  95,  84, 
      97, 114, 103, 101, 116,   0, 
     171, 171
 };
+ShaderBytes sRGBAShader = { RGBAShader, sizeof(RGBAShader) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
-//
-//
-//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -EComponentAlphaShader
-//    -VnComponentAlphaShader -FhtmpShaderHeader
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+//
+//
+// Buffer Definitions: 
+//
+// cbuffer $Globals
+// {
+//
+//   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
+//   float fLayerOpacity;               // Offset:   16 Size:     4
+//   float4x4 mLayerTransform;          // Offset:   32 Size:    64 [unused]
+//   float4x4 mProjection;              // Offset:   96 Size:    64 [unused]
+//   float4 vRenderTargetOffset;        // Offset:  160 Size:    16 [unused]
+//   float4 vTextureCoords;             // Offset:  176 Size:    16 [unused]
+//   float4 vLayerQuad;                 // Offset:  192 Size:    16 [unused]
+//   float4 vMaskQuad;                  // Offset:  208 Size:    16 [unused]
+//
+// }
+//
+//
+// Resource Bindings:
+//
+// Name                                 Type  Format         Dim Slot Elements
+// ------------------------------ ---------- ------- ----------- ---- --------
+// sSampler                          sampler      NA          NA    0        1
+// tRGB                              texture  float4          2d    0        1
+// $Globals                          cbuffer      NA          NA    0        1
+//
+//
+//
+// Input signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float       
+// TEXCOORD                 0   xy          1     NONE   float   xy  
+//
+//
+// Output signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target                0   xyzw        0   TARGET   float   xyzw
+//
+//
+// Constant buffer to DX9 shader constant mappings:
+//
+// Target Reg Buffer  Start Reg # of Regs        Data Conversion
+// ---------- ------- --------- --------- ----------------------
+// c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
+//
+//
+// Sampler/Resource to DX9 shader sampler mappings:
+//
+// Target Sampler Source Sampler  Source Resource
+// -------------- --------------- ----------------
+// s0             s0              t0               
+//
+//
+// Level9 shader bytecode:
+//
+    ps_2_x
+    dcl t0.xy
+    dcl_2d s0
+    texld r0, t0, s0
+    mul r0, r0, c0.x
+    mul r0.xyz, r0.w, r0
+    mov oC0, r0
+
+// approximately 4 instruction slots used (1 texture, 3 arithmetic)
+ps_4_0
+dcl_constantbuffer cb0[2], immediateIndexed
+dcl_sampler s0, mode_default
+dcl_resource_texture2d (float,float,float,float) t0
+dcl_input_ps linear v1.xy
+dcl_output o0.xyzw
+dcl_temps 1
+sample r0.xyzw, v1.xyxx, t0.xyzw, s0
+mul r0.xyzw, r0.xyzw, cb0[1].xxxx
+mul o0.xyz, r0.wwww, r0.xyzx
+mov o0.w, r0.w
+ret 
+// Approximately 5 instruction slots used
+#endif
+
+const BYTE RGBAShaderPremul[] =
+{
+     68,  88,  66,  67,   9,  19, 
+    234, 250, 161,  24, 191,  52, 
+    148,  34, 157,  98,  40,  39, 
+     76,  48,   1,   0,   0,   0, 
+      4,   5,   0,   0,   6,   0, 
+      0,   0,  56,   0,   0,   0, 
+    208,   0,   0,   0, 164,   1, 
+      0,   0,  32,   2,   0,   0, 
+    120,   4,   0,   0, 208,   4, 
+      0,   0,  65, 111, 110,  57, 
+    144,   0,   0,   0, 144,   0, 
+      0,   0,   0,   2, 255, 255, 
+     92,   0,   0,   0,  52,   0, 
+      0,   0,   1,   0,  40,   0, 
+      0,   0,  52,   0,   0,   0, 
+     52,   0,   1,   0,  36,   0, 
+      0,   0,  52,   0,   0,   0, 
+      0,   0,   0,   0,   1,   0, 
+      1,   0,   0,   0,   0,   0, 
+      0,   0,   1,   2, 255, 255, 
+     31,   0,   0,   2,   0,   0, 
+      0, 128,   0,   0,   3, 176, 
+     31,   0,   0,   2,   0,   0, 
+      0, 144,   0,   8,  15, 160, 
+     66,   0,   0,   3,   0,   0, 
+     15, 128,   0,   0, 228, 176, 
+      0,   8, 228, 160,   5,   0, 
+      0,   3,   0,   0,  15, 128, 
+      0,   0, 228, 128,   0,   0, 
+      0, 160,   5,   0,   0,   3, 
+      0,   0,   7, 128,   0,   0, 
+    255, 128,   0,   0, 228, 128, 
+      1,   0,   0,   2,   0,   8, 
+     15, 128,   0,   0, 228, 128, 
+    255, 255,   0,   0,  83,  72, 
+     68,  82, 204,   0,   0,   0, 
+     64,   0,   0,   0,  51,   0, 
+      0,   0,  89,   0,   0,   4, 
+     70, 142,  32,   0,   0,   0, 
+      0,   0,   2,   0,   0,   0, 
+     90,   0,   0,   3,   0,  96, 
+     16,   0,   0,   0,   0,   0, 
+     88,  24,   0,   4,   0, 112, 
+     16,   0,   0,   0,   0,   0, 
+     85,  85,   0,   0,  98,  16, 
+      0,   3,  50,  16,  16,   0, 
+      1,   0,   0,   0, 101,   0, 
+      0,   3, 242,  32,  16,   0, 
+      0,   0,   0,   0, 104,   0, 
+      0,   2,   1,   0,   0,   0, 
+     69,   0,   0,   9, 242,   0, 
+     16,   0,   0,   0,   0,   0, 
+     70,  16,  16,   0,   1,   0, 
+      0,   0,  70, 126,  16,   0, 
+      0,   0,   0,   0,   0,  96, 
+     16,   0,   0,   0,   0,   0, 
+     56,   0,   0,   8, 242,   0, 
+     16,   0,   0,   0,   0,   0, 
+     70,  14,  16,   0,   0,   0, 
+      0,   0,   6, 128,  32,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,  56,   0,   0,   7, 
+    114,  32,  16,   0,   0,   0, 
+      0,   0, 246,  15,  16,   0, 
+      0,   0,   0,   0,  70,   2, 
+     16,   0,   0,   0,   0,   0, 
+     54,   0,   0,   5, 130,  32, 
+     16,   0,   0,   0,   0,   0, 
+     58,   0,  16,   0,   0,   0, 
+      0,   0,  62,   0,   0,   1, 
+     83,  84,  65,  84, 116,   0, 
+      0,   0,   5,   0,   0,   0, 
+      1,   0,   0,   0,   0,   0, 
+      0,   0,   2,   0,   0,   0, 
+      2,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      1,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      1,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,  82,  68, 
+     69,  70,  80,   2,   0,   0, 
+      1,   0,   0,   0, 148,   0, 
+      0,   0,   3,   0,   0,   0, 
+     28,   0,   0,   0,   0,   4, 
+    255, 255,   0,   1,   0,   0, 
+     29,   2,   0,   0, 124,   0, 
+      0,   0,   3,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,   1,   0,   0,   0, 
+    133,   0,   0,   0,   2,   0, 
+      0,   0,   5,   0,   0,   0, 
+      4,   0,   0,   0, 255, 255, 
+    255, 255,   0,   0,   0,   0, 
+      1,   0,   0,   0,  12,   0, 
+      0,   0, 138,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+      0,   0,   0,   0, 115,  83, 
+     97, 109, 112, 108, 101, 114, 
+      0, 116,  82,  71,  66,   0, 
+     36,  71, 108, 111,  98,  97, 
+    108, 115,   0, 171, 138,   0, 
+      0,   0,   8,   0,   0,   0, 
+    172,   0,   0,   0, 224,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0, 108,   1, 
+      0,   0,   0,   0,   0,   0, 
+     16,   0,   0,   0,   0,   0, 
+      0,   0, 120,   1,   0,   0, 
+      0,   0,   0,   0, 136,   1, 
+      0,   0,  16,   0,   0,   0, 
+      4,   0,   0,   0,   2,   0, 
+      0,   0, 152,   1,   0,   0, 
+      0,   0,   0,   0, 168,   1, 
+      0,   0,  32,   0,   0,   0, 
+     64,   0,   0,   0,   0,   0, 
+      0,   0, 184,   1,   0,   0, 
+      0,   0,   0,   0, 200,   1, 
+      0,   0,  96,   0,   0,   0, 
+     64,   0,   0,   0,   0,   0, 
+      0,   0, 184,   1,   0,   0, 
+      0,   0,   0,   0, 212,   1, 
+      0,   0, 160,   0,   0,   0, 
+     16,   0,   0,   0,   0,   0, 
+      0,   0, 120,   1,   0,   0, 
+      0,   0,   0,   0, 232,   1, 
+      0,   0, 176,   0,   0,   0, 
+     16,   0,   0,   0,   0,   0, 
+      0,   0, 248,   1,   0,   0, 
+      0,   0,   0,   0,   8,   2, 
+      0,   0, 192,   0,   0,   0, 
+     16,   0,   0,   0,   0,   0, 
+      0,   0, 248,   1,   0,   0, 
+      0,   0,   0,   0,  19,   2, 
+      0,   0, 208,   0,   0,   0, 
+     16,   0,   0,   0,   0,   0, 
+      0,   0, 248,   1,   0,   0, 
+      0,   0,   0,   0, 102,  76, 
+     97, 121, 101, 114,  67, 111, 
+    108, 111, 114,   0,   1,   0, 
+      3,   0,   1,   0,   4,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0, 102,  76,  97, 121, 
+    101, 114,  79, 112,  97,  99, 
+    105, 116, 121,   0, 171, 171, 
+      0,   0,   3,   0,   1,   0, 
+      1,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0, 109,  76, 
+     97, 121, 101, 114,  84, 114, 
+     97, 110, 115, 102, 111, 114, 
+    109,   0,   3,   0,   3,   0, 
+      4,   0,   4,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    109,  80, 114, 111, 106, 101, 
+     99, 116, 105, 111, 110,   0, 
+    118,  82, 101, 110, 100, 101, 
+    114,  84,  97, 114, 103, 101, 
+    116,  79, 102, 102, 115, 101, 
+    116,   0, 118,  84, 101, 120, 
+    116, 117, 114, 101,  67, 111, 
+    111, 114, 100, 115,   0, 171, 
+      1,   0,   3,   0,   1,   0, 
+      4,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0, 118,  76, 
+     97, 121, 101, 114,  81, 117, 
+     97, 100,   0, 118,  77,  97, 
+    115, 107,  81, 117,  97, 100, 
+      0,  77, 105,  99, 114, 111, 
+    115, 111, 102, 116,  32,  40, 
+     82,  41,  32,  72,  76,  83, 
+     76,  32,  83, 104,  97, 100, 
+    101, 114,  32,  67, 111, 109, 
+    112, 105, 108, 101, 114,  32, 
+     54,  46,  51,  46,  57,  54, 
+     48,  48,  46,  49,  54,  51, 
+     56,  52,   0, 171,  73,  83, 
+     71,  78,  80,   0,   0,   0, 
+      2,   0,   0,   0,   8,   0, 
+      0,   0,  56,   0,   0,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,   3,   0,   0,   0, 
+      0,   0,   0,   0,  15,   0, 
+      0,   0,  68,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   3,   0,   0,   0, 
+      1,   0,   0,   0,   3,   3, 
+      0,   0,  83,  86,  95,  80, 
+    111, 115, 105, 116, 105, 111, 
+    110,   0,  84,  69,  88,  67, 
+     79,  79,  82,  68,   0, 171, 
+    171, 171,  79,  83,  71,  78, 
+     44,   0,   0,   0,   1,   0, 
+      0,   0,   8,   0,   0,   0, 
+     32,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   0,   0,   0,   0, 
+      0,   0,  15,   0,   0,   0, 
+     83,  86,  95,  84,  97, 114, 
+    103, 101, 116,   0, 171, 171
+};
+ShaderBytes sRGBAShaderPremul = { RGBAShaderPremul, sizeof(RGBAShaderPremul) };
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -1265,28 +1555,28 @@ const BYTE RGBAShader[] =
 // tRGB                              texture  float4          2d    0        1
 // tRGBWhite                         texture  float4          2d    1        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Position              0   xyzw        0      POS  float       
-// TEXCOORD                 0   xy          1     NONE  float   xy  
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float       
+// TEXCOORD                 0   xy          1     NONE   float   xy  
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Target                0   xyzw        0   TARGET  float   xyzw
-// SV_Target                1   xyzw        1   TARGET  float   xyzw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target                0   xyzw        0   TARGET   float   xyzw
+// SV_Target                1   xyzw        1   TARGET   float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -1334,20 +1624,20 @@ mov r1.w, r0.y
 mul o1.xyzw, r0.xyzw, cb0[1].xxxx
 mul o0.xyzw, r1.xyzw, cb0[1].xxxx
 ret 
 // Approximately 8 instruction slots used
 #endif
 
 const BYTE ComponentAlphaShader[] =
 {
-     68,  88,  66,  67, 207, 238, 
-    180, 151, 111,  52, 137,   3, 
-     45, 243, 229, 223,  99, 172, 
-     89,   3,   1,   0,   0,   0, 
+     68,  88,  66,  67, 186, 162, 
+     72,  42,  69,  36, 160,  68, 
+    108, 121, 216, 238, 108,  37, 
+      6, 145,   1,   0,   0,   0, 
      68,   6,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
      64,   1,   0,   0, 160,   2, 
       0,   0,  28,   3,   0,   0, 
     160,   5,   0,   0, 248,   5, 
       0,   0,  65, 111, 110,  57, 
       0,   1,   0,   0,   0,   1, 
       0,   0,   0,   2, 255, 255, 
@@ -1460,17 +1750,17 @@ const BYTE ComponentAlphaShader[] =
       1,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   2,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
-      2,   0,   0,   0,   0,   0, 
+      1,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,  82,  68, 
      69,  70, 124,   2,   0,   0, 
       1,   0,   0,   0, 192,   0, 
@@ -1571,19 +1861,19 @@ const BYTE ComponentAlphaShader[] =
      81, 117,  97, 100,   0, 118, 
      77,  97, 115, 107,  81, 117, 
      97, 100,   0,  77, 105,  99, 
     114, 111, 115, 111, 102, 116, 
      32,  40,  82,  41,  32,  72, 
      76,  83,  76,  32,  83, 104, 
      97, 100, 101, 114,  32,  67, 
     111, 109, 112, 105, 108, 101, 
-    114,  32,  57,  46,  50,  57, 
-     46,  57,  53,  50,  46,  51, 
-     49,  49,  49,   0, 171, 171, 
+    114,  32,  54,  46,  51,  46, 
+     57,  54,  48,  48,  46,  49, 
+     54,  51,  56,  52,   0, 171, 
      73,  83,  71,  78,  80,   0, 
       0,   0,   2,   0,   0,   0, 
       8,   0,   0,   0,  56,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
      15,   0,   0,   0,  68,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -1603,23 +1893,20 @@ const BYTE ComponentAlphaShader[] =
       0,   0,  56,   0,   0,   0, 
       1,   0,   0,   0,   0,   0, 
       0,   0,   3,   0,   0,   0, 
       1,   0,   0,   0,  15,   0, 
       0,   0,  83,  86,  95,  84, 
      97, 114, 103, 101, 116,   0, 
     171, 171
 };
+ShaderBytes sComponentAlphaShader = { ComponentAlphaShader, sizeof(ComponentAlphaShader) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
-//
-//
-//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -EYCbCrShader
-//    -VnYCbCrShader -FhtmpShaderHeader
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -1643,27 +1930,27 @@ const BYTE ComponentAlphaShader[] =
 // tCb                               texture  float4          2d    1        1
 // tCr                               texture  float4          2d    2        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Position              0   xyzw        0      POS  float       
-// TEXCOORD                 0   xy          1     NONE  float   xy  
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float       
+// TEXCOORD                 0   xy          1     NONE   float   xy  
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Target                0   xyzw        0   TARGET  float   xyzw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target                0   xyzw        0   TARGET   float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -1727,20 +2014,20 @@ mad r1.z, r0.z, l(1.164380), r0.x
 mov r1.w, l(1.000000)
 mul o0.xyzw, r1.xyzw, cb0[1].xxxx
 ret 
 // Approximately 15 instruction slots used
 #endif
 
 const BYTE YCbCrShader[] =
 {
-     68,  88,  66,  67,  54,  63, 
-    153,   7,  84, 231,  22,  28, 
-    117, 160,  57,  24, 123, 163, 
-     52, 109,   1,   0,   0,   0, 
+     68,  88,  66,  67, 127, 202, 
+     65,  67, 171,  51, 222, 111, 
+    252, 139,  60, 115,  30, 112, 
+    240,  10,   1,   0,   0,   0, 
     212,   7,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     220,   1,   0,   0,  44,   4, 
       0,   0, 168,   4,   0,   0, 
      72,   7,   0,   0, 160,   7, 
       0,   0,  65, 111, 110,  57, 
     156,   1,   0,   0, 156,   1, 
       0,   0,   0,   2, 255, 255, 
@@ -1909,17 +2196,17 @@ const BYTE YCbCrShader[] =
      70,  14,  16,   0,   1,   0, 
       0,   0,   6, 128,  32,   0, 
       0,   0,   0,   0,   1,   0, 
       0,   0,  62,   0,   0,   1, 
      83,  84,  65,  84, 116,   0, 
       0,   0,  15,   0,   0,   0, 
       3,   0,   0,   0,   0,   0, 
       0,   0,   2,   0,   0,   0, 
-      6,   0,   0,   0,   0,   0, 
+     10,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -2035,19 +2322,19 @@ const BYTE YCbCrShader[] =
      97, 100,   0, 118,  77,  97, 
     115, 107,  81, 117,  97, 100, 
       0,  77, 105,  99, 114, 111, 
     115, 111, 102, 116,  32,  40, 
      82,  41,  32,  72,  76,  83, 
      76,  32,  83, 104,  97, 100, 
     101, 114,  32,  67, 111, 109, 
     112, 105, 108, 101, 114,  32, 
-     57,  46,  50,  57,  46,  57, 
-     53,  50,  46,  51,  49,  49, 
-     49,   0, 171, 171,  73,  83, 
+     54,  46,  51,  46,  57,  54, 
+     48,  48,  46,  49,  54,  51, 
+     56,  52,   0, 171,  73,  83, 
      71,  78,  80,   0,   0,   0, 
       2,   0,   0,   0,   8,   0, 
       0,   0,  56,   0,   0,   0, 
       0,   0,   0,   0,   1,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  68,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -2062,23 +2349,20 @@ const BYTE YCbCrShader[] =
       0,   0,   8,   0,   0,   0, 
      32,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       3,   0,   0,   0,   0,   0, 
       0,   0,  15,   0,   0,   0, 
      83,  86,  95,  84,  97, 114, 
     103, 101, 116,   0, 171, 171
 };
+ShaderBytes sYCbCrShader = { YCbCrShader, sizeof(YCbCrShader) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
-//
-//
-//   fxc -nologo -Tvs_4_0_level_9_3 CompositorD3D11.hlsl -ELayerQuadMaskVS
-//    -VnLayerQuadMaskVS -FhtmpShaderHeader
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4x4 mLayerTransform;          // Offset:    0 Size:    64
@@ -2098,28 +2382,28 @@ const BYTE YCbCrShader[] =
 // Name                                 Type  Format         Dim Slot Elements
 // ------------------------------ ---------- ------- ----------- ---- --------
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// POSITION                 0   xy          0     NONE  float   xy  
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// POSITION                 0   xy          0     NONE   float   xy  
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Position              0   xyzw        0      POS  float   xyzw
-// TEXCOORD                 0   xy          1     NONE  float   xy  
-// TEXCOORD                 1     zw        1     NONE  float     zw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float   xyzw
+// TEXCOORD                 0   xy          1     NONE   float   xy  
+// TEXCOORD                 1     zw        1     NONE   float     zw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c1         cb0             0         2  ( FLT, FLT, FLT, FLT)
 // c3         cb0             3         9  ( FLT, FLT, FLT, FLT)
@@ -2181,20 +2465,20 @@ mad r1.xyzw, cb0[6].xyzw, r0.zzzz, r1.xy
 mad o0.xyzw, cb0[7].xyzw, r0.wwww, r1.xyzw
 mad o1.xy, v0.xyxx, cb0[9].zwzz, cb0[9].xyxx
 ret 
 // Approximately 16 instruction slots used
 #endif
 
 const BYTE LayerQuadMaskVS[] =
 {
-     68,  88,  66,  67,  15, 196, 
-    252, 199, 211, 188,  92,  26, 
-     46, 113, 249,  29, 135, 110, 
-     83, 119,   1,   0,   0,   0, 
+     68,  88,  66,  67, 223, 251, 
+     10,  17,  13,  90,  47,  25, 
+    119, 198,  20, 157, 124, 193, 
+    251, 234,   1,   0,   0,   0, 
     120,   7,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     224,   1,   0,   0,  76,   4, 
       0,   0, 200,   4,   0,   0, 
     212,   6,   0,   0,   8,   7, 
       0,   0,  65, 111, 110,  57, 
     160,   1,   0,   0, 160,   1, 
       0,   0,   0,   2, 254, 255, 
@@ -2368,17 +2652,17 @@ const BYTE LayerQuadMaskVS[] =
      32,   0,   0,   0,   0,   0, 
       9,   0,   0,   0,  70, 128, 
      32,   0,   0,   0,   0,   0, 
       9,   0,   0,   0,  62,   0, 
       0,   1,  83,  84,  65,  84, 
     116,   0,   0,   0,  16,   0, 
       0,   0,   2,   0,   0,   0, 
       0,   0,   0,   0,   4,   0, 
-      0,   0,   8,   0,   0,   0, 
+      0,   0,  14,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -2469,19 +2753,19 @@ const BYTE LayerQuadMaskVS[] =
       0,   0,   3,   0,   1,   0, 
       1,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,  77, 105, 
      99, 114, 111, 115, 111, 102, 
     116,  32,  40,  82,  41,  32, 
      72,  76,  83,  76,  32,  83, 
     104,  97, 100, 101, 114,  32, 
      67, 111, 109, 112, 105, 108, 
-    101, 114,  32,  57,  46,  50, 
-     57,  46,  57,  53,  50,  46, 
-     51,  49,  49,  49,   0, 171, 
+    101, 114,  32,  54,  46,  51, 
+     46,  57,  54,  48,  48,  46, 
+     49,  54,  51,  56,  52,   0, 
     171, 171,  73,  83,  71,  78, 
      44,   0,   0,   0,   1,   0, 
       0,   0,   8,   0,   0,   0, 
      32,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       3,   0,   0,   0,   0,   0, 
       0,   0,   3,   3,   0,   0, 
      80,  79,  83,  73,  84,  73, 
@@ -2501,23 +2785,20 @@ const BYTE LayerQuadMaskVS[] =
       0,   0,   0,   0,   3,   0, 
       0,   0,   1,   0,   0,   0, 
      12,   3,   0,   0,  83,  86, 
      95,  80, 111, 115, 105, 116, 
     105, 111, 110,   0,  84,  69, 
      88,  67,  79,  79,  82,  68, 
       0, 171, 171, 171
 };
+ShaderBytes sLayerQuadMaskVS = { LayerQuadMaskVS, sizeof(LayerQuadMaskVS) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
-//
-//
-//   fxc -nologo -Tvs_4_0_level_9_3 CompositorD3D11.hlsl -ELayerQuadMask3DVS
-//    -VnLayerQuadMask3DVS -FhtmpShaderHeader
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4x4 mLayerTransform;          // Offset:    0 Size:    64
@@ -2537,28 +2818,28 @@ const BYTE LayerQuadMaskVS[] =
 // Name                                 Type  Format         Dim Slot Elements
 // ------------------------------ ---------- ------- ----------- ---- --------
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// POSITION                 0   xy          0     NONE  float   xy  
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// POSITION                 0   xy          0     NONE   float   xy  
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Position              0   xyzw        0      POS  float   xyzw
-// TEXCOORD                 0   xy          1     NONE  float   xy  
-// TEXCOORD                 1   xyz         2     NONE  float   xyz 
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float   xyzw
+// TEXCOORD                 0   xy          1     NONE   float   xy  
+// TEXCOORD                 1   xyz         2     NONE   float   xyz 
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c1         cb0             0         2  ( FLT, FLT, FLT, FLT)
 // c3         cb0             3         9  ( FLT, FLT, FLT, FLT)
@@ -2624,20 +2905,20 @@ mad o1.xy, v0.xyxx, cb0[9].zwzz, cb0[9].
 mov r0.z, l(1.000000)
 mul o2.xyz, r0.wwww, r0.xyzx
 ret 
 // Approximately 17 instruction slots used
 #endif
 
 const BYTE LayerQuadMask3DVS[] =
 {
-     68,  88,  66,  67, 100,  40, 
-     55,  29, 238,  71, 107,  78, 
-    214, 182,  73, 149, 138,  22, 
-    163, 187,   1,   0,   0,   0, 
+     68,  88,  66,  67, 151, 141, 
+     11,  11, 111, 244,  17, 242, 
+    119, 116, 248,  53, 235, 192, 
+     38, 193,   1,   0,   0,   0, 
     204,   7,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
      24,   2,   0,   0, 160,   4, 
       0,   0,  28,   5,   0,   0, 
      40,   7,   0,   0,  92,   7, 
       0,   0,  65, 111, 110,  57, 
     216,   1,   0,   0, 216,   1, 
       0,   0,   0,   2, 254, 255, 
@@ -2825,27 +3106,27 @@ const BYTE LayerQuadMask3DVS[] =
      16,   0,   2,   0,   0,   0, 
     246,  15,  16,   0,   0,   0, 
       0,   0,  70,   2,  16,   0, 
       0,   0,   0,   0,  62,   0, 
       0,   1,  83,  84,  65,  84, 
     116,   0,   0,   0,  17,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,   4,   0, 
-      0,   0,   9,   0,   0,   0, 
+      0,   0,  15,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
-      0,   0,   2,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
      82,  68,  69,  70,   4,   2, 
       0,   0,   1,   0,   0,   0, 
@@ -2926,19 +3207,19 @@ const BYTE LayerQuadMask3DVS[] =
       0,   0,   3,   0,   1,   0, 
       1,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,  77, 105, 
      99, 114, 111, 115, 111, 102, 
     116,  32,  40,  82,  41,  32, 
      72,  76,  83,  76,  32,  83, 
     104,  97, 100, 101, 114,  32, 
      67, 111, 109, 112, 105, 108, 
-    101, 114,  32,  57,  46,  50, 
-     57,  46,  57,  53,  50,  46, 
-     51,  49,  49,  49,   0, 171, 
+    101, 114,  32,  54,  46,  51, 
+     46,  57,  54,  48,  48,  46, 
+     49,  54,  51,  56,  52,   0, 
     171, 171,  73,  83,  71,  78, 
      44,   0,   0,   0,   1,   0, 
       0,   0,   8,   0,   0,   0, 
      32,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       3,   0,   0,   0,   0,   0, 
       0,   0,   3,   3,   0,   0, 
      80,  79,  83,  73,  84,  73, 
@@ -2958,23 +3239,20 @@ const BYTE LayerQuadMask3DVS[] =
       0,   0,   0,   0,   3,   0, 
       0,   0,   2,   0,   0,   0, 
       7,   8,   0,   0,  83,  86, 
      95,  80, 111, 115, 105, 116, 
     105, 111, 110,   0,  84,  69, 
      88,  67,  79,  79,  82,  68, 
       0, 171, 171, 171
 };
+ShaderBytes sLayerQuadMask3DVS = { LayerQuadMask3DVS, sizeof(LayerQuadMask3DVS) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
-//
-//
-//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ESolidColorShaderMask
-//    -VnSolidColorShaderMask -FhtmpShaderHeader
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16
@@ -2996,28 +3274,28 @@ const BYTE LayerQuadMask3DVS[] =
 // sSampler                          sampler      NA          NA    0        1
 // tMask                             texture  float4          2d    3        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Position              0   xyzw        0      POS  float       
-// TEXCOORD                 0   xy          1     NONE  float       
-// TEXCOORD                 1     zw        1     NONE  float     zw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float       
+// TEXCOORD                 0   xy          1     NONE   float       
+// TEXCOORD                 1     zw        1     NONE   float     zw
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Target                0   xyzw        0   TARGET  float   xyzw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target                0   xyzw        0   TARGET   float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             0         1  ( FLT, FLT, FLT, FLT)
 //
@@ -3050,20 +3328,20 @@ dcl_temps 1
 sample r0.xyzw, v1.zwzz, t3.xyzw, s0
 mul o0.xyzw, r0.xxxx, cb0[0].xyzw
 ret 
 // Approximately 3 instruction slots used
 #endif
 
 const BYTE SolidColorShaderMask[] =
 {
-     68,  88,  66,  67, 218,  73, 
-     87,  32, 206,  67,  79,  54, 
-     31, 104, 228, 152, 133, 115, 
-    245,   3,   1,   0,   0,   0, 
+     68,  88,  66,  67, 189,  88, 
+    190, 169, 235, 115, 239, 219, 
+    181, 194, 113, 122, 250, 177, 
+    212, 243,   1,   0,   0,   0, 
     232,   4,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     204,   0,   0,   0, 112,   1, 
       0,   0, 236,   1,   0,   0, 
      68,   4,   0,   0, 180,   4, 
       0,   0,  65, 111, 110,  57, 
     140,   0,   0,   0, 140,   0, 
       0,   0,   0,   2, 255, 255, 
@@ -3229,19 +3507,19 @@ const BYTE SolidColorShaderMask[] =
      81, 117,  97, 100,   0, 118, 
      77,  97, 115, 107,  81, 117, 
      97, 100,   0,  77, 105,  99, 
     114, 111, 115, 111, 102, 116, 
      32,  40,  82,  41,  32,  72, 
      76,  83,  76,  32,  83, 104, 
      97, 100, 101, 114,  32,  67, 
     111, 109, 112, 105, 108, 101, 
-    114,  32,  57,  46,  50,  57, 
-     46,  57,  53,  50,  46,  51, 
-     49,  49,  49,   0, 171, 171, 
+    114,  32,  54,  46,  51,  46, 
+     57,  54,  48,  48,  46,  49, 
+     54,  51,  56,  52,   0, 171, 
      73,  83,  71,  78, 104,   0, 
       0,   0,   3,   0,   0,   0, 
       8,   0,   0,   0,  80,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
      15,   0,   0,   0,  92,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -3261,23 +3539,20 @@ const BYTE SolidColorShaderMask[] =
       0,   0,  32,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  83,  86,  95,  84, 
      97, 114, 103, 101, 116,   0, 
     171, 171
 };
+ShaderBytes sSolidColorShaderMask = { SolidColorShaderMask, sizeof(SolidColorShaderMask) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
-//
-//
-//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ERGBShaderMask
-//    -VnRGBShaderMask -FhtmpShaderHeader
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -3300,28 +3575,28 @@ const BYTE SolidColorShaderMask[] =
 // tRGB                              texture  float4          2d    0        1
 // tMask                             texture  float4          2d    3        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Position              0   xyzw        0      POS  float       
-// TEXCOORD                 0   xy          1     NONE  float   xy  
-// TEXCOORD                 1     zw        1     NONE  float     zw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float       
+// TEXCOORD                 0   xy          1     NONE   float   xy  
+// TEXCOORD                 1     zw        1     NONE   float     zw
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Target                0   xyzw        0   TARGET  float   xyzw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target                0   xyzw        0   TARGET   float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -3364,20 +3639,20 @@ sample r1.xyzw, v1.zwzz, t3.xyzw, s0
 mov r0.w, cb0[1].x
 mul o0.xyzw, r0.xyzw, r1.xxxx
 ret 
 // Approximately 6 instruction slots used
 #endif
 
 const BYTE RGBShaderMask[] =
 {
-     68,  88,  66,  67,  77,  94, 
-    252, 215, 133,  78, 101, 216, 
-    220,   8,  70, 254,  89, 142, 
-    130, 135,   1,   0,   0,   0, 
+     68,  88,  66,  67, 151, 113, 
+      6, 167,  51, 154, 234, 112, 
+     72, 240,  46, 160, 193, 164, 
+     13, 255,   1,   0,   0,   0, 
     192,   5,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
       8,   1,   0,   0,  32,   2, 
       0,   0, 156,   2,   0,   0, 
      28,   5,   0,   0, 140,   5, 
       0,   0,  65, 111, 110,  57, 
     200,   0,   0,   0, 200,   0, 
       0,   0,   0,   2, 255, 255, 
@@ -3579,19 +3854,19 @@ const BYTE RGBShaderMask[] =
      81, 117,  97, 100,   0, 118, 
      77,  97, 115, 107,  81, 117, 
      97, 100,   0,  77, 105,  99, 
     114, 111, 115, 111, 102, 116, 
      32,  40,  82,  41,  32,  72, 
      76,  83,  76,  32,  83, 104, 
      97, 100, 101, 114,  32,  67, 
     111, 109, 112, 105, 108, 101, 
-    114,  32,  57,  46,  50,  57, 
-     46,  57,  53,  50,  46,  51, 
-     49,  49,  49,   0, 171, 171, 
+    114,  32,  54,  46,  51,  46, 
+     57,  54,  48,  48,  46,  49, 
+     54,  51,  56,  52,   0, 171, 
      73,  83,  71,  78, 104,   0, 
       0,   0,   3,   0,   0,   0, 
       8,   0,   0,   0,  80,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
      15,   0,   0,   0,  92,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -3611,23 +3886,20 @@ const BYTE RGBShaderMask[] =
       0,   0,  32,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  83,  86,  95,  84, 
      97, 114, 103, 101, 116,   0, 
     171, 171
 };
+ShaderBytes sRGBShaderMask = { RGBShaderMask, sizeof(RGBShaderMask) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
-//
-//
-//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ERGBAShaderMask
-//    -VnRGBAShaderMask -FhtmpShaderHeader
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -3650,28 +3922,28 @@ const BYTE RGBShaderMask[] =
 // tRGB                              texture  float4          2d    0        1
 // tMask                             texture  float4          2d    3        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Position              0   xyzw        0      POS  float       
-// TEXCOORD                 0   xy          1     NONE  float   xy  
-// TEXCOORD                 1     zw        1     NONE  float     zw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float       
+// TEXCOORD                 0   xy          1     NONE   float   xy  
+// TEXCOORD                 1     zw        1     NONE   float     zw
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Target                0   xyzw        0   TARGET  float   xyzw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target                0   xyzw        0   TARGET   float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -3712,20 +3984,20 @@ mul r0.xyzw, r0.xyzw, cb0[1].xxxx
 sample r1.xyzw, v1.zwzz, t3.xyzw, s0
 mul o0.xyzw, r0.xyzw, r1.xxxx
 ret 
 // Approximately 5 instruction slots used
 #endif
 
 const BYTE RGBAShaderMask[] =
 {
-     68,  88,  66,  67, 138,  69, 
-     81, 181, 217,  15, 199,  10, 
-    146, 208, 232, 248,  24,  27, 
-    141,  26,   1,   0,   0,   0, 
+     68,  88,  66,  67, 182, 158, 
+     23,  70, 121, 188, 140, 117, 
+    148, 125,  14, 205, 185, 113, 
+    155,  74,   1,   0,   0,   0, 
     156,   5,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     252,   0,   0,   0, 252,   1, 
       0,   0, 120,   2,   0,   0, 
     248,   4,   0,   0, 104,   5, 
       0,   0,  65, 111, 110,  57, 
     188,   0,   0,   0, 188,   0, 
       0,   0,   0,   2, 255, 255, 
@@ -3921,19 +4193,19 @@ const BYTE RGBAShaderMask[] =
      81, 117,  97, 100,   0, 118, 
      77,  97, 115, 107,  81, 117, 
      97, 100,   0,  77, 105,  99, 
     114, 111, 115, 111, 102, 116, 
      32,  40,  82,  41,  32,  72, 
      76,  83,  76,  32,  83, 104, 
      97, 100, 101, 114,  32,  67, 
     111, 109, 112, 105, 108, 101, 
-    114,  32,  57,  46,  50,  57, 
-     46,  57,  53,  50,  46,  51, 
-     49,  49,  49,   0, 171, 171, 
+    114,  32,  54,  46,  51,  46, 
+     57,  54,  48,  48,  46,  49, 
+     54,  51,  56,  52,   0, 171, 
      73,  83,  71,  78, 104,   0, 
       0,   0,   3,   0,   0,   0, 
       8,   0,   0,   0,  80,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
      15,   0,   0,   0,  92,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -3953,23 +4225,372 @@ const BYTE RGBAShaderMask[] =
       0,   0,  32,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  83,  86,  95,  84, 
      97, 114, 103, 101, 116,   0, 
     171, 171
 };
+ShaderBytes sRGBAShaderMask = { RGBAShaderMask, sizeof(RGBAShaderMask) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
-//
-//
-//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ERGBAShaderMask3D
-//    -VnRGBAShaderMask3D -FhtmpShaderHeader
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+//
+//
+// Buffer Definitions: 
+//
+// cbuffer $Globals
+// {
+//
+//   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
+//   float fLayerOpacity;               // Offset:   16 Size:     4
+//   float4x4 mLayerTransform;          // Offset:   32 Size:    64 [unused]
+//   float4x4 mProjection;              // Offset:   96 Size:    64 [unused]
+//   float4 vRenderTargetOffset;        // Offset:  160 Size:    16 [unused]
+//   float4 vTextureCoords;             // Offset:  176 Size:    16 [unused]
+//   float4 vLayerQuad;                 // Offset:  192 Size:    16 [unused]
+//   float4 vMaskQuad;                  // Offset:  208 Size:    16 [unused]
+//
+// }
+//
+//
+// Resource Bindings:
+//
+// Name                                 Type  Format         Dim Slot Elements
+// ------------------------------ ---------- ------- ----------- ---- --------
+// sSampler                          sampler      NA          NA    0        1
+// tRGB                              texture  float4          2d    0        1
+// tMask                             texture  float4          2d    3        1
+// $Globals                          cbuffer      NA          NA    0        1
+//
+//
+//
+// Input signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float       
+// TEXCOORD                 0   xy          1     NONE   float   xy  
+// TEXCOORD                 1     zw        1     NONE   float     zw
+//
+//
+// Output signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target                0   xyzw        0   TARGET   float   xyzw
+//
+//
+// Constant buffer to DX9 shader constant mappings:
+//
+// Target Reg Buffer  Start Reg # of Regs        Data Conversion
+// ---------- ------- --------- --------- ----------------------
+// c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
+//
+//
+// Sampler/Resource to DX9 shader sampler mappings:
+//
+// Target Sampler Source Sampler  Source Resource
+// -------------- --------------- ----------------
+// s0             s0              t3               
+// s1             s0              t0               
+//
+//
+// Level9 shader bytecode:
+//
+    ps_2_x
+    dcl t0
+    dcl_2d s0
+    dcl_2d s1
+    mov r0.xy, t0.wzzw
+    texld r1, t0, s1
+    texld r0, r0, s0
+    mul r1, r1, c0.x
+    mul r0, r0.x, r1
+    mul r0.xyz, r0.w, r0
+    mov oC0, r0
+
+// approximately 7 instruction slots used (2 texture, 5 arithmetic)
+ps_4_0
+dcl_constantbuffer cb0[2], immediateIndexed
+dcl_sampler s0, mode_default
+dcl_resource_texture2d (float,float,float,float) t0
+dcl_resource_texture2d (float,float,float,float) t3
+dcl_input_ps linear v1.xy
+dcl_input_ps linear v1.zw
+dcl_output o0.xyzw
+dcl_temps 2
+sample r0.xyzw, v1.xyxx, t0.xyzw, s0
+mul r0.xyzw, r0.xyzw, cb0[1].xxxx
+sample r1.xyzw, v1.zwzz, t3.xyzw, s0
+mul r0.xyzw, r0.xyzw, r1.xxxx
+mul o0.xyz, r0.wwww, r0.xyzx
+mov o0.w, r0.w
+ret 
+// Approximately 7 instruction slots used
+#endif
+
+const BYTE RGBAShaderMaskPremul[] =
+{
+     68,  88,  66,  67, 170, 142, 
+     83, 183,  24, 153, 194, 125, 
+     42, 169,  16, 185, 222,  43, 
+    161, 111,   1,   0,   0,   0, 
+    220,   5,   0,   0,   6,   0, 
+      0,   0,  56,   0,   0,   0, 
+     12,   1,   0,   0,  60,   2, 
+      0,   0, 184,   2,   0,   0, 
+     56,   5,   0,   0, 168,   5, 
+      0,   0,  65, 111, 110,  57, 
+    204,   0,   0,   0, 204,   0, 
+      0,   0,   0,   2, 255, 255, 
+    148,   0,   0,   0,  56,   0, 
+      0,   0,   1,   0,  44,   0, 
+      0,   0,  56,   0,   0,   0, 
+     56,   0,   2,   0,  36,   0, 
+      0,   0,  56,   0,   3,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,   1,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      1,   2, 255, 255,  31,   0, 
+      0,   2,   0,   0,   0, 128, 
+      0,   0,  15, 176,  31,   0, 
+      0,   2,   0,   0,   0, 144, 
+      0,   8,  15, 160,  31,   0, 
+      0,   2,   0,   0,   0, 144, 
+      1,   8,  15, 160,   1,   0, 
+      0,   2,   0,   0,   3, 128, 
+      0,   0, 235, 176,  66,   0, 
+      0,   3,   1,   0,  15, 128, 
+      0,   0, 228, 176,   1,   8, 
+    228, 160,  66,   0,   0,   3, 
+      0,   0,  15, 128,   0,   0, 
+    228, 128,   0,   8, 228, 160, 
+      5,   0,   0,   3,   1,   0, 
+     15, 128,   1,   0, 228, 128, 
+      0,   0,   0, 160,   5,   0, 
+      0,   3,   0,   0,  15, 128, 
+      0,   0,   0, 128,   1,   0, 
+    228, 128,   5,   0,   0,   3, 
+      0,   0,   7, 128,   0,   0, 
+    255, 128,   0,   0, 228, 128, 
+      1,   0,   0,   2,   0,   8, 
+     15, 128,   0,   0, 228, 128, 
+    255, 255,   0,   0,  83,  72, 
+     68,  82,  40,   1,   0,   0, 
+     64,   0,   0,   0,  74,   0, 
+      0,   0,  89,   0,   0,   4, 
+     70, 142,  32,   0,   0,   0, 
+      0,   0,   2,   0,   0,   0, 
+     90,   0,   0,   3,   0,  96, 
+     16,   0,   0,   0,   0,   0, 
+     88,  24,   0,   4,   0, 112, 
+     16,   0,   0,   0,   0,   0, 
+     85,  85,   0,   0,  88,  24, 
+      0,   4,   0, 112,  16,   0, 
+      3,   0,   0,   0,  85,  85, 
+      0,   0,  98,  16,   0,   3, 
+     50,  16,  16,   0,   1,   0, 
+      0,   0,  98,  16,   0,   3, 
+    194,  16,  16,   0,   1,   0, 
+      0,   0, 101,   0,   0,   3, 
+    242,  32,  16,   0,   0,   0, 
+      0,   0, 104,   0,   0,   2, 
+      2,   0,   0,   0,  69,   0, 
+      0,   9, 242,   0,  16,   0, 
+      0,   0,   0,   0,  70,  16, 
+     16,   0,   1,   0,   0,   0, 
+     70, 126,  16,   0,   0,   0, 
+      0,   0,   0,  96,  16,   0, 
+      0,   0,   0,   0,  56,   0, 
+      0,   8, 242,   0,  16,   0, 
+      0,   0,   0,   0,  70,  14, 
+     16,   0,   0,   0,   0,   0, 
+      6, 128,  32,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+     69,   0,   0,   9, 242,   0, 
+     16,   0,   1,   0,   0,   0, 
+    230,  26,  16,   0,   1,   0, 
+      0,   0,  70, 126,  16,   0, 
+      3,   0,   0,   0,   0,  96, 
+     16,   0,   0,   0,   0,   0, 
+     56,   0,   0,   7, 242,   0, 
+     16,   0,   0,   0,   0,   0, 
+     70,  14,  16,   0,   0,   0, 
+      0,   0,   6,   0,  16,   0, 
+      1,   0,   0,   0,  56,   0, 
+      0,   7, 114,  32,  16,   0, 
+      0,   0,   0,   0, 246,  15, 
+     16,   0,   0,   0,   0,   0, 
+     70,   2,  16,   0,   0,   0, 
+      0,   0,  54,   0,   0,   5, 
+    130,  32,  16,   0,   0,   0, 
+      0,   0,  58,   0,  16,   0, 
+      0,   0,   0,   0,  62,   0, 
+      0,   1,  83,  84,  65,  84, 
+    116,   0,   0,   0,   7,   0, 
+      0,   0,   2,   0,   0,   0, 
+      0,   0,   0,   0,   3,   0, 
+      0,   0,   3,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      2,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+     82,  68,  69,  70, 120,   2, 
+      0,   0,   1,   0,   0,   0, 
+    188,   0,   0,   0,   4,   0, 
+      0,   0,  28,   0,   0,   0, 
+      0,   4, 255, 255,   0,   1, 
+      0,   0,  69,   2,   0,   0, 
+    156,   0,   0,   0,   3,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      1,   0,   0,   0,   1,   0, 
+      0,   0, 165,   0,   0,   0, 
+      2,   0,   0,   0,   5,   0, 
+      0,   0,   4,   0,   0,   0, 
+    255, 255, 255, 255,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+     12,   0,   0,   0, 170,   0, 
+      0,   0,   2,   0,   0,   0, 
+      5,   0,   0,   0,   4,   0, 
+      0,   0, 255, 255, 255, 255, 
+      3,   0,   0,   0,   1,   0, 
+      0,   0,  13,   0,   0,   0, 
+    176,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      1,   0,   0,   0,   0,   0, 
+      0,   0, 115,  83,  97, 109, 
+    112, 108, 101, 114,   0, 116, 
+     82,  71,  66,   0, 116,  77, 
+     97, 115, 107,   0,  36,  71, 
+    108, 111,  98,  97, 108, 115, 
+      0, 171, 171, 171, 176,   0, 
+      0,   0,   8,   0,   0,   0, 
+    212,   0,   0,   0, 224,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0, 148,   1, 
+      0,   0,   0,   0,   0,   0, 
+     16,   0,   0,   0,   0,   0, 
+      0,   0, 160,   1,   0,   0, 
+      0,   0,   0,   0, 176,   1, 
+      0,   0,  16,   0,   0,   0, 
+      4,   0,   0,   0,   2,   0, 
+      0,   0, 192,   1,   0,   0, 
+      0,   0,   0,   0, 208,   1, 
+      0,   0,  32,   0,   0,   0, 
+     64,   0,   0,   0,   0,   0, 
+      0,   0, 224,   1,   0,   0, 
+      0,   0,   0,   0, 240,   1, 
+      0,   0,  96,   0,   0,   0, 
+     64,   0,   0,   0,   0,   0, 
+      0,   0, 224,   1,   0,   0, 
+      0,   0,   0,   0, 252,   1, 
+      0,   0, 160,   0,   0,   0, 
+     16,   0,   0,   0,   0,   0, 
+      0,   0, 160,   1,   0,   0, 
+      0,   0,   0,   0,  16,   2, 
+      0,   0, 176,   0,   0,   0, 
+     16,   0,   0,   0,   0,   0, 
+      0,   0,  32,   2,   0,   0, 
+      0,   0,   0,   0,  48,   2, 
+      0,   0, 192,   0,   0,   0, 
+     16,   0,   0,   0,   0,   0, 
+      0,   0,  32,   2,   0,   0, 
+      0,   0,   0,   0,  59,   2, 
+      0,   0, 208,   0,   0,   0, 
+     16,   0,   0,   0,   0,   0, 
+      0,   0,  32,   2,   0,   0, 
+      0,   0,   0,   0, 102,  76, 
+     97, 121, 101, 114,  67, 111, 
+    108, 111, 114,   0,   1,   0, 
+      3,   0,   1,   0,   4,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0, 102,  76,  97, 121, 
+    101, 114,  79, 112,  97,  99, 
+    105, 116, 121,   0, 171, 171, 
+      0,   0,   3,   0,   1,   0, 
+      1,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0, 109,  76, 
+     97, 121, 101, 114,  84, 114, 
+     97, 110, 115, 102, 111, 114, 
+    109,   0,   3,   0,   3,   0, 
+      4,   0,   4,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    109,  80, 114, 111, 106, 101, 
+     99, 116, 105, 111, 110,   0, 
+    118,  82, 101, 110, 100, 101, 
+    114,  84,  97, 114, 103, 101, 
+    116,  79, 102, 102, 115, 101, 
+    116,   0, 118,  84, 101, 120, 
+    116, 117, 114, 101,  67, 111, 
+    111, 114, 100, 115,   0, 171, 
+      1,   0,   3,   0,   1,   0, 
+      4,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0, 118,  76, 
+     97, 121, 101, 114,  81, 117, 
+     97, 100,   0, 118,  77,  97, 
+    115, 107,  81, 117,  97, 100, 
+      0,  77, 105,  99, 114, 111, 
+    115, 111, 102, 116,  32,  40, 
+     82,  41,  32,  72,  76,  83, 
+     76,  32,  83, 104,  97, 100, 
+    101, 114,  32,  67, 111, 109, 
+    112, 105, 108, 101, 114,  32, 
+     54,  46,  51,  46,  57,  54, 
+     48,  48,  46,  49,  54,  51, 
+     56,  52,   0, 171,  73,  83, 
+     71,  78, 104,   0,   0,   0, 
+      3,   0,   0,   0,   8,   0, 
+      0,   0,  80,   0,   0,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,   3,   0,   0,   0, 
+      0,   0,   0,   0,  15,   0, 
+      0,   0,  92,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   3,   0,   0,   0, 
+      1,   0,   0,   0,   3,   3, 
+      0,   0,  92,   0,   0,   0, 
+      1,   0,   0,   0,   0,   0, 
+      0,   0,   3,   0,   0,   0, 
+      1,   0,   0,   0,  12,  12, 
+      0,   0,  83,  86,  95,  80, 
+    111, 115, 105, 116, 105, 111, 
+    110,   0,  84,  69,  88,  67, 
+     79,  79,  82,  68,   0, 171, 
+    171, 171,  79,  83,  71,  78, 
+     44,   0,   0,   0,   1,   0, 
+      0,   0,   8,   0,   0,   0, 
+     32,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   0,   0,   0,   0, 
+      0,   0,  15,   0,   0,   0, 
+     83,  86,  95,  84,  97, 114, 
+    103, 101, 116,   0, 171, 171
+};
+ShaderBytes sRGBAShaderMaskPremul = { RGBAShaderMaskPremul, sizeof(RGBAShaderMaskPremul) };
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -3993,28 +4614,28 @@ const BYTE RGBAShaderMask[] =
 // tRGB                              texture  float4          2d    0        1
 // tMask                             texture  float4          2d    3        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Position              0   xyzw        0      POS  float       
-// TEXCOORD                 0   xy          1     NONE  float   xy  
-// TEXCOORD                 1   xyz         2     NONE  float   xyz 
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float       
+// TEXCOORD                 0   xy          1     NONE   float   xy  
+// TEXCOORD                 1   xyz         2     NONE   float   xyz 
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Target                0   xyzw        0   TARGET  float   xyzw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target                0   xyzw        0   TARGET   float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -4059,20 +4680,20 @@ sample r1.xyzw, v1.xyxx, t0.xyzw, s0
 mul r1.xyzw, r1.xyzw, cb0[1].xxxx
 mul o0.xyzw, r0.xxxx, r1.xyzw
 ret 
 // Approximately 6 instruction slots used
 #endif
 
 const BYTE RGBAShaderMask3D[] =
 {
-     68,  88,  66,  67,   4, 135, 
-     55,   9, 144, 137,  25,  77, 
-     92, 150, 209,   2,  32, 225, 
-     75, 182,   1,   0,   0,   0, 
+     68,  88,  66,  67, 216,  42, 
+    250, 215, 154,  11,  43,  24, 
+     15, 254,  10,  66,  72, 210, 
+    238, 215,   1,   0,   0,   0, 
      24,   6,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
      24,   1,   0,   0,  64,   2, 
       0,   0, 188,   2,   0,   0, 
     116,   5,   0,   0, 228,   5, 
       0,   0,  65, 111, 110,  57, 
     216,   0,   0,   0, 216,   0, 
       0,   0,   0,   2, 255, 255, 
@@ -4289,19 +4910,19 @@ const BYTE RGBAShaderMask3D[] =
      97, 100,   0, 118,  77,  97, 
     115, 107,  81, 117,  97, 100, 
       0,  77, 105,  99, 114, 111, 
     115, 111, 102, 116,  32,  40, 
      82,  41,  32,  72,  76,  83, 
      76,  32,  83, 104,  97, 100, 
     101, 114,  32,  67, 111, 109, 
     112, 105, 108, 101, 114,  32, 
-     57,  46,  50,  57,  46,  57, 
-     53,  50,  46,  51,  49,  49, 
-     49,   0, 171, 171,  73,  83, 
+     54,  46,  51,  46,  57,  54, 
+     48,  48,  46,  49,  54,  51, 
+     56,  52,   0, 171,  73,  83, 
      71,  78, 104,   0,   0,   0, 
       3,   0,   0,   0,   8,   0, 
       0,   0,  80,   0,   0,   0, 
       0,   0,   0,   0,   1,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  92,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -4320,23 +4941,398 @@ const BYTE RGBAShaderMask3D[] =
       0,   0,   8,   0,   0,   0, 
      32,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       3,   0,   0,   0,   0,   0, 
       0,   0,  15,   0,   0,   0, 
      83,  86,  95,  84,  97, 114, 
     103, 101, 116,   0, 171, 171
 };
+ShaderBytes sRGBAShaderMask3D = { RGBAShaderMask3D, sizeof(RGBAShaderMask3D) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
-//
-//
-//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -EYCbCrShaderMask
-//    -VnYCbCrShaderMask -FhtmpShaderHeader
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+//
+//
+// Buffer Definitions: 
+//
+// cbuffer $Globals
+// {
+//
+//   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
+//   float fLayerOpacity;               // Offset:   16 Size:     4
+//   float4x4 mLayerTransform;          // Offset:   32 Size:    64 [unused]
+//   float4x4 mProjection;              // Offset:   96 Size:    64 [unused]
+//   float4 vRenderTargetOffset;        // Offset:  160 Size:    16 [unused]
+//   float4 vTextureCoords;             // Offset:  176 Size:    16 [unused]
+//   float4 vLayerQuad;                 // Offset:  192 Size:    16 [unused]
+//   float4 vMaskQuad;                  // Offset:  208 Size:    16 [unused]
+//
+// }
+//
+//
+// Resource Bindings:
+//
+// Name                                 Type  Format         Dim Slot Elements
+// ------------------------------ ---------- ------- ----------- ---- --------
+// sSampler                          sampler      NA          NA    0        1
+// LayerTextureSamplerLinear         sampler      NA          NA    1        1
+// tRGB                              texture  float4          2d    0        1
+// tMask                             texture  float4          2d    3        1
+// $Globals                          cbuffer      NA          NA    0        1
+//
+//
+//
+// Input signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float       
+// TEXCOORD                 0   xy          1     NONE   float   xy  
+// TEXCOORD                 1   xyz         2     NONE   float   xyz 
+//
+//
+// Output signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target                0   xyzw        0   TARGET   float   xyzw
+//
+//
+// Constant buffer to DX9 shader constant mappings:
+//
+// Target Reg Buffer  Start Reg # of Regs        Data Conversion
+// ---------- ------- --------- --------- ----------------------
+// c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
+//
+//
+// Sampler/Resource to DX9 shader sampler mappings:
+//
+// Target Sampler Source Sampler  Source Resource
+// -------------- --------------- ----------------
+// s0             s0              t0               
+// s1             s1              t3               
+//
+//
+// Level9 shader bytecode:
+//
+    ps_2_x
+    dcl t0.xy
+    dcl t1.xyz
+    dcl_2d s0
+    dcl_2d s1
+    rcp r0.w, t1.z
+    mul r0.xy, r0.w, t1
+    texld r1, t0, s0
+    texld r0, r0, s1
+    mul r1, r1, c0.x
+    mul r0, r0.x, r1
+    mul r0.xyz, r0.w, r0
+    mov oC0, r0
+
+// approximately 8 instruction slots used (2 texture, 6 arithmetic)
+ps_4_0
+dcl_constantbuffer cb0[2], immediateIndexed
+dcl_sampler s0, mode_default
+dcl_sampler s1, mode_default
+dcl_resource_texture2d (float,float,float,float) t0
+dcl_resource_texture2d (float,float,float,float) t3
+dcl_input_ps linear v1.xy
+dcl_input_ps linear v2.xyz
+dcl_output o0.xyzw
+dcl_temps 2
+div r0.xy, v2.xyxx, v2.zzzz
+sample r0.xyzw, r0.xyxx, t3.xyzw, s1
+sample r1.xyzw, v1.xyxx, t0.xyzw, s0
+mul r1.xyzw, r1.xyzw, cb0[1].xxxx
+mul r0.xyzw, r0.xxxx, r1.xyzw
+mul o0.xyz, r0.wwww, r0.xyzx
+mov o0.w, r0.w
+ret 
+// Approximately 8 instruction slots used
+#endif
+
+const BYTE RGBAShaderMask3DPremul[] =
+{
+     68,  88,  66,  67,  55,   2, 
+    221,  89,  65,  95,  19,  52, 
+    117,  31,  78, 231,   8,  20, 
+    150,  44,   1,   0,   0,   0, 
+     88,   6,   0,   0,   6,   0, 
+      0,   0,  56,   0,   0,   0, 
+     40,   1,   0,   0, 128,   2, 
+      0,   0, 252,   2,   0,   0, 
+    180,   5,   0,   0,  36,   6, 
+      0,   0,  65, 111, 110,  57, 
+    232,   0,   0,   0, 232,   0, 
+      0,   0,   0,   2, 255, 255, 
+    176,   0,   0,   0,  56,   0, 
+      0,   0,   1,   0,  44,   0, 
+      0,   0,  56,   0,   0,   0, 
+     56,   0,   2,   0,  36,   0, 
+      0,   0,  56,   0,   0,   0, 
+      0,   0,   3,   1,   1,   0, 
+      0,   0,   1,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      1,   2, 255, 255,  31,   0, 
+      0,   2,   0,   0,   0, 128, 
+      0,   0,   3, 176,  31,   0, 
+      0,   2,   0,   0,   0, 128, 
+      1,   0,   7, 176,  31,   0, 
+      0,   2,   0,   0,   0, 144, 
+      0,   8,  15, 160,  31,   0, 
+      0,   2,   0,   0,   0, 144, 
+      1,   8,  15, 160,   6,   0, 
+      0,   2,   0,   0,   8, 128, 
+      1,   0, 170, 176,   5,   0, 
+      0,   3,   0,   0,   3, 128, 
+      0,   0, 255, 128,   1,   0, 
+    228, 176,  66,   0,   0,   3, 
+      1,   0,  15, 128,   0,   0, 
+    228, 176,   0,   8, 228, 160, 
+     66,   0,   0,   3,   0,   0, 
+     15, 128,   0,   0, 228, 128, 
+      1,   8, 228, 160,   5,   0, 
+      0,   3,   1,   0,  15, 128, 
+      1,   0, 228, 128,   0,   0, 
+      0, 160,   5,   0,   0,   3, 
+      0,   0,  15, 128,   0,   0, 
+      0, 128,   1,   0, 228, 128, 
+      5,   0,   0,   3,   0,   0, 
+      7, 128,   0,   0, 255, 128, 
+      0,   0, 228, 128,   1,   0, 
+      0,   2,   0,   8,  15, 128, 
+      0,   0, 228, 128, 255, 255, 
+      0,   0,  83,  72,  68,  82, 
+     80,   1,   0,   0,  64,   0, 
+      0,   0,  84,   0,   0,   0, 
+     89,   0,   0,   4,  70, 142, 
+     32,   0,   0,   0,   0,   0, 
+      2,   0,   0,   0,  90,   0, 
+      0,   3,   0,  96,  16,   0, 
+      0,   0,   0,   0,  90,   0, 
+      0,   3,   0,  96,  16,   0, 
+      1,   0,   0,   0,  88,  24, 
+      0,   4,   0, 112,  16,   0, 
+      0,   0,   0,   0,  85,  85, 
+      0,   0,  88,  24,   0,   4, 
+      0, 112,  16,   0,   3,   0, 
+      0,   0,  85,  85,   0,   0, 
+     98,  16,   0,   3,  50,  16, 
+     16,   0,   1,   0,   0,   0, 
+     98,  16,   0,   3, 114,  16, 
+     16,   0,   2,   0,   0,   0, 
+    101,   0,   0,   3, 242,  32, 
+     16,   0,   0,   0,   0,   0, 
+    104,   0,   0,   2,   2,   0, 
+      0,   0,  14,   0,   0,   7, 
+     50,   0,  16,   0,   0,   0, 
+      0,   0,  70,  16,  16,   0, 
+      2,   0,   0,   0, 166,  26, 
+     16,   0,   2,   0,   0,   0, 
+     69,   0,   0,   9, 242,   0, 
+     16,   0,   0,   0,   0,   0, 
+     70,   0,  16,   0,   0,   0, 
+      0,   0,  70, 126,  16,   0, 
+      3,   0,   0,   0,   0,  96, 
+     16,   0,   1,   0,   0,   0, 
+     69,   0,   0,   9, 242,   0, 
+     16,   0,   1,   0,   0,   0, 
+     70,  16,  16,   0,   1,   0, 
+      0,   0,  70, 126,  16,   0, 
+      0,   0,   0,   0,   0,  96, 
+     16,   0,   0,   0,   0,   0, 
+     56,   0,   0,   8, 242,   0, 
+     16,   0,   1,   0,   0,   0, 
+     70,  14,  16,   0,   1,   0, 
+      0,   0,   6, 128,  32,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,  56,   0,   0,   7, 
+    242,   0,  16,   0,   0,   0, 
+      0,   0,   6,   0,  16,   0, 
+      0,   0,   0,   0,  70,  14, 
+     16,   0,   1,   0,   0,   0, 
+     56,   0,   0,   7, 114,  32, 
+     16,   0,   0,   0,   0,   0, 
+    246,  15,  16,   0,   0,   0, 
+      0,   0,  70,   2,  16,   0, 
+      0,   0,   0,   0,  54,   0, 
+      0,   5, 130,  32,  16,   0, 
+      0,   0,   0,   0,  58,   0, 
+     16,   0,   0,   0,   0,   0, 
+     62,   0,   0,   1,  83,  84, 
+     65,  84, 116,   0,   0,   0, 
+      8,   0,   0,   0,   2,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   0,   0,   4,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   2,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,  82,  68,  69,  70, 
+    176,   2,   0,   0,   1,   0, 
+      0,   0, 244,   0,   0,   0, 
+      5,   0,   0,   0,  28,   0, 
+      0,   0,   0,   4, 255, 255, 
+      0,   1,   0,   0, 125,   2, 
+      0,   0, 188,   0,   0,   0, 
+      3,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+      1,   0,   0,   0, 197,   0, 
+      0,   0,   3,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      1,   0,   0,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+    223,   0,   0,   0,   2,   0, 
+      0,   0,   5,   0,   0,   0, 
+      4,   0,   0,   0, 255, 255, 
+    255, 255,   0,   0,   0,   0, 
+      1,   0,   0,   0,  12,   0, 
+      0,   0, 228,   0,   0,   0, 
+      2,   0,   0,   0,   5,   0, 
+      0,   0,   4,   0,   0,   0, 
+    255, 255, 255, 255,   3,   0, 
+      0,   0,   1,   0,   0,   0, 
+     13,   0,   0,   0, 234,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+    115,  83,  97, 109, 112, 108, 
+    101, 114,   0,  76,  97, 121, 
+    101, 114,  84, 101, 120, 116, 
+    117, 114, 101,  83,  97, 109, 
+    112, 108, 101, 114,  76, 105, 
+    110, 101,  97, 114,   0, 116, 
+     82,  71,  66,   0, 116,  77, 
+     97, 115, 107,   0,  36,  71, 
+    108, 111,  98,  97, 108, 115, 
+      0, 171, 234,   0,   0,   0, 
+      8,   0,   0,   0,  12,   1, 
+      0,   0, 224,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0, 204,   1,   0,   0, 
+      0,   0,   0,   0,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+    216,   1,   0,   0,   0,   0, 
+      0,   0, 232,   1,   0,   0, 
+     16,   0,   0,   0,   4,   0, 
+      0,   0,   2,   0,   0,   0, 
+    248,   1,   0,   0,   0,   0, 
+      0,   0,   8,   2,   0,   0, 
+     32,   0,   0,   0,  64,   0, 
+      0,   0,   0,   0,   0,   0, 
+     24,   2,   0,   0,   0,   0, 
+      0,   0,  40,   2,   0,   0, 
+     96,   0,   0,   0,  64,   0, 
+      0,   0,   0,   0,   0,   0, 
+     24,   2,   0,   0,   0,   0, 
+      0,   0,  52,   2,   0,   0, 
+    160,   0,   0,   0,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+    216,   1,   0,   0,   0,   0, 
+      0,   0,  72,   2,   0,   0, 
+    176,   0,   0,   0,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+     88,   2,   0,   0,   0,   0, 
+      0,   0, 104,   2,   0,   0, 
+    192,   0,   0,   0,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+     88,   2,   0,   0,   0,   0, 
+      0,   0, 115,   2,   0,   0, 
+    208,   0,   0,   0,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+     88,   2,   0,   0,   0,   0, 
+      0,   0, 102,  76,  97, 121, 
+    101, 114,  67, 111, 108, 111, 
+    114,   0,   1,   0,   3,   0, 
+      1,   0,   4,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    102,  76,  97, 121, 101, 114, 
+     79, 112,  97,  99, 105, 116, 
+    121,   0, 171, 171,   0,   0, 
+      3,   0,   1,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0, 109,  76,  97, 121, 
+    101, 114,  84, 114,  97, 110, 
+    115, 102, 111, 114, 109,   0, 
+      3,   0,   3,   0,   4,   0, 
+      4,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0, 109,  80, 
+    114, 111, 106, 101,  99, 116, 
+    105, 111, 110,   0, 118,  82, 
+    101, 110, 100, 101, 114,  84, 
+     97, 114, 103, 101, 116,  79, 
+    102, 102, 115, 101, 116,   0, 
+    118,  84, 101, 120, 116, 117, 
+    114, 101,  67, 111, 111, 114, 
+    100, 115,   0, 171,   1,   0, 
+      3,   0,   1,   0,   4,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0, 118,  76,  97, 121, 
+    101, 114,  81, 117,  97, 100, 
+      0, 118,  77,  97, 115, 107, 
+     81, 117,  97, 100,   0,  77, 
+    105,  99, 114, 111, 115, 111, 
+    102, 116,  32,  40,  82,  41, 
+     32,  72,  76,  83,  76,  32, 
+     83, 104,  97, 100, 101, 114, 
+     32,  67, 111, 109, 112, 105, 
+    108, 101, 114,  32,  54,  46, 
+     51,  46,  57,  54,  48,  48, 
+     46,  49,  54,  51,  56,  52, 
+      0, 171,  73,  83,  71,  78, 
+    104,   0,   0,   0,   3,   0, 
+      0,   0,   8,   0,   0,   0, 
+     80,   0,   0,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+      3,   0,   0,   0,   0,   0, 
+      0,   0,  15,   0,   0,   0, 
+     92,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   0,   0,   1,   0, 
+      0,   0,   3,   3,   0,   0, 
+     92,   0,   0,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   0,   0,   2,   0, 
+      0,   0,   7,   7,   0,   0, 
+     83,  86,  95,  80, 111, 115, 
+    105, 116, 105, 111, 110,   0, 
+     84,  69,  88,  67,  79,  79, 
+     82,  68,   0, 171, 171, 171, 
+     79,  83,  71,  78,  44,   0, 
+      0,   0,   1,   0,   0,   0, 
+      8,   0,   0,   0,  32,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   3,   0, 
+      0,   0,   0,   0,   0,   0, 
+     15,   0,   0,   0,  83,  86, 
+     95,  84,  97, 114, 103, 101, 
+    116,   0, 171, 171
+};
+ShaderBytes sRGBAShaderMask3DPremul = { RGBAShaderMask3DPremul, sizeof(RGBAShaderMask3DPremul) };
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -4361,28 +5357,28 @@ const BYTE RGBAShaderMask3D[] =
 // tCr                               texture  float4          2d    2        1
 // tMask                             texture  float4          2d    3        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Position              0   xyzw        0      POS  float       
-// TEXCOORD                 0   xy          1     NONE  float   xy  
-// TEXCOORD                 1     zw        1     NONE  float     zw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float       
+// TEXCOORD                 0   xy          1     NONE   float   xy  
+// TEXCOORD                 1     zw        1     NONE   float     zw
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Target                0   xyzw        0   TARGET  float   xyzw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target                0   xyzw        0   TARGET   float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -4455,20 +5451,20 @@ mul r0.xyzw, r1.xyzw, cb0[1].xxxx
 sample r1.xyzw, v1.zwzz, t3.xyzw, s0
 mul o0.xyzw, r0.xyzw, r1.xxxx
 ret 
 // Approximately 17 instruction slots used
 #endif
 
 const BYTE YCbCrShaderMask[] =
 {
-     68,  88,  66,  67,  74,  33, 
-    155, 235,  22, 178,  84, 169, 
-    113,  91, 240,  98, 157, 143, 
-    221,  19,   1,   0,   0,   0, 
+     68,  88,  66,  67, 154,  30, 
+    246, 171,  67, 224, 184,  33, 
+     20, 150, 106, 233, 226, 126, 
+     80, 130,   1,   0,   0,   0, 
     168,   8,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
      24,   2,   0,   0, 196,   4, 
       0,   0,  64,   5,   0,   0, 
       4,   8,   0,   0, 116,   8, 
       0,   0,  65, 111, 110,  57, 
     216,   1,   0,   0, 216,   1, 
       0,   0,   0,   2, 255, 255, 
@@ -4662,17 +5658,17 @@ const BYTE YCbCrShaderMask[] =
      16,   0,   0,   0,   0,   0, 
      70,  14,  16,   0,   0,   0, 
       0,   0,   6,   0,  16,   0, 
       1,   0,   0,   0,  62,   0, 
       0,   1,  83,  84,  65,  84, 
     116,   0,   0,   0,  17,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,   3,   0, 
-      0,   0,   7,   0,   0,   0, 
+      0,   0,  11,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       4,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -4794,19 +5790,19 @@ const BYTE YCbCrShaderMask[] =
      81, 117,  97, 100,   0, 118, 
      77,  97, 115, 107,  81, 117, 
      97, 100,   0,  77, 105,  99, 
     114, 111, 115, 111, 102, 116, 
      32,  40,  82,  41,  32,  72, 
      76,  83,  76,  32,  83, 104, 
      97, 100, 101, 114,  32,  67, 
     111, 109, 112, 105, 108, 101, 
-    114,  32,  57,  46,  50,  57, 
-     46,  57,  53,  50,  46,  51, 
-     49,  49,  49,   0, 171, 171, 
+    114,  32,  54,  46,  51,  46, 
+     57,  54,  48,  48,  46,  49, 
+     54,  51,  56,  52,   0, 171, 
      73,  83,  71,  78, 104,   0, 
       0,   0,   3,   0,   0,   0, 
       8,   0,   0,   0,  80,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
      15,   0,   0,   0,  92,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -4826,24 +5822,20 @@ const BYTE YCbCrShaderMask[] =
       0,   0,  32,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  83,  86,  95,  84, 
      97, 114, 103, 101, 116,   0, 
     171, 171
 };
+ShaderBytes sYCbCrShaderMask = { YCbCrShaderMask, sizeof(YCbCrShaderMask) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
-//
-//
-//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl
-//    -EComponentAlphaShaderMask -VnComponentAlphaShaderMask
-//    -FhtmpShaderHeader
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -4867,29 +5859,29 @@ const BYTE YCbCrShaderMask[] =
 // tRGBWhite                         texture  float4          2d    1        1
 // tMask                             texture  float4          2d    3        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Position              0   xyzw        0      POS  float       
-// TEXCOORD                 0   xy          1     NONE  float   xy  
-// TEXCOORD                 1     zw        1     NONE  float     zw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float       
+// TEXCOORD                 0   xy          1     NONE   float   xy  
+// TEXCOORD                 1     zw        1     NONE   float     zw
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Target                0   xyzw        0   TARGET  float   xyzw
-// SV_Target                1   xyzw        1   TARGET  float   xyzw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target                0   xyzw        0   TARGET   float   xyzw
+// SV_Target                1   xyzw        1   TARGET   float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -4946,20 +5938,20 @@ mul r2.x, r2.x, cb0[1].x
 mul o0.xyzw, r1.xyzw, r2.xxxx
 mul o1.xyzw, r0.xyzw, r2.xxxx
 ret 
 // Approximately 10 instruction slots used
 #endif
 
 const BYTE ComponentAlphaShaderMask[] =
 {
-     68,  88,  66,  67, 214,  67, 
-    206,  69,  12, 117, 144,  46, 
-    127, 133, 145, 240,  56, 186, 
-    119, 195,   1,   0,   0,   0, 
+     68,  88,  66,  67, 102,   2, 
+     84, 222,  33, 141, 105, 188, 
+    152,  82,  64, 100,  57, 101, 
+    192, 110,   1,   0,   0,   0, 
      20,   7,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     124,   1,   0,   0,  52,   3, 
       0,   0, 176,   3,   0,   0, 
      88,   6,   0,   0, 200,   6, 
       0,   0,  65, 111, 110,  57, 
      60,   1,   0,   0,  60,   1, 
       0,   0,   0,   2, 255, 255, 
@@ -5096,17 +6088,17 @@ const BYTE ComponentAlphaShaderMask[] =
       0,   0,   0,   0,   1,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   2,   0, 
+      0,   0,   0,   0,   1,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,  82,  68,  69,  70, 
     160,   2,   0,   0,   1,   0, 
@@ -5214,19 +6206,19 @@ const BYTE ComponentAlphaShaderMask[] =
      97, 100,   0, 118,  77,  97, 
     115, 107,  81, 117,  97, 100, 
       0,  77, 105,  99, 114, 111, 
     115, 111, 102, 116,  32,  40, 
      82,  41,  32,  72,  76,  83, 
      76,  32,  83, 104,  97, 100, 
     101, 114,  32,  67, 111, 109, 
     112, 105, 108, 101, 114,  32, 
-     57,  46,  50,  57,  46,  57, 
-     53,  50,  46,  51,  49,  49, 
-     49,   0, 171, 171,  73,  83, 
+     54,  46,  51,  46,  57,  54, 
+     48,  48,  46,  49,  54,  51, 
+     56,  52,   0, 171,  73,  83, 
      71,  78, 104,   0,   0,   0, 
       3,   0,   0,   0,   8,   0, 
       0,   0,  80,   0,   0,   0, 
       0,   0,   0,   0,   1,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  92,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -5249,8 +6241,9 @@ const BYTE ComponentAlphaShaderMask[] =
       0,   0,  15,   0,   0,   0, 
      56,   0,   0,   0,   1,   0, 
       0,   0,   0,   0,   0,   0, 
       3,   0,   0,   0,   1,   0, 
       0,   0,  15,   0,   0,   0, 
      83,  86,  95,  84,  97, 114, 
     103, 101, 116,   0, 171, 171
 };
+ShaderBytes sComponentAlphaShaderMask = { ComponentAlphaShaderMask, sizeof(ComponentAlphaShaderMask) };
--- a/gfx/layers/d3d11/CompositorD3D11ShadersVR.h
+++ b/gfx/layers/d3d11/CompositorD3D11ShadersVR.h
@@ -1,15 +1,11 @@
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
-//
-//
-//   fxc -nologo -Tvs_4_0_level_9_3 CompositorD3D11VR.hlsl
-//    -EOculusVRDistortionVS -VnOculusVRDistortionVS -FhtmpShaderHeader
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 VREyeToSource;              // Offset:    0 Size:    16
@@ -23,34 +19,34 @@
 // Name                                 Type  Format         Dim Slot Elements
 // ------------------------------ ---------- ------- ----------- ---- --------
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// POSITION                 0   xy          0     NONE  float   xy  
-// TEXCOORD                 0   xy          1     NONE  float   xy  
-// TEXCOORD                 1   xy          2     NONE  float   xy  
-// TEXCOORD                 2   xy          3     NONE  float   xy  
-// COLOR                    0   xyzw        4     NONE  float   xyzw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// POSITION                 0   xy          0     NONE   float   xy  
+// TEXCOORD                 0   xy          1     NONE   float   xy  
+// TEXCOORD                 1   xy          2     NONE   float   xy  
+// TEXCOORD                 2   xy          3     NONE   float   xy  
+// COLOR                    0   xyzw        4     NONE   float   xyzw
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Position              0   xyzw        0      POS  float   xyzw
-// TEXCOORD                 0   xyz         1     NONE  float   xyz 
-// TEXCOORD                 1   xyz         2     NONE  float   xyz 
-// TEXCOORD                 2   xyz         3     NONE  float   xyz 
-// COLOR                    0   xyzw        4     NONE  float   xyzw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float   xyzw
+// TEXCOORD                 0   xyz         1     NONE   float   xyz 
+// TEXCOORD                 1   xyz         2     NONE   float   xyz 
+// TEXCOORD                 2   xyz         3     NONE   float   xyz 
+// COLOR                    0   xyzw        4     NONE   float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c1         cb0             0         2  ( FLT, FLT, FLT, FLT)
 //
@@ -105,20 +101,20 @@ mad o3.xy, v3.xyxx, cb0[0].zwzz, cb0[0].
 mov o3.z, l(1.000000)
 mov o4.xyzw, v4.xyzw
 ret 
 // Approximately 10 instruction slots used
 #endif
 
 const BYTE Oculus050VRDistortionVS[] =
 {
-     68,  88,  66,  67, 206, 154, 
-    203,  64, 121,  47, 121, 169, 
-    222, 206, 108, 175, 167, 227, 
-    154,  37,   1,   0,   0,   0, 
+     68,  88,  66,  67,   3,  61, 
+    196, 122,  10,  53,  44, 234, 
+     18, 242, 195, 238,  42,  90, 
+     72, 193,   1,   0,   0,   0, 
     244,   5,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     108,   1,   0,   0,  44,   3, 
       0,   0, 168,   3,   0,   0, 
     176,   4,   0,   0,  80,   5, 
       0,   0,  65, 111, 110,  57, 
      44,   1,   0,   0,  44,   1, 
       0,   0,   0,   2, 254, 255, 
@@ -244,17 +240,17 @@ const BYTE Oculus050VRDistortionVS[] =
     128,  63,  54,   0,   0,   5, 
     242,  32,  16,   0,   4,   0, 
       0,   0,  70,  30,  16,   0, 
       4,   0,   0,   0,  62,   0, 
       0,   1,  83,  84,  65,  84, 
     116,   0,   0,   0,  10,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,  10,   0, 
-      0,   0,   0,   0,   0,   0, 
+      0,   0,   4,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -302,19 +298,19 @@ const BYTE Oculus050VRDistortionVS[] =
      99,  97, 108, 101,  65, 110, 
     100,  79, 102, 102, 115, 101, 
     116,   0,  77, 105,  99, 114, 
     111, 115, 111, 102, 116,  32, 
      40,  82,  41,  32,  72,  76, 
      83,  76,  32,  83, 104,  97, 
     100, 101, 114,  32,  67, 111, 
     109, 112, 105, 108, 101, 114, 
-     32,  57,  46,  50,  57,  46, 
-     57,  53,  50,  46,  51,  49, 
-     49,  49,   0, 171, 171, 171, 
+     32,  54,  46,  51,  46,  57, 
+     54,  48,  48,  46,  49,  54, 
+     51,  56,  52,   0, 171, 171, 
      73,  83,  71,  78, 152,   0, 
       0,   0,   5,   0,   0,   0, 
       8,   0,   0,   0, 128,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
       3,   3,   0,   0, 137,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -360,50 +356,47 @@ const BYTE Oculus050VRDistortionVS[] =
       0,   0,   3,   0,   0,   0, 
       4,   0,   0,   0,  15,   0, 
       0,   0,  83,  86,  95,  80, 
     111, 115, 105, 116, 105, 111, 
     110,   0,  84,  69,  88,  67, 
      79,  79,  82,  68,   0,  67, 
      79,  76,  79,  82,   0, 171
 };
+ShaderBytes sOculus050VRDistortionVS = { Oculus050VRDistortionVS, sizeof(Oculus050VRDistortionVS) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
-//
-//
-//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11VR.hlsl
-//    -EOculusVRDistortionPS -VnOculusVRDistortionPS -FhtmpShaderHeader
+// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
 //
 //
 // Resource Bindings:
 //
 // Name                                 Type  Format         Dim Slot Elements
 // ------------------------------ ---------- ------- ----------- ---- --------
 // Linear                            sampler      NA          NA    0        1
 // Texture                           texture  float4          2d    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Position              0   xyzw        0      POS  float       
-// TEXCOORD                 0   xyz         1     NONE  float   xy  
-// TEXCOORD                 1   xyz         2     NONE  float   xy  
-// TEXCOORD                 2   xyz         3     NONE  float   xy  
-// COLOR                    0   xyzw        4     NONE  float   x   
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float       
+// TEXCOORD                 0   xyz         1     NONE   float   xy  
+// TEXCOORD                 1   xyz         2     NONE   float   xy  
+// TEXCOORD                 2   xyz         3     NONE   float   xy  
+// COLOR                    0   xyzw        4     NONE   float   x   
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue Format   Used
-// -------------------- ----- ------ -------- -------- ------ ------
-// SV_Target                0   xyzw        0   TARGET  float   xyzw
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target                0   xyzw        0   TARGET   float   xyzw
 //
 //
 // Sampler/Resource to DX9 shader sampler mappings:
 //
 // Target Sampler Source Sampler  Source Resource
 // -------------- --------------- ----------------
 // s0             s0              t0               
 //
@@ -444,25 +437,25 @@ sample r0.xyzw, v3.xyxx, t0.xyzw, s0
 mul o0.z, r0.z, v4.x
 mov o0.w, l(1.000000)
 ret 
 // Approximately 8 instruction slots used
 #endif
 
 const BYTE Oculus050VRDistortionPS[] =
 {
-     68,  88,  66,  67,  48, 161, 
-    127, 216, 149, 107,  53,  57, 
-    164,  84,  84, 154,  58, 227, 
-    125,  61,   1,   0,   0,   0, 
-    124,   4,   0,   0,   6,   0, 
+     68,  88,  66,  67, 108, 219, 
+     61, 216,  27,   0,  27, 222, 
+    242, 132, 183,  21, 166, 141, 
+    130,  39,   1,   0,   0,   0, 
+    128,   4,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
      60,   1,   0,   0, 132,   2, 
       0,   0,   0,   3,   0,   0, 
-    164,   3,   0,   0,  72,   4, 
+    168,   3,   0,   0,  76,   4, 
       0,   0,  65, 111, 110,  57, 
     252,   0,   0,   0, 252,   0, 
       0,   0,   0,   2, 255, 255, 
     212,   0,   0,   0,  40,   0, 
       0,   0,   0,   0,  40,   0, 
       0,   0,  40,   0,   0,   0, 
      40,   0,   1,   0,  36,   0, 
       0,   0,  40,   0,   0,   0, 
@@ -572,17 +565,17 @@ const BYTE Oculus050VRDistortionPS[] =
       0,   0,   0,   0,   0,   0, 
       0,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
-     82,  68,  69,  70, 156,   0, 
+     82,  68,  69,  70, 160,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   2,   0, 
       0,   0,  28,   0,   0,   0, 
       0,   4, 255, 255,   0,   1, 
       0,   0, 107,   0,   0,   0, 
      92,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -597,48 +590,49 @@ const BYTE Oculus050VRDistortionPS[] =
     110, 101,  97, 114,   0,  84, 
     101, 120, 116, 117, 114, 101, 
       0,  77, 105,  99, 114, 111, 
     115, 111, 102, 116,  32,  40, 
      82,  41,  32,  72,  76,  83, 
      76,  32,  83, 104,  97, 100, 
     101, 114,  32,  67, 111, 109, 
     112, 105, 108, 101, 114,  32, 
-     57,  46,  50,  57,  46,  57, 
-     53,  50,  46,  51,  49,  49, 
-     49,   0,  73,  83,  71,  78, 
-    156,   0,   0,   0,   5,   0, 
+     54,  46,  51,  46,  57,  54, 
+     48,  48,  46,  49,  54,  51, 
+     56,  52,   0, 171, 171, 171, 
+     73,  83,  71,  78, 156,   0, 
+      0,   0,   5,   0,   0,   0, 
+      8,   0,   0,   0, 128,   0, 
+      0,   0,   0,   0,   0,   0, 
+      1,   0,   0,   0,   3,   0, 
+      0,   0,   0,   0,   0,   0, 
+     15,   0,   0,   0, 140,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   3,   0, 
+      0,   0,   1,   0,   0,   0, 
+      7,   3,   0,   0, 140,   0, 
+      0,   0,   1,   0,   0,   0, 
+      0,   0,   0,   0,   3,   0, 
+      0,   0,   2,   0,   0,   0, 
+      7,   3,   0,   0, 140,   0, 
+      0,   0,   2,   0,   0,   0, 
+      0,   0,   0,   0,   3,   0, 
+      0,   0,   3,   0,   0,   0, 
+      7,   3,   0,   0, 149,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   3,   0, 
+      0,   0,   4,   0,   0,   0, 
+     15,   1,   0,   0,  83,  86, 
+     95,  80, 111, 115, 105, 116, 
+    105, 111, 110,   0,  84,  69, 
+     88,  67,  79,  79,  82,  68, 
+      0,  67,  79,  76,  79,  82, 
+      0, 171,  79,  83,  71,  78, 
+     44,   0,   0,   0,   1,   0, 
       0,   0,   8,   0,   0,   0, 
-    128,   0,   0,   0,   0,   0, 
-      0,   0,   1,   0,   0,   0, 
+     32,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
       3,   0,   0,   0,   0,   0, 
       0,   0,  15,   0,   0,   0, 
-    140,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      3,   0,   0,   0,   1,   0, 
-      0,   0,   7,   3,   0,   0, 
-    140,   0,   0,   0,   1,   0, 
-      0,   0,   0,   0,   0,   0, 
-      3,   0,   0,   0,   2,   0, 
-      0,   0,   7,   3,   0,   0, 
-    140,   0,   0,   0,   2,   0, 
-      0,   0,   0,   0,   0,   0, 
-      3,   0,   0,   0,   3,   0, 
-      0,   0,   7,   3,   0,   0, 
-    149,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      3,   0,   0,   0,   4,   0, 
-      0,   0,  15,   1,   0,   0, 
-     83,  86,  95,  80, 111, 115, 
-    105, 116, 105, 111, 110,   0, 
-     84,  69,  88,  67,  79,  79, 
-     82,  68,   0,  67,  79,  76, 
-     79,  82,   0, 171,  79,  83, 
-     71,  78,  44,   0,   0,   0, 
-      1,   0,   0,   0,   8,   0, 
-      0,   0,  32,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   3,   0,   0,   0, 
-      0,   0,   0,   0,  15,   0, 
-      0,   0,  83,  86,  95,  84, 
-     97, 114, 103, 101, 116,   0, 
-    171, 171
+     83,  86,  95,  84,  97, 114, 
+    103, 101, 116,   0, 171, 171
 };
+ShaderBytes sOculus050VRDistortionPS = { Oculus050VRDistortionPS, sizeof(Oculus050VRDistortionPS) };
--- a/gfx/layers/d3d11/genshaders.sh
+++ b/gfx/layers/d3d11/genshaders.sh
@@ -9,40 +9,46 @@ FXC_FLAGS=""
 
 # If DEBUG is in the environment, then rebuild with debug info
 if [ "$DEBUG" != "" ] ; then
   FXC_FLAGS="$FXC_DEBUG_FLAGS"
 fi
 
 makeShaderVS() {
     fxc -nologo $FXC_FLAGS -Tvs_4_0_level_9_3 $SRC -E$1 -Vn$1 -Fh$tempfile
+    echo "ShaderBytes s$1 = { $1, sizeof($1) };" >> $tempfile;
     cat $tempfile >> $DEST
 }
 
 makeShaderPS() {
     fxc -nologo $FXC_FLAGS -Tps_4_0_level_9_3 $SRC -E$1 -Vn$1 -Fh$tempfile
+    echo "ShaderBytes s$1 = { $1, sizeof($1) };" >> $tempfile;
     cat $tempfile >> $DEST
 }
 
 SRC=CompositorD3D11.hlsl
 DEST=CompositorD3D11Shaders.h
 
 rm -f $DEST
+echo "struct ShaderBytes { const void* mData; size_t mLength; };" >> $DEST;
 makeShaderVS LayerQuadVS
 makeShaderPS SolidColorShader
 makeShaderPS RGBShader
 makeShaderPS RGBAShader
+makeShaderPS RGBAShaderPremul
 makeShaderPS ComponentAlphaShader
 makeShaderPS YCbCrShader
 makeShaderVS LayerQuadMaskVS
 makeShaderVS LayerQuadMask3DVS
 makeShaderPS SolidColorShaderMask
 makeShaderPS RGBShaderMask
 makeShaderPS RGBAShaderMask
+makeShaderPS RGBAShaderMaskPremul
 makeShaderPS RGBAShaderMask3D
+makeShaderPS RGBAShaderMask3DPremul
 makeShaderPS YCbCrShaderMask
 makeShaderPS ComponentAlphaShaderMask
 
 SRC=CompositorD3D11VR.hlsl
 DEST=CompositorD3D11ShadersVR.h
 
 rm -f $DEST
 makeShaderVS Oculus050VRDistortionVS
--- a/gfx/thebes/SoftwareVsyncSource.cpp
+++ b/gfx/thebes/SoftwareVsyncSource.cpp
@@ -1,16 +1,17 @@
 /* -*- 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 "SoftwareVsyncSource.h"
 #include "base/task.h"
+#include "gfxPlatform.h"
 #include "nsThreadUtils.h"
 
 SoftwareVsyncSource::SoftwareVsyncSource()
 {
   MOZ_ASSERT(NS_IsMainThread());
   mGlobalDisplay = new SoftwareDisplay();
 }
 
@@ -22,17 +23,17 @@ SoftwareVsyncSource::~SoftwareVsyncSourc
 }
 
 SoftwareDisplay::SoftwareDisplay()
   : mCurrentVsyncTask(nullptr)
   , mVsyncEnabled(false)
 {
   // Mimic 60 fps
   MOZ_ASSERT(NS_IsMainThread());
-  const double rate = 1000 / 60.0;
+  const double rate = 1000.0 / (double) gfxPlatform::GetSoftwareVsyncRate();
   mVsyncRate = mozilla::TimeDuration::FromMilliseconds(rate);
   mVsyncThread = new base::Thread("SoftwareVsyncThread");
   MOZ_RELEASE_ASSERT(mVsyncThread->Start(), "Could not start software vsync thread");
 }
 
 SoftwareDisplay::~SoftwareDisplay() {}
 
 void
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -576,17 +576,21 @@ gfxPlatform::Init()
     nsCOMPtr<imgITools> imgTools = do_GetService("@mozilla.org/image/tools;1");
     if (!imgTools) {
       NS_RUNTIMEABORT("Could not initialize ImageLib");
     }
 
     RegisterStrongMemoryReporter(new GfxMemoryImageReporter());
 
     if (XRE_IsParentProcess()) {
-      gPlatform->mVsyncSource = gPlatform->CreateHardwareVsyncSource();
+      if (gfxPlatform::ForceSoftwareVsync()) {
+        gPlatform->mVsyncSource = (gPlatform)->gfxPlatform::CreateHardwareVsyncSource();
+      } else {
+        gPlatform->mVsyncSource = gPlatform->CreateHardwareVsyncSource();
+      }
     }
 }
 
 static bool sLayersIPCIsUp = false;
 
 void
 gfxPlatform::Shutdown()
 {
@@ -2323,16 +2327,23 @@ gfxPlatform::UsesOffMainThreadCompositin
 
 #endif
     firstTime = false;
   }
 
   return result;
 }
 
+/***
+ * The preference "layout.frame_rate" has 3 meanings depending on the value:
+ *
+ * -1 = Auto (default), use hardware vsync or software vsync @ 60 hz if hw vsync fails.
+ *  0 = ASAP mode - used during talos testing.
+ *  X = Software vsync at a rate of X times per second.
+ */
 already_AddRefed<mozilla::gfx::VsyncSource>
 gfxPlatform::CreateHardwareVsyncSource()
 {
   NS_WARNING("Hardware Vsync support not yet implemented. Falling back to software timers");
   nsRefPtr<mozilla::gfx::VsyncSource> softwareVsync = new SoftwareVsyncSource();
   return softwareVsync.forget();
 }
 
@@ -2342,16 +2353,39 @@ gfxPlatform::IsInLayoutAsapMode()
   // There are 2 modes of ASAP mode.
   // 1 is that the refresh driver and compositor are in lock step
   // the second is that the compositor goes ASAP and the refresh driver
   // goes at whatever the configurated rate is. This only checks the version
   // talos uses, which is the refresh driver and compositor are in lockstep.
   return Preferences::GetInt("layout.frame_rate", -1) == 0;
 }
 
+/* static */ bool
+gfxPlatform::ForceSoftwareVsync()
+{
+  return Preferences::GetInt("layout.frame_rate", -1) > 0;
+}
+
+/* static */ int
+gfxPlatform::GetSoftwareVsyncRate()
+{
+  int preferenceRate = Preferences::GetInt("layout.frame_rate",
+                                           gfxPlatform::GetDefaultFrameRate());
+  if (preferenceRate <= 0) {
+    return gfxPlatform::GetDefaultFrameRate();
+  }
+  return preferenceRate;
+}
+
+/* static */ int
+gfxPlatform::GetDefaultFrameRate()
+{
+  return 60;
+}
+
 static nsString
 DetectBadApzWheelInputPrefs()
 {
   static const char *sBadMultiplierPrefs[] = {
     "mousewheel.default.delta_multiplier_x",
     "mousewheel.with_alt.delta_multiplier_x",
     "mousewheel.with_control.delta_multiplier_x",
     "mousewheel.with_meta.delta_multiplier_x",
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -603,16 +603,31 @@ public:
     /**
      * True if layout rendering should use ASAP mode, which means
      * the refresh driver and compositor should render ASAP.
      * Used for talos testing purposes
      */
     static bool IsInLayoutAsapMode();
 
     /**
+     * Returns the software vsync rate to use.
+     */
+    static int GetSoftwareVsyncRate();
+
+    /**
+     * Returns whether or not a custom vsync rate is set.
+     */
+    static bool ForceSoftwareVsync();
+
+    /**
+     * Returns the default frame rate for the refresh driver / software vsync.
+     */
+    static int GetDefaultFrameRate();
+
+    /**
      * Used to test which input types are handled via APZ.
      */
     virtual bool SupportsApzWheelInput() const {
       return false;
     }
     virtual bool SupportsApzTouchInput() const {
       return false;
     }
--- a/js/src/jit-test/tests/ion/bug1107011-2.js
+++ b/js/src/jit-test/tests/ion/bug1107011-2.js
@@ -3,10 +3,10 @@ function foo() {
     function bar() {
         x = y;
         y = a[0];
     }
     for (var i = 0; i < 1000; i++) {
         bar();
     }
 }
-for (var i=0; i<10000; i++)
+for (var i=0; i < 50; i++)
     foo();
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -2445,42 +2445,59 @@ CodeGeneratorARM::visitUDiv(LUDiv* ins)
     Register rhs = ToRegister(ins->rhs());
     Register output = ToRegister(ins->output());
 
     Label done;
     generateUDivModZeroCheck(rhs, output, &done, ins->snapshot(), ins->mir());
 
     masm.ma_udiv(lhs, rhs, output);
 
+    // Check for large unsigned result - represent as double.
     if (!ins->mir()->isTruncated()) {
+        MOZ_ASSERT(ins->mir()->fallible());
         masm.ma_cmp(output, Imm32(0));
         bailoutIf(Assembler::LessThan, ins->snapshot());
     }
 
-    masm.bind(&done);
+    // Check for non-zero remainder if not truncating to int.
+    if (!ins->mir()->canTruncateRemainder()) {
+        MOZ_ASSERT(ins->mir()->fallible());
+        {
+            ScratchRegisterScope scratch(masm);
+            masm.ma_mul(rhs, output, scratch);
+            masm.ma_cmp(scratch, lhs);
+        }
+        bailoutIf(Assembler::NotEqual, ins->snapshot());
+    }
+
+    if (done.used())
+        masm.bind(&done);
 }
 
 void
 CodeGeneratorARM::visitUMod(LUMod* ins)
 {
     Register lhs = ToRegister(ins->lhs());
     Register rhs = ToRegister(ins->rhs());
     Register output = ToRegister(ins->output());
 
     Label done;
     generateUDivModZeroCheck(rhs, output, &done, ins->snapshot(), ins->mir());
 
     masm.ma_umod(lhs, rhs, output);
 
+    // Check for large unsigned result - represent as double.
     if (!ins->mir()->isTruncated()) {
+        MOZ_ASSERT(ins->mir()->fallible());
         masm.ma_cmp(output, Imm32(0));
         bailoutIf(Assembler::LessThan, ins->snapshot());
     }
 
-    masm.bind(&done);
+    if (done.used())
+        masm.bind(&done);
 }
 
 template<class T>
 void
 CodeGeneratorARM::generateUDivModZeroCheck(Register rhs, Register output, Label* done,
                                            LSnapshot* snapshot, T* mir)
 {
     if (!mir)
copy from js/src/jit/mips32/Lowering-mips32.cpp
copy to js/src/jit/mips-shared/Lowering-mips-shared.cpp
--- a/js/src/jit/mips32/Lowering-mips32.cpp
+++ b/js/src/jit/mips-shared/Lowering-mips-shared.cpp
@@ -1,249 +1,107 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 "jit/mips-shared/Lowering-mips-shared.h"
+
 #include "mozilla/MathAlgorithms.h"
 
-
-#include "jit/Lowering.h"
-#include "jit/mips32/Assembler-mips32.h"
 #include "jit/MIR.h"
 
 #include "jit/shared/Lowering-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::FloorLog2;
 
-void
-LIRGeneratorMIPS::useBoxFixed(LInstruction* lir, size_t n, MDefinition* mir, Register reg1,
-                              Register reg2, bool useAtStart)
-{
-    MOZ_ASSERT(mir->type() == MIRType_Value);
-    MOZ_ASSERT(reg1 != reg2);
-
-    ensureDefined(mir);
-    lir->setOperand(n, LUse(reg1, mir->virtualRegister(), useAtStart));
-    lir->setOperand(n + 1, LUse(reg2, VirtualRegisterOfPayload(mir), useAtStart));
-}
-
 LAllocation
-LIRGeneratorMIPS::useByteOpRegister(MDefinition* mir)
+LIRGeneratorMIPSShared::useByteOpRegister(MDefinition* mir)
 {
     return useRegister(mir);
 }
 
 LAllocation
-LIRGeneratorMIPS::useByteOpRegisterOrNonDoubleConstant(MDefinition* mir)
+LIRGeneratorMIPSShared::useByteOpRegisterOrNonDoubleConstant(MDefinition* mir)
 {
     return useRegisterOrNonDoubleConstant(mir);
 }
 
 LDefinition
-LIRGeneratorMIPS::tempByteOpRegister()
+LIRGeneratorMIPSShared::tempByteOpRegister()
 {
     return temp();
 }
 
-void
-LIRGeneratorMIPS::visitBox(MBox* box)
-{
-    MDefinition* inner = box->getOperand(0);
-
-    // If the box wrapped a double, it needs a new register.
-    if (IsFloatingPointType(inner->type())) {
-        defineBox(new(alloc()) LBoxFloatingPoint(useRegisterAtStart(inner),
-                                                 tempCopy(inner, 0), inner->type()), box);
-        return;
-    }
-
-    if (box->canEmitAtUses()) {
-        emitAtUses(box);
-        return;
-    }
-
-    if (inner->isConstant()) {
-        defineBox(new(alloc()) LValue(inner->toConstant()->value()), box);
-        return;
-    }
-
-    LBox* lir = new(alloc()) LBox(use(inner), inner->type());
-
-    // Otherwise, we should not define a new register for the payload portion
-    // of the output, so bypass defineBox().
-    uint32_t vreg = getVirtualRegister();
-
-    // Note that because we're using BogusTemp(), we do not change the type of
-    // the definition. We also do not define the first output as "TYPE",
-    // because it has no corresponding payload at (vreg + 1). Also note that
-    // although we copy the input's original type for the payload half of the
-    // definition, this is only for clarity. BogusTemp() definitions are
-    // ignored.
-    lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL));
-    lir->setDef(1, LDefinition::BogusTemp());
-    box->setVirtualRegister(vreg);
-    add(lir);
-}
-
-void
-LIRGeneratorMIPS::visitUnbox(MUnbox* unbox)
-{
-    MDefinition* inner = unbox->getOperand(0);
-
-    if (inner->type() == MIRType_ObjectOrNull) {
-        LUnboxObjectOrNull* lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(inner));
-        if (unbox->fallible())
-            assignSnapshot(lir, unbox->bailoutKind());
-        defineReuseInput(lir, unbox, 0);
-        return;
-    }
-
-    // An unbox on mips reads in a type tag (either in memory or a register) and
-    // a payload. Unlike most instructions consuming a box, we ask for the type
-    // second, so that the result can re-use the first input.
-    MOZ_ASSERT(inner->type() == MIRType_Value);
-
-    ensureDefined(inner);
-
-    if (IsFloatingPointType(unbox->type())) {
-        LUnboxFloatingPoint* lir = new(alloc()) LUnboxFloatingPoint(unbox->type());
-        if (unbox->fallible())
-            assignSnapshot(lir, unbox->bailoutKind());
-        useBox(lir, LUnboxFloatingPoint::Input, inner);
-        define(lir, unbox);
-        return;
-    }
-
-    // Swap the order we use the box pieces so we can re-use the payload
-    // register.
-    LUnbox* lir = new(alloc()) LUnbox;
-    lir->setOperand(0, usePayloadInRegisterAtStart(inner));
-    lir->setOperand(1, useType(inner, LUse::REGISTER));
-
-    if (unbox->fallible())
-        assignSnapshot(lir, unbox->bailoutKind());
-
-    // Types and payloads form two separate intervals. If the type becomes dead
-    // before the payload, it could be used as a Value without the type being
-    // recoverable. Unbox's purpose is to eagerly kill the definition of a type
-    // tag, so keeping both alive (for the purpose of gcmaps) is unappealing.
-    // Instead, we create a new virtual register.
-    defineReuseInput(lir, unbox, 0);
-}
-
-void
-LIRGeneratorMIPS::visitReturn(MReturn* ret)
-{
-    MDefinition* opd = ret->getOperand(0);
-    MOZ_ASSERT(opd->type() == MIRType_Value);
-
-    LReturn* ins = new(alloc()) LReturn;
-    ins->setOperand(0, LUse(JSReturnReg_Type));
-    ins->setOperand(1, LUse(JSReturnReg_Data));
-    fillBoxUses(ins, 0, opd);
-    add(ins);
-}
-
 // x = !y
 void
-LIRGeneratorMIPS::lowerForALU(LInstructionHelper<1, 1, 0>* ins,
-                              MDefinition* mir, MDefinition* input)
+LIRGeneratorMIPSShared::lowerForALU(LInstructionHelper<1, 1, 0>* ins,
+                                    MDefinition* mir, MDefinition* input)
 {
     ins->setOperand(0, useRegister(input));
     define(ins, mir, LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::REGISTER));
 }
 
 // z = x+y
 void
-LIRGeneratorMIPS::lowerForALU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
-                              MDefinition* lhs, MDefinition* rhs)
+LIRGeneratorMIPSShared::lowerForALU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
+                                    MDefinition* lhs, MDefinition* rhs)
 {
     ins->setOperand(0, useRegister(lhs));
     ins->setOperand(1, useRegisterOrConstant(rhs));
     define(ins, mir, LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::REGISTER));
 }
 
 void
-LIRGeneratorMIPS::lowerForFPU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir,
-                              MDefinition* input)
+LIRGeneratorMIPSShared::lowerForFPU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir,
+                                    MDefinition* input)
 {
     ins->setOperand(0, useRegister(input));
     define(ins, mir, LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::REGISTER));
 }
 
 template<size_t Temps>
 void
-LIRGeneratorMIPS::lowerForFPU(LInstructionHelper<1, 2, Temps>* ins, MDefinition* mir,
-                              MDefinition* lhs, MDefinition* rhs)
+LIRGeneratorMIPSShared::lowerForFPU(LInstructionHelper<1, 2, Temps>* ins, MDefinition* mir,
+                                    MDefinition* lhs, MDefinition* rhs)
 {
     ins->setOperand(0, useRegister(lhs));
     ins->setOperand(1, useRegister(rhs));
     define(ins, mir, LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::REGISTER));
 }
 
-template void LIRGeneratorMIPS::lowerForFPU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
-                                            MDefinition* lhs, MDefinition* rhs);
-template void LIRGeneratorMIPS::lowerForFPU(LInstructionHelper<1, 2, 1>* ins, MDefinition* mir,
-                                            MDefinition* lhs, MDefinition* rhs);
+template void LIRGeneratorMIPSShared::lowerForFPU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
+                                                  MDefinition* lhs, MDefinition* rhs);
+template void LIRGeneratorMIPSShared::lowerForFPU(LInstructionHelper<1, 2, 1>* ins, MDefinition* mir,
+                                                  MDefinition* lhs, MDefinition* rhs);
 
 void
-LIRGeneratorMIPS::lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir,
-                                          MDefinition* lhs, MDefinition* rhs)
+LIRGeneratorMIPSShared::lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir,
+                                                MDefinition* lhs, MDefinition* rhs)
 {
     baab->setOperand(0, useRegisterAtStart(lhs));
     baab->setOperand(1, useRegisterOrConstantAtStart(rhs));
     add(baab, mir);
 }
 
 void
-LIRGeneratorMIPS::defineUntypedPhi(MPhi* phi, size_t lirIndex)
-{
-    LPhi* type = current->getPhi(lirIndex + VREG_TYPE_OFFSET);
-    LPhi* payload = current->getPhi(lirIndex + VREG_DATA_OFFSET);
-
-    uint32_t typeVreg = getVirtualRegister();
-    phi->setVirtualRegister(typeVreg);
-
-    uint32_t payloadVreg = getVirtualRegister();
-    MOZ_ASSERT(typeVreg + 1 == payloadVreg);
-
-    type->setDef(0, LDefinition(typeVreg, LDefinition::TYPE));
-    payload->setDef(0, LDefinition(payloadVreg, LDefinition::PAYLOAD));
-    annotate(type);
-    annotate(payload);
-}
-
-void
-LIRGeneratorMIPS::lowerUntypedPhiInput(MPhi* phi, uint32_t inputPosition,
-                                       LBlock* block, size_t lirIndex)
-{
-    MDefinition* operand = phi->getOperand(inputPosition);
-    LPhi* type = block->getPhi(lirIndex + VREG_TYPE_OFFSET);
-    LPhi* payload = block->getPhi(lirIndex + VREG_DATA_OFFSET);
-    type->setOperand(inputPosition, LUse(operand->virtualRegister() + VREG_TYPE_OFFSET,
-                                         LUse::ANY));
-    payload->setOperand(inputPosition, LUse(VirtualRegisterOfPayload(operand), LUse::ANY));
-}
-
-void
-LIRGeneratorMIPS::lowerForShift(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
-                                MDefinition* lhs, MDefinition* rhs)
+LIRGeneratorMIPSShared::lowerForShift(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
+                                      MDefinition* lhs, MDefinition* rhs)
 {
     ins->setOperand(0, useRegister(lhs));
     ins->setOperand(1, useRegisterOrConstant(rhs));
     define(ins, mir);
 }
 
 void
-LIRGeneratorMIPS::lowerDivI(MDiv* div)
+LIRGeneratorMIPSShared::lowerDivI(MDiv* div)
 {
     if (div->isUnsigned()) {
         lowerUDiv(div);
         return;
     }
 
     // Division instructions are slow. Division by constant denominators can be
     // rewritten to use other instructions.
@@ -266,27 +124,27 @@ LIRGeneratorMIPS::lowerDivI(MDiv* div)
 
     LDivI* lir = new(alloc()) LDivI(useRegister(div->lhs()), useRegister(div->rhs()), temp());
     if (div->fallible())
         assignSnapshot(lir, Bailout_DoubleOutput);
     define(lir, div);
 }
 
 void
-LIRGeneratorMIPS::lowerMulI(MMul* mul, MDefinition* lhs, MDefinition* rhs)
+LIRGeneratorMIPSShared::lowerMulI(MMul* mul, MDefinition* lhs, MDefinition* rhs)
 {
     LMulI* lir = new(alloc()) LMulI;
     if (mul->fallible())
         assignSnapshot(lir, Bailout_DoubleOutput);
 
     lowerForALU(lir, mul, lhs, rhs);
 }
 
 void
-LIRGeneratorMIPS::lowerModI(MMod* mod)
+LIRGeneratorMIPSShared::lowerModI(MMod* mod)
 {
     if (mod->isUnsigned()) {
         lowerUMod(mod);
         return;
     }
 
     if (mod->rhs()->isConstant()) {
         int32_t rhs = mod->rhs()->toConstant()->value().toInt32();
@@ -312,135 +170,135 @@ LIRGeneratorMIPS::lowerModI(MMod* mod)
                            temp(LDefinition::GENERAL));
 
     if (mod->fallible())
         assignSnapshot(lir, Bailout_DoubleOutput);
     define(lir, mod);
 }
 
 void
-LIRGeneratorMIPS::visitPowHalf(MPowHalf* ins)
+LIRGeneratorMIPSShared::visitPowHalf(MPowHalf* ins)
 {
     MDefinition* input = ins->input();
     MOZ_ASSERT(input->type() == MIRType_Double);
     LPowHalfD* lir = new(alloc()) LPowHalfD(useRegisterAtStart(input));
     defineReuseInput(lir, ins, 0);
 }
 
 LTableSwitch*
-LIRGeneratorMIPS::newLTableSwitch(const LAllocation& in, const LDefinition& inputCopy,
-                                  MTableSwitch* tableswitch)
+LIRGeneratorMIPSShared::newLTableSwitch(const LAllocation& in, const LDefinition& inputCopy,
+                                        MTableSwitch* tableswitch)
 {
     return new(alloc()) LTableSwitch(in, inputCopy, temp(), tableswitch);
 }
 
 LTableSwitchV*
-LIRGeneratorMIPS::newLTableSwitchV(MTableSwitch* tableswitch)
+LIRGeneratorMIPSShared::newLTableSwitchV(MTableSwitch* tableswitch)
 {
     return new(alloc()) LTableSwitchV(temp(), tempDouble(), temp(), tableswitch);
 }
 
 void
-LIRGeneratorMIPS::visitGuardShape(MGuardShape* ins)
+LIRGeneratorMIPSShared::visitGuardShape(MGuardShape* ins)
 {
     MOZ_ASSERT(ins->obj()->type() == MIRType_Object);
 
     LDefinition tempObj = temp(LDefinition::OBJECT);
     LGuardShape* guard = new(alloc()) LGuardShape(useRegister(ins->obj()), tempObj);
     assignSnapshot(guard, ins->bailoutKind());
     add(guard, ins);
     redefine(ins, ins->obj());
 }
 
 void
-LIRGeneratorMIPS::visitGuardObjectGroup(MGuardObjectGroup* ins)
+LIRGeneratorMIPSShared::visitGuardObjectGroup(MGuardObjectGroup* ins)
 {
     MOZ_ASSERT(ins->obj()->type() == MIRType_Object);
 
     LDefinition tempObj = temp(LDefinition::OBJECT);
     LGuardObjectGroup* guard = new(alloc()) LGuardObjectGroup(useRegister(ins->obj()), tempObj);
     assignSnapshot(guard, ins->bailoutKind());
     add(guard, ins);
     redefine(ins, ins->obj());
 }
 
 void
-LIRGeneratorMIPS::lowerUrshD(MUrsh* mir)
+LIRGeneratorMIPSShared::lowerUrshD(MUrsh* mir)
 {
     MDefinition* lhs = mir->lhs();
     MDefinition* rhs = mir->rhs();
 
     MOZ_ASSERT(lhs->type() == MIRType_Int32);
     MOZ_ASSERT(rhs->type() == MIRType_Int32);
 
     LUrshD* lir = new(alloc()) LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp());
     define(lir, mir);
 }
 
 void
-LIRGeneratorMIPS::visitAsmJSNeg(MAsmJSNeg* ins)
+LIRGeneratorMIPSShared::visitAsmJSNeg(MAsmJSNeg* ins)
 {
     if (ins->type() == MIRType_Int32) {
         define(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins);
     } else if (ins->type() == MIRType_Float32) {
         define(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins);
     } else {
         MOZ_ASSERT(ins->type() == MIRType_Double);
         define(new(alloc()) LNegD(useRegisterAtStart(ins->input())), ins);
     }
 }
 
 void
-LIRGeneratorMIPS::lowerUDiv(MDiv* div)
+LIRGeneratorMIPSShared::lowerUDiv(MDiv* div)
 {
     MDefinition* lhs = div->getOperand(0);
     MDefinition* rhs = div->getOperand(1);
 
     LUDivOrMod* lir = new(alloc()) LUDivOrMod;
     lir->setOperand(0, useRegister(lhs));
     lir->setOperand(1, useRegister(rhs));
     if (div->fallible())
         assignSnapshot(lir, Bailout_DoubleOutput);
 
     define(lir, div);
 }
 
 void
-LIRGeneratorMIPS::lowerUMod(MMod* mod)
+LIRGeneratorMIPSShared::lowerUMod(MMod* mod)
 {
     MDefinition* lhs = mod->getOperand(0);
     MDefinition* rhs = mod->getOperand(1);
 
     LUDivOrMod* lir = new(alloc()) LUDivOrMod;
     lir->setOperand(0, useRegister(lhs));
     lir->setOperand(1, useRegister(rhs));
     if (mod->fallible())
         assignSnapshot(lir, Bailout_DoubleOutput);
 
     define(lir, mod);
 }
 
 void
-LIRGeneratorMIPS::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble* ins)
+LIRGeneratorMIPSShared::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble* ins)
 {
     MOZ_ASSERT(ins->input()->type() == MIRType_Int32);
     LAsmJSUInt32ToDouble* lir = new(alloc()) LAsmJSUInt32ToDouble(useRegisterAtStart(ins->input()));
     define(lir, ins);
 }
 
 void
-LIRGeneratorMIPS::visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32* ins)
+LIRGeneratorMIPSShared::visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32* ins)
 {
     MOZ_ASSERT(ins->input()->type() == MIRType_Int32);
     LAsmJSUInt32ToFloat32* lir = new(alloc()) LAsmJSUInt32ToFloat32(useRegisterAtStart(ins->input()));
     define(lir, ins);
 }
 
 void
-LIRGeneratorMIPS::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins)
+LIRGeneratorMIPSShared::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins)
 {
     MDefinition* ptr = ins->ptr();
     MOZ_ASSERT(ptr->type() == MIRType_Int32);
     LAllocation ptrAlloc;
 
     // For MIPS it is best to keep the 'ptr' in a register if a bounds check
     // is needed.
     if (ptr->isConstantValue() && !ins->needsBoundsCheck()) {
@@ -449,132 +307,114 @@ LIRGeneratorMIPS::visitAsmJSLoadHeap(MAs
         ptrAlloc = LAllocation(ptr->constantVp());
     } else
         ptrAlloc = useRegisterAtStart(ptr);
 
     define(new(alloc()) LAsmJSLoadHeap(ptrAlloc), ins);
 }
 
 void
-LIRGeneratorMIPS::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins)
+LIRGeneratorMIPSShared::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins)
 {
     MDefinition* ptr = ins->ptr();
     MOZ_ASSERT(ptr->type() == MIRType_Int32);
     LAllocation ptrAlloc;
 
     if (ptr->isConstantValue() && !ins->needsBoundsCheck()) {
         MOZ_ASSERT(ptr->constantValue().toInt32() >= 0);
         ptrAlloc = LAllocation(ptr->constantVp());
     } else
         ptrAlloc = useRegisterAtStart(ptr);
 
     add(new(alloc()) LAsmJSStoreHeap(ptrAlloc, useRegisterAtStart(ins->value())), ins);
 }
 
 void
-LIRGeneratorMIPS::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr* ins)
+LIRGeneratorMIPSShared::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr* ins)
 {
     define(new(alloc()) LAsmJSLoadFuncPtr(useRegister(ins->index())), ins);
 }
 
 void
-LIRGeneratorMIPS::lowerTruncateDToInt32(MTruncateToInt32* ins)
-{
-    MDefinition* opd = ins->input();
-    MOZ_ASSERT(opd->type() == MIRType_Double);
-
-    define(new(alloc()) LTruncateDToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
-}
-
-void
-LIRGeneratorMIPS::lowerTruncateFToInt32(MTruncateToInt32* ins)
-{
-    MDefinition* opd = ins->input();
-    MOZ_ASSERT(opd->type() == MIRType_Float32);
-
-    define(new(alloc()) LTruncateFToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
-}
-
-void
-LIRGeneratorMIPS::visitSubstr(MSubstr* ins)
+LIRGeneratorMIPSShared::visitSubstr(MSubstr* ins)
 {
     LSubstr* lir = new (alloc()) LSubstr(useRegister(ins->string()),
                                          useRegister(ins->begin()),
                                          useRegister(ins->length()),
                                          temp(),
                                          temp(),
                                          tempByteOpRegister());
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
-LIRGeneratorMIPS::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
+LIRGeneratorMIPSShared::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorMIPS::visitSimdBinaryArith(MSimdBinaryArith* ins)
+LIRGeneratorMIPSShared::visitSimdBinaryArith(MSimdBinaryArith* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorMIPS::visitSimdSelect(MSimdSelect* ins)
+LIRGeneratorMIPSShared::visitSimdSelect(MSimdSelect* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorMIPS::visitSimdSplatX4(MSimdSplatX4* ins)
+LIRGeneratorMIPSShared::visitSimdSplatX4(MSimdSplatX4* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorMIPS::visitSimdValueX4(MSimdValueX4* ins)
+LIRGeneratorMIPSShared::visitSimdValueX4(MSimdValueX4* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorMIPS::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins)
+LIRGeneratorMIPSShared::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorMIPS::visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins)
+LIRGeneratorMIPSShared::visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorMIPS::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins)
+LIRGeneratorMIPSShared::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorMIPS::visitAsmJSAtomicExchangeHeap(MAsmJSAtomicExchangeHeap* ins)
+LIRGeneratorMIPSShared::visitAsmJSAtomicExchangeHeap(MAsmJSAtomicExchangeHeap* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorMIPS::visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap* ins)
+LIRGeneratorMIPSShared::visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorMIPS::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins)
+LIRGeneratorMIPSShared::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-LIRGeneratorMIPS::visitRandom(MRandom* ins)
+LIRGeneratorMIPSShared::visitRandom(MRandom* ins)
 {
     LRandom* lir = new(alloc()) LRandom(tempFixed(CallTempReg0), tempFixed(CallTempReg1));
     defineReturn(lir, ins);
 }
copy from js/src/jit/mips32/Lowering-mips32.h
copy to js/src/jit/mips-shared/Lowering-mips-shared.h
--- a/js/src/jit/mips32/Lowering-mips32.h
+++ b/js/src/jit/mips-shared/Lowering-mips-shared.h
@@ -1,49 +1,38 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 jit_mips32_Lowering_mips32_h
-#define jit_mips32_Lowering_mips32_h
+#ifndef jit_mips_shared_Lowering_mips_shared_h
+#define jit_mips_shared_Lowering_mips_shared_h
 
 #include "jit/shared/Lowering-shared.h"
 
 namespace js {
 namespace jit {
 
-class LIRGeneratorMIPS : public LIRGeneratorShared
+class LIRGeneratorMIPSShared : public LIRGeneratorShared
 {
   protected:
-    LIRGeneratorMIPS(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
+    LIRGeneratorMIPSShared(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
       : LIRGeneratorShared(gen, graph, lirGraph)
     { }
 
   protected:
-    // Adds a box input to an instruction, setting operand |n| to the type and
-    // |n+1| to the payload.
-    void useBoxFixed(LInstruction* lir, size_t n, MDefinition* mir, Register reg1, Register reg2,
-                     bool useAtStart = false);
-
     // x86 has constraints on what registers can be formatted for 1-byte
     // stores and loads; on MIPS all registers are okay.
     LAllocation useByteOpRegister(MDefinition* mir);
     LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition* mir);
     LDefinition tempByteOpRegister();
 
-    inline LDefinition tempToUnbox() {
-        return LDefinition::BogusTemp();
-    }
-
     bool needTempForPostBarrier() { return false; }
 
-    void lowerUntypedPhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex);
-    void defineUntypedPhi(MPhi* phi, size_t lirIndex);
     void lowerForShift(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir, MDefinition* lhs,
                        MDefinition* rhs);
     void lowerUrshD(MUrsh* mir);
 
     void lowerForALU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir,
                      MDefinition* input);
     void lowerForALU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
                      MDefinition* lhs, MDefinition* rhs);
@@ -62,34 +51,29 @@ class LIRGeneratorMIPS : public LIRGener
     void lowerForCompFx4(LSimdBinaryCompFx4* ins, MSimdBinaryComp* mir,
                          MDefinition* lhs, MDefinition* rhs)
     {
         return lowerForFPU(ins, mir, lhs, rhs);
     }
 
     void lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir,
                                  MDefinition* lhs, MDefinition* rhs);
-    void lowerTruncateDToInt32(MTruncateToInt32* ins);
-    void lowerTruncateFToInt32(MTruncateToInt32* ins);
     void lowerDivI(MDiv* div);
     void lowerModI(MMod* mod);
     void lowerMulI(MMul* mul, MDefinition* lhs, MDefinition* rhs);
     void lowerUDiv(MDiv* div);
     void lowerUMod(MMod* mod);
     void visitPowHalf(MPowHalf* ins);
     void visitAsmJSNeg(MAsmJSNeg* ins);
 
     LTableSwitch* newLTableSwitch(const LAllocation& in, const LDefinition& inputCopy,
                                   MTableSwitch* ins);
     LTableSwitchV* newLTableSwitchV(MTableSwitch* ins);
 
   public:
-    void visitBox(MBox* box);
-    void visitUnbox(MUnbox* unbox);
-    void visitReturn(MReturn* ret);
     void lowerPhi(MPhi* phi);
     void visitGuardShape(MGuardShape* ins);
     void visitGuardObjectGroup(MGuardObjectGroup* ins);
     void visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble* ins);
     void visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32* ins);
     void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins);
     void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins);
     void visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins);
@@ -103,14 +87,12 @@ class LIRGeneratorMIPS : public LIRGener
     void visitSimdValueX4(MSimdValueX4* ins);
     void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins);
     void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins);
     void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins);
     void visitSubstr(MSubstr* ins);
     void visitRandom(MRandom* ins);
 };
 
-typedef LIRGeneratorMIPS LIRGeneratorSpecific;
-
 } // namespace jit
 } // namespace js
 
-#endif /* jit_mips32_Lowering_mips32_h */
+#endif /* jit_mips_shared_Lowering_mips_shared_h */
--- a/js/src/jit/mips32/Lowering-mips32.cpp
+++ b/js/src/jit/mips32/Lowering-mips32.cpp
@@ -1,58 +1,37 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 "mozilla/MathAlgorithms.h"
-
+#include "jit/mips32/Lowering-mips32.h"
 
-#include "jit/Lowering.h"
 #include "jit/mips32/Assembler-mips32.h"
+
 #include "jit/MIR.h"
 
 #include "jit/shared/Lowering-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
-using mozilla::FloorLog2;
-
 void
 LIRGeneratorMIPS::useBoxFixed(LInstruction* lir, size_t n, MDefinition* mir, Register reg1,
                               Register reg2, bool useAtStart)
 {
     MOZ_ASSERT(mir->type() == MIRType_Value);
     MOZ_ASSERT(reg1 != reg2);
 
     ensureDefined(mir);
     lir->setOperand(n, LUse(reg1, mir->virtualRegister(), useAtStart));
     lir->setOperand(n + 1, LUse(reg2, VirtualRegisterOfPayload(mir), useAtStart));
 }
 
-LAllocation
-LIRGeneratorMIPS::useByteOpRegister(MDefinition* mir)
-{
-    return useRegister(mir);
-}
-
-LAllocation
-LIRGeneratorMIPS::useByteOpRegisterOrNonDoubleConstant(MDefinition* mir)
-{
-    return useRegisterOrNonDoubleConstant(mir);
-}
-
-LDefinition
-LIRGeneratorMIPS::tempByteOpRegister()
-{
-    return temp();
-}
-
 void
 LIRGeneratorMIPS::visitBox(MBox* box)
 {
     MDefinition* inner = box->getOperand(0);
 
     // If the box wrapped a double, it needs a new register.
     if (IsFloatingPointType(inner->type())) {
         defineBox(new(alloc()) LBoxFloatingPoint(useRegisterAtStart(inner),
@@ -142,67 +121,16 @@ LIRGeneratorMIPS::visitReturn(MReturn* r
 
     LReturn* ins = new(alloc()) LReturn;
     ins->setOperand(0, LUse(JSReturnReg_Type));
     ins->setOperand(1, LUse(JSReturnReg_Data));
     fillBoxUses(ins, 0, opd);
     add(ins);
 }
 
-// x = !y
-void
-LIRGeneratorMIPS::lowerForALU(LInstructionHelper<1, 1, 0>* ins,
-                              MDefinition* mir, MDefinition* input)
-{
-    ins->setOperand(0, useRegister(input));
-    define(ins, mir, LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::REGISTER));
-}
-
-// z = x+y
-void
-LIRGeneratorMIPS::lowerForALU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
-                              MDefinition* lhs, MDefinition* rhs)
-{
-    ins->setOperand(0, useRegister(lhs));
-    ins->setOperand(1, useRegisterOrConstant(rhs));
-    define(ins, mir, LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::REGISTER));
-}
-
-void
-LIRGeneratorMIPS::lowerForFPU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir,
-                              MDefinition* input)
-{
-    ins->setOperand(0, useRegister(input));
-    define(ins, mir, LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::REGISTER));
-}
-
-template<size_t Temps>
-void
-LIRGeneratorMIPS::lowerForFPU(LInstructionHelper<1, 2, Temps>* ins, MDefinition* mir,
-                              MDefinition* lhs, MDefinition* rhs)
-{
-    ins->setOperand(0, useRegister(lhs));
-    ins->setOperand(1, useRegister(rhs));
-    define(ins, mir, LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::REGISTER));
-}
-
-template void LIRGeneratorMIPS::lowerForFPU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
-                                            MDefinition* lhs, MDefinition* rhs);
-template void LIRGeneratorMIPS::lowerForFPU(LInstructionHelper<1, 2, 1>* ins, MDefinition* mir,
-                                            MDefinition* lhs, MDefinition* rhs);
-
-void
-LIRGeneratorMIPS::lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir,
-                                          MDefinition* lhs, MDefinition* rhs)
-{
-    baab->setOperand(0, useRegisterAtStart(lhs));
-    baab->setOperand(1, useRegisterOrConstantAtStart(rhs));
-    add(baab, mir);
-}
-
 void
 LIRGeneratorMIPS::defineUntypedPhi(MPhi* phi, size_t lirIndex)
 {
     LPhi* type = current->getPhi(lirIndex + VREG_TYPE_OFFSET);
     LPhi* payload = current->getPhi(lirIndex + VREG_DATA_OFFSET);
 
     uint32_t typeVreg = getVirtualRegister();
     phi->setVirtualRegister(typeVreg);
@@ -224,357 +152,24 @@ LIRGeneratorMIPS::lowerUntypedPhiInput(M
     LPhi* type = block->getPhi(lirIndex + VREG_TYPE_OFFSET);
     LPhi* payload = block->getPhi(lirIndex + VREG_DATA_OFFSET);
     type->setOperand(inputPosition, LUse(operand->virtualRegister() + VREG_TYPE_OFFSET,
                                          LUse::ANY));
     payload->setOperand(inputPosition, LUse(VirtualRegisterOfPayload(operand), LUse::ANY));
 }
 
 void
-LIRGeneratorMIPS::lowerForShift(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
-                                MDefinition* lhs, MDefinition* rhs)
-{
-    ins->setOperand(0, useRegister(lhs));
-    ins->setOperand(1, useRegisterOrConstant(rhs));
-    define(ins, mir);
-}
-
-void
-LIRGeneratorMIPS::lowerDivI(MDiv* div)
-{
-    if (div->isUnsigned()) {
-        lowerUDiv(div);
-        return;
-    }
-
-    // Division instructions are slow. Division by constant denominators can be
-    // rewritten to use other instructions.
-    if (div->rhs()->isConstant()) {
-        int32_t rhs = div->rhs()->toConstant()->value().toInt32();
-        // Check for division by a positive power of two, which is an easy and
-        // important case to optimize. Note that other optimizations are also
-        // possible; division by negative powers of two can be optimized in a
-        // similar manner as positive powers of two, and division by other
-        // constants can be optimized by a reciprocal multiplication technique.
-        int32_t shift = FloorLog2(rhs);
-        if (rhs > 0 && 1 << shift == rhs) {
-            LDivPowTwoI* lir = new(alloc()) LDivPowTwoI(useRegister(div->lhs()), shift, temp());
-            if (div->fallible())
-                assignSnapshot(lir, Bailout_DoubleOutput);
-            define(lir, div);
-            return;
-        }
-    }
-
-    LDivI* lir = new(alloc()) LDivI(useRegister(div->lhs()), useRegister(div->rhs()), temp());
-    if (div->fallible())
-        assignSnapshot(lir, Bailout_DoubleOutput);
-    define(lir, div);
-}
-
-void
-LIRGeneratorMIPS::lowerMulI(MMul* mul, MDefinition* lhs, MDefinition* rhs)
-{
-    LMulI* lir = new(alloc()) LMulI;
-    if (mul->fallible())
-        assignSnapshot(lir, Bailout_DoubleOutput);
-
-    lowerForALU(lir, mul, lhs, rhs);
-}
-
-void
-LIRGeneratorMIPS::lowerModI(MMod* mod)
-{
-    if (mod->isUnsigned()) {
-        lowerUMod(mod);
-        return;
-    }
-
-    if (mod->rhs()->isConstant()) {
-        int32_t rhs = mod->rhs()->toConstant()->value().toInt32();
-        int32_t shift = FloorLog2(rhs);
-        if (rhs > 0 && 1 << shift == rhs) {
-            LModPowTwoI* lir = new(alloc()) LModPowTwoI(useRegister(mod->lhs()), shift);
-            if (mod->fallible())
-                assignSnapshot(lir, Bailout_DoubleOutput);
-            define(lir, mod);
-            return;
-        } else if (shift < 31 && (1 << (shift + 1)) - 1 == rhs) {
-            LModMaskI* lir = new(alloc()) LModMaskI(useRegister(mod->lhs()),
-                                                    temp(LDefinition::GENERAL),
-                                                    temp(LDefinition::GENERAL),
-                                                    shift + 1);
-            if (mod->fallible())
-                assignSnapshot(lir, Bailout_DoubleOutput);
-            define(lir, mod);
-            return;
-        }
-    }
-    LModI* lir = new(alloc()) LModI(useRegister(mod->lhs()), useRegister(mod->rhs()),
-                           temp(LDefinition::GENERAL));
-
-    if (mod->fallible())
-        assignSnapshot(lir, Bailout_DoubleOutput);
-    define(lir, mod);
-}
-
-void
-LIRGeneratorMIPS::visitPowHalf(MPowHalf* ins)
-{
-    MDefinition* input = ins->input();
-    MOZ_ASSERT(input->type() == MIRType_Double);
-    LPowHalfD* lir = new(alloc()) LPowHalfD(useRegisterAtStart(input));
-    defineReuseInput(lir, ins, 0);
-}
-
-LTableSwitch*
-LIRGeneratorMIPS::newLTableSwitch(const LAllocation& in, const LDefinition& inputCopy,
-                                  MTableSwitch* tableswitch)
-{
-    return new(alloc()) LTableSwitch(in, inputCopy, temp(), tableswitch);
-}
-
-LTableSwitchV*
-LIRGeneratorMIPS::newLTableSwitchV(MTableSwitch* tableswitch)
-{
-    return new(alloc()) LTableSwitchV(temp(), tempDouble(), temp(), tableswitch);
-}
-
-void
-LIRGeneratorMIPS::visitGuardShape(MGuardShape* ins)
-{
-    MOZ_ASSERT(ins->obj()->type() == MIRType_Object);
-
-    LDefinition tempObj = temp(LDefinition::OBJECT);
-    LGuardShape* guard = new(alloc()) LGuardShape(useRegister(ins->obj()), tempObj);
-    assignSnapshot(guard, ins->bailoutKind());
-    add(guard, ins);
-    redefine(ins, ins->obj());
-}
-
-void
-LIRGeneratorMIPS::visitGuardObjectGroup(MGuardObjectGroup* ins)
-{
-    MOZ_ASSERT(ins->obj()->type() == MIRType_Object);
-
-    LDefinition tempObj = temp(LDefinition::OBJECT);
-    LGuardObjectGroup* guard = new(alloc()) LGuardObjectGroup(useRegister(ins->obj()), tempObj);
-    assignSnapshot(guard, ins->bailoutKind());
-    add(guard, ins);
-    redefine(ins, ins->obj());
-}
-
-void
-LIRGeneratorMIPS::lowerUrshD(MUrsh* mir)
-{
-    MDefinition* lhs = mir->lhs();
-    MDefinition* rhs = mir->rhs();
-
-    MOZ_ASSERT(lhs->type() == MIRType_Int32);
-    MOZ_ASSERT(rhs->type() == MIRType_Int32);
-
-    LUrshD* lir = new(alloc()) LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp());
-    define(lir, mir);
-}
-
-void
-LIRGeneratorMIPS::visitAsmJSNeg(MAsmJSNeg* ins)
-{
-    if (ins->type() == MIRType_Int32) {
-        define(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins);
-    } else if (ins->type() == MIRType_Float32) {
-        define(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins);
-    } else {
-        MOZ_ASSERT(ins->type() == MIRType_Double);
-        define(new(alloc()) LNegD(useRegisterAtStart(ins->input())), ins);
-    }
-}
-
-void
-LIRGeneratorMIPS::lowerUDiv(MDiv* div)
-{
-    MDefinition* lhs = div->getOperand(0);
-    MDefinition* rhs = div->getOperand(1);
-
-    LUDivOrMod* lir = new(alloc()) LUDivOrMod;
-    lir->setOperand(0, useRegister(lhs));
-    lir->setOperand(1, useRegister(rhs));
-    if (div->fallible())
-        assignSnapshot(lir, Bailout_DoubleOutput);
-
-    define(lir, div);
-}
-
-void
-LIRGeneratorMIPS::lowerUMod(MMod* mod)
-{
-    MDefinition* lhs = mod->getOperand(0);
-    MDefinition* rhs = mod->getOperand(1);
-
-    LUDivOrMod* lir = new(alloc()) LUDivOrMod;
-    lir->setOperand(0, useRegister(lhs));
-    lir->setOperand(1, useRegister(rhs));
-    if (mod->fallible())
-        assignSnapshot(lir, Bailout_DoubleOutput);
-
-    define(lir, mod);
-}
-
-void
-LIRGeneratorMIPS::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble* ins)
-{
-    MOZ_ASSERT(ins->input()->type() == MIRType_Int32);
-    LAsmJSUInt32ToDouble* lir = new(alloc()) LAsmJSUInt32ToDouble(useRegisterAtStart(ins->input()));
-    define(lir, ins);
-}
-
-void
-LIRGeneratorMIPS::visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32* ins)
-{
-    MOZ_ASSERT(ins->input()->type() == MIRType_Int32);
-    LAsmJSUInt32ToFloat32* lir = new(alloc()) LAsmJSUInt32ToFloat32(useRegisterAtStart(ins->input()));
-    define(lir, ins);
-}
-
-void
-LIRGeneratorMIPS::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins)
-{
-    MDefinition* ptr = ins->ptr();
-    MOZ_ASSERT(ptr->type() == MIRType_Int32);
-    LAllocation ptrAlloc;
-
-    // For MIPS it is best to keep the 'ptr' in a register if a bounds check
-    // is needed.
-    if (ptr->isConstantValue() && !ins->needsBoundsCheck()) {
-        // A bounds check is only skipped for a positive index.
-        MOZ_ASSERT(ptr->constantValue().toInt32() >= 0);
-        ptrAlloc = LAllocation(ptr->constantVp());
-    } else
-        ptrAlloc = useRegisterAtStart(ptr);
-
-    define(new(alloc()) LAsmJSLoadHeap(ptrAlloc), ins);
-}
-
-void
-LIRGeneratorMIPS::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins)
-{
-    MDefinition* ptr = ins->ptr();
-    MOZ_ASSERT(ptr->type() == MIRType_Int32);
-    LAllocation ptrAlloc;
-
-    if (ptr->isConstantValue() && !ins->needsBoundsCheck()) {
-        MOZ_ASSERT(ptr->constantValue().toInt32() >= 0);
-        ptrAlloc = LAllocation(ptr->constantVp());
-    } else
-        ptrAlloc = useRegisterAtStart(ptr);
-
-    add(new(alloc()) LAsmJSStoreHeap(ptrAlloc, useRegisterAtStart(ins->value())), ins);
-}
-
-void
-LIRGeneratorMIPS::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr* ins)
-{
-    define(new(alloc()) LAsmJSLoadFuncPtr(useRegister(ins->index())), ins);
-}
-
-void
 LIRGeneratorMIPS::lowerTruncateDToInt32(MTruncateToInt32* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType_Double);
 
     define(new(alloc()) LTruncateDToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
 }
 
 void
 LIRGeneratorMIPS::lowerTruncateFToInt32(MTruncateToInt32* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType_Float32);
 
     define(new(alloc()) LTruncateFToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
 }
-
-void
-LIRGeneratorMIPS::visitSubstr(MSubstr* ins)
-{
-    LSubstr* lir = new (alloc()) LSubstr(useRegister(ins->string()),
-                                         useRegister(ins->begin()),
-                                         useRegister(ins->length()),
-                                         temp(),
-                                         temp(),
-                                         tempByteOpRegister());
-    define(lir, ins);
-    assignSafepoint(lir, ins);
-}
-
-void
-LIRGeneratorMIPS::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
-LIRGeneratorMIPS::visitSimdBinaryArith(MSimdBinaryArith* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
-LIRGeneratorMIPS::visitSimdSelect(MSimdSelect* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
-LIRGeneratorMIPS::visitSimdSplatX4(MSimdSplatX4* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
-LIRGeneratorMIPS::visitSimdValueX4(MSimdValueX4* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
-LIRGeneratorMIPS::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
-LIRGeneratorMIPS::visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
-LIRGeneratorMIPS::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
-LIRGeneratorMIPS::visitAsmJSAtomicExchangeHeap(MAsmJSAtomicExchangeHeap* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
-LIRGeneratorMIPS::visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
-LIRGeneratorMIPS::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
-LIRGeneratorMIPS::visitRandom(MRandom* ins)
-{
-    LRandom* lir = new(alloc()) LRandom(tempFixed(CallTempReg0), tempFixed(CallTempReg1));
-    defineReturn(lir, ins);
-}
--- a/js/src/jit/mips32/Lowering-mips32.h
+++ b/js/src/jit/mips32/Lowering-mips32.h
@@ -2,115 +2,48 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 jit_mips32_Lowering_mips32_h
 #define jit_mips32_Lowering_mips32_h
 
-#include "jit/shared/Lowering-shared.h"
+#include "jit/mips-shared/Lowering-mips-shared.h"
 
 namespace js {
 namespace jit {
 
-class LIRGeneratorMIPS : public LIRGeneratorShared
+class LIRGeneratorMIPS : public LIRGeneratorMIPSShared
 {
   protected:
     LIRGeneratorMIPS(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
-      : LIRGeneratorShared(gen, graph, lirGraph)
+      : LIRGeneratorMIPSShared(gen, graph, lirGraph)
     { }
 
   protected:
     // Adds a box input to an instruction, setting operand |n| to the type and
     // |n+1| to the payload.
     void useBoxFixed(LInstruction* lir, size_t n, MDefinition* mir, Register reg1, Register reg2,
                      bool useAtStart = false);
 
-    // x86 has constraints on what registers can be formatted for 1-byte
-    // stores and loads; on MIPS all registers are okay.
-    LAllocation useByteOpRegister(MDefinition* mir);
-    LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition* mir);
-    LDefinition tempByteOpRegister();
-
     inline LDefinition tempToUnbox() {
         return LDefinition::BogusTemp();
     }
 
-    bool needTempForPostBarrier() { return false; }
-
     void lowerUntypedPhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex);
     void defineUntypedPhi(MPhi* phi, size_t lirIndex);
-    void lowerForShift(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir, MDefinition* lhs,
-                       MDefinition* rhs);
-    void lowerUrshD(MUrsh* mir);
 
-    void lowerForALU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir,
-                     MDefinition* input);
-    void lowerForALU(LInstructionHelper<1, 2, 0>* ins, MDefinition* mir,
-                     MDefinition* lhs, MDefinition* rhs);
-
-    void lowerForFPU(LInstructionHelper<1, 1, 0>* ins, MDefinition* mir,
-                     MDefinition* src);
-    template<size_t Temps>
-    void lowerForFPU(LInstructionHelper<1, 2, Temps>* ins, MDefinition* mir,
-                     MDefinition* lhs, MDefinition* rhs);
-
-    void lowerForCompIx4(LSimdBinaryCompIx4* ins, MSimdBinaryComp* mir,
-                         MDefinition* lhs, MDefinition* rhs)
-    {
-        return lowerForFPU(ins, mir, lhs, rhs);
-    }
-    void lowerForCompFx4(LSimdBinaryCompFx4* ins, MSimdBinaryComp* mir,
-                         MDefinition* lhs, MDefinition* rhs)
-    {
-        return lowerForFPU(ins, mir, lhs, rhs);
-    }
-
-    void lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir,
-                                 MDefinition* lhs, MDefinition* rhs);
     void lowerTruncateDToInt32(MTruncateToInt32* ins);
     void lowerTruncateFToInt32(MTruncateToInt32* ins);
-    void lowerDivI(MDiv* div);
-    void lowerModI(MMod* mod);
-    void lowerMulI(MMul* mul, MDefinition* lhs, MDefinition* rhs);
-    void lowerUDiv(MDiv* div);
-    void lowerUMod(MMod* mod);
-    void visitPowHalf(MPowHalf* ins);
-    void visitAsmJSNeg(MAsmJSNeg* ins);
-
-    LTableSwitch* newLTableSwitch(const LAllocation& in, const LDefinition& inputCopy,
-                                  MTableSwitch* ins);
-    LTableSwitchV* newLTableSwitchV(MTableSwitch* ins);
 
   public:
     void visitBox(MBox* box);
     void visitUnbox(MUnbox* unbox);
     void visitReturn(MReturn* ret);
-    void lowerPhi(MPhi* phi);
-    void visitGuardShape(MGuardShape* ins);
-    void visitGuardObjectGroup(MGuardObjectGroup* ins);
-    void visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble* ins);
-    void visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32* ins);
-    void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins);
-    void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins);
-    void visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins);
-    void visitAsmJSAtomicExchangeHeap(MAsmJSAtomicExchangeHeap* ins);
-    void visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap* ins);
-    void visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr* ins);
-    void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins);
-    void visitSimdBinaryArith(MSimdBinaryArith* ins);
-    void visitSimdSelect(MSimdSelect* ins);
-    void visitSimdSplatX4(MSimdSplatX4* ins);
-    void visitSimdValueX4(MSimdValueX4* ins);
-    void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins);
-    void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins);
-    void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins);
-    void visitSubstr(MSubstr* ins);
-    void visitRandom(MRandom* ins);
 };
 
 typedef LIRGeneratorMIPS LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_mips32_Lowering_mips32_h */
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -463,16 +463,17 @@ elif CONFIG['JS_CODEGEN_ARM64']:
             'jit/arm64/vixl/Debugger-vixl.cpp',
             'jit/arm64/vixl/MozSimulator-vixl.cpp',
             'jit/arm64/vixl/Simulator-vixl.cpp'
         ]
 elif CONFIG['JS_CODEGEN_MIPS32']:
     UNIFIED_SOURCES += [
         'jit/mips-shared/Architecture-mips-shared.cpp',
         'jit/mips-shared/Assembler-mips-shared.cpp',
+        'jit/mips-shared/Lowering-mips-shared.cpp',
     ]
     if CONFIG['JS_CODEGEN_MIPS32']:
         UNIFIED_SOURCES += [
             'jit/mips32/Architecture-mips32.cpp',
             'jit/mips32/Assembler-mips32.cpp',
             'jit/mips32/Bailouts-mips32.cpp',
             'jit/mips32/BaselineCompiler-mips32.cpp',
             'jit/mips32/BaselineIC-mips32.cpp',
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -73,17 +73,16 @@
 using namespace mozilla;
 using namespace mozilla::widget;
 using namespace mozilla::ipc;
 using namespace mozilla::layout;
 
 static PRLogModuleInfo *gLog = nullptr;
 #define LOG(...) MOZ_LOG(gLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
 
-#define DEFAULT_FRAME_RATE 60
 #define DEFAULT_THROTTLED_FRAME_RATE 1
 #define DEFAULT_RECOMPUTE_VISIBILITY_INTERVAL_MS 1000
 // after 10 minutes, stop firing off inactive timers
 #define DEFAULT_INACTIVE_TIMER_DISABLE_SECONDS 600
 
 namespace mozilla {
 
 /*
@@ -760,33 +759,33 @@ nsRefreshDriver::Shutdown()
     timeEndPeriod(1);
   }
 #endif
 }
 
 /* static */ int32_t
 nsRefreshDriver::DefaultInterval()
 {
-  return NSToIntRound(1000.0 / DEFAULT_FRAME_RATE);
+  return NSToIntRound(1000.0 / gfxPlatform::GetDefaultFrameRate());
 }
 
 // Compute the interval to use for the refresh driver timer, in milliseconds.
 // outIsDefault indicates that rate was not explicitly set by the user
 // so we might choose other, more appropriate rates (e.g. vsync, etc)
 // layout.frame_rate=0 indicates "ASAP mode".
 // In ASAP mode rendering is iterated as fast as possible (typically for stress testing).
 // A target rate of 10k is used internally instead of special-handling 0.
 // Backends which block on swap/present/etc should try to not block
 // when layout.frame_rate=0 - to comply with "ASAP" as much as possible.
 double
 nsRefreshDriver::GetRegularTimerInterval(bool *outIsDefault) const
 {
   int32_t rate = Preferences::GetInt("layout.frame_rate", -1);
   if (rate < 0) {
-    rate = DEFAULT_FRAME_RATE;
+    rate = gfxPlatform::GetDefaultFrameRate();
     if (outIsDefault) {
       *outIsDefault = true;
     }
   } else {
     if (outIsDefault) {
       *outIsDefault = false;
     }
   }
--- a/media/mtransport/nricectx.h
+++ b/media/mtransport/nricectx.h
@@ -169,30 +169,31 @@ class NrIceTurnServer : public NrIceStun
       NrIceStunServer(transport), username_(username), password_(password) {}
 
   std::string username_;
   std::vector<unsigned char> password_;
 };
 
 class NrIceProxyServer {
  public:
-  NrIceProxyServer() :
-    host_(), port_(0) {
+  NrIceProxyServer(const std::string& host, uint16_t port,
+                   const std::string& alpn) :
+    host_(host), port_(port), alpn_(alpn) {
   }
 
-  NrIceProxyServer(const std::string& host, uint16_t port) :
-    host_(host), port_(port) {
-  }
+  NrIceProxyServer() : NrIceProxyServer("", 0, "") {}
 
   const std::string& host() const { return host_; }
   uint16_t port() const { return port_; }
+  const std::string& alpn() const { return alpn_; }
 
  private:
   std::string host_;
   uint16_t port_;
+  std::string alpn_;
 };
 
 
 class NrIceCtx {
  public:
   enum ConnectionState { ICE_CTX_INIT,
                          ICE_CTX_CHECKING,
                          ICE_CTX_OPEN,
--- a/media/mtransport/test/proxy_tunnel_socket_unittest.cpp
+++ b/media/mtransport/test/proxy_tunnel_socket_unittest.cpp
@@ -41,19 +41,23 @@ const uint16_t kRemotePort = 3333;
 
 const std::string kProxyHost = "example.com";
 const std::string kProxyAddr = "192.0.2.134";
 const uint16_t kProxyPort = 9999;
 
 const std::string kHelloMessage = "HELLO";
 const std::string kGarbageMessage = "xxxxxxxxxx";
 
-std::string connect_message(const std::string &host, uint16_t port, const std::string &tail = "") {
+std::string connect_message(const std::string &host, uint16_t port, const std::string &alpn, const std::string &tail) {
   std::stringstream ss;
-  ss << "CONNECT " << host << ":" << port << " HTTP/1.0\r\n\r\n" << tail;
+  ss << "CONNECT " << host << ":" << port << " HTTP/1.0\r\n";
+  if (!alpn.empty()) {
+    ss << "ALPN: " << alpn << "\r\n";
+  }
+  ss << "\r\n" << tail;
   return ss.str();
 }
 
 std::string connect_response(int code, const std::string &tail = "") {
   std::stringstream ss;
   ss << "HTTP/1.0 " << code << "\r\n\r\n" << tail;
   return ss.str();
 }
@@ -111,41 +115,60 @@ class ProxyTunnelSocketTest : public ::t
         nr_socket_(nullptr) {}
 
   ~ProxyTunnelSocketTest() {
     nr_socket_destroy(&nr_socket_);
     nr_proxy_tunnel_config_destroy(&config_);
   }
 
   void SetUp() {
-    nsRefPtr<DummySocket> dummy(new DummySocket());
-
     nr_resolver_ = resolver_impl_.get_nr_resolver();
 
     int r = nr_str_port_to_transport_addr(
         (char *)kRemoteAddr.c_str(), kRemotePort, IPPROTO_TCP, &remote_addr_);
     ASSERT_EQ(0, r);
 
     r = nr_str_port_to_transport_addr(
         (char *)kProxyAddr.c_str(), kProxyPort, IPPROTO_TCP, &proxy_addr_);
     ASSERT_EQ(0, r);
 
     nr_proxy_tunnel_config_create(&config_);
     nr_proxy_tunnel_config_set_resolver(config_, nr_resolver_);
     nr_proxy_tunnel_config_set_proxy(config_, kProxyAddr.c_str(), kProxyPort);
 
-    r = nr_socket_proxy_tunnel_create(
+    Configure();
+  }
+
+  // This reconfigures the socket with the updated information in config_.
+  void Configure() {
+    if (nr_socket_) {
+      EXPECT_EQ(0, nr_socket_destroy(&nr_socket_));
+      EXPECT_EQ(nullptr, nr_socket_);
+    }
+
+    nsRefPtr<DummySocket> dummy(new DummySocket());
+    int r = nr_socket_proxy_tunnel_create(
         config_,
         dummy->get_nr_socket(),
         &nr_socket_);
     ASSERT_EQ(0, r);
 
     socket_impl_ = dummy.forget();  // Now owned by nr_socket_.
   }
 
+  void Connect(int expectedReturn = 0) {
+    int r = nr_socket_connect(nr_socket_, &remote_addr_);
+    EXPECT_EQ(expectedReturn, r);
+
+    size_t written = 0;
+    r = nr_socket_write(nr_socket_, kHelloMessage.c_str(), kHelloMessage.size(), &written, 0);
+    EXPECT_EQ(0, r);
+    EXPECT_EQ(kHelloMessage.size(), written);
+  }
+
   nr_socket *socket() { return nr_socket_; }
 
  protected:
   nsRefPtr<DummySocket> socket_impl_;
   DummyResolver resolver_impl_;
   nr_socket *nr_socket_;
   nr_resolver *nr_resolver_;
   nr_proxy_tunnel_config *config_;
@@ -161,66 +184,77 @@ TEST_F(ProxyTunnelSocketTest, TestConnec
   int r = nr_socket_connect(nr_socket_, &remote_addr_);
   ASSERT_EQ(0, r);
 
   ASSERT_EQ(0, nr_transport_addr_cmp(socket_impl_->get_connect_addr(), &proxy_addr_,
         NR_TRANSPORT_ADDR_CMP_MODE_ALL));
 }
 
 TEST_F(ProxyTunnelSocketTest, TestConnectProxyRequest) {
-  int r = nr_socket_connect(nr_socket_, &remote_addr_);
-  ASSERT_EQ(0, r);
+  Connect();
+
+  std::string msg = connect_message(kRemoteAddr, kRemotePort, "", kHelloMessage);
+  socket_impl_->CheckWriteBuffer(reinterpret_cast<const uint8_t *>(msg.c_str()), msg.size());
+}
+
+TEST_F(ProxyTunnelSocketTest, TestAlpnConnect) {
+  const std::string alpn = "this,is,alpn";
+  int r = nr_proxy_tunnel_config_set_alpn(config_, alpn.c_str());
+  EXPECT_EQ(0, r);
 
-  size_t written = 0;
-  r = nr_socket_write(nr_socket_, kHelloMessage.c_str(), kHelloMessage.size(), &written, 0);
-  ASSERT_EQ(0, r);
+  Configure();
+  Connect();
+
+  std::string msg = connect_message(kRemoteAddr, kRemotePort, alpn, kHelloMessage);
+  socket_impl_->CheckWriteBuffer(reinterpret_cast<const uint8_t *>(msg.c_str()), msg.size());
+}
 
-  std::string msg = connect_message(kRemoteAddr, kRemotePort, kHelloMessage);
+TEST_F(ProxyTunnelSocketTest, TestNullAlpnConnect) {
+  int r = nr_proxy_tunnel_config_set_alpn(config_, nullptr);
+  EXPECT_EQ(0, r);
+
+  Configure();
+  Connect();
+
+  std::string msg = connect_message(kRemoteAddr, kRemotePort, "", kHelloMessage);
   socket_impl_->CheckWriteBuffer(reinterpret_cast<const uint8_t *>(msg.c_str()), msg.size());
 }
 
 TEST_F(ProxyTunnelSocketTest, TestConnectProxyHostRequest) {
-  int r = nr_socket_destroy(&nr_socket_);
-  ASSERT_EQ(0, r);
-
-  nsRefPtr<DummySocket> dummy(new DummySocket());
-
   nr_proxy_tunnel_config_set_proxy(config_, kProxyHost.c_str(), kProxyPort);
+  Configure();
+  // Because kProxyHost is a domain name and not an IP address,
+  // nr_socket_connect will need to resolve an IP address before continuing.  It
+  // does that, and assumes that resolving the IP will take some time, so it
+  // returns R_WOULDBLOCK.
+  //
+  // However, In this test setup, the resolution happens inline immediately, so
+  // nr_socket_connect is called recursively on the inner socket in
+  // nr_socket_proxy_tunnel_resolved_cb.  That also completes.  Thus, the socket
+  // is actually successfully connected after this call, even though
+  // nr_socket_connect reports an error.
+  //
+  // Arguably nr_socket_proxy_tunnel_connect() is busted, because it shouldn't
+  // report an error when it doesn't need any further assistance from the
+  // calling code, but that's pretty minor.
+  Connect(R_WOULDBLOCK);
 
-  r = nr_socket_proxy_tunnel_create(
-      config_,
-      dummy->get_nr_socket(),
-      &nr_socket_);
-  ASSERT_EQ(0, r);
-
-  socket_impl_ = dummy.forget();  // Now owned by nr_socket_.
-
-  r = nr_socket_connect(nr_socket_, &remote_addr_);
-  ASSERT_EQ(R_WOULDBLOCK, r);
-
-  size_t written = 0;
-  r = nr_socket_write(nr_socket_, kHelloMessage.c_str(), kHelloMessage.size(), &written, 0);
-  ASSERT_EQ(0, r);
-
-  std::string msg = connect_message(kRemoteAddr, kRemotePort, kHelloMessage);
+  std::string msg = connect_message(kRemoteAddr, kRemotePort, "", kHelloMessage);
   socket_impl_->CheckWriteBuffer(reinterpret_cast<const uint8_t *>(msg.c_str()), msg.size());
 }
 
 TEST_F(ProxyTunnelSocketTest, TestConnectProxyWrite) {
-  int r = nr_socket_connect(nr_socket_, &remote_addr_);
-  ASSERT_EQ(0, r);
-
-  size_t written = 0;
-  r = nr_socket_write(nr_socket_, kHelloMessage.c_str(), kHelloMessage.size(), &written, 0);
-  ASSERT_EQ(0, r);
+  Connect();
 
   socket_impl_->ClearWriteBuffer();
 
-  r = nr_socket_write(nr_socket_, kHelloMessage.c_str(), kHelloMessage.size(), &written, 0);
-  ASSERT_EQ(0, r);
+  size_t written = 0;
+  int r = nr_socket_write(nr_socket_, kHelloMessage.c_str(), kHelloMessage.size(), &written, 0);
+  EXPECT_EQ(0, r);
+  EXPECT_EQ(kHelloMessage.size(), written);
 
   socket_impl_->CheckWriteBuffer(reinterpret_cast<const uint8_t *>(kHelloMessage.c_str()),
       kHelloMessage.size());
 }
 
 TEST_F(ProxyTunnelSocketTest, TestConnectProxySuccessResponse) {
   int r = nr_socket_connect(nr_socket_, &remote_addr_);
   ASSERT_EQ(0, r);
--- a/media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.c
+++ b/media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.c
@@ -36,17 +36,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 #include <nr_api.h>
 
 #include <assert.h>
 
 #include "nr_proxy_tunnel.h"
 
 #define MAX_HTTP_CONNECT_ADDR_SIZE 256
 #define MAX_HTTP_CONNECT_BUFFER_SIZE 1024
-#define ENDLN "\r\n\r\n"
+#define MAX_ALPN_LENGTH 64
+#ifndef CRLF
+#define CRLF "\r\n"
+#endif
+#define END_HEADERS CRLF CRLF
 
 typedef struct nr_socket_proxy_tunnel_ {
   nr_proxy_tunnel_config *config;
   nr_socket *inner;
   nr_transport_addr remote_addr;
   int connect_requested;
   int connect_answered;
   int connect_failed;
@@ -89,59 +93,76 @@ static nr_socket_vtbl nr_socket_proxy_tu
 };
 
 static int send_http_connect(nr_socket_proxy_tunnel *sock)
 {
   int r, _status;
   int port;
   int printed;
   char addr[MAX_HTTP_CONNECT_ADDR_SIZE];
-  char mesg[MAX_HTTP_CONNECT_ADDR_SIZE + 64];
+  char mesg[MAX_HTTP_CONNECT_ADDR_SIZE + MAX_ALPN_LENGTH + 128];
+  size_t offset = 0;
   size_t bytes_sent;
 
   r_log(LOG_GENERIC,LOG_DEBUG,"send_http_connect");
 
   if ((r=nr_transport_addr_get_port(&sock->remote_addr, &port))) {
     ABORT(r);
   }
 
   if ((r=nr_transport_addr_get_addrstring(&sock->remote_addr, addr, sizeof(addr)))) {
     ABORT(r);
   }
 
-  printed = snprintf(mesg, sizeof(mesg), "CONNECT %s:%d HTTP/1.0%s", addr, port, ENDLN);
-  if (printed < 0 || ((size_t)printed >= sizeof(mesg))) {
+  printed = snprintf(mesg + offset, sizeof(mesg) - offset,
+                     "CONNECT %s:%d HTTP/1.0", addr, port);
+  offset += printed;
+  if (printed < 0 || (offset >= sizeof(mesg))) {
     ABORT(R_FAILED);
   }
 
-  if ((r=nr_socket_write(sock->inner, mesg, strlen(mesg), &bytes_sent, 0))) {
+  if (sock->config->alpn) {
+    printed = snprintf(mesg + offset, sizeof(mesg) - offset,
+                       CRLF "ALPN: %s", sock->config->alpn);
+    offset += printed;
+    if (printed < 0 || (offset >= sizeof(mesg))) {
+      ABORT(R_FAILED);
+    }
+  }
+  if (offset + sizeof(END_HEADERS) >= sizeof(mesg)) {
+    ABORT(R_FAILED);
+  }
+  memcpy(mesg + offset, END_HEADERS, strlen(END_HEADERS));
+  offset += strlen(END_HEADERS);
+
+  if ((r=nr_socket_write(sock->inner, mesg, offset, &bytes_sent, 0))) {
     ABORT(r);
   }
 
-  if (bytes_sent < strlen(mesg)) {
+  if (bytes_sent < offset) {
     /* TODO(bug 1116583): buffering and wait for */
     r_log(LOG_GENERIC,LOG_DEBUG,"send_http_connect should be buffering %lu", (unsigned long)bytes_sent);
     ABORT(R_IO_ERROR);
   }
 
   sock->connect_requested = 1;
 
   _status = 0;
 abort:
   return(_status);
 }
 
 static char *find_http_terminator(char *response, size_t len)
 {
   char *term = response;
   char *end = response + len;
-  int N = strlen(ENDLN);
+  int N = strlen(END_HEADERS);
 
   for (; term = memchr(term, '\r', end - term); ++term) {
-    if (end - term >= N && memcmp(term, ENDLN, N) == 0) {
+    if (end - term >= N && memcmp(term, END_HEADERS, N) == 0) {
       return term;
     }
   }
 
   return NULL;
 }
 
 static int parse_http_response(char *begin, char *end, unsigned int *status)
@@ -362,17 +383,17 @@ int nr_socket_proxy_tunnel_read(void *ob
 
     /* TODO (bug 1115934): Handle authentication challenges. */
     if (http_status < 200 || http_status >= 300) {
       r_log(LOG_GENERIC,LOG_ERR,"nr_socket_proxy_tunnel_read unable to connect %u",
             http_status);
       ABORT(R_FAILED);
     }
 
-    ptr = http_term + strlen(ENDLN);
+    ptr = http_term + strlen(END_HEADERS);
     pending = sock->buffered_bytes - (ptr - sock->buffer);
 
     if (pending == 0) {
       ABORT(R_WOULDBLOCK);
     }
 
     assert(pending <= maxlen);
     *len = pending;
@@ -426,16 +447,17 @@ int nr_proxy_tunnel_config_destroy(nr_pr
 
   if (!configpp || !*configpp)
     return 0;
 
   configp = *configpp;
   *configpp = 0;
 
   RFREE(configp->proxy_host);
+  RFREE(configp->alpn);
   RFREE(configp);
 
   return 0;
 }
 
 int nr_proxy_tunnel_config_set_proxy(nr_proxy_tunnel_config *config,
                                      const char *host, UINT2 port)
 {
@@ -466,30 +488,61 @@ int nr_proxy_tunnel_config_set_resolver(
 {
   r_log(LOG_GENERIC,LOG_DEBUG,"nr_proxy_tunnel_config_set_resolver");
 
   config->resolver = resolver;
 
   return 0;
 }
 
+int nr_proxy_tunnel_config_set_alpn(nr_proxy_tunnel_config *config,
+                                    const char *alpn)
+{
+  r_log(LOG_GENERIC,LOG_DEBUG,"nr_proxy_tunnel_config_set_alpn");
+
+  if (alpn && (strlen(alpn) > MAX_ALPN_LENGTH)) {
+    return R_BAD_ARGS;
+  }
+
+  if (config->alpn) {
+    RFREE(config->alpn);
+  }
+
+  config->alpn = NULL;
+
+  if (alpn) {
+    char *alpndup = r_strdup(alpn);
+
+    if (!alpndup) {
+      return R_NO_MEMORY;
+    }
+
+    config->alpn = alpndup;
+  }
+
+  return 0;
+}
+
 int nr_proxy_tunnel_config_copy(nr_proxy_tunnel_config *config, nr_proxy_tunnel_config **copypp)
 {
   int r,_status;
   nr_proxy_tunnel_config *copy = 0;
 
   if ((r=nr_proxy_tunnel_config_create(&copy)))
     ABORT(r);
 
   if ((r=nr_proxy_tunnel_config_set_proxy(copy, config->proxy_host, config->proxy_port)))
     ABORT(r);
 
   if ((r=nr_proxy_tunnel_config_set_resolver(copy, config->resolver)))
     ABORT(r);
 
+  if ((r=nr_proxy_tunnel_config_set_alpn(copy, config->alpn)))
+    ABORT(r);
+
   *copypp = copy;
 
   _status=0;
 abort:
   if (_status) {
     nr_proxy_tunnel_config_destroy(&copy);
   }
   return(_status);
--- a/media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.h
+++ b/media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.h
@@ -39,28 +39,32 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 #include "nr_socket.h"
 #include "nr_resolver.h"
 #include "nr_socket_wrapper.h"
 
 typedef struct nr_proxy_tunnel_config_ {
   nr_resolver *resolver;
   char *proxy_host;
   UINT2 proxy_port;
+  char *alpn;
 } nr_proxy_tunnel_config;
 
 int nr_proxy_tunnel_config_create(nr_proxy_tunnel_config **config);
 
 int nr_proxy_tunnel_config_destroy(nr_proxy_tunnel_config **config);
 
 int nr_proxy_tunnel_config_set_proxy(nr_proxy_tunnel_config *config,
                                      const char* host, UINT2 port);
 
 int nr_proxy_tunnel_config_set_resolver(nr_proxy_tunnel_config *config,
                                         nr_resolver *resolver);
 
+int nr_proxy_tunnel_config_set_alpn(nr_proxy_tunnel_config *config,
+                                    const char *alpn);
+
 int nr_socket_proxy_tunnel_create(nr_proxy_tunnel_config *config,
                                   nr_socket *inner,
                                   nr_socket **socketpp);
 
 int nr_socket_wrapper_factory_proxy_tunnel_create(nr_proxy_tunnel_config *config,
                                                   nr_socket_wrapper_factory **factory);
 
 #endif
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -200,19 +200,25 @@ PeerConnectionMedia::ProtocolProxyQueryH
   rv = proxyinfo.GetPort(&httpsProxyPort);
   if (NS_FAILED(rv)) {
     CSFLogError(logTag, "%s: Failed to get proxy server port", __FUNCTION__);
     return;
   }
 
   if (pcm_->mIceCtx.get()) {
     assert(httpsProxyPort >= 0 && httpsProxyPort < (1 << 16));
+    // Note that this could check if PrivacyRequested() is set on the PC and
+    // remove "webrtc" from the ALPN list.  But that would only work if the PC
+    // was constructed with a peerIdentity constraint, not when isolated
+    // streams are added.  If we ever need to signal to the proxy that the
+    // media is isolated, then we would need to restructure this code.
     pcm_->mProxyServer.reset(
       new NrIceProxyServer(httpsProxyHost.get(),
-                           static_cast<uint16_t>(httpsProxyPort)));
+                           static_cast<uint16_t>(httpsProxyPort),
+                           "webrtc,c-webrtc"));
   } else {
     CSFLogError(logTag, "%s: Failed to set proxy server (ICE ctx unavailable)",
         __FUNCTION__);
   }
 }
 
 NS_IMPL_ISUPPORTS(PeerConnectionMedia::ProtocolProxyQueryHandler, nsIProtocolProxyCallback)
 #endif // !defined(MOZILLA_XPCOMRT_API)
--- a/memory/build/jemalloc_config.cpp
+++ b/memory/build/jemalloc_config.cpp
@@ -116,17 +116,17 @@ private:
   static bool
   CommitHook(void* chunk, size_t size, size_t offset, size_t length,
              unsigned arena_ind)
   {
     void* addr = reinterpret_cast<void*>(
       reinterpret_cast<uintptr_t>(chunk) + static_cast<uintptr_t>(offset));
 
     if (!VirtualAlloc(addr, length, MEM_COMMIT, PAGE_READWRITE))
-      MOZ_CRASH();
+      return true;
 
     return false;
   }
 
   static bool
   DecommitHook(void* chunk, size_t size, size_t offset, size_t length,
                unsigned arena_ind)
   {
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/AccountsHelper.java
@@ -0,0 +1,254 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * 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/. */
+
+package org.mozilla.gecko;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.mozilla.gecko.fxa.FirefoxAccounts;
+import org.mozilla.gecko.fxa.FxAccountConstants;
+import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
+import org.mozilla.gecko.fxa.login.Engaged;
+import org.mozilla.gecko.fxa.login.State;
+import org.mozilla.gecko.sync.Utils;
+import org.mozilla.gecko.sync.setup.SyncAccounts;
+import org.mozilla.gecko.util.EventCallback;
+import org.mozilla.gecko.util.NativeEventListener;
+import org.mozilla.gecko.util.NativeJSObject;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
+import java.security.GeneralSecurityException;
+
+/**
+ * Helper class to manage Android Accounts corresponding to Firefox Accounts.
+ */
+public class AccountsHelper implements NativeEventListener {
+    public static final String LOGTAG = "GeckoAccounts";
+
+    protected final Context mContext;
+    protected final GeckoProfile mProfile;
+
+    public AccountsHelper(Context context, GeckoProfile profile) {
+        mContext = context;
+        mProfile = profile;
+
+        EventDispatcher dispatcher = EventDispatcher.getInstance();
+        if (dispatcher == null) {
+            Log.e(LOGTAG, "Gecko event dispatcher must not be null", new RuntimeException());
+            return;
+        }
+        dispatcher.registerGeckoThreadListener(this,
+                "Accounts:CreateFirefoxAccountFromJSON",
+                "Accounts:UpdateFirefoxAccountFromJSON",
+                "Accounts:Create",
+                "Accounts:DeleteFirefoxAccount",
+                "Accounts:Exist");
+    }
+
+    public synchronized void uninit() {
+        EventDispatcher dispatcher = EventDispatcher.getInstance();
+        if (dispatcher == null) {
+            Log.e(LOGTAG, "Gecko event dispatcher must not be null", new RuntimeException());
+            return;
+        }
+        dispatcher.unregisterGeckoThreadListener(this,
+                "Accounts:CreateFirefoxAccountFromJSON",
+                "Accounts:UpdateFirefoxAccountFromJSON",
+                "Accounts:Create",
+                "Accounts:DeleteFirefoxAccount",
+                "Accounts:Exist");
+    }
+
+    @Override
+    public void handleMessage(String event, NativeJSObject message, final EventCallback callback) {
+        if ("Accounts:CreateFirefoxAccountFromJSON".equals(event)) {
+            AndroidFxAccount fxAccount = null;
+            try {
+                final NativeJSObject json = message.getObject("json");
+                final String email = json.getString("email");
+                final String uid = json.getString("uid");
+                final boolean verified = json.optBoolean("verified", false);
+                final byte[] unwrapkB = Utils.hex2Byte(json.getString("unwrapBKey"));
+                final byte[] sessionToken = Utils.hex2Byte(json.getString("sessionToken"));
+                final byte[] keyFetchToken = Utils.hex2Byte(json.getString("keyFetchToken"));
+                final String authServerEndpoint =
+                        json.optString("authServerEndpoint", FxAccountConstants.DEFAULT_AUTH_SERVER_ENDPOINT);
+                final String tokenServerEndpoint =
+                        json.optString("tokenServerEndpoint", FxAccountConstants.DEFAULT_TOKEN_SERVER_ENDPOINT);
+                final String profileServerEndpoint =
+                        json.optString("profileServerEndpoint", FxAccountConstants.DEFAULT_PROFILE_SERVER_ENDPOINT);
+                // TODO: handle choose what to Sync.
+                State state = new Engaged(email, uid, verified, unwrapkB, sessionToken, keyFetchToken);
+                fxAccount = AndroidFxAccount.addAndroidAccount(mContext,
+                        email,
+                        mProfile.getName(),
+                        authServerEndpoint,
+                        tokenServerEndpoint,
+                        profileServerEndpoint,
+                        state,
+                        AndroidFxAccount.DEFAULT_AUTHORITIES_TO_SYNC_AUTOMATICALLY_MAP);
+            } catch (URISyntaxException | GeneralSecurityException | UnsupportedEncodingException e) {
+                Log.w(LOGTAG, "Got exception creating Firefox Account from JSON; ignoring.", e);
+                if (callback != null) {
+                    callback.sendError("Could not create Firefox Account from JSON: " + e.toString());
+                    return;
+                }
+            }
+            if (callback != null) {
+                callback.sendSuccess(fxAccount != null);
+            }
+
+        } else if ("Accounts:UpdateFirefoxAccountFromJSON".equals(event)) {
+            try {
+                final Account account = FirefoxAccounts.getFirefoxAccount(mContext);
+                if (account == null) {
+                    if (callback != null) {
+                        callback.sendError("Could not update Firefox Account since none exists");
+                    }
+                    return;
+                }
+
+                final NativeJSObject json = message.getObject("json");
+                final String email = json.getString("email");
+                final String uid = json.getString("uid");
+
+                // Protect against cross-connecting accounts.
+                if (account.name == null || !account.name.equals(email)) {
+                    final String errorMessage = "Cannot update Firefox Account from JSON: datum has different email address!";
+                    Log.e(LOGTAG, errorMessage);
+                    if (callback != null) {
+                        callback.sendError(errorMessage);
+                    }
+                    return;
+                }
+
+                final boolean verified = json.optBoolean("verified", false);
+                final byte[] unwrapkB = Utils.hex2Byte(json.getString("unwrapBKey"));
+                final byte[] sessionToken = Utils.hex2Byte(json.getString("sessionToken"));
+                final byte[] keyFetchToken = Utils.hex2Byte(json.getString("keyFetchToken"));
+                final State state = new Engaged(email, uid, verified, unwrapkB, sessionToken, keyFetchToken);
+
+                final AndroidFxAccount fxAccount = new AndroidFxAccount(mContext, account);
+                fxAccount.setState(state);
+
+                if (callback != null) {
+                    callback.sendSuccess(true);
+                }
+            } catch (NativeJSObject.InvalidPropertyException e) {
+                Log.w(LOGTAG, "Got exception updating Firefox Account from JSON; ignoring.", e);
+                if (callback != null) {
+                    callback.sendError("Could not update Firefox Account from JSON: " + e.toString());
+                    return;
+                }
+            }
+
+        } else if ("Accounts:Create".equals(event)) {
+            // Do exactly the same thing as if you tapped 'Sync' in Settings.
+            final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_GET_STARTED);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            final NativeJSObject extras = message.optObject("extras", null);
+            if (extras != null) {
+                intent.putExtra("extras", extras.toString());
+            }
+            mContext.startActivity(intent);
+
+        } else if ("Accounts:DeleteFirefoxAccount".equals(event)) {
+            try {
+                final Account account = FirefoxAccounts.getFirefoxAccount(mContext);
+                if (account == null) {
+                    Log.w(LOGTAG, "Could not delete Firefox Account since none exists!");
+                    if (callback != null) {
+                        callback.sendError("Could not delete Firefox Account since none exists");
+                    }
+                    return;
+                }
+
+                final AccountManagerCallback<Boolean> accountManagerCallback = new AccountManagerCallback<Boolean>() {
+                    @Override
+                    public void run(AccountManagerFuture<Boolean> future) {
+                        try {
+                            final boolean result = future.getResult();
+                            Log.i(LOGTAG, "Account named like " + Utils.obfuscateEmail(account.name) + " removed: " + result);
+                            if (callback != null) {
+                                callback.sendSuccess(result);
+                            }
+                        } catch (OperationCanceledException | IOException | AuthenticatorException e) {
+                            if (callback != null) {
+                                callback.sendError("Could not delete Firefox Account: " + e.toString());
+                            }
+                        }
+                    }
+                };
+
+                AccountManager.get(mContext).removeAccount(account, accountManagerCallback, null);
+            } catch (Exception e) {
+                Log.w(LOGTAG, "Got exception updating Firefox Account from JSON; ignoring.", e);
+                if (callback != null) {
+                    callback.sendError("Could not update Firefox Account from JSON: " + e.toString());
+                    return;
+                }
+            }
+
+        } else if ("Accounts:Exist".equals(event)) {
+            if (callback == null) {
+                Log.w(LOGTAG, "Accounts:Exist requires a callback");
+                return;
+            }
+
+            final String kind = message.optString("kind", null);
+            final JSONObject response = new JSONObject();
+
+            try {
+                if ("any".equals(kind)) {
+                    response.put("exists", SyncAccounts.syncAccountsExist(mContext) ||
+                            FirefoxAccounts.firefoxAccountsExist(mContext));
+                    callback.sendSuccess(response);
+                } else if ("fxa".equals(kind)) {
+                    final Account account = FirefoxAccounts.getFirefoxAccount(mContext);
+                    response.put("exists", account != null);
+                    if (account != null) {
+                        response.put("email", account.name);
+                        // We should always be able to extract the server endpoints.
+                        final AndroidFxAccount fxAccount = new AndroidFxAccount(mContext, account);
+                        response.put("authServerEndpoint", fxAccount.getAccountServerURI());
+                        response.put("profileServerEndpoint", fxAccount.getProfileServerURI());
+                        response.put("tokenServerEndpoint", fxAccount.getTokenServerURI());
+                        try {
+                            // It is possible for the state fetch to fail and us to not be able to provide a UID.
+                            // Long term, the UID (and verification flag) will be attached to the Android account
+                            // user data and not the internal state representation.
+                            final State state = fxAccount.getState();
+                            response.put("uid", state.uid);
+                        } catch (Exception e) {
+                            Log.w(LOGTAG, "Got exception extracting account UID; ignoring.", e);
+                        }
+                    }
+
+                    callback.sendSuccess(response);
+                } else if ("sync11".equals(kind)) {
+                    response.put("exists", SyncAccounts.syncAccountsExist(mContext));
+                    callback.sendSuccess(response);
+                } else {
+                    callback.sendError("Could not query account existence: unknown kind.");
+                }
+            } catch (JSONException e) {
+                Log.w(LOGTAG, "Got exception querying account existence; ignoring.", e);
+                callback.sendError("Could not query account existence: " + e.toString());
+                return;
+            }
+        }
+    }
+}
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -19,22 +19,16 @@ import org.mozilla.gecko.db.BrowserContr
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.db.SuggestedSites;
 import org.mozilla.gecko.distribution.Distribution;
 import org.mozilla.gecko.favicons.Favicons;
 import org.mozilla.gecko.favicons.LoadFaviconTask;
 import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
 import org.mozilla.gecko.favicons.decoders.IconDirectoryEntry;
 import org.mozilla.gecko.firstrun.FirstrunPane;
-import org.mozilla.gecko.fxa.FirefoxAccounts;
-import org.mozilla.gecko.fxa.FxAccountConstants;
-import org.mozilla.gecko.fxa.activities.FxAccountGetStartedActivity;
-import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
-import org.mozilla.gecko.fxa.login.Engaged;
-import org.mozilla.gecko.fxa.login.State;
 import org.mozilla.gecko.gfx.BitmapUtils;
 import org.mozilla.gecko.gfx.DynamicToolbarAnimator;
 import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.health.BrowserHealthRecorder;
 import org.mozilla.gecko.health.BrowserHealthReporter;
 import org.mozilla.gecko.health.HealthRecorder;
 import org.mozilla.gecko.health.SessionInformation;
@@ -52,19 +46,17 @@ import org.mozilla.gecko.menu.GeckoMenuI
 import org.mozilla.gecko.mozglue.ContextUtils;
 import org.mozilla.gecko.mozglue.ContextUtils.SafeIntent;
 import org.mozilla.gecko.overlays.ui.ShareDialog;
 import org.mozilla.gecko.preferences.ClearOnShutdownPref;
 import org.mozilla.gecko.preferences.GeckoPreferences;
 import org.mozilla.gecko.prompts.Prompt;
 import org.mozilla.gecko.prompts.PromptListItem;
 import org.mozilla.gecko.restrictions.Restriction;
-import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository;
-import org.mozilla.gecko.sync.setup.SyncAccounts;
 import org.mozilla.gecko.tabqueue.TabQueueHelper;
 import org.mozilla.gecko.tabqueue.TabQueuePrompt;
 import org.mozilla.gecko.tabs.TabHistoryController;
 import org.mozilla.gecko.tabs.TabHistoryController.OnShowTabHistory;
 import org.mozilla.gecko.tabs.TabHistoryFragment;
 import org.mozilla.gecko.tabs.TabHistoryPage;
 import org.mozilla.gecko.tabs.TabsPanel;
 import org.mozilla.gecko.toolbar.AutocompleteHandler;
@@ -257,16 +249,18 @@ public class BrowserApp extends GeckoApp
     private SharedPreferencesHelper mSharedPreferencesHelper;
 
     private OrderedBroadcastHelper mOrderedBroadcastHelper;
 
     private BrowserHealthReporter mBrowserHealthReporter;
 
     private ReadingListHelper mReadingListHelper;
 
+    private AccountsHelper mAccountsHelper;
+
     // The tab to be selected on editing mode exit.
     private Integer mTargetTabForEditingMode;
 
     private final TabEditingState mLastTabEditingState = new TabEditingState();
 
     // The animator used to toggle HomePager visibility has a race where if the HomePager is shown
     // (starting the animation), the HomePager is hidden, and the HomePager animation completes,
     // both the web content and the HomePager will be hidden. This flag is used to prevent the
@@ -834,22 +828,19 @@ public class BrowserApp extends GeckoApp
         mFindInPageBar = (FindInPageBar) findViewById(R.id.find_in_page);
         mMediaCastingBar = (MediaCastingBar) findViewById(R.id.media_casting);
 
         EventDispatcher.getInstance().registerGeckoThreadListener((GeckoEventListener)this,
             "Menu:Open",
             "Menu:Update",
             "LightweightTheme:Update",
             "Search:Keyword",
-            "Prompt:ShowTop",
-            "Accounts:Exist");
+            "Prompt:ShowTop");
 
         EventDispatcher.getInstance().registerGeckoThreadListener((NativeEventListener)this,
-            "Accounts:Create",
-            "Accounts:CreateFirefoxAccountFromJSON",
             "CharEncoding:Data",
             "CharEncoding:State",
             "Favicon:CacheLoad",
             "Feedback:LastUrl",
             "Feedback:MaybeLater",
             "Feedback:OpenPlayStore",
             "Menu:Add",
             "Menu:Remove",
@@ -867,16 +858,17 @@ public class BrowserApp extends GeckoApp
         final BrowserDB db = getProfile().getDB();
         db.setSuggestedSites(suggestedSites);
 
         JavaAddonManager.getInstance().init(appContext);
         mSharedPreferencesHelper = new SharedPreferencesHelper(appContext);
         mOrderedBroadcastHelper = new OrderedBroadcastHelper(appContext);
         mBrowserHealthReporter = new BrowserHealthReporter();
         mReadingListHelper = new ReadingListHelper(appContext, getProfile(), this);
+        mAccountsHelper = new AccountsHelper(appContext, getProfile());
 
         if (AppConstants.MOZ_ANDROID_BEAM) {
             NfcAdapter nfc = NfcAdapter.getDefaultAdapter(this);
             if (nfc != null) {
                 nfc.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() {
                     @Override
                     public NdefMessage createNdefMessage(NfcEvent event) {
                         Tab tab = Tabs.getInstance().getSelectedTab();
@@ -1410,31 +1402,34 @@ public class BrowserApp extends GeckoApp
             mBrowserHealthReporter.uninit();
             mBrowserHealthReporter = null;
         }
 
         if (mReadingListHelper != null) {
             mReadingListHelper.uninit();
             mReadingListHelper = null;
         }
+
+        if (mAccountsHelper != null) {
+            mAccountsHelper.uninit();
+            mAccountsHelper = null;
+        }
+
         if (mZoomedView != null) {
             mZoomedView.destroy();
         }
 
         EventDispatcher.getInstance().unregisterGeckoThreadListener((GeckoEventListener) this,
             "Menu:Open",
             "Menu:Update",
             "LightweightTheme:Update",
             "Search:Keyword",
-            "Prompt:ShowTop",
-            "Accounts:Exist");
+            "Prompt:ShowTop");
 
         EventDispatcher.getInstance().unregisterGeckoThreadListener((NativeEventListener) this,
-            "Accounts:Create",
-            "Accounts:CreateFirefoxAccountFromJSON",
             "CharEncoding:Data",
             "CharEncoding:State",
             "Favicon:CacheLoad",
             "Feedback:LastUrl",
             "Feedback:MaybeLater",
             "Feedback:OpenPlayStore",
             "Menu:Add",
             "Menu:Remove",
@@ -1683,63 +1678,17 @@ public class BrowserApp extends GeckoApp
         }
 
         mBrowserToolbar.refresh();
     }
 
     @Override
     public void handleMessage(final String event, final NativeJSObject message,
                               final EventCallback callback) {
-        if ("Accounts:CreateFirefoxAccountFromJSON".equals(event)) {
-            AndroidFxAccount fxAccount = null;
-            try {
-                final NativeJSObject json = message.getObject("json");
-                final String email = json.getString("email");
-                final String uid = json.getString("uid");
-                final boolean verified = json.optBoolean("verified", false);
-                final byte[] unwrapkB = Utils.hex2Byte(json.getString("unwrapBKey"));
-                final byte[] sessionToken = Utils.hex2Byte(json.getString("sessionToken"));
-                final byte[] keyFetchToken = Utils.hex2Byte(json.getString("keyFetchToken"));
-                final String authServerEndpoint =
-                    json.optString("authServerEndpoint", FxAccountConstants.DEFAULT_AUTH_SERVER_ENDPOINT);
-                final String tokenServerEndpoint =
-                    json.optString("tokenServerEndpoint", FxAccountConstants.DEFAULT_TOKEN_SERVER_ENDPOINT);
-                final String profileServerEndpoint =
-                    json.optString("profileServerEndpoint", FxAccountConstants.DEFAULT_PROFILE_SERVER_ENDPOINT);
-                // TODO: handle choose what to Sync.
-                State state = new Engaged(email, uid, verified, unwrapkB, sessionToken, keyFetchToken);
-                fxAccount = AndroidFxAccount.addAndroidAccount(this,
-                        email,
-                        getProfile().getName(),
-                        authServerEndpoint,
-                        tokenServerEndpoint,
-                        profileServerEndpoint,
-                        state,
-                        AndroidFxAccount.DEFAULT_AUTHORITIES_TO_SYNC_AUTOMATICALLY_MAP);
-            } catch (Exception e) {
-                Log.w(LOGTAG, "Got exception creating Firefox Account from JSON; ignoring.", e);
-                if (callback == null) {
-                    callback.sendError("Could not create Firefox Account from JSON: " + e.toString());
-                }
-            }
-            if (callback != null) {
-                callback.sendSuccess(fxAccount != null);
-            }
-
-        } else if ("Accounts:Create".equals(event)) {
-            // Do exactly the same thing as if you tapped 'Sync' in Settings.
-            final Intent intent = new Intent(getContext(), FxAccountGetStartedActivity.class);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            final NativeJSObject extras = message.optObject("extras", null);
-            if (extras != null) {
-                intent.putExtra("extras", extras.toString());
-            }
-            getContext().startActivity(intent);
-
-        } else if ("CharEncoding:Data".equals(event)) {
+        if ("CharEncoding:Data".equals(event)) {
             final NativeJSObject[] charsets = message.getObjectArray("charsets");
             final int selected = message.getInt("selected");
 
             final String[] titleArray = new String[charsets.length];
             final String[] codeArray = new String[charsets.length];
             for (int i = 0; i < charsets.length; i++) {
                 final NativeJSObject charset = charsets[i];
                 titleArray[i] = charset.getString("title");
@@ -2028,34 +1977,16 @@ public class BrowserApp extends GeckoApp
                     }
                 });
             } else if (event.equals("Prompt:ShowTop")) {
                 // Bring this activity to front so the prompt is visible..
                 Intent bringToFrontIntent = new Intent();
                 bringToFrontIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
                 bringToFrontIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
                 startActivity(bringToFrontIntent);
-            } else if (event.equals("Accounts:Exist")) {
-                final String kind = message.getString("kind");
-                final JSONObject response = new JSONObject();
-
-                if ("any".equals(kind)) {
-                    response.put("exists", SyncAccounts.syncAccountsExist(getContext()) ||
-                                           FirefoxAccounts.firefoxAccountsExist(getContext()));
-                    EventDispatcher.sendResponse(message, response);
-                } else if ("fxa".equals(kind)) {
-                    response.put("exists", FirefoxAccounts.firefoxAccountsExist(getContext()));
-                    EventDispatcher.sendResponse(message, response);
-                } else if ("sync11".equals(kind)) {
-                    response.put("exists", SyncAccounts.syncAccountsExist(getContext()));
-                    EventDispatcher.sendResponse(message, response);
-                } else {
-                    response.put("error", "Unknown kind");
-                    EventDispatcher.sendError(message, response);
-                }
             } else {
                 super.handleMessage(event, message);
             }
         } catch (Exception e) {
             Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
         }
     }
 
--- a/mobile/android/base/ThumbnailHelper.java
+++ b/mobile/android/base/ThumbnailHelper.java
@@ -27,17 +27,17 @@ import java.util.concurrent.atomic.Atomi
  * applied between thumbnail processing. This allows a single thumbnail buffer to
  * be used for all thumbnails.
  */
 public final class ThumbnailHelper {
     private static final String LOGTAG = "GeckoThumbnailHelper";
 
     public static final float TABS_PANEL_THUMBNAIL_ASPECT_RATIO = 0.8333333f;
     public static final float TOP_SITES_THUMBNAIL_ASPECT_RATIO = 0.571428571f;  // this is a 4:7 ratio (as per UX decision)
-    private static final float THUMBNAIL_ASPECT_RATIO;
+    public static final float THUMBNAIL_ASPECT_RATIO;
 
     static {
       // As we only want to generate one thumbnail for each tab, we calculate the
       // largest aspect ratio required and create the thumbnail based off that.
       // Any views with a smaller aspect ratio will use a cropped version of the
       // same image.
       THUMBNAIL_ASPECT_RATIO = Math.max(TABS_PANEL_THUMBNAIL_ASPECT_RATIO, TOP_SITES_THUMBNAIL_ASPECT_RATIO);
     }
--- a/mobile/android/base/android-services.mozbuild
+++ b/mobile/android/base/android-services.mozbuild
@@ -848,26 +848,31 @@ sync_java_files = [
     'browserid/verifier/BrowserIDVerifierDelegate.java',
     'browserid/verifier/BrowserIDVerifierException.java',
     'browserid/VerifyingPublicKey.java',
     'fxa/AccountLoader.java',
     'fxa/activities/FxAccountAbstractActivity.java',
     'fxa/activities/FxAccountAbstractSetupActivity.java',
     'fxa/activities/FxAccountAbstractUpdateCredentialsActivity.java',
     'fxa/activities/FxAccountConfirmAccountActivity.java',
+    'fxa/activities/FxAccountConfirmAccountActivityWeb.java',
     'fxa/activities/FxAccountCreateAccountActivity.java',
     'fxa/activities/FxAccountCreateAccountNotAllowedActivity.java',
     'fxa/activities/FxAccountFinishMigratingActivity.java',
+    'fxa/activities/FxAccountFinishMigratingActivityWeb.java',
     'fxa/activities/FxAccountGetStartedActivity.java',
+    'fxa/activities/FxAccountGetStartedActivityWeb.java',
     'fxa/activities/FxAccountMigrationFinishedActivity.java',
     'fxa/activities/FxAccountSignInActivity.java',
     'fxa/activities/FxAccountStatusActivity.java',
     'fxa/activities/FxAccountStatusFragment.java',
     'fxa/activities/FxAccountUpdateCredentialsActivity.java',
+    'fxa/activities/FxAccountUpdateCredentialsActivityWeb.java',
     'fxa/activities/FxAccountVerifiedAccountActivity.java',
+    'fxa/activities/FxAccountWebFlowActivity.java',
     'fxa/activities/PicassoPreferenceIconTarget.java',
     'fxa/authenticator/AccountPickler.java',
     'fxa/authenticator/AndroidFxAccount.java',
     'fxa/authenticator/FxAccountAuthenticator.java',
     'fxa/authenticator/FxAccountAuthenticatorService.java',
     'fxa/authenticator/FxAccountLoginDelegate.java',
     'fxa/authenticator/FxAccountLoginException.java',
     'fxa/authenticator/FxADefaultLoginStateMachineDelegate.java',
--- a/mobile/android/base/firstrun/WelcomePanel.java
+++ b/mobile/android/base/firstrun/WelcomePanel.java
@@ -8,31 +8,32 @@ package org.mozilla.gecko.firstrun;
 import android.content.Intent;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
-import org.mozilla.gecko.fxa.activities.FxAccountGetStartedActivity;
+import org.mozilla.gecko.fxa.FxAccountConstants;
 
 public class WelcomePanel extends FirstrunPanel {
     public static final int TITLE_RES = R.string.firstrun_panel_title_welcome;
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance) {
         final ViewGroup root = (ViewGroup) inflater.inflate(R.layout.firstrun_welcome_fragment, container, false);
         root.findViewById(R.id.welcome_account).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.BUTTON, "firstrun-sync");
 
-                final Intent accountIntent = new Intent(getActivity(), FxAccountGetStartedActivity.class);
-                startActivity(accountIntent);
+                final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_GET_STARTED);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
+                startActivity(intent);
 
                 close();
             }
         });
 
         root.findViewById(R.id.welcome_browse).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
--- a/mobile/android/base/fxa/FxAccountConstants.java
+++ b/mobile/android/base/fxa/FxAccountConstants.java
@@ -89,9 +89,15 @@ public class FxAccountConstants {
    * This action is broadcast when an Android Firefox Account's internal state
    * is changed.
    * <p>
    * It is protected by signing-level permission PER_ACCOUNT_TYPE_PERMISSION and
    * can be received only by Firefox versions sharing the same Android Firefox
    * Account type.
    */
   public static final String ACCOUNT_STATE_CHANGED_ACTION = AppConstants.MOZ_ANDROID_SHARED_FXACCOUNT_TYPE + ".accounts.ACCOUNT_STATE_CHANGED_ACTION";
+
+  public static final String ACTION_FXA_CONFIRM_ACCOUNT            = AppConstants.ANDROID_PACKAGE_NAME + ".ACTION_FXA_CONFIRM_ACCOUNT";
+  public static final String ACTION_FXA_FINISH_MIGRATING           = AppConstants.ANDROID_PACKAGE_NAME + ".ACTION_FXA_FINISH_MIGRATING";
+  public static final String ACTION_FXA_GET_STARTED                = AppConstants.ANDROID_PACKAGE_NAME + ".ACTION_FXA_GET_STARTED";
+  public static final String ACTION_FXA_STATUS                     = AppConstants.ANDROID_PACKAGE_NAME + ".ACTION_FXA_STATUS";
+  public static final String ACTION_FXA_UPDATE_CREDENTIALS         = AppConstants.ANDROID_PACKAGE_NAME + ".ACTION_FXA_UPDATE_CREDENTIALS";
 }
--- a/mobile/android/base/fxa/activities/FxAccountAbstractActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountAbstractActivity.java
@@ -1,28 +1,28 @@
 /* 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/. */
 
 package org.mozilla.gecko.fxa.activities;
 
-import org.mozilla.gecko.Locales.LocaleAwareActivity;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.fxa.FxAccountAgeLockoutHelper;
-import org.mozilla.gecko.fxa.FirefoxAccounts;
-import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
-import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
-
 import android.accounts.Account;
 import android.app.Activity;
 import android.content.Intent;
 import android.os.SystemClock;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.TextView;
+import org.mozilla.gecko.Locales.LocaleAwareActivity;
+import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.background.fxa.FxAccountAgeLockoutHelper;
+import org.mozilla.gecko.fxa.FirefoxAccounts;
+import org.mozilla.gecko.fxa.FxAccountConstants;
+import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
+import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
 
 public abstract class FxAccountAbstractActivity extends LocaleAwareActivity {
   private static final String LOG_TAG = FxAccountAbstractActivity.class.getSimpleName();
 
   protected final boolean cannotResumeWhenAccountsExist;
   protected final boolean cannotResumeWhenNoAccountsExist;
   protected final boolean cannotResumeWhenLockedOut;
 
@@ -38,36 +38,40 @@ public abstract class FxAccountAbstractA
     this.cannotResumeWhenLockedOut = 0 != (resume & CANNOT_RESUME_WHEN_LOCKED_OUT);
   }
 
   /**
    * Many Firefox Accounts activities shouldn't display if an account already
    * exists or if account creation is locked out due to an age verification
    * check failing (getting started, create account, sign in). This function
    * redirects as appropriate.
+   *
+   * @return true if redirected.
    */
-  protected void redirectIfAppropriate() {
+  protected boolean redirectIfAppropriate() {
     if (cannotResumeWhenAccountsExist || cannotResumeWhenNoAccountsExist) {
       final Account account = FirefoxAccounts.getFirefoxAccount(this);
       if (cannotResumeWhenAccountsExist && account != null) {
-        redirectToActivity(FxAccountStatusActivity.class);
-        return;
+        redirectToAction(FxAccountConstants.ACTION_FXA_STATUS);
+        return true;
       }
       if (cannotResumeWhenNoAccountsExist && account == null) {
-        redirectToActivity(FxAccountGetStartedActivity.class);
-        return;
+        redirectToAction(FxAccountConstants.ACTION_FXA_GET_STARTED);
+        return true;
       }
     }
     if (cannotResumeWhenLockedOut) {
       if (FxAccountAgeLockoutHelper.isLockedOut(SystemClock.elapsedRealtime())) {
         this.setResult(RESULT_CANCELED);
-        redirectToActivity(FxAccountCreateAccountNotAllowedActivity.class);
-        return;
+        launchActivity(FxAccountCreateAccountNotAllowedActivity.class);
+        finish();
+        return true;
       }
     }
+    return false;
   }
 
   @Override
   public void onResume() {
     super.onResume();
     redirectIfAppropriate();
   }
 
@@ -80,18 +84,22 @@ public abstract class FxAccountAbstractA
   protected void launchActivity(Class<? extends Activity> activityClass) {
     Intent intent = new Intent(this, activityClass);
     // Per http://stackoverflow.com/a/8992365, this triggers a known bug with
     // the soft keyboard not being shown for the started activity. Why, Android, why?
     intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
     startActivity(intent);
   }
 
-  protected void redirectToActivity(Class<? extends Activity> activityClass) {
-    launchActivity(activityClass);
+  protected void redirectToAction(final String action) {
+    final Intent intent = new Intent(action);
+    // Per http://stackoverflow.com/a/8992365, this triggers a known bug with
+    // the soft keyboard not being shown for the started activity. Why, Android, why?
+    intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
+    startActivity(intent);
     finish();
   }
 
   /**
    * Helper to find view or error if it is missing.
    *
    * @param id of view to find.
    * @param description to print in error.
--- a/mobile/android/base/fxa/activities/FxAccountAbstractUpdateCredentialsActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountAbstractUpdateCredentialsActivity.java
@@ -1,44 +1,44 @@
 /* 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/. */
 
 package org.mozilla.gecko.fxa.activities;
 
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.AutoCompleteTextView;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ProgressBar;
+import android.widget.TextView;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.common.telemetry.TelemetryWrapper;
 import org.mozilla.gecko.background.fxa.FxAccountClient;
 import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate;
 import org.mozilla.gecko.background.fxa.FxAccountClient20;
 import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse;
 import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException;
 import org.mozilla.gecko.background.fxa.FxAccountUtils;
 import org.mozilla.gecko.background.fxa.PasswordStretcher;
 import org.mozilla.gecko.fxa.FirefoxAccounts;
+import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
 import org.mozilla.gecko.fxa.login.Engaged;
 import org.mozilla.gecko.fxa.login.State;
 import org.mozilla.gecko.fxa.tasks.FxAccountSignInTask;
 import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
 import org.mozilla.gecko.sync.telemetry.TelemetryContract;
 
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.AutoCompleteTextView;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ProgressBar;
-import android.widget.TextView;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
 
 /**
  * Abstract activity which displays a screen for updating the local password.
  */
 public abstract class FxAccountAbstractUpdateCredentialsActivity extends FxAccountAbstractSetupActivity {
   protected static final String LOG_TAG = FxAccountAbstractUpdateCredentialsActivity.class.getSimpleName();
 
   protected AndroidFxAccount fxAccount;
@@ -104,17 +104,17 @@ public abstract class FxAccountAbstractU
 
     @Override
     public void handleFailure(FxAccountClientRemoteException e) {
       if (e.isUpgradeRequired()) {
         Logger.error(LOG_TAG, "Got upgrade required from remote server; transitioning Firefox Account to Doghouse state.");
         final State state = fxAccount.getState();
         fxAccount.setState(state.makeDoghouseState());
         // The status activity will say that the user needs to upgrade.
-        redirectToActivity(FxAccountStatusActivity.class);
+        redirectToAction(FxAccountConstants.ACTION_FXA_STATUS);
         return;
       }
       showRemoteError(e, R.string.fxaccount_update_credentials_unknown_error);
     }
 
     @Override
     public void handleSuccess(LoginResponse result) {
       Logger.info(LOG_TAG, "Got success signing in.");
--- a/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java
@@ -1,34 +1,34 @@
 /* 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/. */
 
 package org.mozilla.gecko.fxa.activities;
 
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.fxa.FirefoxAccounts;
-import org.mozilla.gecko.fxa.SyncStatusListener;
-import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
-import org.mozilla.gecko.fxa.login.Engaged;
-import org.mozilla.gecko.fxa.login.State;
-import org.mozilla.gecko.fxa.login.State.Action;
-import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper;
-import org.mozilla.gecko.fxa.tasks.FxAccountCodeResender;
-import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
-
 import android.accounts.Account;
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.TextView;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.fxa.FirefoxAccounts;
+import org.mozilla.gecko.fxa.FxAccountConstants;
+import org.mozilla.gecko.fxa.SyncStatusListener;
+import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
+import org.mozilla.gecko.fxa.login.Engaged;
+import org.mozilla.gecko.fxa.login.State;
+import org.mozilla.gecko.fxa.login.State.Action;
+import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper;
+import org.mozilla.gecko.fxa.tasks.FxAccountCodeResender;
+import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
 
 /**
  * Activity which displays account created successfully screen to the user, and
  * starts them on the email verification path.
  */
 public class FxAccountConfirmAccountActivity extends FxAccountAbstractActivity implements OnClickListener {
   private static final String LOG_TAG = FxAccountConfirmAccountActivity.class.getSimpleName();
 
@@ -141,17 +141,17 @@ public class FxAccountConfirmAccountActi
     case NeedsVerification:
       // This is what we're here to handle.
       break;
     default:
       // We're not in the right place!  Redirect to status.
       Logger.warn(LOG_TAG, "No need to verify Firefox Account that needs action " + neededAction.toString() +
           " (in state " + state.getStateLabel() + ").");
       setResult(RESULT_CANCELED);
-      this.redirectToActivity(FxAccountStatusActivity.class);
+      redirectToAction(FxAccountConstants.ACTION_FXA_STATUS);
       return;
     }
 
     final String email = fxAccount.getEmail();
     final String text = getResources().getString(R.string.fxaccount_confirm_account_verification_link, email);
     verificationLinkTextView.setText(text);
 
     boolean resendLinkShouldBeEnabled = ((Engaged) state).getSessionToken() != null;
copy from mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java
copy to mobile/android/base/fxa/activities/FxAccountConfirmAccountActivityWeb.java
--- a/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivityWeb.java
@@ -1,172 +1,11 @@
 /* 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/. */
 
 package org.mozilla.gecko.fxa.activities;
 
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.fxa.FirefoxAccounts;
-import org.mozilla.gecko.fxa.SyncStatusListener;
-import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
-import org.mozilla.gecko.fxa.login.Engaged;
-import org.mozilla.gecko.fxa.login.State;
-import org.mozilla.gecko.fxa.login.State.Action;
-import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper;
-import org.mozilla.gecko.fxa.tasks.FxAccountCodeResender;
-import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
-
-import android.accounts.Account;
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.TextView;
-
-/**
- * Activity which displays account created successfully screen to the user, and
- * starts them on the email verification path.
- */
-public class FxAccountConfirmAccountActivity extends FxAccountAbstractActivity implements OnClickListener {
-  private static final String LOG_TAG = FxAccountConfirmAccountActivity.class.getSimpleName();
-
-  // Set in onCreate.
-  protected TextView verificationLinkTextView;
-  protected View resendLink;
-  protected View changeEmail;
-
-  // Set in onResume.
-  protected AndroidFxAccount fxAccount;
-
-  protected final InnerSyncStatusDelegate syncStatusDelegate = new InnerSyncStatusDelegate();
-
-  public FxAccountConfirmAccountActivity() {
-    super(CANNOT_RESUME_WHEN_NO_ACCOUNTS_EXIST);
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public void onCreate(Bundle icicle) {
-    Logger.debug(LOG_TAG, "onCreate(" + icicle + ")");
-
-    super.onCreate(icicle);
-    setContentView(R.layout.fxaccount_confirm_account);
-
-    verificationLinkTextView = (TextView) ensureFindViewById(null, R.id.verification_link_text, "verification link text");
-    resendLink = ensureFindViewById(null, R.id.resend_confirmation_email_link, "resend confirmation email link");
-    resendLink.setOnClickListener(this);
-    changeEmail = ensureFindViewById(null, R.id.change_confirmation_email_link, "change confirmation email address");
-    changeEmail.setOnClickListener(this);
-
-    View backToBrowsingButton = ensureFindViewById(null, R.id.button, "back to browsing button");
-    backToBrowsingButton.setOnClickListener(new OnClickListener() {
-      @Override
-      public void onClick(View v) {
-        ActivityUtils.openURLInFennec(v.getContext(), null);
-        setResult(Activity.RESULT_OK);
-        finish();
-      }
-    });
-  }
-
-  @Override
-  public void onResume() {
-    super.onResume();
-    this.fxAccount = getAndroidFxAccount();
-    if (fxAccount == null) {
-      Logger.warn(LOG_TAG, "Could not get Firefox Account.");
-      setResult(RESULT_CANCELED);
-      finish();
-      return;
-    }
-
-    FxAccountSyncStatusHelper.getInstance().startObserving(syncStatusDelegate);
-
-    refresh();
-
-    fxAccount.requestSync(FirefoxAccounts.NOW);
-  }
-
-  @Override
-  public void onPause() {
-    super.onPause();
-    FxAccountSyncStatusHelper.getInstance().stopObserving(syncStatusDelegate);
-
-    if (fxAccount != null) {
-      fxAccount.requestSync(FirefoxAccounts.SOON);
-    }
-  }
-
-  protected class InnerSyncStatusDelegate implements SyncStatusListener {
-    protected final Runnable refreshRunnable = new Runnable() {
-      @Override
-      public void run() {
-        refresh();
-      }
-    };
-
-    @Override
-    public Context getContext() {
-      return FxAccountConfirmAccountActivity.this;
-    }
-
-    @Override
-    public Account getAccount() {
-      return fxAccount.getAndroidAccount();
-    }
-
-    @Override
-    public void onSyncStarted() {
-      Logger.info(LOG_TAG, "Got sync started message; ignoring.");
-    }
-
-    @Override
-    public void onSyncFinished() {
-      if (fxAccount == null) {
-        return;
-      }
-      Logger.info(LOG_TAG, "Got sync finished message; refreshing.");
-      runOnUiThread(refreshRunnable);
-    }
-  }
-
-  protected void refresh() {
-    final State state = fxAccount.getState();
-    final Action neededAction = state.getNeededAction();
-    switch (neededAction) {
-    case NeedsVerification:
-      // This is what we're here to handle.
-      break;
-    default:
-      // We're not in the right place!  Redirect to status.
-      Logger.warn(LOG_TAG, "No need to verify Firefox Account that needs action " + neededAction.toString() +
-          " (in state " + state.getStateLabel() + ").");
-      setResult(RESULT_CANCELED);
-      this.redirectToActivity(FxAccountStatusActivity.class);
-      return;
-    }
-
-    final String email = fxAccount.getEmail();
-    final String text = getResources().getString(R.string.fxaccount_confirm_account_verification_link, email);
-    verificationLinkTextView.setText(text);
-
-    boolean resendLinkShouldBeEnabled = ((Engaged) state).getSessionToken() != null;
-    resendLink.setEnabled(resendLinkShouldBeEnabled);
-    resendLink.setClickable(resendLinkShouldBeEnabled);
-  }
-
-  @Override
-  public void onClick(View v) {
-    if (v.equals(resendLink)) {
-        FxAccountCodeResender.resendCode(this, fxAccount);
-    } else if (v.equals(changeEmail)) {
-      final Account account = fxAccount.getAndroidAccount();
-      Intent intent = new Intent(this, FxAccountGetStartedActivity.class);
-      FxAccountStatusActivity.maybeDeleteAndroidAccount(this, account, intent);
-    }
+public class FxAccountConfirmAccountActivityWeb extends FxAccountWebFlowActivity {
+  public FxAccountConfirmAccountActivityWeb() {
+    super(CANNOT_RESUME_WHEN_NO_ACCOUNTS_EXIST, "settings");
   }
 }
--- a/mobile/android/base/fxa/activities/FxAccountCreateAccountActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountCreateAccountActivity.java
@@ -424,17 +424,18 @@ public class FxAccountCreateAccountActiv
             : AndroidFxAccount.DEFAULT_AUTHORITIES_TO_SYNC_AUTOMATICALLY_MAP;
         if (FxAccountAgeLockoutHelper.passesAgeCheck(dayOfBirth, zeroBasedMonthOfBirth, yearEdit.getText().toString(), yearItems)) {
           FxAccountUtils.pii(LOG_TAG, "Passed age check.");
           createAccount(email, password, engines, authoritiesMap);
         } else {
           FxAccountUtils.pii(LOG_TAG, "Failed age check!");
           FxAccountAgeLockoutHelper.lockOut(SystemClock.elapsedRealtime());
           setResult(RESULT_CANCELED);
-          redirectToActivity(FxAccountCreateAccountNotAllowedActivity.class);
+          launchActivity(FxAccountCreateAccountNotAllowedActivity.class);
+          finish();
         }
       }
     });
   }
 
   /**
    * The "Choose what to sync" checkbox pops up a multi-choice dialog when it is
    * unchecked. It toggles to unchecked from checked.
copy from mobile/android/base/fxa/activities/FxAccountFinishMigratingActivity.java
copy to mobile/android/base/fxa/activities/FxAccountFinishMigratingActivityWeb.java
--- a/mobile/android/base/fxa/activities/FxAccountFinishMigratingActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountFinishMigratingActivityWeb.java
@@ -1,63 +1,11 @@
 /* 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/. */
 
 package org.mozilla.gecko.fxa.activities;
 
-import java.util.Map;
-
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse;
-import org.mozilla.gecko.fxa.login.State;
-import org.mozilla.gecko.fxa.login.State.StateLabel;
-
-import android.content.Intent;
-
-/**
- * Activity which displays a screen for inputting the password and finishing
- * migrating to Firefox Accounts / Sync 1.5.
- */
-public class FxAccountFinishMigratingActivity extends FxAccountAbstractUpdateCredentialsActivity {
-  protected static final String LOG_TAG = FxAccountFinishMigratingActivity.class.getSimpleName();
-
-  public FxAccountFinishMigratingActivity() {
-    super(R.layout.fxaccount_finish_migrating);
-  }
-
-  @Override
-  public void onResume() {
-    super.onResume();
-    this.fxAccount = getAndroidFxAccount();
-    if (fxAccount == null) {
-      Logger.warn(LOG_TAG, "Could not get Firefox Account.");
-      setResult(RESULT_CANCELED);
-      finish();
-      return;
-    }
-    final State state = fxAccount.getState();
-    if (state.getStateLabel() != StateLabel.MigratedFromSync11) {
-      Logger.warn(LOG_TAG, "Cannot finish migrating from Firefox Account in state: " + state.getStateLabel());
-      setResult(RESULT_CANCELED);
-      finish();
-      return;
-    }
-    emailEdit.setText(fxAccount.getEmail());
-  }
-
-  @Override
-  public Intent makeSuccessIntent(String email, LoginResponse result) {
-    final Intent successIntent = new Intent(this, FxAccountMigrationFinishedActivity.class);
-    // Per http://stackoverflow.com/a/8992365, this triggers a known bug with
-    // the soft keyboard not being shown for the started activity. Why, Android, why?
-    successIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
-    return successIntent;
-  }
-
-  @Override
-  protected Map<String, String> getQueryParameters() {
-    final Map<String, String> queryParameters = super.getQueryParameters();
-    queryParameters.put("migration", "sync11");
-    return queryParameters;
+public class FxAccountFinishMigratingActivityWeb extends FxAccountWebFlowActivity {
+  public FxAccountFinishMigratingActivityWeb() {
+    super(CANNOT_RESUME_WHEN_NO_ACCOUNTS_EXIST, "signin", "migration=sync11");
   }
 }
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/fxa/activities/FxAccountGetStartedActivityWeb.java
@@ -0,0 +1,11 @@
+/* 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/. */
+
+package org.mozilla.gecko.fxa.activities;
+
+public class FxAccountGetStartedActivityWeb extends FxAccountWebFlowActivity {
+  public FxAccountGetStartedActivityWeb() {
+    super(CANNOT_RESUME_WHEN_ACCOUNTS_EXIST, "signin");
+  }
+}
--- a/mobile/android/base/fxa/activities/FxAccountStatusActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountStatusActivity.java
@@ -1,23 +1,14 @@
 /* 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/. */
 
 package org.mozilla.gecko.fxa.activities;
 
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.Locales.LocaleAwareFragmentActivity;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.fxa.FxAccountUtils;
-import org.mozilla.gecko.fxa.FirefoxAccounts;
-import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
-import org.mozilla.gecko.sync.Utils;
-
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.AccountManagerCallback;
 import android.accounts.AccountManagerFuture;
 import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
 import android.app.ActionBar;
 import android.app.Activity;
@@ -27,16 +18,25 @@ import android.content.DialogInterface;
 import android.content.Intent;
 import android.os.Build;
 import android.os.Bundle;
 import android.util.TypedValue;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.widget.Toast;
+import org.mozilla.gecko.AppConstants;
+import org.mozilla.gecko.Locales.LocaleAwareFragmentActivity;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.background.fxa.FxAccountUtils;
+import org.mozilla.gecko.fxa.FirefoxAccounts;
+import org.mozilla.gecko.fxa.FxAccountConstants;
+import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
+import org.mozilla.gecko.sync.Utils;
 
 /**
  * Activity which displays account status.
  */
 public class FxAccountStatusActivity extends LocaleAwareFragmentActivity {
   private static final String LOG_TAG = FxAccountStatusActivity.class.getSimpleName();
 
   protected FxAccountStatusFragment statusFragment;
@@ -80,17 +80,17 @@ public class FxAccountStatusActivity ext
   public void onResume() {
     super.onResume();
 
     final AndroidFxAccount fxAccount = getAndroidFxAccount();
     if (fxAccount == null) {
       Logger.warn(LOG_TAG, "Could not get Firefox Account.");
 
       // Gracefully redirect to get started.
-      Intent intent = new Intent(this, FxAccountGetStartedActivity.class);
+      final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_GET_STARTED);
       // Per http://stackoverflow.com/a/8992365, this triggers a known bug with
       // the soft keyboard not being shown for the started activity. Why, Android, why?
       intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
       startActivity(intent);
 
       setResult(RESULT_CANCELED);
       finish();
       return;
--- a/mobile/android/base/fxa/activities/FxAccountStatusFragment.java
+++ b/mobile/android/base/fxa/activities/FxAccountStatusFragment.java
@@ -1,40 +1,14 @@
 /* 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/. */
 
 package org.mozilla.gecko.fxa.activities;
 
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.fxa.FxAccountUtils;
-import org.mozilla.gecko.background.preferences.PreferenceFragment;
-import org.mozilla.gecko.fxa.FirefoxAccounts;
-import org.mozilla.gecko.fxa.FxAccountConstants;
-import org.mozilla.gecko.fxa.SyncStatusListener;
-import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
-import org.mozilla.gecko.fxa.login.Married;
-import org.mozilla.gecko.fxa.login.State;
-import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper;
-import org.mozilla.gecko.fxa.tasks.FxAccountCodeResender;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.SharedPreferencesClientsDataDelegate;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.util.HardwareUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-
 import android.accounts.Account;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.os.Bundle;
@@ -44,19 +18,43 @@ import android.preference.EditTextPrefer
 import android.preference.Preference;
 import android.preference.Preference.OnPreferenceChangeListener;
 import android.preference.Preference.OnPreferenceClickListener;
 import android.preference.PreferenceCategory;
 import android.preference.PreferenceScreen;
 import android.support.v4.content.LocalBroadcastManager;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
-
 import com.squareup.picasso.Picasso;
 import com.squareup.picasso.Target;
+import org.mozilla.gecko.AppConstants;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.background.fxa.FxAccountUtils;
+import org.mozilla.gecko.background.preferences.PreferenceFragment;
+import org.mozilla.gecko.fxa.FirefoxAccounts;
+import org.mozilla.gecko.fxa.FxAccountConstants;
+import org.mozilla.gecko.fxa.SyncStatusListener;
+import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
+import org.mozilla.gecko.fxa.login.Married;
+import org.mozilla.gecko.fxa.login.State;
+import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper;
+import org.mozilla.gecko.fxa.tasks.FxAccountCodeResender;
+import org.mozilla.gecko.sync.ExtendedJSONObject;
+import org.mozilla.gecko.sync.SharedPreferencesClientsDataDelegate;
+import org.mozilla.gecko.sync.SyncConfiguration;
+import org.mozilla.gecko.util.HardwareUtils;
+import org.mozilla.gecko.util.ThreadUtils;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * A fragment that displays the status of an AndroidFxAccount.
  * <p>
  * The owning activity is responsible for providing an AndroidFxAccount at
  * appropriate times.
  */
 public class FxAccountStatusFragment
@@ -232,47 +230,49 @@ public class FxAccountStatusFragment