Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Sun, 14 Oct 2012 16:39:23 -0400
changeset 110365 942ed5747b63807e625f5b692564fe31496c3117
parent 110316 57304bbf9c0e8fd5ffbfc79a43ea5ccdd53074b1 (current diff)
parent 110364 45cf07ab3a5ef5d6142c6e44f39a30e9cd3f0487 (diff)
child 110366 5f4a6a4744556201c38d0869381fe4ab1454fa0f
child 110420 1764fa8b0450ad67a1b55934a1c6f1e87606245b
child 111006 51b26b095a27eaa681c70f091567485b482d5f31
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
milestone19.0a1
Merge inbound to m-c.
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
content/base/src/nsDocument.cpp
dom/bindings/Bindings.conf
dom/imptests/failures/webapps/DOMCore/tests/approved/test_interfaces.html.json
dom/tests/mochitest/chrome/file_bug799299.xul
dom/tests/mochitest/chrome/test_bug799299.xul
js/src/jit-test/tests/debug/Debugger-debuggees-07.js
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -268,17 +268,17 @@ Accessible::Name(nsString& aName)
 
   nsCOMPtr<nsIXBLAccessible> xblAccessible(do_QueryInterface(mContent));
   if (xblAccessible) {
     xblAccessible->GetAccessibleName(aName);
     if (!aName.IsEmpty())
       return eNameOK;
   }
 
-  nsresult rv = GetNameInternal(aName);
+  ENameValueFlag nameFlag = NativeName(aName);
   if (!aName.IsEmpty())
     return eNameOK;
 
   // In the end get the name from tooltip.
   if (mContent->IsHTML()) {
     if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) {
       aName.CompressWhitespace();
       return eNameFromTooltip;
@@ -287,17 +287,17 @@ Accessible::Name(nsString& aName)
     if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, aName)) {
       aName.CompressWhitespace();
       return eNameFromTooltip;
     }
   } else {
     return eNameOK;
   }
 
-  if (rv != NS_OK_EMPTY_NAME)
+  if (nameFlag != eNoNameOnPurpose)
     aName.SetIsVoid(true);
 
   return eNameOK;
 }
 
 NS_IMETHODIMP
 Accessible::GetDescription(nsAString& aDescription)
 {
@@ -1050,120 +1050,105 @@ Accessible::TakeFocus()
   nsCOMPtr<nsIDOMElement> element(do_QueryInterface(focusContent));
   nsFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm)
     fm->SetFocus(element, 0);
 
   return NS_OK;
 }
 
-nsresult
-Accessible::GetHTMLName(nsAString& aLabel)
+void
+Accessible::GetHTMLName(nsString& aLabel)
 {
-  nsAutoString label;
-
   Accessible* labelAcc = nullptr;
   HTMLLabelIterator iter(Document(), this);
   while ((labelAcc = iter.Next())) {
-    nsresult rv = nsTextEquivUtils::
-      AppendTextEquivFromContent(this, labelAcc->GetContent(), &label);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    label.CompressWhitespace();
+    nsTextEquivUtils::AppendTextEquivFromContent(this, labelAcc->GetContent(),
+                                                 &aLabel);
+    aLabel.CompressWhitespace();
   }
 
-  if (label.IsEmpty())
-    return nsTextEquivUtils::GetNameFromSubtree(this, aLabel);
-
-  aLabel = label;
-  return NS_OK;
+  if (aLabel.IsEmpty())
+    nsTextEquivUtils::GetNameFromSubtree(this, aLabel);
 }
 
 /**
   * 3 main cases for XUL Controls to be labeled
   *   1 - control contains label="foo"
   *   2 - control has, as a child, a label element
   *        - label has either value="foo" or children
   *   3 - non-child label contains control="controlID"
   *        - label has either value="foo" or children
   * Once a label is found, the search is discontinued, so a control
   *  that has a label child as well as having a label external to
   *  the control that uses the control="controlID" syntax will use
   *  the child label for its Name.
   */
-nsresult
-Accessible::GetXULName(nsAString& aLabel)
+void
+Accessible::GetXULName(nsString& aName)
 {
   // CASE #1 (via label attribute) -- great majority of the cases
-  nsresult rv = NS_OK;
-
-  nsAutoString label;
-  nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl(do_QueryInterface(mContent));
+  nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl =
+    do_QueryInterface(mContent);
   if (labeledEl) {
-    rv = labeledEl->GetLabel(label);
-  }
-  else {
-    nsCOMPtr<nsIDOMXULSelectControlItemElement> itemEl(do_QueryInterface(mContent));
+    labeledEl->GetLabel(aName);
+  } else {
+    nsCOMPtr<nsIDOMXULSelectControlItemElement> itemEl =
+      do_QueryInterface(mContent);
     if (itemEl) {
-      rv = itemEl->GetLabel(label);
-    }
-    else {
-      nsCOMPtr<nsIDOMXULSelectControlElement> select(do_QueryInterface(mContent));
+      itemEl->GetLabel(aName);
+    } else {
+      nsCOMPtr<nsIDOMXULSelectControlElement> select =
+        do_QueryInterface(mContent);
       // Use label if this is not a select control element which 
       // uses label attribute to indicate which option is selected
       if (!select) {
         nsCOMPtr<nsIDOMXULElement> xulEl(do_QueryInterface(mContent));
-        if (xulEl) {
-          rv = xulEl->GetAttribute(NS_LITERAL_STRING("label"), label);
-        }
+        if (xulEl)
+          xulEl->GetAttribute(NS_LITERAL_STRING("label"), aName);
       }
     }
   }
 
   // CASES #2 and #3 ------ label as a child or <label control="id" ... > </label>
-  if (NS_FAILED(rv) || label.IsEmpty()) {
-    label.Truncate();
-
+  if (aName.IsEmpty()) {
     Accessible* labelAcc = nullptr;
     XULLabelIterator iter(Document(), mContent);
     while ((labelAcc = iter.Next())) {
       nsCOMPtr<nsIDOMXULLabelElement> xulLabel =
         do_QueryInterface(labelAcc->GetContent());
       // Check if label's value attribute is used
-      if (xulLabel && NS_SUCCEEDED(xulLabel->GetValue(label)) && label.IsEmpty()) {
+      if (xulLabel && NS_SUCCEEDED(xulLabel->GetValue(aName)) && aName.IsEmpty()) {
         // If no value attribute, a non-empty label must contain
         // children that define its text -- possibly using HTML
         nsTextEquivUtils::
-          AppendTextEquivFromContent(this, labelAcc->GetContent(), &label);
+          AppendTextEquivFromContent(this, labelAcc->GetContent(), &aName);
       }
     }
   }
 
   // XXX If CompressWhiteSpace worked on nsAString we could avoid a copy
-  label.CompressWhitespace();
-  if (!label.IsEmpty()) {
-    aLabel = label;
-    return NS_OK;
-  }
+  aName.CompressWhitespace();
+  if (!aName.IsEmpty())
+    return;
 
   // Can get text from title of <toolbaritem> if we're a child of a <toolbaritem>
   nsIContent *bindingParent = mContent->GetBindingParent();
   nsIContent *parent = bindingParent? bindingParent->GetParent() :
                                       mContent->GetParent();
   while (parent) {
     if (parent->Tag() == nsGkAtoms::toolbaritem &&
-        parent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, label)) {
-      label.CompressWhitespace();
-      aLabel = label;
-      return NS_OK;
+        parent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) {
+      aName.CompressWhitespace();
+      return;
     }
     parent = parent->GetParent();
   }
 
-  return nsTextEquivUtils::GetNameFromSubtree(this, aLabel);
+  nsTextEquivUtils::GetNameFromSubtree(this, aName);
 }
 
 nsresult
 Accessible::HandleAccEvent(AccEvent* aEvent)
 {
   NS_ENSURE_ARG_POINTER(aEvent);
 
   nsCOMPtr<nsIObserverService> obsService =
@@ -2428,19 +2413,16 @@ Accessible::Shutdown()
 
   InvalidateChildren();
   if (mParent)
     mParent->RemoveChild(this);
 
   nsAccessNodeWrap::Shutdown();
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// Accessible public methods
-
 // Accessible protected
 void
 Accessible::ARIAName(nsAString& aName)
 {
   nsAutoString label;
 
   // aria-labelledby now takes precedence over aria-label
   nsresult rv = nsTextEquivUtils::
@@ -2453,26 +2435,26 @@ Accessible::ARIAName(nsAString& aName)
   if (label.IsEmpty() &&
       mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_label,
                         label)) {
     label.CompressWhitespace();
     aName = label;
   }
 }
 
-nsresult
-Accessible::GetNameInternal(nsAString& aName)
+// Accessible protected
+ENameValueFlag
+Accessible::NativeName(nsString& aName)
 {
   if (mContent->IsHTML())
-    return GetHTMLName(aName);
-
-  if (mContent->IsXUL())
-    return GetXULName(aName);
-
-  return NS_OK;
+    GetHTMLName(aName);
+  else if (mContent->IsXUL())
+    GetXULName(aName);
+
+  return eNameOK;
 }
 
 // Accessible protected
 void
 Accessible::BindToParent(Accessible* aParent, uint32_t aIndexInParent)
 {
   NS_PRECONDITION(aParent, "This method isn't used to set null parent!");
 
@@ -2485,25 +2467,29 @@ Accessible::BindToParent(Accessible* aPa
       return;
     }
   }
 
   mParent = aParent;
   mIndexInParent = aIndexInParent;
 }
 
+// Accessible protected
 void
 Accessible::UnbindFromParent()
 {
   mParent = nullptr;
   mIndexInParent = -1;
   mIndexOfEmbeddedChild = -1;
   mGroupInfo = nullptr;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// Accessible public methods
+
 void
 Accessible::InvalidateChildren()
 {
   int32_t childCount = mChildren.Length();
   for (int32_t childIdx = 0; childIdx < childCount; childIdx++) {
     Accessible* child = mChildren.ElementAt(childIdx);
     child->UnbindFromParent();
   }
--- a/accessible/src/generic/Accessible.h
+++ b/accessible/src/generic/Accessible.h
@@ -44,20 +44,29 @@ class XULTreeAccessible;
 /**
  * Name type flags.
  */
 enum ENameValueFlag {
   /**
    * Name either
    *  a) present (not empty): !name.IsEmpty()
    *  b) no name (was missed): name.IsVoid()
-   *  c) was left empty by the author on demand: name.IsEmpty() && !name.IsVoid()
    */
  eNameOK,
- eNameFromTooltip // Tooltip was used as a name
+
+ /**
+  * Name was left empty by the author on purpose:
+  * name.IsEmpty() && !name.IsVoid().
+  */
+ eNoNameOnPurpose,
+
+ /**
+  * Tooltip was used as a name.
+  */
+ eNameFromTooltip
 };
 
 /**
  * Group position (level, position in set and set size).
  */
 struct GroupPos
 {
   GroupPos() : level(0), posInSet(0), setSize(0) { }
@@ -127,16 +136,19 @@ public:
 
   /**
    * Get the value of this accessible.
    */
   virtual void Value(nsString& aValue);
 
   /**
    * Get the name of this accessible.
+   *
+   * Note: aName.IsVoid() when name was left empty by the author on purpose.
+   * aName.IsEmpty() when the author missed name, AT can try to repair a name.
    */
   virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
 
   /**
    * Return DOM node associated with this accessible.
    */
   inline already_AddRefed<nsIDOMNode> DOMNode() const
   {
@@ -151,28 +163,16 @@ public:
    * argument should hold states for accessible before you pass it into this
    * method.
    *
    * @param  [in/out] where to fill the states into.
    */
   virtual void ApplyARIAState(uint64_t* aState) const;
 
   /**
-   * Returns the accessible name provided by native markup. It doesn't take
-   * into account ARIA markup used to specify the name.
-   *
-   * @param  aName             [out] the accessible name
-   *
-   * @return NS_OK_EMPTY_NAME  points empty name was specified by native markup
-   *                           explicitly (see nsIAccessible::name attribute for
-   *                           details)
-   */
-  virtual nsresult GetNameInternal(nsAString& aName);
-
-  /**
    * Return enumerated accessible role (see constants in Role.h).
    */
   mozilla::a11y::role Role();
 
   /**
    * Return true if ARIA role is specified on the element.
    */
   bool HasARIARole() const
@@ -789,29 +789,31 @@ protected:
    * Return ARIA role (helper method).
    */
   mozilla::a11y::role ARIATransformRole(mozilla::a11y::role aRole);
 
   //////////////////////////////////////////////////////////////////////////////
   // Name helpers
 
   /**
+   * 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);
+
+  /**
    * Returns the accessible name specified by ARIA.
    */
   void ARIAName(nsAString& aName);
 
   /**
-   * Compute the name of HTML node.
+   * Compute the name of HTML/XUL node.
    */
-  nsresult GetHTMLName(nsAString& aName);
-
-  /**
-   * Compute the name for XUL node.
-   */
-  nsresult GetXULName(nsAString& aName);
+  void GetHTMLName(nsString& aName);
+  void GetXULName(nsString& aName);
 
   // helper method to verify frames
   static nsresult GetFullKeyName(const nsAString& aModifierName, const nsAString& aKeyName, nsAString& aStringOut);
 
   /**
    * Return an accessible for the given DOM node, or if that node isn't
    * accessible, return the accessible for the next DOM node which has one
    * (based on forward depth first search).
--- a/accessible/src/generic/HyperTextAccessible.cpp
+++ b/accessible/src/generic/HyperTextAccessible.cpp
@@ -1944,33 +1944,30 @@ HyperTextAccessible::ScrollSubstringToPo
   }
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Accessible public
 
-nsresult
-HyperTextAccessible::GetNameInternal(nsAString& aName)
+// Accessible protected
+ENameValueFlag
+HyperTextAccessible::NativeName(nsString& aName)
 {
-  nsresult rv = AccessibleWrap::GetNameInternal(aName);
-  NS_ENSURE_SUCCESS(rv, rv);
+  AccessibleWrap::NativeName(aName);
 
   // Get name from title attribute for HTML abbr and acronym elements making it
   // a valid name from markup. Otherwise their name isn't picked up by recursive
   // name computation algorithm. See NS_OK_NAME_FROM_TOOLTIP.
-  if (aName.IsEmpty() && IsAbbreviation()) {
-    nsAutoString name;
-    if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, name)) {
-      name.CompressWhitespace();
-      aName = name;
-    }
-  }
-  return NS_OK;
+  if (aName.IsEmpty() && IsAbbreviation() &&
+      mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName))
+    aName.CompressWhitespace();
+
+  return eNameOK;
 }
 
 void
 HyperTextAccessible::InvalidateChildren()
 {
   mOffsets.Clear();
 
   AccessibleWrap::InvalidateChildren();
--- a/accessible/src/generic/HyperTextAccessible.h
+++ b/accessible/src/generic/HyperTextAccessible.h
@@ -47,17 +47,16 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIACCESSIBLETEXT
   NS_DECL_NSIACCESSIBLEHYPERTEXT
   NS_DECL_NSIACCESSIBLEEDITABLETEXT
 
   // Accessible
   virtual int32_t GetLevelInternal();
   virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual mozilla::a11y::role NativeRole();
   virtual uint64_t NativeState();
 
   virtual void InvalidateChildren();
   virtual bool RemoveChild(Accessible* aAccessible);
 
   // HyperTextAccessible (static helper method)
 
@@ -238,16 +237,19 @@ public:
   // EditableTextAccessible
 
   /**
    * Return the editor associated with the accessible.
    */
   virtual already_AddRefed<nsIEditor> GetEditor() const;
 
 protected:
+  // Accessible
+  virtual mozilla::a11y::ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
+
   // HyperTextAccessible
 
   /**
    * Transform magic offset into text offset.
    */
   int32_t ConvertMagicOffset(int32_t aOffset)
   {
     if (aOffset == nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT)
--- a/accessible/src/generic/ImageAccessible.cpp
+++ b/accessible/src/generic/ImageAccessible.cpp
@@ -64,36 +64,34 @@ ImageAccessible::NativeState()
     imgContainer->GetAnimated(&animated);
     if (animated)
       state |= states::ANIMATED;
   }
 
   return state;
 }
 
-nsresult
-ImageAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+ImageAccessible::NativeName(nsString& aName)
 {
   bool hasAltAttrib =
     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName);
   if (!aName.IsEmpty())
-    return NS_OK;
+    return eNameOK;
 
-  nsresult rv = Accessible::GetNameInternal(aName);
-  NS_ENSURE_SUCCESS(rv, rv);
-
+  Accessible::NativeName(aName);
   if (aName.IsEmpty() && hasAltAttrib) {
     // No accessible name but empty 'alt' attribute is present. If further name
     // computation algorithm doesn't provide non empty name then it means
     // an empty 'alt' attribute was used to indicate a decorative image (see
     // nsIAccessible::name attribute for details).
-    return NS_OK_EMPTY_NAME;
+    return eNoNameOnPurpose;
   }
 
-  return NS_OK;
+  return eNameOK;
 }
 
 role
 ImageAccessible::NativeRole()
 {
   return roles::GRAPHIC;
 }
 
--- a/accessible/src/generic/ImageAccessible.h
+++ b/accessible/src/generic/ImageAccessible.h
@@ -31,24 +31,27 @@ public:
   // nsIAccessible
   NS_IMETHOD GetActionName(uint8_t aIndex, nsAString& aName);
   NS_IMETHOD DoAction(uint8_t index);
 
   // nsIAccessibleImage
   NS_DECL_NSIACCESSIBLEIMAGE
 
   // Accessible
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual a11y::role NativeRole();
   virtual uint64_t NativeState();
   virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
 
   // ActionAccessible
   virtual uint8_t ActionCount();
 
+protected:
+  // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
+
 private:
   /**
    * Return whether the element has a longdesc URI.
    */
   bool HasLongDesc() const
   {
     nsCOMPtr<nsIURI> uri = GetLongDescURI();
     return uri;
--- a/accessible/src/html/HTMLElementAccessibles.cpp
+++ b/accessible/src/html/HTMLElementAccessibles.cpp
@@ -36,33 +36,34 @@ HTMLBRAccessible::NativeRole()
 }
 
 uint64_t
 HTMLBRAccessible::NativeState()
 {
   return states::READONLY;
 }
 
-nsresult
-HTMLBRAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+HTMLBRAccessible::NativeName(nsString& aName)
 {
   aName = static_cast<PRUnichar>('\n');    // Newline char
-  return NS_OK;
+  return eNameOK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLLabelAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 NS_IMPL_ISUPPORTS_INHERITED0(HTMLLabelAccessible, HyperTextAccessible)
 
-nsresult
-HTMLLabelAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+HTMLLabelAccessible::NativeName(nsString& aName)
 {
-  return nsTextEquivUtils::GetNameFromSubtree(this, aName);
+  nsTextEquivUtils::GetNameFromSubtree(this, aName);
+  return eNameOK;
 }
 
 role
 HTMLLabelAccessible::NativeRole()
 {
   return roles::LABEL;
 }
 
--- a/accessible/src/html/HTMLElementAccessibles.h
+++ b/accessible/src/html/HTMLElementAccessibles.h
@@ -27,41 +27,45 @@ public:
 };
 
 /**
  * Used for HTML br element.
  */
 class HTMLBRAccessible : public LeafAccessible
 {
 public:
-
   HTMLBRAccessible(nsIContent* aContent, DocAccessible* aDoc) :
     LeafAccessible(aContent, aDoc) {};
 
   // Accessible
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual a11y::role NativeRole();
   virtual uint64_t NativeState();
+
+protected:
+  // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
 };
 
 /**
  * Used for HTML label element.
  */
 class HTMLLabelAccessible : public HyperTextAccessibleWrap
 {
 public:
 
   HTMLLabelAccessible(nsIContent* aContent, DocAccessible* aDoc) :
     HyperTextAccessibleWrap(aContent, aDoc) {};
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // Accessible
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual a11y::role NativeRole();
+
+protected:
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
 };
 
 /**
  * Used for HTML output element.
  */
 class HTMLOutputAccessible : public HyperTextAccessibleWrap
 {
 public:
--- a/accessible/src/html/HTMLFormControlAccessible.cpp
+++ b/accessible/src/html/HTMLFormControlAccessible.cpp
@@ -251,47 +251,42 @@ HTMLButtonAccessible::NativeState()
 }
 
 role
 HTMLButtonAccessible::NativeRole()
 {
   return roles::PUSHBUTTON;
 }
 
-nsresult
-HTMLButtonAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+HTMLButtonAccessible::NativeName(nsString& aName)
 {
-  Accessible::GetNameInternal(aName);
+  Accessible::NativeName(aName);
   if (!aName.IsEmpty() || mContent->Tag() != nsGkAtoms::input)
-    return NS_OK;
+    return eNameOK;
 
   // No name from HTML or ARIA
-  nsAutoString name;
-  if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value,
-                         name) &&
-      !mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt,
-                         name)) {
+  if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aName) &&
+      !mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName)) {
     // Use the button's (default) label if nothing else works
     nsIFrame* frame = GetFrame();
     if (frame) {
       nsIFormControlFrame* fcFrame = do_QueryFrame(frame);
       if (fcFrame)
-        fcFrame->GetFormProperty(nsGkAtoms::defaultLabel, name);
+        fcFrame->GetFormProperty(nsGkAtoms::defaultLabel, aName);
     }
   }
 
-  if (name.IsEmpty() &&
-      !mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, name)) {
-    mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, name);
+  if (aName.IsEmpty() &&
+      !mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, aName)) {
+    mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, aName);
   }
 
-  name.CompressWhitespace();
-  aName = name;
-
-  return NS_OK;
+  aName.CompressWhitespace();
+  return eNameOK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLButtonAccessible: Widgets
 
 bool
 HTMLButtonAccessible::IsWidget() const
 {
@@ -320,44 +315,40 @@ HTMLTextFieldAccessible::NativeRole()
   if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
                             nsGkAtoms::password, eIgnoreCase)) {
     return roles::PASSWORD_TEXT;
   }
   
   return roles::ENTRY;
 }
 
-nsresult
-HTMLTextFieldAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+HTMLTextFieldAccessible::NativeName(nsString& aName)
 {
-  nsresult rv = Accessible::GetNameInternal(aName);
-  NS_ENSURE_SUCCESS(rv, rv);
+  Accessible::NativeName(aName);
+  if (!aName.IsEmpty())
+    return eNameOK;
 
-  if (!aName.IsEmpty())
-    return NS_OK;
-
-  if (mContent->GetBindingParent())
-  {
+  if (mContent->GetBindingParent()) {
     // XXX: bug 459640
     // There's a binding parent.
     // This means we're part of another control, so use parent accessible for name.
     // This ensures that a textbox inside of a XUL widget gets
     // an accessible name.
     Accessible* parent = Parent();
     if (parent)
       parent->GetName(aName);
   }
 
   if (!aName.IsEmpty())
-    return NS_OK;
+    return eNameOK;
 
   // text inputs and textareas might have useful placeholder text
   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::placeholder, aName);
-
-  return NS_OK;
+  return eNameOK;
 }
 
 void
 HTMLTextFieldAccessible::Value(nsString& aValue)
 {
   aValue.Truncate();
   if (NativeState() & states::PROTECTED)    // Don't return password text!
     return;
@@ -614,32 +605,28 @@ HTMLGroupboxAccessible::GetLegend()
       // Either XHTML namespace or no namespace
       return legendContent;
     }
   }
 
   return nullptr;
 }
 
-nsresult
-HTMLGroupboxAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+HTMLGroupboxAccessible::NativeName(nsString& aName)
 {
-  nsresult rv = Accessible::GetNameInternal(aName);
-  NS_ENSURE_SUCCESS(rv, rv);
-
+  Accessible::NativeName(aName);
   if (!aName.IsEmpty())
-    return NS_OK;
+    return eNameOK;
 
-  nsIContent *legendContent = GetLegend();
-  if (legendContent) {
-    return nsTextEquivUtils::
-      AppendTextEquivFromContent(this, legendContent, &aName);
-  }
+  nsIContent* legendContent = GetLegend();
+  if (legendContent)
+    nsTextEquivUtils::AppendTextEquivFromContent(this, legendContent, &aName);
 
-  return NS_OK;
+  return eNameOK;
 }
 
 Relation
 HTMLGroupboxAccessible::RelationByType(uint32_t aType)
 {
   Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
     // No override for label, so use <legend> for this <fieldset>
   if (aType == nsIAccessibleRelation::RELATION_LABELLED_BY)
@@ -701,32 +688,28 @@ HTMLFigureAccessible::GetAttributesInter
 }
 
 role
 HTMLFigureAccessible::NativeRole()
 {
   return roles::FIGURE;
 }
 
-nsresult
-HTMLFigureAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+HTMLFigureAccessible::NativeName(nsString& aName)
 {
-  nsresult rv = HyperTextAccessibleWrap::GetNameInternal(aName);
-  NS_ENSURE_SUCCESS(rv, rv);
-
+  HyperTextAccessibleWrap::NativeName(aName);
   if (!aName.IsEmpty())
-    return NS_OK;
+    return eNameOK;
 
   nsIContent* captionContent = Caption();
-  if (captionContent) {
-    return nsTextEquivUtils::
-      AppendTextEquivFromContent(this, captionContent, &aName);
-  }
+  if (captionContent)
+    nsTextEquivUtils::AppendTextEquivFromContent(this, captionContent, &aName);
 
-  return NS_OK;
+  return eNameOK;
 }
 
 Relation
 HTMLFigureAccessible::RelationByType(uint32_t aType)
 {
   Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
   if (aType == nsIAccessibleRelation::RELATION_LABELLED_BY)
     rel.AppendTarget(mDoc, Caption());
--- a/accessible/src/html/HTMLFormControlAccessible.h
+++ b/accessible/src/html/HTMLFormControlAccessible.h
@@ -72,26 +72,29 @@ public:
 
   HTMLButtonAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // nsIAccessible
   NS_IMETHOD GetActionName(uint8_t aIndex, nsAString& aName);
   NS_IMETHOD DoAction(uint8_t index);
 
   // Accessible
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual mozilla::a11y::role NativeRole();
   virtual uint64_t State();
   virtual uint64_t NativeState();
 
   // ActionAccessible
   virtual uint8_t ActionCount();
 
   // Widgets
   virtual bool IsWidget() const;
+
+protected:
+  // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
 };
 
 
 /**
  * Accessible for HTML input@type="text" element.
  */
 class HTMLTextFieldAccessible : public HyperTextAccessibleWrap
 {
@@ -108,27 +111,30 @@ public:
   NS_IMETHOD DoAction(uint8_t index);
 
   // HyperTextAccessible
   virtual already_AddRefed<nsIEditor> GetEditor() const;
 
   // Accessible
   virtual void Value(nsString& aValue);
   virtual void ApplyARIAState(uint64_t* aState) const;
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual mozilla::a11y::role NativeRole();
   virtual uint64_t State();
   virtual uint64_t NativeState();
 
   // ActionAccessible
   virtual uint8_t ActionCount();
 
   // Widgets
   virtual bool IsWidget() const;
   virtual Accessible* ContainerWidget() const;
+
+protected:
+  // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
 };
 
 
 /**
  * Accessible for input@type="file" element.
  */
 class HTMLFileInputAccessible : public HyperTextAccessibleWrap
 {
@@ -144,21 +150,24 @@ public:
  * Accessible for HTML fieldset element.
  */
 class HTMLGroupboxAccessible : public HyperTextAccessibleWrap
 {
 public:
   HTMLGroupboxAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // Accessible
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual mozilla::a11y::role NativeRole();
   virtual Relation RelationByType(uint32_t aType);
 
 protected:
+  // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
+
+  // HTMLGroupboxAccessible
   nsIContent* GetLegend();
 };
 
 
 /**
  * Accessible for HTML legend element.
  */
 class HTMLLegendAccessible : public HyperTextAccessibleWrap
@@ -176,21 +185,24 @@ public:
  */
 class HTMLFigureAccessible : public HyperTextAccessibleWrap
 {
 public:
   HTMLFigureAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // Accessible
   virtual nsresult GetAttributesInternal(nsIPersistentProperties* aAttributes);
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual mozilla::a11y::role NativeRole();
   virtual Relation RelationByType(uint32_t aType);
 
 protected:
+  // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
+
+  // HTMLLegendAccessible
   nsIContent* Caption() const;
 };
 
 
 /**
  * Accessible for HTML5 figcaption element.
  */
 class HTMLFigcaptionAccessible : public HyperTextAccessibleWrap
--- a/accessible/src/html/HTMLImageMapAccessible.cpp
+++ b/accessible/src/html/HTMLImageMapAccessible.cpp
@@ -155,29 +155,27 @@ HTMLAreaAccessible::
   // Make HTML area DOM element not accessible. HTML image map accessible
   // manages its tree itself.
   mFlags |= eNotNodeMapEntry;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLAreaAccessible: nsIAccessible
 
-nsresult
-HTMLAreaAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+HTMLAreaAccessible::NativeName(nsString& aName)
 {
-  nsresult rv = Accessible::GetNameInternal(aName);
-  NS_ENSURE_SUCCESS(rv, rv);
-
+  Accessible::NativeName(aName);
   if (!aName.IsEmpty())
-    return NS_OK;
+    return eNameOK;
 
   if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName))
-    return GetValue(aName);
+    GetValue(aName);
 
-  return NS_OK;
+  return eNameOK;
 }
 
 void
 HTMLAreaAccessible::Description(nsString& aDescription)
 {
   aDescription.Truncate();
 
   // Still to do - follow IE's standard here
--- a/accessible/src/html/HTMLImageMapAccessible.h
+++ b/accessible/src/html/HTMLImageMapAccessible.h
@@ -50,28 +50,27 @@ protected:
 class HTMLAreaAccessible : public HTMLLinkAccessible
 {
 public:
 
   HTMLAreaAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // Accessible
   virtual void Description(nsString& aDescription);
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual Accessible* ChildAtPoint(int32_t aX, int32_t aY,
                                    EWhichChildAtPoint aWhichChild);
   virtual void GetBoundsRect(nsRect& aBounds, nsIFrame** aBoundingFrame);
 
   // HyperLinkAccessible
   virtual uint32_t StartOffset();
   virtual uint32_t EndOffset();
 
 protected:
-
   // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
   virtual void CacheChildren();
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 ////////////////////////////////////////////////////////////////////////////////
 // Accessible downcasting method
--- a/accessible/src/html/HTMLSelectAccessible.cpp
+++ b/accessible/src/html/HTMLSelectAccessible.cpp
@@ -180,44 +180,34 @@ role
 HTMLSelectOptionAccessible::NativeRole()
 {
   if (mParent && mParent->Role() == roles::COMBOBOX_LIST)
     return roles::COMBOBOX_OPTION;
 
   return roles::OPTION;
 }
 
-nsresult
-HTMLSelectOptionAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+HTMLSelectOptionAccessible::NativeName(nsString& aName)
 {
   // CASE #1 -- great majority of the cases
   // find the label attribute - this is what the W3C says we should use
   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::label, aName);
   if (!aName.IsEmpty())
-    return NS_OK;
+    return eNameOK;
 
   // CASE #2 -- no label parameter, get the first child, 
   // use it if it is a text node
   nsIContent* text = mContent->GetFirstChild();
-  if (!text)
-    return NS_OK;
-
-  if (text->IsNodeOfType(nsINode::eTEXT)) {
-    nsAutoString txtValue;
-    nsresult rv = nsTextEquivUtils::
-      AppendTextEquivFromTextContent(text, &txtValue);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // Temp var (txtValue) needed until CompressWhitespace built for nsAString
-    txtValue.CompressWhitespace();
-    aName.Assign(txtValue);
-    return NS_OK;
+  if (text && text->IsNodeOfType(nsINode::eTEXT)) {
+    nsTextEquivUtils::AppendTextEquivFromTextContent(text, &aName);
+    aName.CompressWhitespace();
   }
 
-  return NS_OK;
+  return eNameOK;
 }
 
 uint64_t
 HTMLSelectOptionAccessible::NativeState()
 {
   // As a HTMLSelectOptionAccessible we can have the following states:
   // SELECTABLE, SELECTED, FOCUSED, FOCUSABLE, OFFSCREEN
   // Upcall to Accessible, but skip HyperTextAccessible impl
--- a/accessible/src/html/HTMLSelectAccessible.h
+++ b/accessible/src/html/HTMLSelectAccessible.h
@@ -79,30 +79,33 @@ public:
   virtual ~HTMLSelectOptionAccessible() {}
 
   // nsIAccessible
   NS_IMETHOD DoAction(uint8_t index);
   NS_IMETHOD GetActionName(uint8_t aIndex, nsAString& aName);
   NS_IMETHOD SetSelected(bool aSelect);
 
   // Accessible
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual a11y::role NativeRole();
   virtual uint64_t NativeState();
   virtual uint64_t NativeInteractiveState() const;
 
   virtual int32_t GetLevelInternal();
   virtual void GetBoundsRect(nsRect& aTotalBounds, nsIFrame** aBoundingFrame);
 
   // ActionAccessible
   virtual uint8_t ActionCount();
 
   // Widgets
   virtual Accessible* ContainerWidget() const;
 
+protected:
+  // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
+
 private:
 
   /**
    * Return a select accessible the option belongs to if any.
    */
   Accessible* GetSelect() const
   {
     if (mParent && mParent->IsListControl()) {
--- a/accessible/src/html/HTMLTableAccessible.cpp
+++ b/accessible/src/html/HTMLTableAccessible.cpp
@@ -380,37 +380,37 @@ HTMLTableAccessible::NativeRole()
 }
 
 uint64_t
 HTMLTableAccessible::NativeState()
 {
   return Accessible::NativeState() | states::READONLY;
 }
 
-nsresult
-HTMLTableAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+HTMLTableAccessible::NativeName(nsString& aName)
 {
-  Accessible::GetNameInternal(aName);
+  Accessible::NativeName(aName);
   if (!aName.IsEmpty())
-    return NS_OK;
+    return eNameOK;
 
   // Use table caption as a name.
   Accessible* caption = Caption();
   if (caption) {
     nsIContent* captionContent = caption->GetContent();
     if (captionContent) {
       nsTextEquivUtils::AppendTextEquivFromContent(this, captionContent, &aName);
       if (!aName.IsEmpty())
-        return NS_OK;
+        return eNameOK;
     }
   }
 
   // If no caption then use summary as a name.
   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::summary, aName);
-  return NS_OK;
+  return eNameOK;
 }
 
 nsresult
 HTMLTableAccessible::GetAttributesInternal(nsIPersistentProperties* aAttributes)
 {
   nsresult rv = AccessibleWrap::GetAttributesInternal(aAttributes);
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/accessible/src/html/HTMLTableAccessible.h
+++ b/accessible/src/html/HTMLTableAccessible.h
@@ -138,17 +138,16 @@ public:
   virtual Accessible* AsAccessible() { return this; }
 
   // nsAccessNode
   virtual void Shutdown();
 
   // Accessible
   virtual TableAccessible* AsTable() { return this; }
   virtual void Description(nsString& aDescription);
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual a11y::role NativeRole();
   virtual uint64_t NativeState();
   virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
   virtual Relation RelationByType(uint32_t aRelationType);
 
   // HTMLTableAccessible
 
   /**
@@ -158,18 +157,18 @@ public:
                      nsIDOMElement* &aCell);
 
   /**
    * Return nsITableLayout for the frame of the accessible table.
    */
   nsITableLayout* GetTableLayout();
 
 protected:
-
   // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
   virtual void CacheChildren();
 
   // HTMLTableAccessible
 
   /**
    * Add row or column to selection.
    *
    * @param aIndex   [in] index of row or column to be selected
--- a/accessible/src/msaa/AccessibleWrap.cpp
+++ b/accessible/src/msaa/AccessibleWrap.cpp
@@ -259,17 +259,17 @@ AccessibleWrap::get_accName(
   if (xpAccessible->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   nsAutoString name;
   xpAccessible->Name(name);
 
   // The name was not provided, e.g. no alt attribute for an image. A screen
   // reader may choose to invent its own accessible name, e.g. from an image src
-  // attribute. Refer to NS_OK_EMPTY_NAME return value.
+  // attribute. Refer to eNoNameOnPurpose return value.
   if (name.IsVoid())
     return S_FALSE;
 
   *pszName = ::SysAllocStringLen(name.get(), name.Length());
   if (!*pszName)
     return E_OUTOFMEMORY;
 
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
--- a/accessible/src/xforms/nsXFormsAccessible.cpp
+++ b/accessible/src/xforms/nsXFormsAccessible.cpp
@@ -153,21 +153,22 @@ nsXFormsAccessible::NativelyUnavailable(
 {
   nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mContent));
 
   bool isRelevant = false;
   sXFormsService->IsRelevant(DOMNode, &isRelevant);
   return !isRelevant;
 }
 
-nsresult
-nsXFormsAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+nsXFormsAccessible::NativeName(nsString& aName)
 {
   // search the xforms:label element
-  return GetBoundChildElementValue(NS_LITERAL_STRING("label"), aName);
+  GetBoundChildElementValue(NS_LITERAL_STRING("label"), aName);
+  return eNameOK;
 }
 
 void
 nsXFormsAccessible::Description(nsString& aDescription)
 {
   nsTextEquivUtils::
     GetTextEquivFromIDRefs(this, nsGkAtoms::aria_describedby,
                            aDescription);
--- a/accessible/src/xforms/nsXFormsAccessible.h
+++ b/accessible/src/xforms/nsXFormsAccessible.h
@@ -41,29 +41,31 @@ public:
 
   // Accessible
   // Returns value of child xforms 'hint' element.
   virtual void Description(nsString& aDescription);
 
   // Returns value of instance node that xforms element is bound to.
   virtual void Value(nsString& aValue);
 
-  // Returns value of child xforms 'label' element.
-  virtual nsresult GetNameInternal(nsAString& aName);
-
   // Returns state of xforms element taking into account state of instance node
   // that it is bound to.
   virtual uint64_t NativeState();
   virtual bool NativelyUnavailable() const;
 
   // Denies accessible nodes in anonymous content of xforms element by
   // always returning false value.
   virtual bool CanHaveAnonChildren();
 
+
 protected:
+  // Accessible
+  // Returns value of child xforms 'label' element.
+  virtual mozilla::a11y::ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
+
   // Returns value of first child xforms element by tagname that is bound to
   // instance node.
   nsresult GetBoundChildElementValue(const nsAString& aTagName,
                                      nsAString& aValue);
 
   // Cache accessible child item/choices elements. For example, the method is
   // used for full appearance select/select1 elements or for their child choices
   // element. Note, those select/select1 elements that use native widget
--- a/accessible/src/xforms/nsXFormsFormControlsAccessible.cpp
+++ b/accessible/src/xforms/nsXFormsFormControlsAccessible.cpp
@@ -22,21 +22,21 @@ nsXFormsLabelAccessible::
 }
 
 role
 nsXFormsLabelAccessible::NativeRole()
 {
   return roles::LABEL;
 }
 
-nsresult
-nsXFormsLabelAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+nsXFormsLabelAccessible::NativeName(nsString& aName)
 {
   // XXX Correct name calculation for this, see bug 453594.
-  return NS_OK;
+  return eNameOK;
 }
 
 void
 nsXFormsLabelAccessible::Description(nsString& aDescription)
 {
   nsTextEquivUtils::
     GetTextEquivFromIDRefs(this, nsGkAtoms::aria_describedby,
                            aDescription);
--- a/accessible/src/xforms/nsXFormsFormControlsAccessible.h
+++ b/accessible/src/xforms/nsXFormsFormControlsAccessible.h
@@ -14,18 +14,21 @@
 
 class nsXFormsLabelAccessible : public nsXFormsAccessible
 {
 public:
   nsXFormsLabelAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // Accessible
   virtual void Description(nsString& aDescription);
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual mozilla::a11y::role NativeRole();
+
+protected:
+  // Accessible
+  virtual mozilla::a11y::ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
 };
 
 /**
  * Accessible object for xforms:output.
  */
 
 class nsXFormsOutputAccessible : public nsXFormsAccessible
 {
--- a/accessible/src/xforms/nsXFormsWidgetsAccessible.cpp
+++ b/accessible/src/xforms/nsXFormsWidgetsAccessible.cpp
@@ -128,22 +128,22 @@ nsXFormsComboboxPopupWidgetAccessible::N
 }
 
 uint64_t
 nsXFormsComboboxPopupWidgetAccessible::NativeInteractiveState() const
 {
   return NativelyUnavailable() ? states::UNAVAILABLE : states::FOCUSABLE;
 }
 
-nsresult
-nsXFormsComboboxPopupWidgetAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+nsXFormsComboboxPopupWidgetAccessible::NativeName(nsString& aName)
 {
   // Override nsXFormsAccessible::GetName() to prevent name calculation by
   // XForms rules.
-  return NS_OK;
+  return eNameOK;
 }
 
 void
 nsXFormsComboboxPopupWidgetAccessible::Description(nsString& aDescription)
 {
   aDescription.Truncate();
 }
 
--- a/accessible/src/xforms/nsXFormsWidgetsAccessible.h
+++ b/accessible/src/xforms/nsXFormsWidgetsAccessible.h
@@ -56,19 +56,19 @@ class nsXFormsComboboxPopupWidgetAccessi
 {
 public:
   nsXFormsComboboxPopupWidgetAccessible(nsIContent* aContent,
                                         DocAccessible* aDoc);
 
   // Accessible
   virtual void Description(nsString& aDescription);
   virtual void Value(nsString& aValue);
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual mozilla::a11y::role NativeRole();
   virtual uint64_t NativeState();
   virtual uint64_t NativeInteractiveState() const;
 
 protected:
   // Accessible
+  virtual mozilla::a11y::ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
   virtual void CacheChildren();
 };
 
 #endif
--- a/accessible/src/xul/XULElementAccessibles.cpp
+++ b/accessible/src/xul/XULElementAccessibles.cpp
@@ -27,23 +27,23 @@ using namespace mozilla::a11y;
 ////////////////////////////////////////////////////////////////////////////////
 
 XULLabelAccessible::
   XULLabelAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   HyperTextAccessibleWrap(aContent, aDoc)
 {
 }
 
-nsresult
-XULLabelAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+XULLabelAccessible::NativeName(nsString& aName)
 {
   // if the value attr doesn't exist, the screen reader must get the accessible text
   // from the accessible text interface or from the children
   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aName);
-  return NS_OK;
+  return eNameOK;
 }
 
 role
 XULLabelAccessible::NativeRole()
 {
   return roles::LABEL;
 }
 
@@ -116,24 +116,24 @@ NS_IMPL_ISUPPORTS_INHERITED1(XULLinkAcce
 void
 XULLinkAccessible::Value(nsString& aValue)
 {
   aValue.Truncate();
 
   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, aValue);
 }
 
-nsresult
-XULLinkAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+XULLinkAccessible::NativeName(nsString& aName)
 {
   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aName);
-  if (!aName.IsEmpty())
-    return NS_OK;
+  if (aName.IsEmpty())
+    nsTextEquivUtils::GetNameFromSubtree(this, aName);
 
-  return nsTextEquivUtils::GetNameFromSubtree(this, aName);
+  return eNameOK;
 }
 
 role
 XULLinkAccessible::NativeRole()
 {
   return roles::LINK;
 }
 
--- a/accessible/src/xul/XULElementAccessibles.h
+++ b/accessible/src/xul/XULElementAccessibles.h
@@ -16,20 +16,23 @@ namespace a11y {
  * Used for XUL description and label elements.
  */
 class XULLabelAccessible : public HyperTextAccessibleWrap
 {
 public:
   XULLabelAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // Accessible
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual a11y::role NativeRole();
   virtual uint64_t NativeState();
   virtual Relation RelationByType(uint32_t aRelationType);
+
+protected:
+  // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
 };
 
 /**
  * Used for XUL tooltip element.
  */
 class XULTooltipAccessible : public LeafAccessible
 {
 
@@ -50,30 +53,32 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIAccessible
   NS_IMETHOD GetActionName(uint8_t aIndex, nsAString& aName);
   NS_IMETHOD DoAction(uint8_t aIndex);
 
   // Accessible
   virtual void Value(nsString& aValue);
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual a11y::role NativeRole();
   virtual uint64_t NativeLinkState() const;
 
   // ActionAccessible
   virtual uint8_t ActionCount();
 
   // HyperLinkAccessible
   virtual bool IsLink();
   virtual uint32_t StartOffset();
   virtual uint32_t EndOffset();
   virtual already_AddRefed<nsIURI> AnchorURIAt(uint32_t aAnchorIndex);
 
 protected:
+  // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
+
   enum { eAction_Jump = 0 };
 
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/src/xul/XULFormControlAccessible.cpp
+++ b/accessible/src/xul/XULFormControlAccessible.cpp
@@ -408,26 +408,26 @@ XULGroupboxAccessible::
 }
 
 role
 XULGroupboxAccessible::NativeRole()
 {
   return roles::GROUPING;
 }
 
-nsresult
-XULGroupboxAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+XULGroupboxAccessible::NativeName(nsString& aName)
 {
   // XXX: we use the first related accessible only.
   Accessible* label =
     RelationByType(nsIAccessibleRelation::RELATION_LABELLED_BY).Next();
   if (label)
-    return label->GetName(aName);
+    return label->Name(aName);
 
-  return NS_OK;
+  return eNameOK;
 }
 
 Relation
 XULGroupboxAccessible::RelationByType(uint32_t aType)
 {
   Relation rel = AccessibleWrap::RelationByType(aType);
   if (aType != nsIAccessibleRelation::RELATION_LABELLED_BY)
     return rel;
@@ -634,26 +634,23 @@ XULToolbarAccessible::
 }
 
 role
 XULToolbarAccessible::NativeRole()
 {
   return roles::TOOLBAR;
 }
 
-nsresult
-XULToolbarAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+XULToolbarAccessible::NativeName(nsString& aName)
 {
-  nsAutoString name;
-  if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::toolbarname, name)) {
-    name.CompressWhitespace();
-    aName = name;
-  }
+  if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::toolbarname, aName))
+    aName.CompressWhitespace();
 
-  return NS_OK;
+  return eNameOK;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULToolbarAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 XULToolbarSeparatorAccessible::
--- a/accessible/src/xul/XULFormControlAccessible.h
+++ b/accessible/src/xul/XULFormControlAccessible.h
@@ -112,18 +112,21 @@ private:
  */
 class XULGroupboxAccessible : public AccessibleWrap
 {
 public:
   XULGroupboxAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // Accessible
   virtual mozilla::a11y::role NativeRole();
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual Relation RelationByType(uint32_t aRelationType);
+
+protected:
+  // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
 };
 
 /**
  * Used for XUL radio element (radio button).
  */
 class XULRadioButtonAccessible : public RadioButtonAccessible
 {
 
@@ -189,17 +192,20 @@ public:
  */
 class XULToolbarAccessible : public AccessibleWrap
 {
 public:
   XULToolbarAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // Accessible
   virtual mozilla::a11y::role NativeRole();
-  virtual nsresult GetNameInternal(nsAString& aName);
+
+protected:
+  // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
 };
 
 /**
  * Used for XUL toolbarseparator element.
  */
 class XULToolbarSeparatorAccessible : public LeafAccessible
 {
 public:
--- a/accessible/src/xul/XULListboxAccessible.cpp
+++ b/accessible/src/xul/XULListboxAccessible.cpp
@@ -617,28 +617,30 @@ XULListitemAccessible::Description(nsStr
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULListitemAccessible. nsIAccessible
 
 /**
   * If there is a Listcell as a child ( not anonymous ) use it, otherwise
   *   default to getting the name from GetXULName
   */
-nsresult
-XULListitemAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+XULListitemAccessible::NativeName(nsString& aName)
 {
   nsIContent* childContent = mContent->GetFirstChild();
   if (childContent) {
     if (childContent->NodeInfo()->Equals(nsGkAtoms::listcell,
                                          kNameSpaceID_XUL)) {
       childContent->GetAttr(kNameSpaceID_None, nsGkAtoms::label, aName);
-      return NS_OK;
+      return eNameOK;
     }
   }
-  return GetXULName(aName);
+
+  GetXULName(aName);
+  return eNameOK;
 }
 
 role
 XULListitemAccessible::NativeRole()
 {
   Accessible* list = GetListAccessible();
   if (!list) {
     NS_ERROR("No list accessible for listitem accessible!");
--- a/accessible/src/xul/XULListboxAccessible.h
+++ b/accessible/src/xul/XULListboxAccessible.h
@@ -126,26 +126,30 @@ public:
   virtual ~XULListitemAccessible() {}
 
   // nsIAccessible
   NS_IMETHOD GetActionName(uint8_t index, nsAString& aName);
   // Don't use XUL menuitems's description attribute
 
   // Accessible
   virtual void Description(nsString& aDesc);
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual a11y::role NativeRole();
   virtual uint64_t NativeState();
   virtual uint64_t NativeInteractiveState() const;
   virtual bool CanHaveAnonChildren();
 
   // Widgets
   virtual Accessible* ContainerWidget() const;
 
 protected:
+  // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
+
+  // XULListitemAccessible
+
   /**
    * Return listbox accessible for the listitem.
    */
   Accessible* GetListAccessible();
 
 private:
   bool mIsCheckbox;
 };
--- a/accessible/src/xul/XULMenuAccessible.cpp
+++ b/accessible/src/xul/XULMenuAccessible.cpp
@@ -129,21 +129,21 @@ XULMenuitemAccessible::NativeInteractive
       return states::UNAVAILABLE;
 
     return states::UNAVAILABLE | states::FOCUSABLE | states::SELECTABLE;
   }
 
   return states::FOCUSABLE | states::SELECTABLE;
 }
 
-nsresult
-XULMenuitemAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+XULMenuitemAccessible::NativeName(nsString& aName)
 {
   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::label, aName);
-  return NS_OK;
+  return eNameOK;
 }
 
 void
 XULMenuitemAccessible::Description(nsString& aDescription)
 {
   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::description,
                     aDescription);
 }
@@ -391,20 +391,20 @@ XULMenuSeparatorAccessible::
 uint64_t
 XULMenuSeparatorAccessible::NativeState()
 {
   // Isn't focusable, but can be offscreen/invisible -- only copy those states
   return XULMenuitemAccessible::NativeState() &
     (states::OFFSCREEN | states::INVISIBLE);
 }
 
-nsresult
-XULMenuSeparatorAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+XULMenuSeparatorAccessible::NativeName(nsString& aName)
 {
-  return NS_OK;
+  return eNameOK;
 }
 
 role
 XULMenuSeparatorAccessible::NativeRole()
 {
   return roles::SEPARATOR;
 }
 
@@ -464,26 +464,26 @@ XULMenupopupAccessible::NativeState()
 #endif
 
   if (state & states::INVISIBLE)
     state |= states::OFFSCREEN | states::COLLAPSED;
 
   return state;
 }
 
-nsresult
-XULMenupopupAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+XULMenupopupAccessible::NativeName(nsString& aName)
 {
-  nsIContent *content = mContent;
+  nsIContent* content = mContent;
   while (content && aName.IsEmpty()) {
     content->GetAttr(kNameSpaceID_None, nsGkAtoms::label, aName);
     content = content->GetParent();
   }
 
-  return NS_OK;
+  return eNameOK;
 }
 
 role
 XULMenupopupAccessible::NativeRole()
 {
   // If accessible is not bound to the tree (this happens while children are
   // cached) return general role.
   if (mParent) {
@@ -567,21 +567,21 @@ XULMenupopupAccessible::ContainerWidget(
 ////////////////////////////////////////////////////////////////////////////////
 
 XULMenubarAccessible::
   XULMenubarAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   AccessibleWrap(aContent, aDoc)
 {
 }
 
-nsresult
-XULMenubarAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+XULMenubarAccessible::NativeName(nsString& aName)
 {
   aName.AssignLiteral("Application");
-  return NS_OK;
+  return eNameOK;
 }
 
 role
 XULMenubarAccessible::NativeRole()
 {
   return roles::MENUBAR;
 }
 
--- a/accessible/src/xul/XULMenuAccessible.h
+++ b/accessible/src/xul/XULMenuAccessible.h
@@ -24,93 +24,105 @@ public:
   XULMenuitemAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // nsIAccessible
   NS_IMETHOD DoAction(uint8_t index);
   NS_IMETHOD GetActionName(uint8_t aIndex, nsAString& aName);
 
   // Accessible
   virtual void Description(nsString& aDescription);
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual a11y::role NativeRole();
   virtual uint64_t NativeState();
   virtual uint64_t NativeInteractiveState() const;
   virtual int32_t GetLevelInternal();
 
   virtual bool CanHaveAnonChildren();
 
   // ActionAccessible
   virtual uint8_t ActionCount();
   virtual KeyBinding AccessKey() const;
   virtual KeyBinding KeyboardShortcut() const;
 
   // Widgets
   virtual bool IsActiveWidget() const;
   virtual bool AreItemsOperable() const;
   virtual Accessible* ContainerWidget() const;
+
+protected:
+  // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
 };
 
 /**
  * Used for XUL menuseparator element.
  */
 class XULMenuSeparatorAccessible : public XULMenuitemAccessible
 {
 public:
   XULMenuSeparatorAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // nsIAccessible
   NS_IMETHOD DoAction(uint8_t index);
   NS_IMETHOD GetActionName(uint8_t aIndex, nsAString& aName);
 
   // Accessible
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual a11y::role NativeRole();
   virtual uint64_t NativeState();
 
   // ActionAccessible
   virtual uint8_t ActionCount();
+
+protected:
+  // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
 };
 
 
 /**
  * Used for XUL menupopup and panel.
  */
 class XULMenupopupAccessible : public XULSelectControlAccessible
 {
 public:
   XULMenupopupAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // Accessible
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual a11y::role NativeRole();
   virtual uint64_t NativeState();
 
   // Widgets
   virtual bool IsWidget() const;
   virtual bool IsActiveWidget() const;
   virtual bool AreItemsOperable() const;
 
   virtual Accessible* ContainerWidget() const;
+
+protected:
+  // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
 };
 
 /**
  * Used for XUL menubar element.
  */
 class XULMenubarAccessible : public AccessibleWrap
 {
 public:
   XULMenubarAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // Accessible
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual a11y::role NativeRole();
 
   // Widget
   virtual bool IsActiveWidget() const;
   virtual bool AreItemsOperable() const;
   virtual Accessible* CurrentItem();
   virtual void SetCurrentItem(Accessible* aItem);
+
+protected:
+  // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/src/xul/XULTabAccessible.cpp
+++ b/accessible/src/xul/XULTabAccessible.cpp
@@ -149,21 +149,21 @@ XULTabsAccessible::ActionCount()
 }
 
 void
 XULTabsAccessible::Value(nsString& aValue)
 {
   aValue.Truncate();
 }
 
-nsresult
-XULTabsAccessible::GetNameInternal(nsAString& aName)
+ENameValueFlag
+XULTabsAccessible::NativeName(nsString& aName)
 {
   // no name
-  return NS_OK;
+  return eNameOK;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULDeckAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 role
--- a/accessible/src/xul/XULTabAccessible.h
+++ b/accessible/src/xul/XULTabAccessible.h
@@ -43,21 +43,24 @@ public:
  */
 class XULTabsAccessible : public XULSelectControlAccessible
 {
 public:
   XULTabsAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // Accessible
   virtual void Value(nsString& aValue);
-  virtual nsresult GetNameInternal(nsAString& aName);
   virtual a11y::role NativeRole();
 
   // ActionAccessible
   virtual uint8_t ActionCount();
+
+protected:
+  // Accessible
+  virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
 };
 
 
 /**
  * A container of tab panels, xul:tabpanels element.
  */
 class XULDeckAccessible : public AccessibleWrap
 {
--- a/configure.in
+++ b/configure.in
@@ -3779,23 +3779,16 @@ if test "$MALLOC_H" != ""; then
    AC_DEFINE_UNQUOTED(MALLOC_H, <$MALLOC_H>)
 fi
 
 MOZ_ALLOCATING_FUNCS="strndup posix_memalign memalign valloc"
 AC_CHECK_FUNCS(strndup posix_memalign memalign valloc)
 
 dnl See if compiler supports some gcc-style attributes
 
-AC_CACHE_CHECK(for __attribute__((always_inline)),
-               ac_cv_attribute_always_inline,
-               [AC_TRY_COMPILE([inline void f(void) __attribute__((always_inline));],
-                               [],
-                               ac_cv_attribute_always_inline=yes,
-                               ac_cv_attribute_always_inline=no)])
-
 AC_CACHE_CHECK(for __attribute__((malloc)),
                ac_cv_attribute_malloc,
                [AC_TRY_COMPILE([void* f(int) __attribute__((malloc));],
                                [],
                                ac_cv_attribute_malloc=yes,
                                ac_cv_attribute_malloc=no)])
 
 AC_CACHE_CHECK(for __attribute__((warn_unused_result)),
@@ -3837,22 +3830,16 @@ fi
 
 dnl Mozilla specific options
 dnl ========================================================
 dnl The macros used for command line options
 dnl are defined in build/autoconf/altoptions.m4.
 
 dnl If the compiler supports these attributes, define them as
 dnl convenience macros.
-if test "$ac_cv_attribute_always_inline" = yes ; then
-  AC_DEFINE(NS_ALWAYS_INLINE, [__attribute__((always_inline))])
-else
-  AC_DEFINE(NS_ALWAYS_INLINE,)
-fi
-
 if test "$ac_cv_attribute_malloc" = yes ; then
   AC_DEFINE(NS_ATTR_MALLOC, [__attribute__((malloc))])
 else
   AC_DEFINE(NS_ATTR_MALLOC,)
 fi
 
 if test "$ac_cv_attribute_warn_unused" = yes ; then
   AC_DEFINE(NS_WARN_UNUSED_RESULT, [__attribute__((warn_unused_result))])
@@ -7147,16 +7134,18 @@ if test -n "$_WRAP_MALLOC"; then
     if test -n "$GNU_CC"; then
         WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=malloc,--wrap=calloc,--wrap=valloc,--wrap=free,--wrap=realloc,--wrap=memalign"
         WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=__builtin_new,--wrap=__builtin_vec_new,--wrap=__builtin_delete,--wrap=__builtin_vec_delete"
         WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=strdup,--wrap=strndup"
         WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=posix_memalign,--wrap=malloc_usable_size"
         dnl Wrap operator new and operator delete on Android.
         if test "$OS_TARGET" = "Android"; then
             WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=_Znwj,--wrap=_Znaj,--wrap=_ZdlPv,--wrap=_ZdaPv"
+            dnl Wrap the nothrow variants too.
+            WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=_ZnwjRKSt9nothrow_t,--wrap=_ZnajRKSt9nothrow_t,--wrap=_ZdlPvRKSt9nothrow_t,--wrap=_ZdaPvRKSt9nothrow_t"
         fi
     else
         AC_MSG_ERROR([--enable-wrap-malloc is not supported for non-GNU toolchains])
     fi
 fi
 
 dnl ========================================================
 dnl = Location of malloc wrapper lib
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1290,39 +1290,48 @@ public:
    * @param aScriptObjectHolder the object that holds JS objects that we want to
    *                            drop
    */
   static nsresult DropJSObjects(void* aScriptObjectHolder);
 
 #ifdef DEBUG
   static bool AreJSObjectsHeld(void* aScriptObjectHolder); 
 
-  static void CheckCCWrapperTraversal(nsISupports* aScriptObjectHolder,
-                                      nsWrapperCache* aCache);
+  static void CheckCCWrapperTraversal(void* aScriptObjectHolder,
+                                      nsWrapperCache* aCache,
+                                      nsScriptObjectTracer* aTracer);
 #endif
 
   static void PreserveWrapper(nsISupports* aScriptObjectHolder,
                               nsWrapperCache* aCache)
   {
     if (!aCache->PreservingWrapper()) {
       nsISupports *ccISupports;
       aScriptObjectHolder->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
                                           reinterpret_cast<void**>(&ccISupports));
       MOZ_ASSERT(ccISupports);
       nsXPCOMCycleCollectionParticipant* participant;
       CallQueryInterface(ccISupports, &participant);
-      HoldJSObjects(ccISupports, participant);
+      PreserveWrapper(ccISupports, aCache, participant);
+    }
+  }
+  static void PreserveWrapper(void* aScriptObjectHolder,
+                              nsWrapperCache* aCache,
+                              nsScriptObjectTracer* aTracer)
+  {
+    if (!aCache->PreservingWrapper()) {
+      HoldJSObjects(aScriptObjectHolder, aTracer);
       aCache->SetPreservingWrapper(true);
 #ifdef DEBUG
       // Make sure the cycle collector will be able to traverse to the wrapper.
-      CheckCCWrapperTraversal(ccISupports, aCache);
+      CheckCCWrapperTraversal(aScriptObjectHolder, aCache, aTracer);
 #endif
     }
   }
-  static void ReleaseWrapper(nsISupports* aScriptObjectHolder,
+  static void ReleaseWrapper(void* aScriptObjectHolder,
                              nsWrapperCache* aCache);
   static void TraceWrapper(nsWrapperCache* aCache, TraceCallback aCallback,
                            void *aClosure);
 
   /*
    * Notify when the first XUL menu is opened and when the all XUL menus are
    * closed. At opening, aInstalling should be TRUE, otherwise, it should be
    * FALSE.
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -273,17 +273,17 @@ public:
   {
   }
 
   ~EventListenerManagerMapEntry()
   {
     NS_ASSERTION(!mListenerManager, "caller must release and disconnect ELM");
   }
 
-private:
+protected:          // declared protected to silence clang warnings
   const void *mKey; // must be first, to look like PLDHashEntryStub
 
 public:
   nsRefPtr<nsEventListenerManager> mListenerManager;
 };
 
 static bool
 EventListenerManagerHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
@@ -6390,36 +6390,34 @@ DebugWrapperTraceCallback(void *p, const
 {
   DebugWrapperTraversalCallback* callback =
     static_cast<DebugWrapperTraversalCallback*>(closure);
   callback->NoteJSChild(p);
 }
 
 // static
 void
-nsContentUtils::CheckCCWrapperTraversal(nsISupports* aScriptObjectHolder,
-                                        nsWrapperCache* aCache)
+nsContentUtils::CheckCCWrapperTraversal(void* aScriptObjectHolder,
+                                        nsWrapperCache* aCache,
+                                        nsScriptObjectTracer* aTracer)
 {
   JSObject* wrapper = aCache->GetWrapper();
   if (!wrapper) {
     return;
   }
 
-  nsXPCOMCycleCollectionParticipant* participant;
-  CallQueryInterface(aScriptObjectHolder, &participant);
-
   DebugWrapperTraversalCallback callback(wrapper);
 
-  participant->Traverse(aScriptObjectHolder, callback);
+  aTracer->Traverse(aScriptObjectHolder, callback);
   NS_ASSERTION(callback.mFound,
                "Cycle collection participant didn't traverse to preserved "
                "wrapper! This will probably crash.");
 
   callback.mFound = false;
-  participant->Trace(aScriptObjectHolder, DebugWrapperTraceCallback, &callback);
+  aTracer->Trace(aScriptObjectHolder, DebugWrapperTraceCallback, &callback);
   NS_ASSERTION(callback.mFound,
                "Cycle collection participant didn't trace preserved wrapper! "
                "This will probably crash.");
 }
 #endif
 
 // static
 bool
@@ -6928,17 +6926,17 @@ nsContentUtils::GetRootDocument(nsIDocum
   while (doc->GetParentDocument()) {
     doc = doc->GetParentDocument();
   }
   return doc;
 }
 
 // static
 void
-nsContentUtils::ReleaseWrapper(nsISupports* aScriptObjectHolder,
+nsContentUtils::ReleaseWrapper(void* aScriptObjectHolder,
                                nsWrapperCache* aCache)
 {
   if (aCache->PreservingWrapper()) {
     // PreserveWrapper puts new DOM bindings in the JS holders hash, but they
     // can also be in the DOM expando hash, so we need to try to remove them
     // from both here.
     JSObject* obj = aCache->GetWrapperPreserveColor();
     if (aCache->IsDOMBinding() && obj) {
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -4936,16 +4936,17 @@ nsDocument::EnableStyleSheetsForSetInter
   }
   EndUpdate(UPDATE_STYLE);
 }
 
 NS_IMETHODIMP
 nsDocument::GetCharacterSet(nsAString& aCharacterSet)
 {
   CopyASCIItoUTF16(GetDocumentCharacterSet(), aCharacterSet);
+  ToLowerCase(aCharacterSet);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::ImportNode(nsIDOMNode* aImportedNode,
                        bool aDeep,
                        uint8_t aArgc,
                        nsIDOMNode** aResult)
@@ -6070,17 +6071,45 @@ nsDocument::GetMozSyntheticDocument(bool
 NS_IMETHODIMP
 nsDocument::GetDocumentURI(nsAString& aDocumentURI)
 {
   if (mDocumentURI) {
     nsAutoCString uri;
     mDocumentURI->GetSpec(uri);
     CopyUTF8toUTF16(uri, aDocumentURI);
   } else {
-    SetDOMStringToNull(aDocumentURI);
+    aDocumentURI.Truncate();
+  }
+
+  return NS_OK;
+}
+
+// Alias of above
+NS_IMETHODIMP
+nsDocument::GetURL(nsAString& aURL)
+{
+  return GetDocumentURI(aURL);
+}
+
+// readonly attribute DOMString compatMode;
+// Returns "BackCompat" if we are in quirks mode, "CSS1Compat" if we are
+// in almost standards or full standards mode. See bug 105640.  This was
+// implemented to match MSIE's compatMode property.
+NS_IMETHODIMP
+nsDocument::GetCompatMode(nsAString& aCompatMode)
+{
+  NS_ASSERTION(mCompatMode == eCompatibility_NavQuirks ||
+               mCompatMode == eCompatibility_AlmostStandards ||
+               mCompatMode == eCompatibility_FullStandards,
+               "mCompatMode is neither quirks nor strict for this document");
+
+  if (mCompatMode == eCompatibility_NavQuirks) {
+    aCompatMode.AssignLiteral("BackCompat");
+  } else {
+    aCompatMode.AssignLiteral("CSS1Compat");
   }
 
   return NS_OK;
 }
 
 static void BlastSubtreeToPieces(nsINode *aNode);
 
 PLDHashOperator
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -849,18 +849,20 @@ nsObjectLoadingContent::OnStopRequest(ns
 
   if (aRequest != mChannel) {
     return NS_BINDING_ABORTED;
   }
 
   mChannel = nullptr;
 
   if (mFinalListener) {
-    mFinalListener->OnStopRequest(aRequest, aContext, aStatusCode);
+    // This may re-enter in the case of plugin listeners
+    nsCOMPtr<nsIStreamListener> listenerGrip(mFinalListener);
     mFinalListener = nullptr;
+    listenerGrip->OnStopRequest(aRequest, aContext, aStatusCode);
   }
 
   // Return value doesn't matter
   return NS_OK;
 }
 
 
 // nsIStreamListener
@@ -872,18 +874,20 @@ nsObjectLoadingContent::OnDataAvailable(
 {
   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
 
   if (aRequest != mChannel) {
     return NS_BINDING_ABORTED;
   }
 
   if (mFinalListener) {
-    return mFinalListener->OnDataAvailable(aRequest, aContext, aInputStream,
-                                           aOffset, aCount);
+    // This may re-enter in the case of plugin listeners
+    nsCOMPtr<nsIStreamListener> listenerGrip(mFinalListener);
+    return listenerGrip->OnDataAvailable(aRequest, aContext, aInputStream,
+                                         aOffset, aCount);
   }
 
   // We shouldn't have a connected channel with no final listener
   NS_NOTREACHED("Got data for channel with no connected final listener");
   mChannel = nullptr;
 
   return NS_ERROR_UNEXPECTED;
 }
@@ -1673,37 +1677,31 @@ nsObjectLoadingContent::LoadObject(bool 
     NS_NOTREACHED("Trying to load with bad channel state");
     rv = NS_ERROR_UNEXPECTED;
     return NS_OK;
   }
 
   ///
   /// Attempt to load new type
   ///
-  
-  // Remove blocker on entering into instantiate
-  mIsLoading = false;
-  
+
+  // We don't set mFinalListener until OnStartRequest has been called, to
+  // prevent re-entry ugliness with CloseChannel()
+  nsCOMPtr<nsIStreamListener> finalListener;
   switch (mType) {
     case eType_Image:
       if (!mChannel) {
         // We have a LoadImage() call, but UpdateObjectParameters requires a
         // channel for images, so this is not a valid state.
         NS_NOTREACHED("Attempting to load image without a channel?");
         rv = NS_ERROR_UNEXPECTED;
         break;
       }
-      rv = LoadImageWithChannel(mChannel, getter_AddRefs(mFinalListener));
-      if (mFinalListener) {
-        // Note that LoadObject is called from mChannel's OnStartRequest
-        // when loading with a channel
-        mSrcStreamLoading = true;
-        rv = mFinalListener->OnStartRequest(mChannel, nullptr);
-        mSrcStreamLoading = false;
-      }
+      rv = LoadImageWithChannel(mChannel, getter_AddRefs(finalListener));
+      // finalListener will receive OnStartRequest below
     break;
     case eType_Plugin:
     {
       if (mChannel) {
         nsRefPtr<nsPluginHost> pluginHost =
           already_AddRefed<nsPluginHost>(nsPluginHost::GetInst());
         if (!pluginHost) {
           NS_NOTREACHED("No pluginHost");
@@ -1720,28 +1718,18 @@ nsObjectLoadingContent::LoadObject(bool 
           // We're un-rendered, and can't instantiate a plugin. HasNewFrame will
           // re-start us when we can proceed.
           LOG(("OBJLC [%p]: Aborting load - plugin-type, but no frame", this));
           CloseChannel();
           break;
         }
         
         rv = pluginHost->NewEmbeddedPluginStreamListener(mURI, this, nullptr,
-                                                         getter_AddRefs(mFinalListener));
-        if (NS_SUCCEEDED(rv)) {
-          // Note that LoadObject is called from mChannel's OnStartRequest
-          // when loading with a channel
-
-          mSrcStreamLoading = true;
-          rv = mFinalListener->OnStartRequest(mChannel, nullptr);
-          mSrcStreamLoading = false;
-          if (NS_SUCCEEDED(rv)) {
-            NotifyContentObjectWrapper();
-          }
-        }
+                                                         getter_AddRefs(finalListener));
+        // finalListener will receive OnStartRequest below
       } else {
         rv = AsyncStartPluginInstance();
       }
     }
     break;
     case eType_Document:
     {
       if (!mChannel) {
@@ -1787,92 +1775,110 @@ nsObjectLoadingContent::LoadObject(bool 
       nsCOMPtr<nsIURILoader>
         uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID, &rv));
       if (NS_FAILED(rv)) {
         NS_NOTREACHED("Failed to get uriLoader service");
         mType = eType_Null;
         break;
       }
       rv = uriLoader->OpenChannel(mChannel, nsIURILoader::DONT_RETARGET, req,
-                                  getter_AddRefs(mFinalListener));
-      if (NS_SUCCEEDED(rv)) {
-        // Note that LoadObject is called from mChannel's OnStartRequest
-        // when loading with a channel
-        mSrcStreamLoading = true;
-        rv = mFinalListener->OnStartRequest(mChannel, nullptr);
-        mSrcStreamLoading = false;
-      }
+                                  getter_AddRefs(finalListener));
+      // finalListener will receive OnStartRequest below
     }
     break;
     case eType_Loading:
       // If our type remains Loading, we need a channel to proceed
       rv = OpenChannel();
       if (NS_FAILED(rv)) {
         LOG(("OBJLC [%p]: OpenChannel returned failure (%u)", this, rv));
       }
     break;
     case eType_Null:
       // Handled below, silence compiler warnings
     break;
   };
 
+  //
+  // Loaded, handle notifications and fallback
+  //
   if (NS_FAILED(rv)) {
     // If we failed in the loading hunk above, switch to fallback
     LOG(("OBJLC [%p]: Loading failed, switching to fallback", this));
     mType = eType_Null;
   }
 
-  // Switching to fallback state
+  // If we didn't load anything, handle switching to fallback state
   if (mType == eType_Null) {
     LOG(("OBJLC [%p]: Loading fallback, type %u", this, fallbackType));
     NS_ASSERTION(!mFrameLoader && !mInstanceOwner,
                  "switched to type null but also loaded something");
 
     if (mChannel) {
       // If we were loading with a channel but then failed over, throw it away
-      // (this also closes mFinalListener)
       CloseChannel();
     }
 
     // Don't notify or send events - we'll handle those ourselves
     // (so really this is just setting mFallbackType)
     LoadFallback(fallbackType, false);
   }
 
   // Notify of our final state if we haven't already
   NotifyStateChanged(oldType, oldState, false, aNotify);
-
+  
   if (mType == eType_Null && !mContentType.IsEmpty() &&
       mFallbackType != eFallbackAlternate) {
     // if we have a content type and are not showing alternate
     // content, fire a pluginerror to trigger (we stopped LoadFallback
     // from doing so above, it doesn't know of our old state)
     FirePluginError(mFallbackType);
   }
 
+  //
+  // Pass load on to finalListener if loading with a channel
+  //
+
+  // If we re-entered and loaded something else, that load will have cleaned up
+  // our our listener.
+  if (!mIsLoading) {
+    LOG(("OBJLC [%p]: Re-entered before dispatching to final listener", this));
+  } else if (finalListener) {
+    NS_ASSERTION(mType != eType_Null && mType != eType_Loading,
+                 "We should not have a final listener with a non-loaded type");
+    // Note that we always enter into LoadObject() from ::OnStartRequest when
+    // loading with a channel.
+    mSrcStreamLoading = true;
+    // Remove blocker on entering into instantiate
+    // (this is otherwise unset by the stack class)
+    mIsLoading = false;
+    mFinalListener = finalListener;
+    finalListener->OnStartRequest(mChannel, nullptr);
+    mSrcStreamLoading = false;
+  }
+
   return NS_OK;
 }
 
+// This call can re-enter when dealing with plugin listeners
 nsresult
 nsObjectLoadingContent::CloseChannel()
 {
   if (mChannel) {
     LOG(("OBJLC [%p]: Closing channel\n", this));
-    // These three statements are carefully ordered:
-    // - onStopRequest should get a channel whose status is the same as the
-    //   status argument
-    // - onStopRequest must get a non-null channel
-    mChannel->Cancel(NS_BINDING_ABORTED);
-    if (mFinalListener) {
-      // NOTE mFinalListener is only created when we load with a channel, which
-      //      LoadObject() requires come from a OnStartRequest call
-      mFinalListener->OnStopRequest(mChannel, nullptr, NS_BINDING_ABORTED);
-      mFinalListener = nullptr;
+    // Null the values before potentially-reentering, and ensure they survive
+    // the call
+    nsCOMPtr<nsIChannel> channelGrip(mChannel);
+    nsCOMPtr<nsIStreamListener> listenerGrip(mFinalListener);
+    mChannel = nullptr;
+    mFinalListener = nullptr;
+    channelGrip->Cancel(NS_BINDING_ABORTED);
+    if (listenerGrip) {
+      // mFinalListener is only set by LoadObject after OnStartRequest
+      listenerGrip->OnStopRequest(channelGrip, nullptr, NS_BINDING_ABORTED);
     }
-    mChannel = nullptr;
   }
   return NS_OK;
 }
 
 nsresult
 nsObjectLoadingContent::OpenChannel()
 {
   nsCOMPtr<nsIContent> thisContent = 
@@ -1968,17 +1974,21 @@ nsObjectLoadingContent::UnloadObject(boo
   // state
   CancelImageRequests(false);
   if (mFrameLoader) {
     mFrameLoader->Destroy();
     mFrameLoader = nullptr;
   }
 
   if (aResetState) {
-    CloseChannel();
+    if (mType != eType_Plugin) {
+      // This can re-enter when dealing with plugins, and StopPluginInstance
+      // will handle it
+      CloseChannel();
+    }
     mChannelLoaded = false;
     mType = eType_Loading;
     mURI = mOriginalURI = mBaseURI = nullptr;
     mContentType.Truncate();
     mOriginalContentType.Truncate();
   }
 
   // This call should be last as it may re-enter
--- a/content/base/test/test_XHRSendData.html
+++ b/content/base/test/test_XHRSendData.html
@@ -25,17 +25,17 @@ var gen = runTests();
 function continueTest() { gen.next(); }
 
 function runTests() {
 
 xhr = new XMLHttpRequest();
 xhr.open("GET", "file_XHRSendData_doc.xml", false);
 xhr.send();
 testDoc1 = xhr.responseXML;
-is(testDoc1.inputEncoding, "ISO-8859-1", "wrong encoding");
+is(testDoc1.inputEncoding, "iso-8859-1", "wrong encoding");
 
 testDoc2 = document.implementation.createDocument("", "", null);
 testDoc2.appendChild(testDoc2.createComment(" doc 2 "));
 testDoc2.appendChild(testDoc2.createElement("res"));
 testDoc2.documentElement.appendChild(testDoc2.createTextNode("text"));
 is(testDoc2.inputEncoding, null, "wrong encoding");
 
 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
@@ -116,27 +116,27 @@ tests = [{ body: null,
          },
          { body: "hi",
            contentType: "foo/bar; charset=uTf-8",
            resBody: "hi",
            resContentType: "foo/bar; charset=uTf-8",
          },
          { body: testDoc1,
            resBody: "<!-- comment -->\n<out>hi</out>",
-           resContentType: "application/xml; charset=ISO-8859-1",
+           resContentType: "application/xml; charset=iso-8859-1",
          },
          { body: testDoc1,
            contentType: "foo/bar",
            resBody: "<!-- comment -->\n<out>hi</out>",
-           resContentType: "foo/bar; charset=ISO-8859-1",
+           resContentType: "foo/bar; charset=iso-8859-1",
          },
          { body: testDoc1,
            contentType: "foo/bar; charset=ascii; baz=bin",
            resBody: "<!-- comment -->\n<out>hi</out>",
-           resContentType: "foo/bar; charset=ISO-8859-1; baz=bin",
+           resContentType: "foo/bar; charset=iso-8859-1; baz=bin",
          },
          { body: testDoc1,
            contentType: "foo/bar; charset=IsO-8859-1",
            resBody: "<!-- comment -->\n<out>hi</out>",
            resContentType: "foo/bar; charset=IsO-8859-1",
          },
          { body: testDoc2,
            resBody: "<!-- doc 2 -->\n<res>text</res>",
--- a/content/base/test/test_bug431701.html
+++ b/content/base/test/test_bug431701.html
@@ -57,27 +57,27 @@ function xhrDoc(idx) {
     return xhr.responseXML;
   };
 }
 
 // Each row has the document getter function, then the characterSet,
 // inputEncoding expected for that document.
 
 var tests = [
- [ frameDoc("one"), "ISO-8859-1", "ISO-8859-1" ],
- [ frameDoc("two"), "UTF-8", "UTF-8" ],
- [ frameDoc("three"), "ISO-8859-1", "ISO-8859-1" ],
- [ frameDoc("four"), "UTF-8", "UTF-8" ],
- [ frameDoc("five"), "UTF-8", "UTF-8" ],
- [ frameDoc("six"), "UTF-8", "UTF-8" ],
- [ frameDoc("seven"), "ISO-8859-1", "ISO-8859-1" ],
- [ createDoc, "UTF-8", null ],
- [ xhrDoc(4), "UTF-8", "UTF-8" ],
- [ xhrDoc(5), "UTF-8", "UTF-8" ],
- [ xhrDoc(6), "ISO-8859-1", "ISO-8859-1" ],
+ [ frameDoc("one"), "iso-8859-1", "iso-8859-1" ],
+ [ frameDoc("two"), "utf-8", "utf-8" ],
+ [ frameDoc("three"), "iso-8859-1", "iso-8859-1" ],
+ [ frameDoc("four"), "utf-8", "utf-8" ],
+ [ frameDoc("five"), "utf-8", "utf-8" ],
+ [ frameDoc("six"), "utf-8", "utf-8" ],
+ [ frameDoc("seven"), "iso-8859-1", "iso-8859-1" ],
+ [ createDoc, "utf-8", null ],
+ [ xhrDoc(4), "utf-8", "utf-8" ],
+ [ xhrDoc(5), "utf-8", "utf-8" ],
+ [ xhrDoc(6), "iso-8859-1", "iso-8859-1" ],
 ];
 
 function doTest(idx) {
   var [docGetter, expectedCharacterSet,
        expectedInputEncoding] = tests[idx];
   var doc = docGetter();
 
   // Have to be careful here to catch null vs ""
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -3257,18 +3257,18 @@ nsEventStateManager::PostHandleEvent(nsP
         if (mDocument && fm) {
           nsCOMPtr<nsIDOMWindow> currentWindow;
           fm->GetFocusedWindow(getter_AddRefs(currentWindow));
           if (currentWindow && mDocument->GetWindow() &&
               currentWindow != mDocument->GetWindow() &&
               !nsContentUtils::IsChromeDoc(mDocument)) {
             nsCOMPtr<nsIDOMWindow> currentTop;
             nsCOMPtr<nsIDOMWindow> newTop;
-            currentWindow->GetScriptableTop(getter_AddRefs(currentTop));
-            mDocument->GetWindow()->GetScriptableTop(getter_AddRefs(newTop));
+            currentWindow->GetTop(getter_AddRefs(currentTop));
+            mDocument->GetWindow()->GetTop(getter_AddRefs(newTop));
             nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(currentWindow);
             nsCOMPtr<nsIDocument> currentDoc = do_QueryInterface(win->GetExtantDocument());
             if (nsContentUtils::IsChromeDoc(currentDoc) ||
                 (currentTop && newTop && currentTop != newTop)) {
               fm->SetFocusedWindow(mDocument->GetWindow());
             }
           }
         }
index 3acaad9e0c25cbb16dd60fcbe6facf1c4aa8ef1f..f0b4f1fa527b112a4666854f77c73258064ce9da
GIT binary patch
literal 2692
zc$~df+iuf95S{0I#nu9vqGGE;AZQaRpsjdlMWq%Yo~o_w5JTcvvC~peznMP(&dl!G
z>%^r6A!ON^z08@jvu9`X<0lPhjrQm*y{1$8K*zLCir&CJqC<K?J&cd3qA5*mYmFY^
z=}B)z1(mc-5uS5e&`0`88D>sMQwX0~t39JRW<>B9!@i_5>l0FpZ$`U#6B^P}+M*|T
zp5yIFG{++aP9iOZXMhMPIB3{0Mm6wD=^0W0<cdb{eFnSns1Tz9pA>zk_?BoX%wukf
zUI`!7VlV(>-^(GDh&e}pAqW*+!Ad2vhE-s8h8bFXXOsiw6IvH|ea`^CC0em~awNm4
zgnfcJQ$b2=uHC&MuuJ$GZp+VVZr;K3pw7)e_N3v|tdZA{)8|_;6h>0a=KfN0F%f3G
zW2s%GpCMl57g<e=S>4RXf;qZ#UaC454l}a4iCW4TKy@?NSGJ{vn-*=lwXrf;v%L0T
ziOc`dJ@3m=3+HBaYP*sGV+JX}H$%KaJg>YHVD{DMeG1#0ps{3RNb5ES>m51q+kqEp
zBrT1#IHhxM4(kMbSvSWRWxuelByB#16DzHdQ|oJGz19kI%7HYs{fV3{E&Y6|Ch#>Q
zn!dy0{^$?ljAca$TKP(>vnBnXb)fT3xV*OeGxX0bnvZ*PPOJJ{`o2!hg|&E(FFdbU
zvR}yxTxD@*aa9xB!i7CjZ$C@~gX~l_7v2pwbIt-g{;%pFqxCTQ5RbZJZB{Zn63_0s
zc!@Y%yAK3qA4+nJOfRb;latw}4cZYTEjl=a2V48#YBJgfmj$dw>FlHEo6Q~L^x-kX
zjD_r2ZtIcJjyWSKtP|PsP53nT)D~72SPqPK4_HPC8&X4Z@HUJTva4?4((tK7*`@IC
z_3>WTo=8Os1>4`H&6SFL`P=znT_Z#JH7bi?^*znF%IEK)UlmrP{{3@X4ce_M$Pn*+
z{Qr53?@MSRr3W1+e%QM4HafTlh{lz40rW&}4K3PHlKHvhB^FJ)$V%>*gqH7DW$y}y
zbZ${5qGncBB4=$@kF~k&c-*?r#i&F1Jo{QsK%>8r)n5rN=fKJ29GLmn`0aK6doWdM
O?$xaJog4Z8DSrX&YNiGN
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -997,30 +997,16 @@ nsHTMLDocument::SetDomain(const nsAStrin
   if (!ok) {
     // Error: illegal domain
     return NS_ERROR_DOM_BAD_DOCUMENT_DOMAIN;
   }
 
   return NodePrincipal()->SetDomain(newURI);
 }
 
-NS_IMETHODIMP
-nsHTMLDocument::GetURL(nsAString& aURL)
-{
-  nsAutoCString str;
-
-  if (mDocumentURI) {
-    mDocumentURI->GetSpec(str);
-  }
-
-  CopyUTF8toUTF16(str, aURL);
-
-  return NS_OK;
-}
-
 nsIContent*
 nsHTMLDocument::GetBody()
 {
   Element* body = GetBodyElement();
 
   if (body) {
     // There is a body element, return that as the body.
     return body;
@@ -2041,37 +2027,16 @@ nsHTMLDocument::ReleaseEvents(int32_t aE
 
 NS_IMETHODIMP
 nsHTMLDocument::RouteEvent(nsIDOMEvent* aEvt)
 {
   ReportUseOfDeprecatedMethod(this, "UseOfRouteEventWarning");
   return NS_OK;
 }
 
-// readonly attribute DOMString compatMode;
-// Returns "BackCompat" if we are in quirks mode, "CSS1Compat" if we are
-// in almost standards or full standards mode. See bug 105640.  This was
-// implemented to match MSIE's compatMode property
-NS_IMETHODIMP
-nsHTMLDocument::GetCompatMode(nsAString& aCompatMode)
-{
-  NS_ASSERTION(mCompatMode == eCompatibility_NavQuirks ||
-               mCompatMode == eCompatibility_AlmostStandards ||
-               mCompatMode == eCompatibility_FullStandards,
-               "mCompatMode is neither quirks nor strict for this document");
-
-  if (mCompatMode == eCompatibility_NavQuirks) {
-    aCompatMode.AssignLiteral("BackCompat");
-  } else {
-    aCompatMode.AssignLiteral("CSS1Compat");
-  }
-
-  return NS_OK;
-}
-
 // Mapped to document.embeds for NS4 compatibility
 NS_IMETHODIMP
 nsHTMLDocument::GetPlugins(nsIDOMHTMLCollection** aPlugins)
 {
   *aPlugins = nullptr;
 
   return GetEmbeds(aPlugins);
 }
--- a/content/html/document/test/test_bug255820.html
+++ b/content/html/document/test/test_bug255820.html
@@ -20,17 +20,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 255820 **/
 SimpleTest.waitForExplicitFinish();
 
-is(document.characterSet, "UTF-8",
+is(document.characterSet, "utf-8",
    "Unexpected character set for our document");
 
 var testsLeft = 4;
 
 function testFinished() {
   --testsLeft;
   if (testsLeft == 0) {
     SimpleTest.finish();
@@ -58,64 +58,64 @@ function f3Continue() {
   is(doc.defaultView.getComputedStyle(doc.body, "").color, "rgb(0, 180, 0)",
      "Wrong color before reload");
   $("f3").
     setAttribute("onload",
                  'var doc = this.contentDocument; ' + 
                  'is(doc.defaultView.getComputedStyle(doc.body, "").color, ' +
                  '   "rgb(0, 180, 0)",' +
                  '   "Wrong color after reload");' +
-                 "charsetTestFinished('f1', this.contentDocument, 'UTF-8')");
+                 "charsetTestFinished('f1', this.contentDocument, 'utf-8')");
   $("f3").contentWindow.location.reload();
 }
 
 function runTest() {
   var doc = $("f1").contentDocument;
-  is(doc.characterSet, "UTF-8",
+  is(doc.characterSet, "utf-8",
      "Unexpected initial character set for first frame");
   doc.open();
   doc.write('<html></html>');
   doc.close();
-  is(doc.characterSet, "UTF-8",
+  is(doc.characterSet, "utf-8",
      "Unexpected character set for first frame after write");
   $("f1").
     setAttribute("onload",
-                 "charsetTestFinished('f1', this.contentDocument, 'UTF-8')");
+                 "charsetTestFinished('f1', this.contentDocument, 'utf-8')");
   $("f1").contentWindow.location.reload();
 
   doc = $("f2").contentDocument;
-  is(doc.characterSet, "UTF-8",
+  is(doc.characterSet, "utf-8",
      "Unexpected initial character set for second frame");
   doc.open();
   var str = '<html><head>';
   str += '<script src="data:application/javascript,"><'+'/script>';
   str += '<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">';
   str += '</head><body>';
   str += '</body></html>';
   doc.write(str);
   doc.close();
-  is(doc.characterSet, "UTF-8",
+  is(doc.characterSet, "utf-8",
      "Unexpected character set for second frame after write");
   $("f2").
     setAttribute("onload",
-      "charsetTestFinished('f2', this.contentDocument, 'UTF-8');" +
+      "charsetTestFinished('f2', this.contentDocument, 'utf-8');" +
       "f2Continue()");
 
   doc = $("f3").contentDocument;
-  is(doc.characterSet, "UTF-8",
+  is(doc.characterSet, "utf-8",
      "Unexpected initial character set for first frame");
   doc.open();
   var str = '<html><head>';
   str += '<style>body { color: rgb(255, 0, 0) }</style>';
   str += '<link type="text/css" rel="stylesheet" href="data:text/css, body { color: rgb(0, 180, 0) }">';
   str += '</head><body>';
   str += '</body></html>';
   doc.write(str);
   doc.close();
-  is(doc.characterSet, "UTF-8",
+  is(doc.characterSet, "utf-8",
      "Unexpected character set for first frame after write");
   $("f3").setAttribute("onload", "f3Continue()");
 }
 
 addLoadEvent(runTest);
 </script>
 </pre>
 </body>
--- a/content/html/document/test/test_bug380383.html
+++ b/content/html/document/test/test_bug380383.html
@@ -16,21 +16,21 @@ https://bugzilla.mozilla.org/show_bug.cg
   <iframe id="f2" name="f2"></iframe>
 </p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
   /** Test for Bug 380383 **/
-  is($("f1").contentDocument.characterSet, "UTF-8",
+  is($("f1").contentDocument.characterSet, "utf-8",
      "Unexpected charset for f1");
 
   function runTest() {
-    is($("f2").contentDocument.characterSet, "UTF-8",
+    is($("f2").contentDocument.characterSet, "utf-8",
        "Unexpected charset for f2");
   }
      
   addLoadEvent(runTest);
   addLoadEvent(SimpleTest.finish);
   SimpleTest.waitForExplicitFinish();
 </script>
 </pre>
--- a/content/media/webaudio/AudioBuffer.cpp
+++ b/content/media/webaudio/AudioBuffer.cpp
@@ -19,17 +19,17 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(AudioBuff
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioBuffer)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mChannels)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
   NS_DROP_JS_OBJECTS(tmp, AudioBuffer);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AudioBuffer)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mContext, AudioContext)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(AudioBuffer)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
   for (uint32_t i = 0; i < tmp->mChannels.Length(); ++i) {
     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mChannels[i])
   }
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -11,23 +11,32 @@
 #include "mozilla/dom/AudioContextBinding.h"
 #include "AudioDestinationNode.h"
 #include "AudioBufferSourceNode.h"
 #include "AudioBuffer.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(AudioContext, mWindow, mDestination)
-NS_IMPL_CYCLE_COLLECTING_ADDREF(AudioContext)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(AudioContext)
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AudioContext)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
+NS_IMPL_CYCLE_COLLECTION_CLASS(AudioContext)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(AudioContext)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mWindow)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDestination)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER_NATIVE
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(AudioContext)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mWindow)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDestination)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_IMPL_CYCLE_COLLECTION_TRACE_NATIVE_BEGIN(AudioContext)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AudioContext, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AudioContext, Release)
 
 AudioContext::AudioContext(nsIDOMWindow* aWindow)
   : mWindow(aWindow)
   , mDestination(new AudioDestinationNode(this))
 {
   SetIsDOMBinding();
 }
 
--- a/content/media/webaudio/AudioContext.h
+++ b/content/media/webaudio/AudioContext.h
@@ -21,27 +21,26 @@ namespace mozilla {
 class ErrorResult;
 
 namespace dom {
 
 class AudioDestinationNode;
 class AudioBufferSourceNode;
 class AudioBuffer;
 
-class AudioContext MOZ_FINAL : public nsISupports,
-                               public nsWrapperCache,
+class AudioContext MOZ_FINAL : public nsWrapperCache,
                                public EnableWebAudioCheck
 {
   explicit AudioContext(nsIDOMWindow* aParentWindow);
 
 public:
   virtual ~AudioContext();
 
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AudioContext)
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AudioContext)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AudioContext)
 
   nsIDOMWindow* GetParentObject() const
   {
     return mWindow;
   }
 
   virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
                                bool* aTriedToWrap);
--- a/content/media/webaudio/AudioNode.cpp
+++ b/content/media/webaudio/AudioNode.cpp
@@ -30,17 +30,17 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(AudioNode
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioNode)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mInputs)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mOutputs)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AudioNode)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mContext, AudioContext)
   TraverseElements(cb, tmp->mInputs, "mInputs[i]");
   TraverseElements(cb, tmp->mOutputs, "mOutputs[i]");
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(AudioNode)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(AudioNode)
--- a/content/svg/document/src/nsSVGDocument.cpp
+++ b/content/svg/document/src/nsSVGDocument.cpp
@@ -53,33 +53,16 @@ nsSVGDocument::GetDomain(nsAString& aDom
     if (domain.IsEmpty() || NS_FAILED(rv))
       return rv;
     CopyUTF8toUTF16(domain, aDomain);
   }
 
   return NS_OK;
 }
 
-/* readonly attribute DOMString URL; */
-NS_IMETHODIMP
-nsSVGDocument::GetURL(nsAString& aURL)
-{
-  SetDOMStringToNull(aURL);
-
-  if (mDocumentURI) {
-    nsAutoCString url;
-    nsresult rv = mDocumentURI->GetSpec(url);
-    if (url.IsEmpty() || NS_FAILED(rv))
-      return rv;
-    CopyUTF8toUTF16(url, aURL);
-  }
-
-  return NS_OK;
-}
-
 /* readonly attribute SVGSVGElement rootElement; */
 NS_IMETHODIMP
 nsSVGDocument::GetRootElement(nsIDOMSVGSVGElement** aRootElement)
 {
   *aRootElement = nullptr;
   Element* root = nsDocument::GetRootElement();
 
   return root ? CallQueryInterface(root, aRootElement) : NS_OK;
--- a/content/xbl/src/nsXBLWindowKeyHandler.cpp
+++ b/content/xbl/src/nsXBLWindowKeyHandler.cpp
@@ -31,47 +31,72 @@
 #include "nsGUIEvent.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 
 static nsINativeKeyBindings *sNativeEditorBindings = nullptr;
 
-class nsXBLSpecialDocInfo
+class nsXBLSpecialDocInfo : public nsIObserver
 {
 public:
   nsRefPtr<nsXBLDocumentInfo> mHTMLBindings;
   nsRefPtr<nsXBLDocumentInfo> mUserHTMLBindings;
 
   static const char sHTMLBindingStr[];
   static const char sUserHTMLBindingStr[];
 
   bool mInitialized;
 
 public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
   void LoadDocInfo();
   void GetAllHandlers(const char* aType,
                       nsXBLPrototypeHandler** handler,
                       nsXBLPrototypeHandler** userHandler);
   void GetHandlers(nsXBLDocumentInfo* aInfo,
                    const nsACString& aRef,
                    nsXBLPrototypeHandler** aResult);
 
   nsXBLSpecialDocInfo() : mInitialized(false) {}
+
+  virtual ~nsXBLSpecialDocInfo() {}
+
 };
 
 const char nsXBLSpecialDocInfo::sHTMLBindingStr[] =
   "chrome://global/content/platformHTMLBindings.xml";
 
+NS_IMPL_ISUPPORTS1(nsXBLSpecialDocInfo, nsIObserver)
+
+NS_IMETHODIMP
+nsXBLSpecialDocInfo::Observe(nsISupports* aSubject,
+                             const char* aTopic,
+                             const PRUnichar* aData)
+{
+  MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"), "wrong topic");
+
+  // On shutdown, clear our fields to avoid an extra cycle collection.
+  mHTMLBindings = nullptr;
+  mUserHTMLBindings = nullptr;
+  mInitialized = false;
+  nsContentUtils::UnregisterShutdownObserver(this);
+
+  return NS_OK;
+}
+
 void nsXBLSpecialDocInfo::LoadDocInfo()
 {
   if (mInitialized)
     return;
   mInitialized = true;
+  nsContentUtils::RegisterShutdownObserver(this);
 
   nsXBLService* xblService = nsXBLService::GetInstance();
   if (!xblService)
     return;
 
   // Obtain the platform doc info
   nsCOMPtr<nsIURI> bindingURI;
   NS_NewURI(getter_AddRefs(bindingURI), sHTMLBindingStr);
@@ -150,18 +175,17 @@ nsXBLWindowKeyHandler::nsXBLWindowKeyHan
 nsXBLWindowKeyHandler::~nsXBLWindowKeyHandler()
 {
   // If mWeakPtrForElement is non-null, we created a prototype handler.
   if (mWeakPtrForElement)
     delete mHandler;
 
   --sRefCnt;
   if (!sRefCnt) {
-    delete sXBLSpecialDocInfo;
-    sXBLSpecialDocInfo = nullptr;
+    NS_IF_RELEASE(sXBLSpecialDocInfo);
   }
 }
 
 NS_IMPL_ISUPPORTS1(nsXBLWindowKeyHandler,
                    nsIDOMEventListener)
 
 static void
 BuildHandlerChain(nsIContent* aContent, nsXBLPrototypeHandler** aResult)
@@ -216,23 +240,19 @@ nsXBLWindowKeyHandler::EnsureHandlers(bo
       *aIsEditor = false;
 
     if (mHandler)
       return NS_OK;
 
     nsCOMPtr<nsIContent> content(do_QueryInterface(el));
     BuildHandlerChain(content, &mHandler);
   } else { // We are an XBL file of handlers.
-    if (!sXBLSpecialDocInfo)
+    if (!sXBLSpecialDocInfo) {
       sXBLSpecialDocInfo = new nsXBLSpecialDocInfo();
-    if (!sXBLSpecialDocInfo) {
-      if (aIsEditor) {
-        *aIsEditor = false;
-      }
-      return NS_ERROR_OUT_OF_MEMORY;
+      NS_ADDREF(sXBLSpecialDocInfo);
     }
     sXBLSpecialDocInfo->LoadDocInfo();
 
     // Now determine which handlers we should be using.
     bool isEditor = IsEditor();
     if (isEditor) {
       sXBLSpecialDocInfo->GetAllHandlers("editor", &mHandler, &mUserHandler);
     }
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -221,16 +221,19 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsWrapperC
 // Cycle collector macros for wrapper caches.
 
 #define NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER \
   nsContentUtils::TraceWrapper(tmp, aCallback, aClosure);
 
 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \
   nsContentUtils::ReleaseWrapper(s, tmp);
 
+#define NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER_NATIVE \
+  nsContentUtils::ReleaseWrapper(tmp, tmp);
+
 #define NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) \
   NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(_class)              \
     NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER        \
   NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 #define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(_class) \
   NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                \
   NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)         \
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <stdarg.h>
 
 #include "BindingUtils.h"
 
+#include "AccessCheck.h"
 #include "WrapperFactory.h"
 #include "xpcprivate.h"
 #include "XPCQuickStubs.h"
 #include "nsIXPConnect.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -135,18 +136,18 @@ InterfaceObjectToString(JSContext* cx, u
 
   return xpc::NonVoidStringToJsval(cx, str, vp);
 }
 
 static JSObject*
 CreateInterfaceObject(JSContext* cx, JSObject* global, JSObject* receiver,
                       JSClass* constructorClass, JSNative constructorNative,
                       unsigned ctorNargs, JSObject* proto,
-                      Prefable<JSFunctionSpec>* staticMethods,
-                      Prefable<ConstantSpec>* constants,
+                      const NativeProperties* properties,
+                      const NativeProperties* chromeOnlyProperties,
                       const char* name)
 {
   JSObject* constructor;
   if (constructorClass) {
     JSObject* functionProto = JS_GetFunctionPrototype(cx, global);
     if (!functionProto) {
       return NULL;
     }
@@ -159,20 +160,16 @@ CreateInterfaceObject(JSContext* cx, JSO
       return NULL;
     }
     constructor = JS_GetFunctionObject(fun);
   }
   if (!constructor) {
     return NULL;
   }
 
-  if (staticMethods && !DefinePrefable(cx, constructor, staticMethods)) {
-    return NULL;
-  }
-
   if (constructorClass) {
     JSFunction* toString = js::DefineFunctionWithReserved(cx, constructor,
                                                           "toString",
                                                           InterfaceObjectToString,
                                                           0, 0);
     if (!toString) {
       return NULL;
     }
@@ -184,18 +181,38 @@ CreateInterfaceObject(JSContext* cx, JSO
     JSString *str = ::JS_InternString(cx, name);
     if (!str) {
       return NULL;
     }
     js::SetFunctionNativeReserved(toStringObj, TOSTRING_NAME_RESERVED_SLOT,
                                   STRING_TO_JSVAL(str));
   }
 
-  if (constants && !DefinePrefable(cx, constructor, constants)) {
-    return NULL;
+  if (properties) {
+    if (properties->staticMethods &&
+        !DefinePrefable(cx, constructor, properties->staticMethods)) {
+      return nullptr;
+    }
+
+    if (properties->constants &&
+        !DefinePrefable(cx, constructor, properties->constants)) {
+      return nullptr;
+    }
+  }
+
+  if (chromeOnlyProperties) {
+    if (chromeOnlyProperties->staticMethods &&
+        !DefinePrefable(cx, constructor, chromeOnlyProperties->staticMethods)) {
+      return nullptr;
+    }
+
+    if (chromeOnlyProperties->constants &&
+        !DefinePrefable(cx, constructor, chromeOnlyProperties->constants)) {
+      return nullptr;
+    }
   }
 
   if (proto && !JS_LinkConstructorAndPrototype(cx, constructor, proto)) {
     return NULL;
   }
 
   JSBool alreadyDefined;
   if (!JS_AlreadyHasOwnProperty(cx, receiver, name, &alreadyDefined)) {
@@ -210,81 +227,107 @@ CreateInterfaceObject(JSContext* cx, JSO
   }
 
   return constructor;
 }
 
 static JSObject*
 CreateInterfacePrototypeObject(JSContext* cx, JSObject* global,
                                JSObject* parentProto, JSClass* protoClass,
-                               Prefable<JSFunctionSpec>* methods,
-                               Prefable<JSPropertySpec>* properties,
-                               Prefable<ConstantSpec>* constants)
+                               const NativeProperties* properties,
+                               const NativeProperties* chromeOnlyProperties)
 {
   JSObject* ourProto = JS_NewObjectWithUniqueType(cx, protoClass, parentProto,
                                                   global);
   if (!ourProto) {
     return NULL;
   }
 
-  if (methods && !DefinePrefable(cx, ourProto, methods)) {
-    return NULL;
+  if (properties) {
+    if (properties->methods &&
+        !DefinePrefable(cx, ourProto, properties->methods)) {
+      return nullptr;
+    }
+
+    if (properties->attributes &&
+        !DefinePrefable(cx, ourProto, properties->attributes)) {
+      return nullptr;
+    }
+
+    if (properties->constants &&
+        !DefinePrefable(cx, ourProto, properties->constants)) {
+      return nullptr;
+    }
   }
 
-  if (properties && !DefinePrefable(cx, ourProto, properties)) {
-    return NULL;
-  }
+  if (chromeOnlyProperties) {
+    if (chromeOnlyProperties->methods &&
+        !DefinePrefable(cx, ourProto, chromeOnlyProperties->methods)) {
+      return nullptr;
+    }
 
-  if (constants && !DefinePrefable(cx, ourProto, constants)) {
-    return NULL;
+    if (chromeOnlyProperties->attributes &&
+        !DefinePrefable(cx, ourProto, chromeOnlyProperties->attributes)) {
+      return nullptr;
+    }
+
+    if (chromeOnlyProperties->constants &&
+        !DefinePrefable(cx, ourProto, chromeOnlyProperties->constants)) {
+      return nullptr;
+    }
   }
 
   return ourProto;
 }
 
 JSObject*
 CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject *receiver,
                        JSObject* protoProto, JSClass* protoClass,
                        JSClass* constructorClass, JSNative constructor,
                        unsigned ctorNargs, const DOMClass* domClass,
-                       Prefable<JSFunctionSpec>* methods,
-                       Prefable<JSPropertySpec>* properties,
-                       Prefable<ConstantSpec>* constants,
-                       Prefable<JSFunctionSpec>* staticMethods, const char* name)
+                       const NativeProperties* properties,
+                       const NativeProperties* chromeOnlyProperties,
+                       const char* name)
 {
   MOZ_ASSERT(protoClass || constructorClass || constructor,
              "Need at least one class or a constructor!");
-  MOZ_ASSERT(!(methods || properties) || protoClass,
+  MOZ_ASSERT(!((properties &&
+                (properties->methods || properties->attributes)) ||
+               (chromeOnlyProperties &&
+                (chromeOnlyProperties->methods ||
+                 chromeOnlyProperties->attributes))) || protoClass,
              "Methods or properties but no protoClass!");
-  MOZ_ASSERT(!staticMethods || constructorClass || constructor,
+  MOZ_ASSERT(!((properties && properties->staticMethods) ||
+               (chromeOnlyProperties && chromeOnlyProperties->staticMethods)) ||
+             constructorClass || constructor,
              "Static methods but no constructorClass or constructor!");
   MOZ_ASSERT(bool(name) == bool(constructorClass || constructor),
              "Must have name precisely when we have an interface object");
   MOZ_ASSERT(!constructorClass || !constructor);
 
   JSObject* proto;
   if (protoClass) {
     proto = CreateInterfacePrototypeObject(cx, global, protoProto, protoClass,
-                                           methods, properties, constants);
+                                           properties, chromeOnlyProperties);
     if (!proto) {
       return NULL;
     }
 
     js::SetReservedSlot(proto, DOM_PROTO_INSTANCE_CLASS_SLOT,
                         JS::PrivateValue(const_cast<DOMClass*>(domClass)));
   }
   else {
     proto = NULL;
   }
 
   JSObject* interface;
   if (constructorClass || constructor) {
     interface = CreateInterfaceObject(cx, global, receiver, constructorClass,
                                       constructor, ctorNargs, proto,
-                                      staticMethods, constants, name);
+                                      properties, chromeOnlyProperties, name);
     if (!interface) {
       return NULL;
     }
   }
 
   return protoClass ? proto : interface;
 }
 
@@ -415,185 +458,217 @@ QueryInterface(JSContext* cx, unsigned a
 }
 
 JSBool
 ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp)
 {
   return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR);
 }
 
-bool
+static bool
 XrayResolveProperty(JSContext* cx, JSObject* wrapper, jsid id,
                     JSPropertyDescriptor* desc,
-                    // And the things we need to determine the descriptor
-                    Prefable<JSFunctionSpec>* methods,
-                    jsid* methodIds,
-                    JSFunctionSpec* methodSpecs,
-                    size_t methodCount,
-                    Prefable<JSPropertySpec>* attributes,
-                    jsid* attributeIds,
-                    JSPropertySpec* attributeSpecs,
-                    size_t attributeCount,
-                    Prefable<ConstantSpec>* constants,
-                    jsid* constantIds,
-                    ConstantSpec* constantSpecs,
-                    size_t constantCount)
+                    const NativeProperties* nativeProperties)
 {
-  for (size_t prefIdx = 0; prefIdx < methodCount; ++prefIdx) {
-    MOZ_ASSERT(methods[prefIdx].specs);
-    if (methods[prefIdx].enabled) {
-      // Set i to be the index into our full list of ids/specs that we're
-      // looking at now.
-      size_t i = methods[prefIdx].specs - methodSpecs;
-      for ( ; methodIds[i] != JSID_VOID; ++i) {
-        if (id == methodIds[i]) {
-          JSFunction *fun = JS_NewFunctionById(cx, methodSpecs[i].call.op,
-                                               methodSpecs[i].nargs, 0,
-                                               wrapper, id);
-          if (!fun) {
-            return false;
+  if (nativeProperties->methods) {
+    Prefable<JSFunctionSpec>* method;
+    for (method = nativeProperties->methods; method->specs; ++method) {
+      if (method->enabled) {
+        // Set i to be the index into our full list of ids/specs that we're
+        // looking at now.
+        size_t i = method->specs - nativeProperties->methodsSpecs;
+        for ( ; nativeProperties->methodIds[i] != JSID_VOID; ++i) {
+          if (id == nativeProperties->methodIds[i]) {
+            JSFunctionSpec& methodSpec = nativeProperties->methodsSpecs[i];
+            JSFunction *fun = JS_NewFunctionById(cx, methodSpec.call.op,
+                                                 methodSpec.nargs, 0,
+                                                 wrapper, id);
+            if (!fun) {
+              return false;
+            }
+            SET_JITINFO(fun, methodSpec.call.info);
+            JSObject *funobj = JS_GetFunctionObject(fun);
+            desc->value.setObject(*funobj);
+            desc->attrs = methodSpec.flags;
+            desc->obj = wrapper;
+            desc->setter = nullptr;
+            desc->getter = nullptr;
+           return true;
           }
-          SET_JITINFO(fun, methodSpecs[i].call.info);
-          JSObject *funobj = JS_GetFunctionObject(fun);
-          desc->value.setObject(*funobj);
-          desc->attrs = methodSpecs[i].flags;
-          desc->obj = wrapper;
-          desc->setter = nullptr;
-          desc->getter = nullptr;
-          return true;
         }
       }
     }
   }
 
-  for (size_t prefIdx = 0; prefIdx < attributeCount; ++prefIdx) {
-    MOZ_ASSERT(attributes[prefIdx].specs);
-    if (attributes[prefIdx].enabled) {
-      // Set i to be the index into our full list of ids/specs that we're
-      // looking at now.
-      size_t i = attributes[prefIdx].specs - attributeSpecs;
-      for ( ; attributeIds[i] != JSID_VOID; ++i) {
-        if (id == attributeIds[i]) {
-          // Because of centralization, we need to make sure we fault in the
-          // JitInfos as well. At present, until the JSAPI changes, the easiest
-          // way to do this is wrap them up as functions ourselves.
-          desc->attrs = attributeSpecs[i].flags & ~JSPROP_NATIVE_ACCESSORS;
-          // They all have getters, so we can just make it.
-          JSObject *global = JS_GetGlobalForObject(cx, wrapper);
-          JSFunction *fun = JS_NewFunction(cx, (JSNative)attributeSpecs[i].getter.op,
-                                           0, 0, global, NULL);
-          if (!fun)
-            return false;
-          SET_JITINFO(fun, attributeSpecs[i].getter.info);
-          JSObject *funobj = JS_GetFunctionObject(fun);
-          desc->getter = js::CastAsJSPropertyOp(funobj);
-          desc->attrs |= JSPROP_GETTER;
-          if (attributeSpecs[i].setter.op) {
-            // We have a setter! Make it.
-            fun = JS_NewFunction(cx, (JSNative)attributeSpecs[i].setter.op,
-                                 1, 0, global, NULL);
+  if (nativeProperties->attributes) {
+    Prefable<JSPropertySpec>* attr;
+    for (attr = nativeProperties->attributes; attr->specs; ++attr) {
+      if (attr->enabled) {
+        // Set i to be the index into our full list of ids/specs that we're
+        // looking at now.
+        size_t i = attr->specs - nativeProperties->attributeSpecs;
+        for ( ; nativeProperties->attributeIds[i] != JSID_VOID; ++i) {
+          if (id == nativeProperties->attributeIds[i]) {
+            JSPropertySpec& attrSpec = nativeProperties->attributeSpecs[i];
+            // Because of centralization, we need to make sure we fault in the
+            // JitInfos as well. At present, until the JSAPI changes, the easiest
+            // way to do this is wrap them up as functions ourselves.
+            desc->attrs = attrSpec.flags & ~JSPROP_NATIVE_ACCESSORS;
+            // They all have getters, so we can just make it.
+            JSObject *global = JS_GetGlobalForObject(cx, wrapper);
+            JSFunction *fun = JS_NewFunction(cx, (JSNative)attrSpec.getter.op,
+                                             0, 0, global, nullptr);
             if (!fun)
               return false;
-            SET_JITINFO(fun, attributeSpecs[i].setter.info);
-            funobj = JS_GetFunctionObject(fun);
-            desc->setter = js::CastAsJSStrictPropertyOp(funobj);
-            desc->attrs |= JSPROP_SETTER;
-          } else {
-            desc->setter = NULL;
+            SET_JITINFO(fun, attrSpec.getter.info);
+            JSObject *funobj = JS_GetFunctionObject(fun);
+            desc->getter = js::CastAsJSPropertyOp(funobj);
+            desc->attrs |= JSPROP_GETTER;
+            if (attrSpec.setter.op) {
+              // We have a setter! Make it.
+              fun = JS_NewFunction(cx, (JSNative)attrSpec.setter.op, 1, 0,
+                                   global, nullptr);
+              if (!fun)
+                return false;
+              SET_JITINFO(fun, attrSpec.setter.info);
+              funobj = JS_GetFunctionObject(fun);
+              desc->setter = js::CastAsJSStrictPropertyOp(funobj);
+              desc->attrs |= JSPROP_SETTER;
+            } else {
+              desc->setter = nullptr;
+            }
+            desc->obj = wrapper;
+            return true;
           }
-          desc->obj = wrapper;
-          return true;
         }
       }
     }
   }
 
-  for (size_t prefIdx = 0; prefIdx < constantCount; ++prefIdx) {
-    MOZ_ASSERT(constants[prefIdx].specs);
-    if (constants[prefIdx].enabled) {
-      // Set i to be the index into our full list of ids/specs that we're
-      // looking at now.
-      size_t i = constants[prefIdx].specs - constantSpecs;
-      for ( ; constantIds[i] != JSID_VOID; ++i) {
-        if (id == constantIds[i]) {
-          desc->attrs = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
-          desc->obj = wrapper;
-          desc->value = constantSpecs[i].value;
-          return true;
+  if (nativeProperties->constants) {
+    Prefable<ConstantSpec>* constant;
+    for (constant = nativeProperties->constants; constant->specs; ++constant) {
+      if (constant->enabled) {
+        // Set i to be the index into our full list of ids/specs that we're
+        // looking at now.
+        size_t i = constant->specs - nativeProperties->constantSpecs;
+        for ( ; nativeProperties->constantIds[i] != JSID_VOID; ++i) {
+          if (id == nativeProperties->constantIds[i]) {
+            desc->attrs = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
+            desc->obj = wrapper;
+            desc->value = nativeProperties->constantSpecs[i].value;
+            return true;
+          }
         }
       }
     }
   }
 
   return true;
 }
 
 bool
+XrayResolveProperty(JSContext* cx, JSObject* wrapper, jsid id,
+                    JSPropertyDescriptor* desc,
+                    const NativeProperties* nativeProperties,
+                    const NativeProperties* chromeOnlyNativeProperties)
+{
+  if (nativeProperties &&
+      !XrayResolveProperty(cx, wrapper, id, desc, nativeProperties)) {
+    return false;
+  }
+
+  if (!desc->obj &&
+      chromeOnlyNativeProperties &&
+      xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
+      !XrayResolveProperty(cx, wrapper, id, desc, chromeOnlyNativeProperties)) {
+    return false;
+  }
+
+  return true;
+}
+
+bool
 XrayEnumerateProperties(JS::AutoIdVector& props,
-                        Prefable<JSFunctionSpec>* methods,
-                        jsid* methodIds,
-                        JSFunctionSpec* methodSpecs,
-                        size_t methodCount,
-                        Prefable<JSPropertySpec>* attributes,
-                        jsid* attributeIds,
-                        JSPropertySpec* attributeSpecs,
-                        size_t attributeCount,
-                        Prefable<ConstantSpec>* constants,
-                        jsid* constantIds,
-                        ConstantSpec* constantSpecs,
-                        size_t constantCount)
+                        const NativeProperties* nativeProperties)
 {
-  for (size_t prefIdx = 0; prefIdx < methodCount; ++prefIdx) {
-    MOZ_ASSERT(methods[prefIdx].specs);
-    if (methods[prefIdx].enabled) {
-      // Set i to be the index into our full list of ids/specs that we're
-      // looking at now.
-      size_t i = methods[prefIdx].specs - methodSpecs;
-      for ( ; methodIds[i] != JSID_VOID; ++i) {
-        if ((methodSpecs[i].flags & JSPROP_ENUMERATE) &&
-            !props.append(methodIds[i])) {
-          return false;
+  if (nativeProperties->methods) {
+    Prefable<JSFunctionSpec>* method;
+    for (method = nativeProperties->methods; method->specs; ++method) {
+      if (method->enabled) {
+        // Set i to be the index into our full list of ids/specs that we're
+        // looking at now.
+        size_t i = method->specs - nativeProperties->methodsSpecs;
+        for ( ; nativeProperties->methodIds[i] != JSID_VOID; ++i) {
+          if ((nativeProperties->methodsSpecs[i].flags & JSPROP_ENUMERATE) &&
+              !props.append(nativeProperties->methodIds[i])) {
+            return false;
+          }
         }
       }
     }
   }
 
-  for (size_t prefIdx = 0; prefIdx < attributeCount; ++prefIdx) {
-    MOZ_ASSERT(attributes[prefIdx].specs);
-    if (attributes[prefIdx].enabled) {
-      // Set i to be the index into our full list of ids/specs that we're
-      // looking at now.
-      size_t i = attributes[prefIdx].specs - attributeSpecs;
-      for ( ; attributeIds[i] != JSID_VOID; ++i) {
-        if ((attributeSpecs[i].flags & JSPROP_ENUMERATE) &&
-            !props.append(attributeIds[i])) {
-          return false;
+  if (nativeProperties->attributes) {
+    Prefable<JSPropertySpec>* attr;
+    for (attr = nativeProperties->attributes; attr->specs; ++attr) {
+      if (attr->enabled) {
+        // Set i to be the index into our full list of ids/specs that we're
+        // looking at now.
+        size_t i = attr->specs - nativeProperties->attributeSpecs;
+        for ( ; nativeProperties->attributeIds[i] != JSID_VOID; ++i) {
+          if ((nativeProperties->attributeSpecs[i].flags & JSPROP_ENUMERATE) &&
+              !props.append(nativeProperties->attributeIds[i])) {
+            return false;
+          }
         }
       }
     }
   }
 
-  for (size_t prefIdx = 0; prefIdx < constantCount; ++prefIdx) {
-    MOZ_ASSERT(constants[prefIdx].specs);
-    if (constants[prefIdx].enabled) {
-      // Set i to be the index into our full list of ids/specs that we're
-      // looking at now.
-      size_t i = constants[prefIdx].specs - constantSpecs;
-      for ( ; constantIds[i] != JSID_VOID; ++i) {
-        if (!props.append(constantIds[i])) {
-          return false;
+  if (nativeProperties->constants) {
+    Prefable<ConstantSpec>* constant;
+    for (constant = nativeProperties->constants; constant->specs; ++constant) {
+      if (constant->enabled) {
+        // Set i to be the index into our full list of ids/specs that we're
+        // looking at now.
+        size_t i = constant->specs - nativeProperties->constantSpecs;
+        for ( ; nativeProperties->constantIds[i] != JSID_VOID; ++i) {
+          if (!props.append(nativeProperties->constantIds[i])) {
+            return false;
+          }
         }
       }
     }
   }
 
   return true;
 }
 
 bool
+XrayEnumerateProperties(JSObject* wrapper,
+                        JS::AutoIdVector& props,
+                        const NativeProperties* nativeProperties,
+                        const NativeProperties* chromeOnlyNativeProperties)
+{
+  if (nativeProperties &&
+      !XrayEnumerateProperties(props, nativeProperties)) {
+    return false;
+  }
+
+  if (chromeOnlyNativeProperties &&
+      xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
+      !XrayEnumerateProperties(props, chromeOnlyNativeProperties)) {
+    return false;
+  }
+
+  return true;
+}
+
+bool
 GetPropertyOnPrototype(JSContext* cx, JSObject* proxy, jsid id, bool* found,
                        JS::Value* vp)
 {
   JSObject* proto;
   if (!js::GetObjectProto(cx, proxy, &proto)) {
     return false;
   }
   if (!proto) {
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -339,16 +339,32 @@ struct Prefable {
   // A boolean indicating whether this set of specs is enabled
   bool enabled;
   // Array of specs, terminated in whatever way is customary for T.
   // Null to indicate a end-of-array for Prefable, when such an
   // indicator is needed.
   T* specs;
 };
 
+struct NativeProperties
+{
+  Prefable<JSFunctionSpec>* staticMethods;
+  jsid* staticMethodIds;
+  JSFunctionSpec* staticMethodsSpecs;
+  Prefable<JSFunctionSpec>* methods;
+  jsid* methodIds;
+  JSFunctionSpec* methodsSpecs;
+  Prefable<JSPropertySpec>* attributes;
+  jsid* attributeIds;
+  JSPropertySpec* attributeSpecs;
+  Prefable<ConstantSpec>* constants;
+  jsid* constantIds;
+  ConstantSpec* constantSpecs;
+};
+
 /*
  * Create a DOM interface object (if constructorClass is non-null) and/or a
  * DOM interface prototype object (if protoClass is non-null).
  *
  * global is used as the parent of the interface object and the interface
  *        prototype object
  * receiver is the object on which we need to define the interface object as a
  *          property
@@ -360,43 +376,41 @@ struct Prefable {
  *                  This is null if we should not create an interface object or
  *                  if it should be a function object.
  * constructor is the JSNative to use as a constructor.  If this is non-null, it
  *             should be used as a JSNative to back the interface object, which
  *             should be a Function.  If this is null, then we should create an
  *             object of constructorClass, unless that's also null, in which
  *             case we should not create an interface object at all.
  * ctorNargs is the length of the constructor function; 0 if no constructor
- * instanceClass is the JSClass of instance objects for this class.  This can
- *               be null if this is not a concrete proto.
- * methods and properties are to be defined on the interface prototype object;
- *                        these arguments are allowed to be null if there are no
- *                        methods or properties respectively.
- * constants are to be defined on the interface object and on the interface
- *           prototype object; allowed to be null if there are no constants.
- * staticMethods are to be defined on the interface object; allowed to be null
- *               if there are no static methods.
+ * domClass is the DOMClass of instance objects for this class.  This can be
+ *          null if this is not a concrete proto.
+ * properties contains the methods, attributes and constants to be defined on
+ *            objects in any compartment.
+ * chromeProperties contains the methods, attributes and constants to be defined
+ *                  on objects in chrome compartments. This must be null if the
+ *                  interface doesn't have any ChromeOnly properties or if the
+ *                  object is being created in non-chrome compartment.
  *
  * At least one of protoClass and constructorClass should be non-null.
  * If constructorClass is non-null, the resulting interface object will be
  * defined on the given global with property name |name|, which must also be
  * non-null.
  *
  * returns the interface prototype object if protoClass is non-null, else it
  * returns the interface object.
  */
 JSObject*
 CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject* receiver,
                        JSObject* protoProto, JSClass* protoClass,
                        JSClass* constructorClass, JSNative constructor,
                        unsigned ctorNargs, const DOMClass* domClass,
-                       Prefable<JSFunctionSpec>* methods,
-                       Prefable<JSPropertySpec>* properties,
-                       Prefable<ConstantSpec>* constants,
-                       Prefable<JSFunctionSpec>* staticMethods, const char* name);
+                       const NativeProperties* properties,
+                       const NativeProperties* chromeProperties,
+                       const char* name);
 
 template <class T>
 inline bool
 WrapNewBindingObject(JSContext* cx, JSObject* scope, T* value, JS::Value* vp)
 {
   JSObject* obj = value->GetWrapper();
   if (obj && js::GetObjectCompartment(obj) == js::GetObjectCompartment(scope)) {
     *vp = JS::ObjectValue(*obj);
@@ -616,26 +630,26 @@ struct ParentObject {
 
 inline nsWrapperCache*
 GetWrapperCache(const ParentObject& aParentObject)
 {
   return aParentObject.mWrapperCache;
 }
 
 template<class T>
-inline nsISupports*
+inline T*
 GetParentPointer(T* aObject)
 {
-  return ToSupports(aObject);
+  return aObject;
 }
 
 inline nsISupports*
 GetParentPointer(const ParentObject& aObject)
 {
-  return ToSupports(aObject.mObject);
+  return aObject.mObject;
 }
 
 template<class T>
 inline void
 ClearWrapper(T* p, nsWrapperCache* cache)
 {
   cache->ClearWrapper();
 }
@@ -724,42 +738,99 @@ WrapObject<JSObject>(JSContext* cx, JSOb
   vp->setObjectOrNull(p);
   return true;
 }
 
 bool
 WrapCallbackInterface(JSContext *cx, JSObject *scope, nsISupports* callback,
                       JS::Value* vp);
 
+// This checks whether class T implements WrapObject itself, if so then
+// HasWrapObject<T>::Value will be true. Note that if T inherits WrapObject from
+// a base class but doesn't override it then HasWrapObject<T>::Value will be
+// false. This is a little annoying in some cases (multiple C++ classes using
+// the same binding), but it saves us in the case where a class inherits from
+// nsWrapperCache but doesn't actually override WrapObject. For now we assume
+// that HasWrapObject<T>::Value being false means we have an nsISupports object.
+template<typename T>
+struct HasWrapObject
+{
+private:
+  typedef char yes[1];
+  typedef char no[2];
+  typedef JSObject* (T::*WrapObject)(JSContext*, JSObject*, bool*);
+  template<typename U, U> struct SFINAE;
+  template <typename V> static yes& Check(SFINAE<WrapObject, &V::WrapObject>*);
+  template <typename V> static no& Check(...);
+
+public:
+  static bool const Value = sizeof(Check<T>(nullptr)) == sizeof(yes);
+};
+
+template<typename T, bool hasWrapObject=HasWrapObject<T>::Value >
+struct WrapNativeParentHelper
+{
+  static inline JSObject* Wrap(JSContext* cx, JSObject* scope, T* parent,
+                               nsWrapperCache* cache)
+  {
+    MOZ_ASSERT(cache);
+
+    JSObject* obj;
+    if ((obj = cache->GetWrapper())) {
+      return obj;
+    }
+
+    bool triedToWrap;
+    return parent->WrapObject(cx, scope, &triedToWrap);
+  }
+};
+
+template<typename T>
+struct WrapNativeParentHelper<T, false>
+{
+  static inline JSObject* Wrap(JSContext* cx, JSObject* scope, T* parent,
+                               nsWrapperCache* cache)
+  {
+    JSObject* obj;
+    if (cache && (obj = cache->GetWrapper())) {
+#ifdef DEBUG
+      qsObjectHelper helper(ToSupports(parent), cache);
+      JS::Value debugVal;
+
+      bool ok = XPCOMObjectToJsval(cx, scope, helper, NULL, false, &debugVal);
+      NS_ASSERTION(ok && JSVAL_TO_OBJECT(debugVal) == obj,
+                   "Unexpected object in nsWrapperCache");
+#endif
+      return obj;
+    }
+
+    qsObjectHelper helper(ToSupports(parent), cache);
+    JS::Value v;
+    return XPCOMObjectToJsval(cx, scope, helper, NULL, false, &v) ?
+           JSVAL_TO_OBJECT(v) :
+           NULL;
+  }
+};
+
+template<typename T>
+static inline JSObject*
+WrapNativeParent(JSContext* cx, JSObject* scope, T* p, nsWrapperCache* cache)
+{
+  if (!p) {
+    return scope;
+  }
+
+  return WrapNativeParentHelper<T>::Wrap(cx, scope, p, cache);
+}
+
 template<typename T>
 static inline JSObject*
 WrapNativeParent(JSContext* cx, JSObject* scope, const T& p)
 {
-  if (!GetParentPointer(p))
-    return scope;
-
-  nsWrapperCache* cache = GetWrapperCache(p);
-  JSObject* obj;
-  if (cache && (obj = cache->GetWrapper())) {
-#ifdef DEBUG
-    qsObjectHelper helper(GetParentPointer(p), cache);
-    JS::Value debugVal;
-
-    bool ok = XPCOMObjectToJsval(cx, scope, helper, NULL, false, &debugVal);
-    NS_ASSERTION(ok && JSVAL_TO_OBJECT(debugVal) == obj,
-                 "Unexpected object in nsWrapperCache");
-#endif
-    return obj;
-  }
-
-  qsObjectHelper helper(GetParentPointer(p), cache);
-  JS::Value v;
-  return XPCOMObjectToJsval(cx, scope, helper, NULL, false, &v) ?
-         JSVAL_TO_OBJECT(v) :
-         NULL;
+  return WrapNativeParent(cx, scope, GetParentPointer(p), GetWrapperCache(p));
 }
 
 static inline bool
 InternJSString(JSContext* cx, jsid& id, const char* chars)
 {
   if (JSString *str = ::JS_InternString(cx, chars)) {
     id = INTERNED_STRING_TO_JSID(cx, str);
     return true;
@@ -1116,44 +1187,24 @@ public:
       storage.addr()->~T();
     }
 };
 
 // Implementation of the bits that XrayWrapper needs
 bool
 XrayResolveProperty(JSContext* cx, JSObject* wrapper, jsid id,
                     JSPropertyDescriptor* desc,
-                    // And the things we need to determine the descriptor
-                    Prefable<JSFunctionSpec>* methods,
-                    jsid* methodIds,
-                    JSFunctionSpec* methodSpecs,
-                    size_t methodCount,
-                    Prefable<JSPropertySpec>* attributes,
-                    jsid* attributeIds,
-                    JSPropertySpec* attributeSpecs,
-                    size_t attributeCount,
-                    Prefable<ConstantSpec>* constants,
-                    jsid* constantIds,
-                    ConstantSpec* constantSpecs,
-                    size_t constantCount);
+                    const NativeProperties* nativeProperties,
+                    const NativeProperties* chromeOnlyNativeProperties);
 
 bool
-XrayEnumerateProperties(JS::AutoIdVector& props,
-                        Prefable<JSFunctionSpec>* methods,
-                        jsid* methodIds,
-                        JSFunctionSpec* methodSpecs,
-                        size_t methodCount,
-                        Prefable<JSPropertySpec>* attributes,
-                        jsid* attributeIds,
-                        JSPropertySpec* attributeSpecs,
-                        size_t attributeCount,
-                        Prefable<ConstantSpec>* constants,
-                        jsid* constantIds,
-                        ConstantSpec* constantSpecs,
-                        size_t constantCount);
+XrayEnumerateProperties(JSObject* wrapper,
+                        JS::AutoIdVector& props,
+                        const NativeProperties* nativeProperties,
+                        const NativeProperties* chromeOnlyNativeProperties);
 
 // Transfer reference in ptr to smartPtr.
 template<class T>
 inline void
 Take(nsRefPtr<T>& smartPtr, T* ptr)
 {
   smartPtr = dont_AddRef(ptr);
 }
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -84,16 +84,17 @@
 #   * resultNotAddRefed - attributes and methods specified in the .webidl file
 #                         that do not AddRef the return value
 
 DOMInterfaces = {
 
 'mozAudioContext': {
     'nativeType': 'AudioContext',
     'implicitJSContext': [ 'createBuffer' ],
+    'nativeOwnership': 'refcounted'
 },
 
 'AudioNode' : {
     'concrete': False,
 },
 
 'AudioSourceNode': {
     'concrete': False,
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -88,21 +88,26 @@ def DOMClass(descriptor):
         protoList = ['prototypes::id::' + proto for proto in descriptor.prototypeChain]
         # Pad out the list to the right length with _ID_Count so we
         # guarantee that all the lists are the same length.  _ID_Count
         # is never the ID of any prototype, so it's safe to use as
         # padding.
         protoList.extend(['prototypes::id::_ID_Count'] * (descriptor.config.maxProtoChainLength - len(protoList)))
         prototypeChainString = ', '.join(protoList)
         nativeHooks = "NULL" if descriptor.workers else "&NativeHooks"
+        if descriptor.workers or descriptor.nativeOwnership != 'refcounted':
+            participant = "nullptr"
+        else:
+            participant = "NS_CYCLE_COLLECTION_PARTICIPANT(%s)" % descriptor.nativeType
         return """{
   { %s },
-  %s, %s
+  %s, %s, %s
 }""" % (prototypeChainString, toStringBool(descriptor.nativeOwnership == 'nsisupports'),
-          nativeHooks)
+        nativeHooks,
+        participant)
 
 class CGDOMJSClass(CGThing):
     """
     Generate a DOMJSClass for a given descriptor
     """
     def __init__(self, descriptor):
         CGThing.__init__(self)
         self.descriptor = descriptor
@@ -628,22 +633,23 @@ class CGAddPropertyHook(CGAbstractClassH
     """
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'), Argument('JSHandleObject', 'obj'),
                 Argument('JSHandleId', 'id'), Argument('JSMutableHandleValue', 'vp')]
         CGAbstractClassHook.__init__(self, descriptor, ADDPROPERTY_HOOK_NAME,
                                      'JSBool', args)
 
     def generate_code(self):
-        # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=774279
-        # Using a real trace hook might enable us to deal with non-nsISupports
-        # wrappercached things here.
-        assert self.descriptor.nativeOwnership == 'nsisupports'
-        return """  nsContentUtils::PreserveWrapper(reinterpret_cast<nsISupports*>(self), self);
-  return true;"""
+        assert not self.descriptor.workers and self.descriptor.wrapperCache
+        if self.descriptor.nativeOwnership == 'nsisupports':
+            preserveArgs = "reinterpret_cast<nsISupports*>(self), self"
+        else:
+            preserveArgs = "self, self, NS_CYCLE_COLLECTION_PARTICIPANT(%s)" % self.descriptor.nativeType
+        return """  nsContentUtils::PreserveWrapper(%s);
+  return true;""" % preserveArgs
 
 def DeferredFinalizeSmartPtr(descriptor):
     if descriptor.nativeOwnership == 'owned':
         smartPtr = 'nsAutoPtr<%s>'
     else:
         assert descriptor.nativeOwnership == 'refcounted'
         smartPtr = 'nsRefPtr<%s>'
     return smartPtr % descriptor.nativeType
@@ -855,55 +861,52 @@ def isChromeOnly(m):
     return m.getExtendedAttribute("ChromeOnly")
 
 class PropertyDefiner:
     """
     A common superclass for defining things on prototype objects.
 
     Subclasses should implement generateArray to generate the actual arrays of
     things we're defining.  They should also set self.chrome to the list of
-    things exposed to chrome and self.regular to the list of things exposed to
-    web pages.  self.chrome must be a superset of self.regular but also include
-    all the ChromeOnly stuff.
+    things only exposed to chrome and self.regular to the list of things exposed
+    to both chrome and web pages.
     """
     def __init__(self, descriptor, name):
         self.descriptor = descriptor
         self.name = name
         # self.prefCacheData will store an array of (prefname, bool*)
         # pairs for our bool var caches.  generateArray will fill it
         # in as needed.
         self.prefCacheData = []
     def hasChromeOnly(self):
-        return len(self.chrome) > len(self.regular)
+        return len(self.chrome) > 0
     def hasNonChromeOnly(self):
         return len(self.regular) > 0
     def variableName(self, chrome):
-        if chrome and self.hasChromeOnly():
-            return "sChrome" + self.name
-        if self.hasNonChromeOnly():
-            return "s" + self.name
-        return "NULL"
-    def usedForXrays(self, chrome):
-        # We only need Xrays for methods, attributes and constants.  And we only
-        # need them for the non-chrome ones if we have no chromeonly things.
-        # Otherwise (we have chromeonly attributes) we need Xrays for the chrome
-        # methods/attributes/constants.  Finally, in workers there are no Xrays.
-        return ((self.name is "Methods" or self.name is "Attributes" or
-                 self.name is "Constants") and
-                chrome == self.hasChromeOnly() and
-                not self.descriptor.workers)
+        if chrome:
+            if self.hasChromeOnly():
+                return "sChrome" + self.name
+        else:
+            if self.hasNonChromeOnly():
+                return "s" + self.name
+        return "nullptr"
+    def usedForXrays(self):
+        # We only need Xrays for methods, attributes and constants, but in
+        # workers there are no Xrays.
+        return (self.name is "Methods" or self.name is "Attributes" or
+                self.name is "Constants") and not self.descriptor.workers
 
     def __str__(self):
         # We only need to generate id arrays for things that will end
         # up used via ResolveProperty or EnumerateProperties.
         str = self.generateArray(self.regular, self.variableName(False),
-                                 self.usedForXrays(False))
+                                 self.usedForXrays())
         if self.hasChromeOnly():
             str += self.generateArray(self.chrome, self.variableName(True),
-                                      self.usedForXrays(True))
+                                      self.usedForXrays())
         return str
 
     @staticmethod
     def getControllingPref(interfaceMember):
         prefName = interfaceMember.getExtendedAttribute("Pref")
         if prefName is None:
             return None
         # It's a list of strings
@@ -1007,31 +1010,25 @@ class MethodDefiner(PropertyDefiner):
         #       identifier. For now we check if the name starts with __
         methods = [m for m in descriptor.interface.members if
                    m.isMethod() and m.isStatic() == static and
                    not m.isIdentifierLess()]
         self.chrome = [{"name": m.identifier.name,
                         "length": methodLength(m),
                         "flags": "JSPROP_ENUMERATE",
                         "pref": PropertyDefiner.getControllingPref(m) }
-                       for m in methods]
+                       for m in methods if isChromeOnly(m)]
         self.regular = [{"name": m.identifier.name,
                          "length": methodLength(m),
                          "flags": "JSPROP_ENUMERATE",
                          "pref": PropertyDefiner.getControllingPref(m) }
                         for m in methods if not isChromeOnly(m)]
 
         # FIXME Check for an existing iterator on the interface first.
         if any(m.isGetter() and m.isIndexed() for m in methods):
-            self.chrome.append({"name": 'iterator',
-                                "methodInfo": False,
-                                "nativeName": "JS_ArrayIterator",
-                                "length": 0,
-                                "flags": "JSPROP_ENUMERATE",
-                                "pref": None })
             self.regular.append({"name": 'iterator',
                                  "methodInfo": False,
                                  "nativeName": "JS_ArrayIterator",
                                  "length": 0,
                                  "flags": "JSPROP_ENUMERATE",
                                  "pref": None })
 
         if not descriptor.interface.parent and not static and descriptor.nativeOwnership == 'nsisupports':
@@ -1072,18 +1069,19 @@ class MethodDefiner(PropertyDefiner):
             '  JS_FS_END',
             'JSFunctionSpec',
             pref, specData, doIdArrays)
 
 class AttrDefiner(PropertyDefiner):
     def __init__(self, descriptor, name):
         PropertyDefiner.__init__(self, descriptor, name)
         self.name = name
-        self.chrome = [m for m in descriptor.interface.members if m.isAttr()]
-        self.regular = [m for m in self.chrome if not isChromeOnly(m)]
+        attributes = [m for m in descriptor.interface.members if m.isAttr()]
+        self.chrome = [m for m in attributes if isChromeOnly(m)]
+        self.regular = [m for m in attributes if not isChromeOnly(m)]
 
     def generateArray(self, array, name, doIdArrays):
         if len(array) == 0:
             return ""
 
         def flags(attr):
             return "JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS"
 
@@ -1116,18 +1114,19 @@ class AttrDefiner(PropertyDefiner):
 
 class ConstDefiner(PropertyDefiner):
     """
     A class for definining constants on the interface object
     """
     def __init__(self, descriptor, name):
         PropertyDefiner.__init__(self, descriptor, name)
         self.name = name
-        self.chrome = [m for m in descriptor.interface.members if m.isConst()]
-        self.regular = [m for m in self.chrome if not isChromeOnly(m)]
+        constants = [m for m in descriptor.interface.members if m.isConst()]
+        self.chrome = [m for m in constants if isChromeOnly(m)]
+        self.regular = [m for m in constants if not isChromeOnly(m)]
 
     def generateArray(self, array, name, doIdArrays):
         if len(array) == 0:
             return ""
 
         def specData(const):
             return (const.identifier.name,
                     convertConstIDLValueToJSVal(const.value))
@@ -1150,29 +1149,59 @@ class PropertyArrays():
     def arrayNames():
         return [ "staticMethods", "methods", "attrs", "consts" ]
 
     @staticmethod
     def xrayRelevantArrayNames():
         return [ "methods", "attrs", "consts" ]
 
     def hasChromeOnly(self):
-        return reduce(lambda b, a: b or getattr(self, a).hasChromeOnly(),
-                      self.arrayNames(), False)
-    def variableNames(self, chrome):
-        names = {}
-        for array in self.arrayNames():
-            names[array] = getattr(self, array).variableName(chrome)
-        return names
+        return any(getattr(self, a).hasChromeOnly() for a in self.arrayNames())
+    def hasNonChromeOnly(self):
+        return any(getattr(self, a).hasNonChromeOnly() for a in self.arrayNames())
     def __str__(self):
         define = ""
         for array in self.arrayNames():
             define += str(getattr(self, array))
         return define
 
+class CGNativeProperties(CGList):
+    def __init__(self, descriptor, properties):
+        def generateNativeProperties(name, chrome):
+            def check(p):
+                return p.hasChromeOnly() if chrome else p.hasNonChromeOnly()
+
+            nativeProps = []
+            for array in properties.arrayNames():
+                propertyArray = getattr(properties, array)
+                if check(propertyArray):
+                    if descriptor.workers:
+                        props = "%(name)s, nullptr, %(name)s_specs"
+                    else:
+                        if propertyArray.usedForXrays():
+                            ids = "%(name)s_ids"
+                        else:
+                            ids = "nullptr"
+                        props = "%(name)s, " + ids + ", %(name)s_specs"
+                    props = (props %
+                             { 'name': propertyArray.variableName(chrome) })
+                else:
+                    props = "nullptr, nullptr, nullptr"
+                nativeProps.append(CGGeneric(props))
+            return CGWrapper(CGIndenter(CGList(nativeProps, ",\n")),
+                             pre="static const NativeProperties %s = {\n" % name,
+                             post="\n};")
+        
+        regular = generateNativeProperties("sNativeProperties", False)
+        chrome = generateNativeProperties("sChromeOnlyNativeProperties", True)
+        CGList.__init__(self, [regular, chrome], "\n\n")
+
+    def declare(self):
+        return ""
+
 class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
     """
     Generate the CreateInterfaceObjects method for an interface descriptor.
 
     properties should be a PropertyArrays instance.
     """
     def __init__(self, descriptor, properties):
         args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal'),
@@ -1198,17 +1227,17 @@ class CGCreateInterfaceObjectsMethod(CGA
         # There is no need to init any IDs in workers, because worker bindings
         # don't have Xrays.
         if not self.descriptor.workers:
             for var in self.properties.xrayRelevantArrayNames():
                 props = getattr(self.properties, var)
                 # We only have non-chrome ids to init if we have no chrome ids.
                 if props.hasChromeOnly():
                     idsToInit.append(props.variableName(True))
-                elif props.hasNonChromeOnly():
+                if props.hasNonChromeOnly():
                     idsToInit.append(props.variableName(False))
         if len(idsToInit) > 0:
             initIds = CGList(
                 [CGGeneric("!InitIds(aCx, %s, %s_ids)" % (varname, varname)) for
                  varname in idsToInit], ' ||\n')
             if len(idsToInit) > 1:
                 initIds = CGWrapper(initIds, pre="(", post=")", reindent=True)
             initIds = CGList(
@@ -1259,42 +1288,44 @@ class CGCreateInterfaceObjectsMethod(CGA
         if self.descriptor.concrete:
             if self.descriptor.proxy:
                 domClass = "&Class"
             else:
                 domClass = "&Class.mClass"
         else:
             domClass = "nullptr"
 
+        if self.properties.hasNonChromeOnly():
+            properties = "&sNativeProperties"
+        else:
+            properties = "nullptr"
+        if self.properties.hasChromeOnly():
+            if self.descriptor.workers:
+                accessCheck = "mozilla::dom::workers::GetWorkerPrivateFromContext(aCx)->IsChromeWorker()"
+            else:
+                accessCheck = "xpc::AccessCheck::isChrome(aGlobal)"
+            chromeProperties = accessCheck + " ? &sChromeOnlyNativeProperties : nullptr"
+        else:
+            chromeProperties = "nullptr"
         call = """return dom::CreateInterfaceObjects(aCx, aGlobal, aReceiver, parentProto,
                                    %s, %s, %s, %d,
                                    %s,
-                                   %%(methods)s, %%(attrs)s,
-                                   %%(consts)s, %%(staticMethods)s,
+                                   %s,
+                                   %s,
                                    %s);""" % (
             "&PrototypeClass" if needInterfacePrototypeObject else "NULL",
             "&InterfaceObjectClass" if needInterfaceObjectClass else "NULL",
             constructHook if needConstructor else "NULL",
             constructArgs,
             domClass,
+            properties,
+            chromeProperties,
             '"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "NULL")
-        if self.properties.hasChromeOnly():
-            if self.descriptor.workers:
-                accessCheck = "mozilla::dom::workers::GetWorkerPrivateFromContext(aCx)->IsChromeWorker()"
-            else:
-                accessCheck = "xpc::AccessCheck::isChrome(js::GetObjectCompartment(aGlobal))"
-            chrome = CGIfWrapper(CGGeneric(call % self.properties.variableNames(True)),
-                                 accessCheck)
-            chrome = CGWrapper(chrome, pre="\n\n")
-        else:
-            chrome = None
-
         functionBody = CGList(
-            [CGGeneric(getParentProto), initIds, prefCache, chrome,
-             CGGeneric(call % self.properties.variableNames(False))],
+            [CGGeneric(getParentProto), initIds, prefCache, CGGeneric(call)],
             "\n\n")
         return CGIndenter(functionBody).define()
 
 class CGGetPerInterfaceObject(CGAbstractMethod):
     """
     A method for getting a per-interface object (a prototype object or interface
     constructor object).
     """
@@ -4530,46 +4561,30 @@ class CGEnumerateOwnProperties(CGAbstrac
 """
 
 class CGXrayHelper(CGAbstractMethod):
     def __init__(self, descriptor, name, args, properties):
         CGAbstractMethod.__init__(self, descriptor, name, "bool", args)
         self.properties = properties
 
     def definition_body(self):
-        varNames = self.properties.variableNames(True)
-
-        methods = self.properties.methods
-        if methods.hasNonChromeOnly() or methods.hasChromeOnly():
-            methodArgs = """// %(methods)s has an end-of-list marker at the end that we ignore
-%(methods)s, %(methods)s_ids, %(methods)s_specs, ArrayLength(%(methods)s) - 1""" % varNames
+        prefixArgs = CGGeneric(self.getPrefixArgs())
+        if self.properties.hasNonChromeOnly():
+            regular = "&sNativeProperties"
         else:
-            methodArgs = "NULL, NULL, NULL, 0"
-        methodArgs = CGGeneric(methodArgs)
-
-        attrs = self.properties.attrs
-        if attrs.hasNonChromeOnly() or attrs.hasChromeOnly():
-            attrArgs = """// %(attrs)s has an end-of-list marker at the end that we ignore
-%(attrs)s, %(attrs)s_ids, %(attrs)s_specs, ArrayLength(%(attrs)s) - 1""" % varNames
+            regular = "nullptr"
+        regular = CGGeneric(regular)
+        if self.properties.hasChromeOnly():
+            chrome = "&sChromeOnlyNativeProperties"
         else:
-            attrArgs = "NULL, NULL, NULL, 0"
-        attrArgs = CGGeneric(attrArgs)
-
-        consts = self.properties.consts
-        if consts.hasNonChromeOnly() or consts.hasChromeOnly():
-            constArgs = """// %(consts)s has an end-of-list marker at the end that we ignore
-%(consts)s, %(consts)s_ids, %(consts)s_specs, ArrayLength(%(consts)s) - 1""" % varNames
-        else:
-            constArgs = "NULL, NULL, NULL, 0"
-        constArgs = CGGeneric(constArgs)
-
-        prefixArgs = CGGeneric(self.getPrefixArgs())
+            chrome = "nullptr"
+        chrome = CGGeneric(chrome)
 
         return CGIndenter(
-            CGWrapper(CGList([prefixArgs, methodArgs, attrArgs, constArgs], ",\n"),
+            CGWrapper(CGList([prefixArgs, regular, chrome], ",\n"),
                       pre=("return Xray%s(" % self.name),
                       post=");",
                       reindent=True)).define()
 
 class CGResolveProperty(CGXrayHelper):
     def __init__(self, descriptor, properties):
         args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'),
                 Argument('jsid', 'id'), Argument('bool', 'set'),
@@ -4584,17 +4599,17 @@ class CGResolveProperty(CGXrayHelper):
 class CGEnumerateProperties(CGXrayHelper):
     def __init__(self, descriptor, properties):
         args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'),
                 Argument('JS::AutoIdVector&', 'props')]
         CGXrayHelper.__init__(self, descriptor, "EnumerateProperties", args,
                               properties)
 
     def getPrefixArgs(self):
-        return "props"
+        return "wrapper, props"
 
 class CGPrototypeTraitsClass(CGClass):
     def __init__(self, descriptor, indent=''):
         templateArgs = [Argument('prototypes::ID', 'PrototypeID')]
         templateSpecialization = ['prototypes::id::' + descriptor.name]
         enums = [ClassEnum('', ['Depth'],
                            [descriptor.interface.inheritanceDepth()])]
         typedefs = [ClassTypedef('NativeType', descriptor.nativeType)]
@@ -5237,16 +5252,17 @@ class CGDescriptor(CGThing):
             cgThings.append(CGClassHasInstanceHook(descriptor))
             cgThings.append(CGInterfaceObjectJSClass(descriptor))
 
         if descriptor.interface.hasInterfacePrototypeObject():
             cgThings.append(CGPrototypeJSClass(descriptor))
 
         properties = PropertyArrays(descriptor)
         cgThings.append(CGGeneric(define=str(properties)))
+        cgThings.append(CGNativeProperties(descriptor, properties))
         cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
         if descriptor.interface.hasInterfacePrototypeObject():
             cgThings.append(CGGetProtoObjectMethod(descriptor))
         else:
             cgThings.append(CGGetConstructorObjectMethod(descriptor))
 
         # Set up our Xray callbacks as needed.  Note that we don't need to do
         # it in workers.
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -261,17 +261,19 @@ class Descriptor(DescriptorProvider):
             self.nativeOwnership = desc.get('nativeOwnership', 'nsisupports')
             if not self.nativeOwnership in ['owned', 'refcounted', 'nsisupports']:
                 raise TypeError("Descriptor for %s has unrecognized value (%s) "
                                 "for nativeOwnership" %
                                 (self.interface.identifier.name, self.nativeOwnership))
         self.customTrace = desc.get('customTrace', self.workers)
         self.customFinalize = desc.get('customFinalize', self.workers)
         self.wrapperCache = (not self.interface.isCallback() and
-                             (self.workers or desc.get('wrapperCache', True)))
+                             (self.workers or
+                              (self.nativeOwnership != 'owned' and
+                               desc.get('wrapperCache', True))))
 
         if not self.wrapperCache and self.prefable:
             raise TypeError("Descriptor for %s is prefable but not wrappercached" %
                             self.interface.identifier.name)
 
         def make_name(name):
             return name + "_workers" if self.workers else name
         self.name = make_name(interface.identifier.name)
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -6,16 +6,18 @@
 #ifndef mozilla_dom_DOMJSClass_h
 #define mozilla_dom_DOMJSClass_h
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 
 #include "mozilla/dom/PrototypeList.h" // auto-generated
 
+class nsCycleCollectionParticipant;
+
 // We use slot 0 for holding the raw object.  This is safe for both
 // globals and non-globals.
 #define DOM_OBJECT_SLOT 0
 
 // We use slot 1 for holding the expando object. This is not safe for globals
 // until bug 760095 is fixed, so that bug blocks converting Window to new
 // bindings.
 #define DOM_XRAY_EXPANDO_SLOT 1
@@ -61,16 +63,21 @@ struct DOMClass
 
   // We store the DOM object in reserved slot with index DOM_OBJECT_SLOT or in
   // the proxy private if we use a proxy object.
   // Sometimes it's an nsISupports and sometimes it's not; this class tells
   // us which it is.
   const bool mDOMObjectIsISupports;
 
   const NativePropertyHooks* mNativeHooks;
+
+  // This stores the CC participant for the native, null if this class is for a
+  // worker or for a native inheriting from nsISupports (we can get the CC
+  // participant by QI'ing in that case).
+  nsCycleCollectionParticipant* mParticipant;
 };
 
 // Special JSClass for reflected DOM objects.
 struct DOMJSClass
 {
   // It would be nice to just inherit from JSClass, but that precludes pure
   // compile-time initialization of the form |DOMJSClass = {...};|, since C++
   // only allows brace initialization for aggregate/POD types.
--- a/dom/imptests/failures/webapps/DOMCore/tests/approved/test_interfaces.html.json
+++ b/dom/imptests/failures/webapps/DOMCore/tests/approved/test_interfaces.html.json
@@ -159,18 +159,16 @@
   "Document interface: operation createEvent(DOMString)": true,
   "Document interface: operation createRange()": true,
   "Document interface: operation createNodeIterator(Node,unsigned long,NodeFilter)": true,
   "Document interface: operation createTreeWalker(Node,unsigned long,NodeFilter)": true,
   "XMLDocument interface: existence and properties of interface object": true,
   "XMLDocument interface: existence and properties of interface prototype object": true,
   "XMLDocument interface: existence and properties of interface prototype object's \"constructor\" property": true,
   "Stringification of xmlDoc": "debug",
-  "Document interface: xmlDoc must inherit property \"URL\" with the proper type (1)": true,
-  "Document interface: xmlDoc must inherit property \"compatMode\" with the proper type (3)": true,
   "Document interface: calling getElementsByTagName(DOMString) on xmlDoc with too few arguments must throw TypeError": true,
   "Document interface: calling getElementsByTagNameNS(DOMString,DOMString) on xmlDoc with too few arguments must throw TypeError": true,
   "Document interface: calling getElementsByClassName(DOMString) on xmlDoc with too few arguments must throw TypeError": true,
   "Document interface: calling getElementById(DOMString) on xmlDoc with too few arguments must throw TypeError": true,
   "Document interface: calling createElement(DOMString) on xmlDoc with too few arguments must throw TypeError": true,
   "Document interface: calling createElementNS(DOMString,DOMString) on xmlDoc with too few arguments must throw TypeError": true,
   "Document interface: calling createTextNode(DOMString) on xmlDoc with too few arguments must throw TypeError": true,
   "Document interface: calling createComment(DOMString) on xmlDoc with too few arguments must throw TypeError": true,
--- a/dom/interfaces/core/nsIDOMDocument.idl
+++ b/dom/interfaces/core/nsIDOMDocument.idl
@@ -22,17 +22,17 @@ interface nsIDOMLocation;
  * cannot exist outside the context of a Document, the nsIDOMDocument 
  * interface also contains the factory methods needed to create these 
  * objects.
  *
  * For more information on this interface please see 
  * http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
  */
 
-[scriptable, uuid(FDB92F4F-C6B4-4509-A29D-A309981E28AC)]
+[scriptable, uuid(22af46a3-64ac-430a-bcc7-d0a9aefe474f)]
 interface nsIDOMDocument : nsIDOMNode
 {
   readonly attribute nsIDOMDocumentType         doctype;
   readonly attribute nsIDOMDOMImplementation    implementation;
   readonly attribute nsIDOMElement              documentElement;
   nsIDOMElement                 createElement(in DOMString tagName)
                                   raises(DOMException);
   nsIDOMDocumentFragment        createDocumentFragment();
@@ -63,16 +63,18 @@ interface nsIDOMDocument : nsIDOMNode
   nsIDOMNodeList                getElementsByTagNameNS(in DOMString namespaceURI,
                                                        in DOMString localName);
   // Introduced in DOM Level 2:
   nsIDOMElement                 getElementById(in DOMString elementId);
   // Introduced in DOM Level 3:
   readonly attribute DOMString       inputEncoding;
   // Introduced in DOM Level 3:
   readonly attribute DOMString       documentURI;
+  // Alias introduced for all documents in recent DOM standards
+  readonly attribute DOMString       URL;
   // Introduced in DOM Level 3:
   nsIDOMNode         adoptNode(in nsIDOMNode source)
                                         raises(DOMException);
 
   /**
    * Create a range
    *
    * @see http://html5.org/specs/dom-range.html#dom-document-createrange
@@ -380,9 +382,15 @@ interface nsIDOMDocument : nsIDOMNode
   [implicit_jscontext] attribute jsval onmouseenter;
   [implicit_jscontext] attribute jsval onmouseleave;
 
   /**
    * Visibility API implementation.
    */
   readonly attribute boolean mozHidden;
   readonly attribute DOMString mozVisibilityState;
+
+  /**
+   * Returns "BackCompat" if we're in quirks mode or "CSS1Compat" if we're in
+   * strict mode.  (XML documents are always in strict mode.)
+   */
+  readonly attribute DOMString compatMode;
 };
--- a/dom/interfaces/html/nsIDOMHTMLDocument.idl
+++ b/dom/interfaces/html/nsIDOMHTMLDocument.idl
@@ -8,25 +8,21 @@
 /**
  * The nsIDOMHTMLDocument interface is the interface to a [X]HTML
  * document object.
  *
  * @see <http://www.whatwg.org/html/>
  */
 interface nsISelection;
 
-[scriptable, uuid(ecae54c6-2ab9-4167-b0ef-61960aadbb68)]
+[scriptable, uuid(3f8666a9-76f0-4733-ae11-4aea8753062d)]
 interface nsIDOMHTMLDocument : nsIDOMDocument
 {
-  readonly attribute DOMString            URL;
            attribute DOMString            domain;
            attribute DOMString            cookie;
-  // returns "BackCompat" if we're in quirks mode,
-  // or "CSS1Compat" if we're in strict mode
-  readonly attribute DOMString            compatMode;
 
   readonly attribute nsIDOMHTMLHeadElement head;
            attribute nsIDOMHTMLElement    body;
 
   readonly attribute nsIDOMHTMLCollection images;
   readonly attribute nsIDOMHTMLCollection embeds;
   // mapped to attribute embeds for NS4 compat
   readonly attribute nsIDOMHTMLCollection plugins;
--- a/dom/interfaces/svg/nsIDOMSVGDocument.idl
+++ b/dom/interfaces/svg/nsIDOMSVGDocument.idl
@@ -2,15 +2,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/. */
 
 #include "nsIDOMDocument.idl"
 
 interface nsIDOMSVGSVGElement;
 
-[scriptable, uuid(4AEBF9E7-F275-4147-AA90-601626476132)]
+[scriptable, uuid(8fe506e4-5563-4b16-9228-182071e3f8f8)]
 interface nsIDOMSVGDocument : nsIDOMDocument
 {
   readonly attribute DOMString domain;
-  readonly attribute DOMString URL;
   readonly attribute nsIDOMSVGSVGElement rootElement;
 };
--- a/dom/plugins/test/mochitest/test_convertpoint.xul
+++ b/dom/plugins/test/mochitest/test_convertpoint.xul
@@ -12,16 +12,23 @@
 <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
 </body>
 <script class="testbody" type="application/javascript">
 <![CDATA[
 SimpleTest.waitForExplicitFinish();
 
 function runTests() {
   var pluginElement = document.getElementById("plugin1");
+  // Poll to see if the plugin is in the right place yet.
+  // Check if x-coordinate 0 in plugin space is 0 in window space. If it is,
+  // the plugin hasn't been placed yet.
+  if (pluginElement.convertPointX(1, 0, 0, 2) == 0) {
+    setTimeout(runTests, 0);
+    return;
+  }
 
   netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 
   var domWindowUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                              .getInterface(Components.interfaces.nsIDOMWindowUtils);
   var devPxPerCSSPx = domWindowUtils.screenPixelsPerCSSPixel;
 
   var pluginRect = pluginElement.getBoundingClientRect();
--- a/dom/tests/mochitest/Makefile.in
+++ b/dom/tests/mochitest/Makefile.in
@@ -17,16 +17,17 @@ DIRS	+= \
 	dom-level2-html \
 	ajax \
 	bugs \
 	chrome \
 	general \
 	whatwg \
 	geolocation \
 	localstorage \
+	media \
 	orientation \
 	sessionstorage \
 	storageevent \
 	pointerlock \
 	webapps \
 	$(NULL)
 
 #needs IPC support, also tests do not run successfully in Firefox for now
--- a/dom/tests/mochitest/chrome/Makefile.in
+++ b/dom/tests/mochitest/chrome/Makefile.in
@@ -45,16 +45,18 @@ MOCHITEST_CHROME_FILES = \
 		test_callback_wrapping.xul \
 		window_callback_wrapping.xul \
 		test_sandbox_postMessage.html \
 		test_sandbox_bindings.xul \
 		test_selectAtPoint.html \
 		selectAtPoint.html \
 		test_bug799299.xul \
 		file_bug799299.xul \
+		test_bug800817.xul \
+		file_bug800817.xul \
 		$(NULL)
 
 ifeq (WINNT,$(OS_ARCH))
 MOCHITEST_CHROME_FILES += \
 		test_sizemode_attribute.xul \
 		sizemode_attribute.xul \
 		$(NULL)
 endif
copy from dom/tests/mochitest/chrome/file_bug799299.xul
copy to dom/tests/mochitest/chrome/file_bug800817.xul
--- a/dom/tests/mochitest/chrome/file_bug799299.xul
+++ b/dom/tests/mochitest/chrome/file_bug800817.xul
@@ -1,62 +1,75 @@
 <?xml version="1.0"?>
 <?xml-stylesheet type="text/css" href="chrome://global/skin"?>
 <?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
 <!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=799299
+https://bugzilla.mozilla.org/show_bug.cgi?id=800817
 -->
-<window title="Mozilla Bug 799299"
+<window title="Mozilla Bug 800817"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
 
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml">
-  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=799299"
-     target="_blank">Mozilla Bug 799299</a>
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=800817"
+     target="_blank">Mozilla Bug 800817</a>
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
-  /** Test for Bug 799299 **/
+  /** Test for Bug 800817 **/
 
   function sendClick(win) {
     var wu = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                 .getInterface(Components.interfaces.nsIDOMWindowUtils);
     wu.sendMouseEventToWindow("mousedown", 10, 10, 0, 0, 0);
     wu.sendMouseEventToWindow("mouseup", 10, 10, 0, 0, 0);
   }
 
   function runTests() {
     var b1 = document.getElementById("b1");
     var b2 = document.getElementById("b2");
+
+    var mozbrowserAttr = opener.wrappedJSObject.testMozBrowser ? "true" : "false";
+    b1.setAttribute("mozbrowser", mozbrowserAttr);
+    b2.setAttribute("mozbrowser", mozbrowserAttr);
+
+    opener.wrappedJSObject.ok(true, "Testing with mozbrowser="+ mozbrowserAttr);
+
     b1.contentWindow.focus();
-    opener.wrappedJSObject.is(document.activeElement, b1);
+    opener.wrappedJSObject.is(document.activeElement, b1,
+                              "Focused first iframe");
 
     var didCallDummy = false;
     b2.contentWindow.addEventListener("mousedown", function(e) { didCallDummy = true; });
     sendClick(b2.contentWindow);
     opener.wrappedJSObject.ok(didCallDummy);
-    opener.wrappedJSObject.is(document.activeElement, b2);
+    opener.wrappedJSObject.is(document.activeElement, b2,
+                              "Focus shifted to second iframe");
 
     b1.contentWindow.focus();
-    opener.wrappedJSObject.is(document.activeElement, b1);
+    opener.wrappedJSObject.is(document.activeElement, b1,
+                              "Re-focused first iframe for the first time");
 
     var didCallListener = false;
     b2.contentWindow.addEventListener("mousedown", function(e) { didCallListener = true; e.preventDefault(); });
     sendClick(b2.contentWindow);
     opener.wrappedJSObject.ok(didCallListener);
-    opener.wrappedJSObject.is(document.activeElement, b2);
+    opener.wrappedJSObject.is(document.activeElement, b1,
+                              "Did not move focus to the second iframe");
 
     window.close();
-    opener.wrappedJSObject.SimpleTest.finish();
+    opener.wrappedJSObject.finishedTests();
   }
 
   SimpleTest.waitForFocus(runTests);
   ]]>
   </script>
-  <hbox flex="1">
-    <browser id="b1" type="content" src="about:blank" flex="1" style="border: 1px solid black;"/>
-    <browser id="b2" type="content" src="about:blank" flex="1" style="border: 1px solid black;"/>
-  </hbox>
+  <iframe xmlns="http://www.w3.org/1999/xhtml"
+          id="b1" type="content" src="about:blank"
+          style="width: 300px; height: 550px; border: 1px solid black;"/>
+  <iframe xmlns="http://www.w3.org/1999/xhtml"
+          id="b2" type="content" src="about:blank"
+          style="width: 300px; height: 550px; border: 1px solid black;"/>
 </window>
copy from dom/tests/mochitest/chrome/test_bug799299.xul
copy to dom/tests/mochitest/chrome/test_bug800817.xul
--- a/dom/tests/mochitest/chrome/test_bug799299.xul
+++ b/dom/tests/mochitest/chrome/test_bug800817.xul
@@ -1,31 +1,43 @@
 <?xml version="1.0"?>
 <?xml-stylesheet type="text/css" href="chrome://global/skin"?>
 <?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
 <!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=799299
+https://bugzilla.mozilla.org/show_bug.cgi?id=800817
 -->
-<window title="Mozilla Bug 799299" onload="runTests()"
+<window title="Mozilla Bug 800817" onload="runTests()"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
 
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml">
-  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=799299"
-     target="_blank">Mozilla Bug 799299</a>
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=800817"
+     target="_blank">Mozilla Bug 800817</a>
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
-  /** Test for Bug 799299 **/
+  /** Test for Bug 800817 **/
+
+  var testMozBrowser = false;
+  function runTests() {
+    // Run a first round of tests for non-mozbrowser iframes.
+    window.open("file_bug800817.xul", "_blank", "chrome,width=600,height=550");
+  }
 
-  function runTests() {
-    window.open("file_bug799299.xul", "_blank", "chrome,width=600,height=550");
+  function finishedTests() {
+    if (!testMozBrowser) {
+      testMozBrowser = true;
+      // Run a second round of tests for mozbrowser iframes.
+      window.open("file_bug800817.xul", "_blank", "chrome,width=600,height=550");
+    } else {
+      SimpleTest.finish();
+    }
   }
 
   SimpleTest.waitForExplicitFinish();
 
   ]]>
   </script>
 </window>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/media/Makefile.in
@@ -0,0 +1,18 @@
+# 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/.
+
+DEPTH = @DEPTH@
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+relativesrcdir = @relativesrcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MOCHITEST_FILES	= \
+  test_getUserMedia_exceptions.html \
+  head.js \
+  $(NULL)
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/media/head.js
@@ -0,0 +1,22 @@
+/* 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/. */
+
+var Cc = SpecialPowers.Cc;
+var Ci = SpecialPowers.Ci;
+var Cr = SpecialPowers.Cr;
+
+/**
+ * Setup any Mochitest for WebRTC by enabling the preference for
+ * peer connections. As by bug 797979 it will also enable mozGetUserMedia().
+ * Additionally, we disable the permissions prompt for these mochitests.
+ *
+ * @param {Function} aCallback Test method to execute after initialization
+ */
+function runTest(aCallback) {
+  SimpleTest.waitForExplicitFinish();
+
+  SpecialPowers.pushPrefEnv({'set': [['media.peerconnection.enabled', true],
+                            ['media.navigator.permission.disabled', true]]},
+                            aCallback);
+}
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/media/test_getUserMedia_exceptions.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=795367
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test mozGetUserMedia Exceptions</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="head.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=795367">Test mozGetUserMedia Exceptions</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/**
+  These tests verify that the appropriate exception is thrown when incorrect
+  values are provided to the immediate mozGetUserMedia call.
+*/
+var exceptionTests = [
+  // Each test here verifies that a caller is required to have all
+  // three arguments in order to call mozGetUserMedia
+  { params: undefined,
+    error: Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS,
+    message: "no arguments specified" },
+  { params: [{video: true, fake: true}],
+    error: Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS,
+    message: "one argument specified" },
+  { params: [{video: true, fake: true}, unexpectedCall],
+    error: Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS,
+    message: "two arguments specified" },
+
+  // Each test here verifies that providing an incorret object
+  // type to any mozGetUserMedia parameter should throw
+  // the correct exception specified
+  { params: [1, unexpectedCall, unexpectedCall],
+    error: Cr.NS_ERROR_XPC_BAD_CONVERT_JS,
+    message: "wrong object type as first parameter" },
+  { params: [{video: true, fake: true}, 1, unexpectedCall],
+    error: Cr.NS_ERROR_XPC_BAD_CONVERT_JS,
+    message: "wrong object type as second parameter" },
+  { params: [{video: true, fake: true}, unexpectedCall, 1],
+    error: Cr.NS_ERROR_XPC_BAD_CONVERT_JS,
+    message: "wrong object type as third parameter" }
+];
+
+/**
+ * A callback function that is only called if a particular
+ * exception was not thrown, resulting in the test failing.
+ *
+ * @param  {MediaStream} argument ignored
+ */
+function unexpectedCall(obj) {
+  ok(false, "Callback should not have been called");
+}
+
+/**
+ * Starts the test run by running through each exception
+ * test by verifying that the correct exception type specified
+ * is thrown on the mozGetUserMedia call with the parameters
+ * specified.
+ */
+runTest(function () {
+  exceptionTests.forEach(function (test) {
+    var exception = false;
+    try {
+      navigator.mozGetUserMedia.apply(navigator, test.params);
+    } catch (e) {
+      exception = (e.result === test.error);
+    }
+    ok(exception, "Exception for " + test.message);
+  });
+
+  SimpleTest.finish();
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/extensions/universalchardet/src/base/nsCodingStateMachine.h
+++ b/extensions/universalchardet/src/base/nsCodingStateMachine.h
@@ -1,44 +1,49 @@
 /* -*- Mode: C; tab-width: 4; 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/. */
 #ifndef nsCodingStateMachine_h__
 #define nsCodingStateMachine_h__
 
 #include "nsPkgInt.h"
+#include "mozilla/Util.h"
 
 typedef enum {
    eStart = 0,
    eError = 1,
    eItsMe = 2 
 } nsSMState;
 
 #define GETCLASS(c) GETFROMPCK(((unsigned char)(c)), mModel->classTable)
 
 //state machine model
 typedef struct 
 {
   nsPkgInt classTable;
   uint32_t classFactor;
   nsPkgInt stateTable;
   const uint32_t* charLenTable;
+#ifdef DEBUG
+  const size_t charLenTableLength;
+#endif
   const char* name;
 } SMModel;
 
 class nsCodingStateMachine {
 public:
   nsCodingStateMachine(const SMModel* sm) : mModel(sm) { mCurrentState = eStart; }
   nsSMState NextState(char c){
     //for each byte we get its class , if it is first byte, we also get byte length
     uint32_t byteCls = GETCLASS(c);
     if (mCurrentState == eStart)
     { 
       mCurrentBytePos = 0; 
+      MOZ_ASSERT(byteCls < mModel->charLenTableLength);
       mCurrentCharLen = mModel->charLenTable[byteCls];
     }
     //from byte's class and stateTable, we get its next state
     mCurrentState=(nsSMState)GETFROMPCK(mCurrentState*(mModel->classFactor)+byteCls,
                                        mModel->stateTable);
     mCurrentBytePos++;
     return mCurrentState;
   }
@@ -63,10 +68,17 @@ extern const SMModel GB18030SMModel;
 extern const SMModel SJISSMModel;
 
 
 extern const SMModel HZSMModel;
 extern const SMModel ISO2022CNSMModel;
 extern const SMModel ISO2022JPSMModel;
 extern const SMModel ISO2022KRSMModel;
 
+#undef CHAR_LEN_TABLE
+#ifdef DEBUG
+#define CHAR_LEN_TABLE(x) x, mozilla::ArrayLength(x)
+#else
+#define CHAR_LEN_TABLE(x) x
+#endif
+
 #endif /* nsCodingStateMachine_h__ */
 
--- a/extensions/universalchardet/src/base/nsEscSM.cpp
+++ b/extensions/universalchardet/src/base/nsEscSM.cpp
@@ -50,17 +50,17 @@ PCK4BITS(     4,eItsMe,eStart,eStart,eSt
 };
 
 static const uint32_t HZCharLenTable[] = {0, 0, 0, 0, 0, 0};
 
 const SMModel HZSMModel = {
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, HZ_cls },
    6,
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, HZ_st },
-  HZCharLenTable,
+  CHAR_LEN_TABLE(HZCharLenTable),
   "HZ-GB-2312",
 };
 
 
 static const uint32_t ISO2022CN_cls [ 256 / 8 ] = {
 PCK4BITS(2,0,0,0,0,0,0,0),  // 00 - 07 
 PCK4BITS(0,0,0,0,0,0,0,0),  // 08 - 0f 
 PCK4BITS(0,0,0,0,0,0,0,0),  // 10 - 17 
@@ -108,17 +108,17 @@ PCK4BITS(eError,eError,eError,eError,eEr
 };
 
 static const uint32_t ISO2022CNCharLenTable[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
 
 const SMModel ISO2022CNSMModel = {
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, ISO2022CN_cls },
   9,
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, ISO2022CN_st },
-  ISO2022CNCharLenTable,
+  CHAR_LEN_TABLE(ISO2022CNCharLenTable),
   "ISO-2022-CN",
 };
 
 static const uint32_t ISO2022JP_cls [ 256 / 8 ] = {
 PCK4BITS(2,0,0,0,0,0,0,0),  // 00 - 07 
 PCK4BITS(0,0,0,0,0,0,2,2),  // 08 - 0f 
 PCK4BITS(0,0,0,0,0,0,0,0),  // 10 - 17 
 PCK4BITS(0,0,0,1,0,0,0,0),  // 18 - 1f 
@@ -160,23 +160,23 @@ PCK4BITS(eError,eError,eError,eError,eIt
 PCK4BITS(eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eError,eError),//18-1f 
 PCK4BITS(eError,     5,eError,eError,eError,     4,eError,eError),//20-27 
 PCK4BITS(eError,eError,eError,     6,eItsMe,eError,eItsMe,eError),//28-2f 
 PCK4BITS(eError,eError,eError,eError,eError,eError,eItsMe,eItsMe),//30-37 
 PCK4BITS(eError,eError,eError,eItsMe,eError,eError,eError,eError),//38-3f 
 PCK4BITS(eError,eError,eError,eError,eItsMe,eError,eStart,eStart) //40-47 
 };
 
-static const uint32_t ISO2022JPCharLenTable[] = {0, 0, 0, 0, 0, 0, 0, 0};
+static const uint32_t ISO2022JPCharLenTable[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
 const SMModel ISO2022JPSMModel = {
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, ISO2022JP_cls },
   10,
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, ISO2022JP_st },
-  ISO2022JPCharLenTable,
+  CHAR_LEN_TABLE(ISO2022JPCharLenTable),
   "ISO-2022-JP",
 };
 
 static const uint32_t ISO2022KR_cls [ 256 / 8 ] = {
 PCK4BITS(2,0,0,0,0,0,0,0),  // 00 - 07 
 PCK4BITS(0,0,0,0,0,0,0,0),  // 08 - 0f 
 PCK4BITS(0,0,0,0,0,0,0,0),  // 10 - 17 
 PCK4BITS(0,0,0,1,0,0,0,0),  // 18 - 1f 
@@ -220,12 +220,12 @@ PCK4BITS(eError,eError,eError,eItsMe,eSt
 };
 
 static const uint32_t ISO2022KRCharLenTable[] = {0, 0, 0, 0, 0, 0};
 
 const SMModel ISO2022KRSMModel = {
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, ISO2022KR_cls },
    6,
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, ISO2022KR_st },
-  ISO2022KRCharLenTable,
+  CHAR_LEN_TABLE(ISO2022KRCharLenTable),
   "ISO-2022-KR",
 };
 
--- a/extensions/universalchardet/src/base/nsMBCSSM.cpp
+++ b/extensions/universalchardet/src/base/nsMBCSSM.cpp
@@ -56,17 +56,17 @@ PCK4BITS(eError,eStart,eStart,eStart,eSt
 };
 
 static const uint32_t Big5CharLenTable[] = {0, 1, 1, 2, 0};
 
 SMModel const Big5SMModel = {
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, BIG5_cls },
     5,
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, BIG5_st },
-  Big5CharLenTable,
+  CHAR_LEN_TABLE(Big5CharLenTable),
   "Big5",
 };
 
 static const uint32_t EUCJP_cls [ 256 / 8 ] = {
 //PCK4BITS(5,4,4,4,4,4,4,4),  // 00 - 07 
 PCK4BITS(4,4,4,4,4,4,4,4),  // 00 - 07 
 PCK4BITS(4,4,4,4,4,4,5,5),  // 08 - 0f 
 PCK4BITS(4,4,4,4,4,4,4,4),  // 10 - 17 
@@ -111,17 +111,17 @@ PCK4BITS(     3,eError,eError,eError,eSt
 };
 
 static const uint32_t EUCJPCharLenTable[] = {2, 2, 2, 3, 1, 0};
 
 const SMModel EUCJPSMModel = {
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, EUCJP_cls },
    6,
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, EUCJP_st },
-  EUCJPCharLenTable,
+  CHAR_LEN_TABLE(EUCJPCharLenTable),
   "EUC-JP",
 };
 
 static const uint32_t EUCKR_cls [ 256 / 8 ] = {
 //PCK4BITS(0,1,1,1,1,1,1,1),  // 00 - 07 
 PCK4BITS(1,1,1,1,1,1,1,1),  // 00 - 07 
 PCK4BITS(1,1,1,1,1,1,0,0),  // 08 - 0f 
 PCK4BITS(1,1,1,1,1,1,1,1),  // 10 - 17 
@@ -163,17 +163,17 @@ PCK4BITS(eItsMe,eItsMe,eItsMe,eItsMe,eEr
 };
 
 static const uint32_t EUCKRCharLenTable[] = {0, 1, 2, 0};
 
 const SMModel EUCKRSMModel = {
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, EUCKR_cls },
   4,
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, EUCKR_st },
-  EUCKRCharLenTable,
+  CHAR_LEN_TABLE(EUCKRCharLenTable),
   "EUC-KR",
 };
 
 static const uint32_t EUCTW_cls [ 256 / 8 ] = {
 //PCK4BITS(0,2,2,2,2,2,2,2),  // 00 - 07 
 PCK4BITS(2,2,2,2,2,2,2,2),  // 00 - 07 
 PCK4BITS(2,2,2,2,2,2,0,0),  // 08 - 0f 
 PCK4BITS(2,2,2,2,2,2,2,2),  // 10 - 17 
@@ -219,17 +219,17 @@ PCK4BITS(eStart,eError,eStart,eStart,eSt
 };
 
 static const uint32_t EUCTWCharLenTable[] = {0, 0, 1, 2, 2, 2, 3};
 
 const SMModel EUCTWSMModel = {
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, EUCTW_cls },
    7,
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, EUCTW_st },
-  EUCTWCharLenTable,
+  CHAR_LEN_TABLE(EUCTWCharLenTable),
   "x-euc-tw",
 };
 
 /* obsolete GB2312 by gb18030
 static uint32_t GB2312_cls [ 256 / 8 ] = {
 //PCK4BITS(0,1,1,1,1,1,1,1),  // 00 - 07 
 PCK4BITS(1,1,1,1,1,1,1,1),  // 00 - 07 
 PCK4BITS(1,1,1,1,1,1,0,0),  // 08 - 0f 
@@ -272,17 +272,17 @@ PCK4BITS(eItsMe,eItsMe,eItsMe,eItsMe,eEr
 };
 
 static const uint32_t GB2312CharLenTable[] = {0, 1, 2, 0};
 
 SMModel GB2312SMModel = {
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, GB2312_cls },
    4,
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, GB2312_st },
-  GB2312CharLenTable,
+  CHAR_LEN_TABLE(GB2312CharLenTable),
   "GB2312",
 };
 */
 
 // the following state machine data was created by perl script in 
 // intl/chardet/tools. It should be the same as in PSM detector.
 static const uint32_t GB18030_cls [ 256 / 8 ] = {
 PCK4BITS(1,1,1,1,1,1,1,1),  // 00 - 07 
@@ -335,17 +335,17 @@ PCK4BITS(eError,eError,eStart,eStart,eSt
 // each code range there as well. So it is safe to set it to be 
 // 2 here. 
 static const uint32_t GB18030CharLenTable[] = {0, 1, 1, 1, 1, 1, 2};
 
 const SMModel GB18030SMModel = {
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, GB18030_cls },
    7,
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, GB18030_st },
-  GB18030CharLenTable,
+  CHAR_LEN_TABLE(GB18030CharLenTable),
   "GB18030",
 };
 
 // sjis
 
 static const uint32_t SJIS_cls [ 256 / 8 ] = {
 //PCK4BITS(0,1,1,1,1,1,1,1),  // 00 - 07 
 PCK4BITS(1,1,1,1,1,1,1,1),  // 00 - 07 
@@ -392,17 +392,17 @@ PCK4BITS(eItsMe,eItsMe,eError,eError,eSt
 };
 
 static const uint32_t SJISCharLenTable[] = {0, 1, 1, 2, 0, 0};
 
 const SMModel SJISSMModel = {
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, SJIS_cls },
    6,
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, SJIS_st },
-  SJISCharLenTable,
+  CHAR_LEN_TABLE(SJISCharLenTable),
   "Shift_JIS",
 };
 
 
 static const uint32_t UTF8_cls [ 256 / 8 ] = {
 //PCK4BITS(0,1,1,1,1,1,1,1),  // 00 - 07 
 PCK4BITS(1,1,1,1,1,1,1,1),  // 00 - 07  //allow 0x00 as a legal value
 PCK4BITS(1,1,1,1,1,1,0,0),  // 08 - 0f 
@@ -470,12 +470,12 @@ PCK4BITS(eError,eError,eError,eError,eEr
 
 static const uint32_t UTF8CharLenTable[] = {0, 1, 0, 0, 0, 0, 2, 3, 
                             3, 3, 4, 4, 5, 5, 6, 6 };
 
 const SMModel UTF8SMModel = {
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, UTF8_cls },
    16,
   {eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, UTF8_st },
-  UTF8CharLenTable,
+  CHAR_LEN_TABLE(UTF8CharLenTable),
   "UTF-8",
 };
 
--- a/extensions/universalchardet/tests/CharsetDetectionTests.js
+++ b/extensions/universalchardet/tests/CharsetDetectionTests.js
@@ -44,19 +44,19 @@ function InitDetectorTests()
     gTestIndex = 0;
     $("testframe").onload = DoDetectionTest;
 
     if (gExpectedCharset == "default") {
         try {
             gExpectedCharset = prefService
                 .getComplexValue("intl.charset.default",
                                  Ci.nsIPrefLocalizedString)
-                .data;
+                .data.toLowerCase();
         } catch (e) {
-            gExpectedCharset = "ISO-8859-8";
+            gExpectedCharset = "iso-8859-8";
         }
     }
 
     // Get the local directory. This needs to be a file: URI because chrome:
     // URIs are always UTF-8 (bug 617339) and we are testing decoding from other
     // charsets.
     var jar = getJar(getRootDirectory(window.location.href));
     var dir = jar ?
--- a/extensions/universalchardet/tests/test_bug306272.html
+++ b/extensions/universalchardet/tests/test_bug306272.html
@@ -17,17 +17,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">  
 </div>
 <iframe id="testframe"></iframe>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 /** Test for Bug 306272 **/
 CharsetDetectionTests("bug306272_text.html",
-		      "UTF-8",
+		      "utf-8",
 		      new Array("ja_parallel_state_machine",
 				"zh_parallel_state_machine",
 				"zhtw_parallel_state_machine",
 				"zhcn_parallel_state_machine",
 				"cjk_parallel_state_machine",
 				"universal_charset_detector"));
 </script>
 </pre>
--- a/extensions/universalchardet/tests/test_bug426271-euc-jp.html
+++ b/extensions/universalchardet/tests/test_bug426271-euc-jp.html
@@ -17,17 +17,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">  
 </div>
 <iframe id="testframe"></iframe>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 /** Test for Bug 426271 **/
 CharsetDetectionTests("bug426271_text-euc-jp.html",
-		      "EUC-JP",
+		      "euc-jp",
 		      new Array("ja_parallel_state_machine",
 				"cjk_parallel_state_machine",
 				"universal_charset_detector"));
 </script>
 </pre>
 </body>
 </html>
 
--- a/extensions/universalchardet/tests/test_bug426271-utf-8.html
+++ b/extensions/universalchardet/tests/test_bug426271-utf-8.html
@@ -17,17 +17,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">  
 </div>
 <iframe id="testframe"></iframe>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 /** Test for Bug 426271 **/
 CharsetDetectionTests("bug426271_text-utf-8.html",
-		      "UTF-8",
+		      "utf-8",
 		      new Array("ja_parallel_state_machine",
 				"zhtw_parallel_state_machine",
 				"zhcn_parallel_state_machine",
 				"zh_parallel_state_machine",
 				"cjk_parallel_state_machine",
 				"universal_charset_detector"));
 </script>
 </pre>
--- a/extensions/universalchardet/tests/test_bug431054-japanese.html
+++ b/extensions/universalchardet/tests/test_bug431054-japanese.html
@@ -17,14 +17,14 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">  
 </div>
 <iframe id="testframe"></iframe>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 /** Test for Bug 431054 **/
 CharsetDetectionTests("bug431054_text.html",
-		      "EUC-JP",
+		      "euc-jp",
 		      new Array("ja_parallel_state_machine"));
 </script>
 </pre>
 </body>
 </html>
--- a/extensions/universalchardet/tests/test_bug488426.html
+++ b/extensions/universalchardet/tests/test_bug488426.html
@@ -17,14 +17,14 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">  
 </div>
 <iframe id="testframe"></iframe>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 /** Test for Bug 488426 **/
 CharsetDetectionTests("bug488426_text.html",
-		      "TIS-620",
+		      "tis-620",
 		      new Array("universal_charset_detector"));
 </script>
 </pre>
 </body>
 </html>
--- a/extensions/universalchardet/tests/test_bug620106.html
+++ b/extensions/universalchardet/tests/test_bug620106.html
@@ -17,14 +17,14 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">  
 </div>
 <iframe id="testframe"></iframe>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 /** Test for Bug 620106 **/
 CharsetDetectionTests("bug620106_text.html",
-		      "EUC-JP",
+		      "euc-jp",
 		      new Array("universal_charset_detector"));
 </script>
 </pre>
 </body>
 </html>
--- a/extensions/universalchardet/tests/test_bug631751be.html
+++ b/extensions/universalchardet/tests/test_bug631751be.html
@@ -18,14 +18,14 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none">  
 </div>
 <iframe id="testframe"></iframe>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 /** Test for Bug 631751 **/
 /* Note! This test uses the chardet test harness but doesn't test chardet! */
 CharsetDetectionTests("bug631751be_text.html",
-		      "UTF-16BE",
+		      "utf-16be",
 		      new Array(""));
 </script>
 </pre>
 </body>
 </html>
--- a/extensions/universalchardet/tests/test_bug631751le.html
+++ b/extensions/universalchardet/tests/test_bug631751le.html
@@ -18,14 +18,14 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none">  
 </div>
 <iframe id="testframe"></iframe>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 /** Test for Bug 631751 **/
 /* Note! This test uses the chardet test harness but doesn't test chardet! */
 CharsetDetectionTests("bug631751le_text.html",
-		      "UTF-16LE",
+		      "utf-16le",
 		      new Array(""));
 </script>
 </pre>
 </body>
 </html>
--- a/extensions/universalchardet/tests/test_bug638318.html
+++ b/extensions/universalchardet/tests/test_bug638318.html
@@ -18,14 +18,14 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none">  
 </div>
 <iframe id="testframe"></iframe>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 /** Test for Bug 638318 **/
 /* Note! This test uses the chardet test harness but doesn't test chardet! */
 CharsetDetectionTests("bug638318_text.html",
-		      "ISO-8859-1",
+		      "iso-8859-1",
 		      new Array(""));
 </script>
 </pre>
 </body>
 </html>
--- a/extensions/universalchardet/tests/test_bug9357.html
+++ b/extensions/universalchardet/tests/test_bug9357.html
@@ -17,17 +17,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">  
 </div>
 <iframe id="testframe"></iframe>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 /** Test for Bug 9357 **/
 CharsetDetectionTests("bug9357_text.html",
-		      "EUC-KR",
+		      "euc-kr",
 		      new Array("ko_parallel_state_machine",
 				"cjk_parallel_state_machine",
 				"universal_charset_detector"));
 </script>
 </pre>
 </body>
 </html>
 
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -230,18 +230,18 @@ RasterImage::RasterImage(imgStatusTracke
   mMultipart(false),
   mDiscardable(false),
   mHasSourceData(false),
   mDecoded(false),
   mHasBeenDecoded(false),
   mInDecoder(false),
   mAnimationFinished(false),
   mFinishing(false),
-  mScaleRequest(this),
-  mInUpdateImageContainer(false)
+  mInUpdateImageContainer(false),
+  mScaleRequest(this)
 {
   // Set up the discard tracker node.
   mDiscardTrackerNode.img = this;
   Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(0);
 
   // Statistics
   num_containers++;
 
--- a/intl/unicharutil/util/nsUnicharUtils.cpp
+++ b/intl/unicharutil/util/nsUnicharUtils.cpp
@@ -31,27 +31,27 @@ static const uint8_t gASCIIToLower [128]
 #define IS_ASCII_UPPER(u) (('A' <= (u)) && ((u) <= 'Z'))
 #define IS_ASCII_LOWER(u) (('a' <= (u)) && ((u) <= 'z'))
 #define IS_ASCII_ALPHA(u) (IS_ASCII_UPPER(u) || IS_ASCII_LOWER(u))
 #define IS_ASCII_SPACE(u) (' ' == (u))
 
 // We want ToLowerCase(uint32_t) and ToLowerCaseASCII(uint32_t) to be fast
 // when they're called from within the case-insensitive comparators, so we
 // define inlined versions.
-static NS_ALWAYS_INLINE uint32_t
+static MOZ_ALWAYS_INLINE uint32_t
 ToLowerCase_inline(uint32_t aChar)
 {
   if (IS_ASCII(aChar)) {
     return gASCIIToLower[aChar];
   }
 
   return mozilla::unicode::GetLowercase(aChar);
 }
 
-static NS_ALWAYS_INLINE uint32_t
+static MOZ_ALWAYS_INLINE uint32_t
 ToLowerCaseASCII_inline(const uint32_t aChar)
 {
   if (IS_ASCII(aChar)) {
     return gASCIIToLower[aChar];
   }
 
   return aChar;
 }
@@ -266,17 +266,17 @@ CaseInsensitiveCompare(const PRUnichar *
 
 // Calculates the codepoint of the UTF8 sequence starting at aStr.  Sets aNext
 // to the byte following the end of the sequence.
 //
 // If the sequence is invalid, or if computing the codepoint would take us off
 // the end of the string (as marked by aEnd), returns -1 and does not set
 // aNext.  Note that this function doesn't check that aStr < aEnd -- it assumes
 // you've done that already.
-static NS_ALWAYS_INLINE uint32_t
+static MOZ_ALWAYS_INLINE uint32_t
 GetLowerUTF8Codepoint(const char* aStr, const char* aEnd, const char **aNext)
 {
   // Convert to unsigned char so that stuffing chars into PRUint32s doesn't
   // sign extend.
   const unsigned char *str = (unsigned char*)aStr;
 
   if (UTF8traits::isASCII(str[0])) {
     // It's ASCII; just convert to lower-case and return it.
--- a/ipc/chromium/src/base/message_loop.cc
+++ b/ipc/chromium/src/base/message_loop.cc
@@ -332,17 +332,17 @@ void MessageLoop::RunTask(Task* task) {
 
   task->Run();
   delete task;
 
   nestable_tasks_allowed_ = true;
 }
 
 bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) {
-  if (pending_task.nestable || state_->run_depth >= run_depth_base_) {
+  if (pending_task.nestable || state_->run_depth <= run_depth_base_) {
     RunTask(pending_task.task);
     // Show that we ran a task (Note: a new one might arrive as a
     // consequence!).
     return true;
   }
 
   // We couldn't run the task now because we're in a nested message loop
   // and the task isn't nestable.
--- a/ipc/chromium/src/chrome/common/ipc_sync_message.h
+++ b/ipc/chromium/src/chrome/common/ipc_sync_message.h
@@ -80,16 +80,17 @@ class SyncMessage : public Message {
 
   static uint32_t next_id_;  // for generation of unique ids
 };
 
 // Used to deserialize parameters from a reply to a synchronous message
 class MessageReplyDeserializer {
  public:
   bool SerializeOutputParameters(const Message& msg);
+  virtual ~MessageReplyDeserializer() {}
  private:
   // Derived classes need to implement this, using the given iterator (which
   // is skipped past the header for synchronous messages).
   virtual bool SerializeOutputParameters(const Message& msg, void* iter) = 0;
 };
 
 }  // namespace IPC
 
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -3089,23 +3089,16 @@ if test "$MALLOC_H" != ""; then
    AC_DEFINE_UNQUOTED(MALLOC_H, <$MALLOC_H>)
 fi
 
 MOZ_ALLOCATING_FUNCS="strndup posix_memalign memalign valloc"
 AC_CHECK_FUNCS(strndup posix_memalign memalign valloc)
 
 dnl See if compiler supports some gcc-style attributes
 
-AC_CACHE_CHECK(for __attribute__((always_inline)),
-               ac_cv_attribute_always_inline,
-               [AC_TRY_COMPILE([inline void f(void) __attribute__((always_inline));],
-                               [],
-                               ac_cv_attribute_always_inline=yes,
-                               ac_cv_attribute_always_inline=no)])
-
 AC_CACHE_CHECK(for __attribute__((malloc)),
                ac_cv_attribute_malloc,
                [AC_TRY_COMPILE([void* f(int) __attribute__((malloc));],
                                [],
                                ac_cv_attribute_malloc=yes,
                                ac_cv_attribute_malloc=no)])
 
 AC_CACHE_CHECK(for __attribute__((warn_unused_result)),
@@ -3147,22 +3140,16 @@ fi
 
 dnl Mozilla specific options
 dnl ========================================================
 dnl The macros used for command line options
 dnl are defined in build/autoconf/altoptions.m4.
 
 dnl If the compiler supports these attributes, define them as
 dnl convenience macros.
-if test "$ac_cv_attribute_always_inline" = yes ; then
-  AC_DEFINE(NS_ALWAYS_INLINE, [__attribute__((always_inline))])
-else
-  AC_DEFINE(NS_ALWAYS_INLINE,)
-fi
-
 if test "$ac_cv_attribute_malloc" = yes ; then
   AC_DEFINE(NS_ATTR_MALLOC, [__attribute__((malloc))])
 else
   AC_DEFINE(NS_ATTR_MALLOC,)
 fi
 
 if test "$ac_cv_attribute_warn_unused" = yes ; then
   AC_DEFINE(NS_WARN_UNUSED_RESULT, [__attribute__((warn_unused_result))])
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/evaluate-catchTermination.js
@@ -0,0 +1,6 @@
+// Test evaluate's catchTermination option.
+
+var x = 0;
+assertEq(evaluate('x = 1; terminate(); x = 2;', { catchTermination: true }),
+         "terminated");
+assertEq(x, 1);
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/Debugger-debuggees-07.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// Handle proto-less objects passed to addDebuggee.
-
-var g = newGlobal('new-compartment');
-var obj = g.eval("Object.create(null)");
-var dbg = new Debugger;
-
-// hasDebuggee and removeDebuggee must tolerate proto-less objects.
-assertEq(dbg.hasDebuggee(obj), false);
-
-// addDebuggee may either succeed or throw a TypeError. Don't care.
-var added;
-try {
-    dbg.addDebuggee(obj);
-    added = true;
-} catch (exc) {
-    if (!(exc instanceof TypeError))
-        throw exc;
-    added = false;
-}
-
-assertEq(dbg.hasDebuggee(obj), added);
-assertEq(dbg.getDebuggees().length, added ? 1 : 0);
-assertEq(dbg.removeDebuggee(obj), undefined);
-assertEq(dbg.hasDebuggee(obj), false);
--- a/js/src/jit-test/tests/debug/Debugger-debuggees-08.js
+++ b/js/src/jit-test/tests/debug/Debugger-debuggees-08.js
@@ -1,9 +1,8 @@
-// addDebuggee(obj), where obj is not global, adds obj's global.
 // Adding a debuggee more than once is redundant.
 
 var dbg = new Debugger;
 var g = newGlobal('new-compartment');
 var w = dbg.addDebuggee(g);
 assertEq(w instanceof Debugger.Object, true);
 
 function usual() {
@@ -14,25 +13,13 @@ function usual() {
     assertEq(arr[0], w);
 }
 
 usual();
 assertEq(dbg.addDebuggee(g), w);
 usual();
 assertEq(dbg.addDebuggee(w), w);
 usual();
-dbg.addDebuggee(g.Math);
-usual();
-dbg.addDebuggee(g.eval("(function () {})"));
-usual();
-
-// w2 is a Debugger.Object in g. Treat it like any other object in g; don't auto-unwrap it.
-g.g2 = newGlobal('new-compartment');
-g.eval("var w2 = new Debugger().addDebuggee(g2)");
-dbg.addDebuggee(g.w2);
-usual();
-assertEq(!dbg.hasDebuggee(g.g2), true);
-assertEq(dbg.hasDebuggee(g.w2), true);
 
 // Removing the debuggee once is enough.
 assertEq(dbg.removeDebuggee(g), undefined);
 assertEq(dbg.hasDebuggee(g), false);
 assertEq(dbg.getDebuggees().length, 0);
--- a/js/src/jit-test/tests/debug/Debugger-debuggees-09.js
+++ b/js/src/jit-test/tests/debug/Debugger-debuggees-09.js
@@ -1,27 +1,22 @@
 // |jit-test| debug
-// Random objects can be the argument to hasDebuggee and removeDebuggee.
 // If hasDebuggee(x) is false, removeDebuggee(x) does nothing.
 
 var dbg = new Debugger;
 
 function check(obj) {
     // If obj is something we could never debug, hasDebuggee(obj) is false.
     assertEq(dbg.hasDebuggee(obj), false);
 
     // If hasDebuggee(x) is false, removeDebuggee(x) does nothing.
     assertEq(dbg.removeDebuggee(obj), undefined);
 }
 
-// objects in this compartment, which we can't debug
-check(this);
-check({});
+// global objects which happen not to be debuggees at the moment
 var g1 = newGlobal('same-compartment');
 check(g1);
-check(g1.eval("({})"));
 
 // objects in a compartment that is already debugging us
 var g2 = newGlobal('new-compartment');
 g2.parent = this;
 g2.eval("var dbg = new Debugger(parent);");
 check(g2);
-check(g2.dbg);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-debuggees-17.js
@@ -0,0 +1,26 @@
+// addDebuggee, hasDebuggee, and removeDebuggee all throw if presented with
+// objects that are not valid global object designators.
+
+load(libdir + 'asserts.js');
+
+var dbg = new Debugger;
+
+function check(bad) {
+  print("check(" + uneval(bad) + ")");
+  assertThrowsInstanceOf(function () { dbg.addDebuggee(bad); }, TypeError);
+  assertEq(dbg.getDebuggees().length, 0);
+  assertThrowsInstanceOf(function () { dbg.hasDebuggee(bad); }, TypeError);
+  assertThrowsInstanceOf(function () { dbg.removeDebuggee(bad); }, TypeError);
+}
+
+var g = newGlobal();
+check(g.Object());
+check(g.Object);
+check(g.Function(""));
+
+// A Debugger.Object belonging to a different Debugger is not a valid way
+// to designate a global, even if its referent is a global.
+var g2 = newGlobal();
+var dbg2 = new Debugger;
+var d2g2 = dbg2.addDebuggee(g2);
+check(d2g2);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-debuggees-18.js
@@ -0,0 +1,117 @@
+// Debugger.prototype.{addDebuggee,hasDebuggee,removeDebuggee} recognize globals
+// regardless of how they are specified.
+
+var dbg = new Debugger;
+
+// Assert that dbg's debuggees are exactly the set passed as arguments.
+// The arguments are assumed to be Debugger.Object instances referring to
+// globals without wrappers --- which is the sort returned by addDebuggee.
+function assertDebuggees() {
+  print("assertDebuggees([" + [g.toSource() for each (g in arguments)] + "])");
+  var debuggees = dbg.getDebuggees();
+  assertEq(arguments.length, debuggees.length);
+  for each (g in arguments)
+    assertEq(debuggees.indexOf(g) != -1, true);
+}
+
+var g1 = newGlobal(); g1.toSource = function () { return "[global g1]"; };
+var g2 = newGlobal(); g2.toSource = function () { return "[global g2]"; };
+
+assertDebuggees();
+
+// Produce every possible way to designate g1, for us to play with.
+// Globals can be designated by any of the following:
+//
+// - "CCW": a Cross-Compartment Wrapper (CCW) of a global object
+// - "D.O": a Debugger.Object whose referent is a global object
+// - "D.O of CCW": a Debugger.Object whose referent is a CCW of a
+//   global object, where the CCW can be securely unwrapped
+//
+// There's no direct "G", since globals are always in their own
+// compartments, never the debugger's; if we ever viewed them directly,
+// that would be a compartment violation.
+
+// "dg1" means "Debugger.Object referring (directly) to g1".
+var dg1 = dbg.addDebuggee(g1);
+dg1.toSource = function() { return "[Debugger.Object for global g1]"; };
+assertEq(dg1.global, dg1);
+assertEq(dg1.unwrap(), dg1);
+assertDebuggees(dg1);
+
+// We need to add g2 as a debuggee; that's the only way to get a D.O referring
+// to it without a wrapper.
+var dg2 = dbg.addDebuggee(g2);
+dg2.toSource = function() { return "[Debugger.Object for global g2]"; };
+assertEq(dg2.global, dg2);
+assertEq(dg2.unwrap(), dg2);
+assertDebuggees(dg1, dg2);
+
+// "dwg1" means "Debugger.Object referring to CCW of g1".
+var dwg1 = dg2.makeDebuggeeValue(g1);
+assertEq(dwg1.global, dg2);
+assertEq(dwg1.unwrap(), dg1);
+dwg1.toSource = function() { return "[Debugger.Object for CCW of global g1]"; };
+
+assertDebuggees(dg1, dg2);
+assertEq(dbg.removeDebuggee(g1), undefined);
+assertEq(dbg.removeDebuggee(g2), undefined);
+assertDebuggees();
+
+// Systematically cover all the single-global possibilities:
+//
+//  | added as    | designated as | addDebuggee | hasDebuggee | removeDebuggee |
+//  |-------------+---------------+-------------+-------------+----------------|
+//  | (not added) | CCW           | X           | X           | X              |
+//  |             | D.O           | X           | X           | X              |
+//  |             | D.O of CCW    | X           | X           | X              |
+//  |-------------+---------------+-------------+-------------+----------------|
+//  | CCW         | CCW           | X           | X           | X              |
+//  |             | D.O           | X           | X           | X              |
+//  |             | D.O of CCW    | X           | X           | X              |
+//  |-------------+---------------+-------------+-------------+----------------|
+//  | D.O         | CCW           | X           | X           | X              |
+//  |             | D.O           | X           | X           | X              |
+//  |             | D.O of CCW    | X           | X           | X              |
+//  |-------------+---------------+-------------+-------------+----------------|
+//  | D.O of CCW  | CCW           | X           | X           | X              |
+//  |             | D.O           | X           | X           | X              |
+//  |             | D.O of CCW    | X           | X           | X              |
+
+// Cover the "(not added)" section of the table, other than "addDebuggee":
+assertEq(dbg.hasDebuggee(g1), false);
+assertEq(dbg.hasDebuggee(dg1), false);
+assertEq(dbg.hasDebuggee(dwg1), false);
+
+assertEq(dbg.removeDebuggee(g1), undefined); assertDebuggees();
+assertEq(dbg.removeDebuggee(dg1), undefined); assertDebuggees();
+assertEq(dbg.removeDebuggee(dwg1), undefined); assertDebuggees();
+
+// Try all operations adding the debuggee using |addAs|, and operating on it
+// using |designateAs|, thereby covering one row of the table (outside the '(not
+// added)' section), and one case in the '(not added)', 'designated as' section.
+//
+// |Direct| should be the Debugger.Object referring directly to the debuggee
+// global, for checking the results from addDebuggee and getDebuggees.
+function combo(addAs, designateAs, direct) {
+  print("combo(" + uneval(addAs) + ", " + uneval(designateAs) + ")");
+  assertDebuggees();
+  assertEq(dbg.addDebuggee(addAs), direct);
+  assertDebuggees(direct);
+  assertEq(dbg.addDebuggee(designateAs), direct);
+  assertDebuggees(direct);
+  assertEq(dbg.hasDebuggee(designateAs), true);
+  assertEq(dbg.removeDebuggee(designateAs), undefined);
+  assertDebuggees();
+}
+
+combo(g1, g1, dg1);
+combo(dg1, g1, dg1);
+combo(dwg1, g1, dg1);
+
+combo(g1, dg1, dg1);
+combo(dg1, dg1, dg1);
+combo(dwg1, dg1, dg1);
+
+combo(g1, dwg1, dg1);
+combo(dg1, dwg1, dg1);
+combo(dwg1, dwg1, dg1);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-findAllGlobals-01.js
@@ -0,0 +1,24 @@
+// Debugger.prototype.findAllGlobals surface.
+
+load(libdir + 'asserts.js');
+
+var dbg = new Debugger;
+var d = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(dbg), 'findAllGlobals');
+assertEq(d.configurable, true);
+assertEq(d.enumerable, false);
+assertEq(d.writable, true);
+assertEq(typeof d.value, 'function');
+assertEq(dbg.findAllGlobals.length, 0);
+assertEq(dbg.findAllGlobals.name, 'findAllGlobals');
+
+// findAllGlobals can only be applied to real Debugger instances.
+assertThrowsInstanceOf(function() {
+                         Debugger.prototype.findAllGlobals.call(Debugger.prototype);
+                       },
+                       TypeError);
+var a = dbg.findAllGlobals();
+assertEq(a instanceof Array, true);
+assertEq(a.length > 0, true);
+for (g of a) {
+  assertEq(g instanceof Debugger.Object, true);
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-findAllGlobals-02.js
@@ -0,0 +1,27 @@
+// Debugger.prototype.findAllGlobals finds ALL the globals!
+
+var g1 = newGlobal();           // Created before the Debugger; debuggee.
+var g2 = newGlobal();           // Created before the Debugger; not debuggee.
+
+var dbg = new Debugger;
+
+var g3 = newGlobal();           // Created after the Debugger; debuggee.
+var g4 = newGlobal();           // Created after the Debugger; not debuggee.
+
+var g1w = dbg.addDebuggee(g1);
+var g3w = dbg.addDebuggee(g3);
+
+var a = dbg.findAllGlobals();
+
+// Get Debugger.Objects viewing the globals from their own compartments;
+// this is the sort that findAllGlobals and addDebuggee return.
+var g2w = g1w.makeDebuggeeValue(g2).unwrap();
+var g4w = g1w.makeDebuggeeValue(g4).unwrap();
+var thisw = g1w.makeDebuggeeValue(this).unwrap();
+
+// Check that they're all there.
+assertEq(a.indexOf(g1w) != -1, true);
+assertEq(a.indexOf(g2w) != -1, true);
+assertEq(a.indexOf(g3w) != -1, true);
+assertEq(a.indexOf(g4w) != -1, true);
+assertEq(a.indexOf(thisw) != -1, true);
--- a/js/src/jit-test/tests/debug/Debugger-findScripts-02.js
+++ b/js/src/jit-test/tests/debug/Debugger-findScripts-02.js
@@ -1,15 +1,16 @@
 // In a debuggee with functions, findScripts finds those functions' scripts.
 
 var g = newGlobal('new-compartment');
 g.eval('function f(){}');
 g.eval('function g(){}');
 g.eval('function h(){}');
 
-var dbg = new Debugger(g);
-var fw = dbg.addDebuggee(g.f);
-var gw = dbg.addDebuggee(g.g);
-var hw = dbg.addDebuggee(g.h);
+var dbg = new Debugger();
+var gw = dbg.addDebuggee(g);
+var fw = gw.makeDebuggeeValue(g.f);
+var gw = gw.makeDebuggeeValue(g.g);
+var hw = gw.makeDebuggeeValue(g.h);
 
 assertEq(dbg.findScripts().indexOf(fw.script) != -1, true);
 assertEq(dbg.findScripts().indexOf(gw.script) != -1, true);
 assertEq(dbg.findScripts().indexOf(hw.script) != -1, true);
--- a/js/src/jit-test/tests/debug/Debugger-findScripts-05.js
+++ b/js/src/jit-test/tests/debug/Debugger-findScripts-05.js
@@ -1,17 +1,18 @@
 // findScripts' result includes scripts for nested functions.
 var g = newGlobal('new-compartment');
-var dbg = new Debugger(g);
+var dbg = new Debugger();
+var gw = dbg.addDebuggee(g);
 var log;
 
 g.eval('function f() { return function g() { return function h() { return "Squee!"; } } }');
-var fw = dbg.addDebuggee(g.f);
-var gw = dbg.addDebuggee(g.f());
-var hw = dbg.addDebuggee(g.f()());
+var fw = gw.makeDebuggeeValue(g.f);
+var gw = gw.makeDebuggeeValue(g.f());
+var hw = gw.makeDebuggeeValue(g.f()());
 
 assertEq(fw.script != gw.script, true);
 assertEq(fw.script != hw.script, true);
 
 var scripts = dbg.findScripts();
 assertEq(scripts.indexOf(fw.script) != -1, true);
 assertEq(scripts.indexOf(gw.script) != -1, true);
 assertEq(scripts.indexOf(hw.script) != -1, true);
--- a/js/src/jit-test/tests/debug/Debugger-findScripts-06.js
+++ b/js/src/jit-test/tests/debug/Debugger-findScripts-06.js
@@ -1,11 +1,13 @@
 // In a debugger with multiple debuggees, findScripts finds scripts across all debuggees.
 var g1 = newGlobal('new-compartment');
 var g2 = newGlobal('new-compartment');
-var dbg = new Debugger(g1, g2);
+var dbg = new Debugger();
+var g1w = dbg.addDebuggee(g1);
+var g2w = dbg.addDebuggee(g2);
 
 g1.eval('function f() {}');
 g2.eval('function g() {}');
 
 var scripts = dbg.findScripts();
-assertEq(scripts.indexOf(dbg.addDebuggee(g1.f).script) != -1, true);
-assertEq(scripts.indexOf(dbg.addDebuggee(g2.g).script) != -1, true);
+assertEq(scripts.indexOf(g1w.makeDebuggeeValue(g1.f).script) != -1, true);
+assertEq(scripts.indexOf(g2w.makeDebuggeeValue(g2.g).script) != -1, true);
--- a/js/src/jit-test/tests/debug/Debugger-findScripts-07.js
+++ b/js/src/jit-test/tests/debug/Debugger-findScripts-07.js
@@ -1,20 +1,22 @@
 // findScripts can filter scripts by global.
 var g1 = newGlobal('new-compartment');
 var g2 = newGlobal('new-compartment');
 var g3 = newGlobal('new-compartment');
 
-var dbg = new Debugger(g1, g2);
+var dbg = new Debugger();
+var g1w = dbg.addDebuggee(g1);
+var g2w = dbg.addDebuggee(g2);
 
 g1.eval('function f() {}');
 g2.eval('function g() {}');
 g2.eval('function h() {}');
-var g1fw = dbg.addDebuggee(g1.f);
-var g2gw = dbg.addDebuggee(g2.g);
+var g1fw = g1w.makeDebuggeeValue(g1.f);
+var g2gw = g2w.makeDebuggeeValue(g2.g);
 
 var scripts;
 
 scripts = dbg.findScripts({});
 assertEq(scripts.indexOf(g1fw.script) != -1, true);
 assertEq(scripts.indexOf(g2gw.script) != -1, true);
 
 scripts = dbg.findScripts({global: g1});
--- a/js/src/jit-test/tests/debug/Debugger-findScripts-08.js
+++ b/js/src/jit-test/tests/debug/Debugger-findScripts-08.js
@@ -6,22 +6,25 @@ var g3 = newGlobal('new-compartment');
 // Define some functions whose url will be this test file.
 g1.eval('function g1f() {}');
 g2.eval('function g2f() {}');
 
 // Define some functions whose url will be a different file.
 url2 = scriptdir + "Debugger-findScripts-08-script2";
 load(url2);
 
-var dbg = new Debugger(g1, g2, g3);
+var dbg = new Debugger();
+var g1w = dbg.addDebuggee(g1);
+var g2w = dbg.addDebuggee(g2);
+var g3w = dbg.addDebuggee(g3);
 
-var g1fw = dbg.addDebuggee(g1.g1f);
-var g1gw = dbg.addDebuggee(g1.g1g);
-var g2fw = dbg.addDebuggee(g2.g2f);
-var g2gw = dbg.addDebuggee(g2.g2g);
+var g1fw = g1w.makeDebuggeeValue(g1.g1f);
+var g1gw = g1w.makeDebuggeeValue(g1.g1g);
+var g2fw = g2w.makeDebuggeeValue(g2.g2f);
+var g2gw = g2w.makeDebuggeeValue(g2.g2g);
 
 // Find the url of this file.
 url = g1fw.script.url;
 
 var scripts;
 
 scripts = dbg.findScripts({});
 assertEq(scripts.indexOf(g1fw.script) != -1, true);
--- a/js/src/jit-test/tests/debug/Debugger-findScripts-09.js
+++ b/js/src/jit-test/tests/debug/Debugger-findScripts-09.js
@@ -1,16 +1,17 @@
 // Passing bad query properties to Debugger.prototype.findScripts throws.
 load(libdir + 'asserts.js');
 
 var dbg = new Debugger();
+var g = newGlobal();
 assertEq(dbg.findScripts().length, 0);
 assertEq(dbg.findScripts({}).length, 0);
 
-assertEq(dbg.findScripts({global:{}}).length, 0);
+assertEq(dbg.findScripts({global:g}).length, 0);
 assertThrowsInstanceOf(function () { dbg.findScripts({global:null}); }, TypeError);
 assertThrowsInstanceOf(function () { dbg.findScripts({global:true}); }, TypeError);
 assertThrowsInstanceOf(function () { dbg.findScripts({global:4}); }, TypeError);
 assertThrowsInstanceOf(function () { dbg.findScripts({global:"I must have fruit!"}); }, TypeError);
 
 assertEq(dbg.findScripts({url:""}).length, 0);
 assertThrowsInstanceOf(function () { dbg.findScripts({url:null}); }, TypeError);
 assertThrowsInstanceOf(function () { dbg.findScripts({url:true}); }, TypeError);
--- a/js/src/jit-test/tests/debug/Debugger-findScripts-11.js
+++ b/js/src/jit-test/tests/debug/Debugger-findScripts-11.js
@@ -1,18 +1,19 @@
 // Debugger.prototype.findScripts can filter scripts by line number.
-var g = newGlobal('new-compartment');
-var dbg = new Debugger(g);
+var g = newGlobal();
+var dbg = new Debugger();
+var gw = dbg.addDebuggee(g);
 
 var scriptname = scriptdir + 'Debugger-findScripts-11-script2';
 g.load(scriptname);
 
-var gfw = dbg.addDebuggee(g.f);
-var ggw = dbg.addDebuggee(g.f());
-var ghw = dbg.addDebuggee(g.h);
+var gfw = gw.makeDebuggeeValue(g.f);
+var ggw = gw.makeDebuggeeValue(g.f());
+var ghw = gw.makeDebuggeeValue(g.h);
 
 // Specifying a line outside of all functions screens out all function scripts.
 assertEq(dbg.findScripts({url:scriptname, line:3}).indexOf(gfw.script) != -1, false);
 assertEq(dbg.findScripts({url:scriptname, line:3}).indexOf(ggw.script) != -1, false);
 assertEq(dbg.findScripts({url:scriptname, line:3}).indexOf(ghw.script) != -1, false);
 
 // Specifying a different url screens out scripts, even when global and line match.
 assertEq(dbg.findScripts({url:"xlerb", line:8}).indexOf(gfw.script) != -1, false);
--- a/js/src/jit-test/tests/debug/Debugger-findScripts-12.js
+++ b/js/src/jit-test/tests/debug/Debugger-findScripts-12.js
@@ -13,17 +13,18 @@ var g2 = newGlobal('new-compartment');
 g2.toSource = function () "[global g2]";
 g2.load(url1);
 g2.load(url2);
 var g3 = newGlobal('new-compartment');
 
 var dbg = new Debugger(g1, g2, g3);
 
 function script(func) {
-    var script = dbg.addDebuggee(func).script;
+    var gw = dbg.addDebuggee(func.global);
+    var script = gw.makeDebuggeeValue(func).script;
     script.toString = function ()
         "[Debugger.Script for " + func.name + " in " + uneval(func.global) + "]";
     return script;
 }
 
 // The function scripts we know of. There may be random eval scripts involved, but
 // we don't care about those.
 var allScripts = ([g1.f, g1.f(), g1.g, g1.h, g1.h(), g1.i,
--- a/js/src/jit-test/tests/debug/Debugger-findScripts-14.js
+++ b/js/src/jit-test/tests/debug/Debugger-findScripts-14.js
@@ -1,15 +1,16 @@
 // Debugger.prototype.findScripts can find the innermost script at a given
 // source location.
 var g = newGlobal('new-compartment');
-var dbg = new Debugger(g);
+var dbg = new Debugger();
+var gw = dbg.addDebuggee(g);
 
 function script(f) {
-    return dbg.addDebuggee(f).script;
+    return gw.makeDebuggeeValue(f).script;
 }
 
 function arrayIsOnly(array, element) {
     return array.length == 1 && array[0] === element;
 }
 
 url = scriptdir + 'Debugger-findScripts-14.script1';
 g.load(url);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-onNewGlobalObject-01.js
@@ -0,0 +1,64 @@
+// Debugger.prototype.onNewGlobalObject surfaces.
+
+load(libdir + 'asserts.js');
+
+var dbg = new Debugger;
+
+function f() { }
+function g() { }
+
+assertEq(Object.getOwnPropertyDescriptor(dbg, 'onNewGlobalObject'), undefined);
+
+var d = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(dbg), 'onNewGlobalObject');
+assertEq(d.enumerable, false);
+assertEq(d.configurable, true);
+assertEq(typeof d.get, "function");
+assertEq(typeof d.set, "function");
+
+assertEq(dbg.onNewGlobalObject, undefined);
+
+assertThrowsInstanceOf(function () { dbg.onNewGlobalObject = ''; }, TypeError);
+assertEq(dbg.onNewGlobalObject, undefined);
+
+assertThrowsInstanceOf(function () { dbg.onNewGlobalObject = false; }, TypeError);
+assertEq(dbg.onNewGlobalObject, undefined);
+
+assertThrowsInstanceOf(function () { dbg.onNewGlobalObject = 0; }, TypeError);
+assertEq(dbg.onNewGlobalObject, undefined);
+
+assertThrowsInstanceOf(function () { dbg.onNewGlobalObject = Math.PI; }, TypeError);
+assertEq(dbg.onNewGlobalObject, undefined);
+
+assertThrowsInstanceOf(function () { dbg.onNewGlobalObject = null; }, TypeError);
+assertEq(dbg.onNewGlobalObject, undefined);
+
+assertThrowsInstanceOf(function () { dbg.onNewGlobalObject = {}; }, TypeError);
+assertEq(dbg.onNewGlobalObject, undefined);
+
+// But any function, even a useless one, is okay. How fair is that?
+dbg.onNewGlobalObject = f;
+assertEq(dbg.onNewGlobalObject, f);
+
+dbg.onNewGlobalObject = undefined;
+assertEq(dbg.onNewGlobalObject, undefined);
+
+var dbg2 = new Debugger;
+assertEq(dbg.onNewGlobalObject, undefined);
+assertEq(dbg2.onNewGlobalObject, undefined);
+
+dbg.onNewGlobalObject = f;
+assertEq(dbg.onNewGlobalObject, f);
+assertEq(dbg2.onNewGlobalObject, undefined);
+
+dbg2.onNewGlobalObject = g;
+assertEq(dbg.onNewGlobalObject, f);
+assertEq(dbg2.onNewGlobalObject, g);
+
+dbg.onNewGlobalObject = undefined;
+assertEq(dbg.onNewGlobalObject, undefined);
+assertEq(dbg2.onNewGlobalObject, g);
+
+// You shouldn't be able to apply the accessor to the prototype.
+assertThrowsInstanceOf(function () {
+                         Debugger.prototype.onNewGlobalObject = function () { };
+                       }, TypeError);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-onNewGlobalObject-02.js
@@ -0,0 +1,23 @@
+// onNewGlobalObject handlers fire, until they are removed.
+
+var dbg = new Debugger;
+var log;
+
+log = '';
+newGlobal();
+assertEq(log, '');
+
+dbg.onNewGlobalObject = function (global) {
+  log += 'n';
+  assertEq(global.seen, undefined);
+  global.seen = true;
+};
+
+log = '';
+newGlobal();
+assertEq(log, 'n');
+
+log = '';
+dbg.onNewGlobalObject = undefined;
+newGlobal();
+assertEq(log, '');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-onNewGlobalObject-03.js
@@ -0,0 +1,40 @@
+// onNewGlobalObject handlers on different Debugger instances are independent.
+
+var dbg1 = new Debugger;
+var log1;
+function h1(global) {
+  log1 += 'n';
+  assertEq(global.seen, undefined);
+  global.seen = true;
+}
+
+var dbg2 = new Debugger;
+var log2;
+function h2(global) {
+  log2 += 'n';
+  assertEq(global.seen, undefined);
+  global.seen = true;
+}
+
+log1 = log2 = '';
+newGlobal();
+assertEq(log1, '');
+assertEq(log2, '');
+
+log1 = log2 = '';
+dbg1.onNewGlobalObject = h1;
+newGlobal();
+assertEq(log1, 'n');
+assertEq(log2, '');
+
+log1 = log2 = '';
+dbg2.onNewGlobalObject = h2;
+newGlobal();
+assertEq(log1, 'n');
+assertEq(log2, 'n');
+
+log1 = log2 = '';
+dbg1.onNewGlobalObject = undefined;
+newGlobal();
+assertEq(log1, '');
+assertEq(log2, 'n');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-onNewGlobalObject-04.js
@@ -0,0 +1,24 @@
+// onNewGlobalObject handlers only fire on enabled Debuggers.
+
+var dbg = new Debugger;
+var log;
+
+dbg.onNewGlobalObject = function (global) {
+  log += 'n';
+  assertEq(global.seen, undefined);
+  global.seen = true;
+};
+
+log = '';
+newGlobal();
+assertEq(log, 'n');
+
+log = '';
+dbg.enabled = false;
+newGlobal();
+assertEq(log, '');
+
+log = '';
+dbg.enabled = true;
+newGlobal();
+assertEq(log, 'n');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-onNewGlobalObject-05.js
@@ -0,0 +1,13 @@
+// An onNewGlobalObject handler can disable itself.
+
+var dbg = new Debugger;
+var log;
+
+dbg.onNewGlobalObject = function (global) {
+  log += 'n';
+  dbg.onNewGlobalObject = undefined;
+};
+
+log = '';
+newGlobal();
+assertEq(log, 'n');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-onNewGlobalObject-06.js
@@ -0,0 +1,20 @@
+// One Debugger's onNewGlobalObject handler can disable another Debugger's handler.
+
+var dbg1 = new Debugger;
+var dbg2 = new Debugger;
+var dbg3 = new Debugger;
+var log;
+var hit;
+
+function handler(global) {
+  hit++;
+  log += hit;
+  if (hit == 2)
+    dbg1.onNewGlobalObject = dbg2.onNewGlobalObject = dbg3.onNewGlobalObject = undefined;
+};
+
+log = '';
+hit = 0;
+dbg1.onNewGlobalObject = dbg2.onNewGlobalObject = dbg3.onNewGlobalObject = handler;
+newGlobal();
+assertEq(log, '12');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-onNewGlobalObject-07.js
@@ -0,0 +1,20 @@
+// One Debugger's onNewGlobalObject handler can disable other Debuggers.
+
+var dbg1 = new Debugger;
+var dbg2 = new Debugger;
+var dbg3 = new Debugger;
+var log;
+var hit;
+
+function handler(global) {
+  hit++;
+  log += hit;
+  if (hit == 2)
+    dbg1.enabled = dbg2.enabled = dbg3.enabled = false;
+};
+
+log = '';
+hit = 0;
+dbg1.onNewGlobalObject = dbg2.onNewGlobalObject = dbg3.onNewGlobalObject = handler;
+newGlobal();
+assertEq(log, '12');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-onNewGlobalObject-08.js
@@ -0,0 +1,26 @@
+// Creating a global within an onNewGlobalObject handler causes a recursive handler invocation.
+//
+// This isn't really desirable behavior, as presumably a global created while a
+// handler is running is one the debugger is creating for its own purposes and
+// should not be observed, but if this behavior changes, we sure want to know.
+
+var dbg = new Debugger;
+var log;
+var depth;
+
+dbg.onNewGlobalObject = function (global) {
+  log += '('; depth++;
+
+  assertEq(global.seen, undefined);
+  global.seen = true;
+
+  if (depth < 3)
+    newGlobal();
+
+  log += ')'; depth--;
+};
+
+log = '';
+depth = 0;
+newGlobal();
+assertEq(log, '((()))');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-onNewGlobalObject-09.js
@@ -0,0 +1,27 @@
+// Resumption values from onNewGlobalObject handlers are respected.
+
+load(libdir + 'asserts.js');
+
+var dbg = new Debugger;
+var log;
+
+dbg.onNewGlobalObject = function (g) { log += 'n'; return undefined; };
+log = '';
+assertEq(typeof newGlobal(), "object");
+assertEq(log, 'n');
+
+// For onNewGlobalObject, { return: V } resumption values are treated like
+// 'undefined': the new global is still returned.
+dbg.onNewGlobalObject = function (g) { log += 'n'; return { return: "snoo" }; };
+log = '';
+assertEq(typeof newGlobal(), "object");
+assertEq(log, 'n');
+
+dbg.onNewGlobalObject = function (g) { log += 'n'; return { throw: "snoo" }; };
+log = '';
+assertThrowsValue(function () { newGlobal(); }, "snoo");
+assertEq(log, 'n');
+
+dbg.onNewGlobalObject = function (g) { log += 'n'; return null; };
+log = '';
+assertEq(evaluate('newGlobal();', { catchTermination: true }), "terminated");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-onNewGlobalObject-10.js
@@ -0,0 +1,23 @@
+// An earlier onNewGlobalObject handler returning a 'throw' resumption
+// value causes later handlers not to run.
+
+load(libdir + 'asserts.js');
+
+var dbg1 = new Debugger;
+var dbg2 = new Debugger;
+var dbg3 = new Debugger;
+var log;
+var count;
+
+dbg1.onNewGlobalObject = dbg2.onNewGlobalObject = dbg3.onNewGlobalObject = function (global) {
+  count++;
+  log += count;
+  if (count == 2)
+    return { throw: "snoo" };
+  return undefined;
+};
+
+log = '';
+count = 0;
+assertThrowsValue(function () { newGlobal(); }, "snoo");
+assertEq(log, '12');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-onNewGlobalObject-11.js
@@ -0,0 +1,30 @@
+// Resumption values from uncaughtExceptionHook from onNewGlobalObject handlers are respected.
+
+load(libdir + 'asserts.js');
+
+var dbg = new Debugger;
+var log;
+
+dbg.onNewGlobalObject = function () {
+  log += 'n';
+  throw 'party';
+};
+
+dbg.uncaughtExceptionHook = function (ex) {
+  log += 'u';
+  assertEq(ex, 'party');
+  return { throw: 'fit' };
+};
+
+log = '';
+assertThrowsValue(newGlobal, 'fit');
+assertEq(log, 'nu');
+
+dbg.uncaughtExceptionHook = function (ex) {
+  log += 'u';
+  assertEq(ex, 'party');
+};
+
+log = '';
+assertEq(typeof newGlobal(), 'object');
+assertEq(log, 'nu');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-onNewGlobalObject-12.js
@@ -0,0 +1,29 @@
+// Resumption values from uncaughtExceptionHook from onNewGlobalObject
+// handlers affect the dispatch of the event to other Debugger instances.
+
+load(libdir + 'asserts.js');
+
+var dbg1 = new Debugger;
+var dbg2 = new Debugger;
+var dbg3 = new Debugger;
+var log;
+var count;
+
+dbg1.onNewGlobalObject = dbg2.onNewGlobalObject = dbg3.onNewGlobalObject = function () {
+  log += 'n';
+  throw 'party';
+};
+
+dbg1.uncaughtExceptionHook = dbg2.uncaughtExceptionHook = dbg3.uncaughtExceptionHook =
+function (ex) {
+  log += 'u';
+  assertEq(ex, 'party');
+  if (++count == 2)
+    return { throw: 'fit' };
+  return undefined;
+};
+
+log = '';
+count = 0;
+assertThrowsValue(newGlobal, 'fit');
+assertEq(log, 'nunu');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-onNewGlobalObject-13.js
@@ -0,0 +1,17 @@
+// onNewGlobalObject handlers receive the correct Debugger.Object instances.
+
+var dbg = new Debugger;
+
+var gw = null;
+dbg.onNewGlobalObject = function (global) {
+  assertEq(arguments.length, 1);
+  assertEq(this, dbg);
+  gw = global;
+};
+var g = newGlobal();
+assertEq(typeof gw, 'object');
+assertEq(dbg.addDebuggee(g), gw);
+
+// The Debugger.Objects passed to onNewGlobalObject are the global as
+// viewed from its own compartment.
+assertEq(gw.makeDebuggeeValue(g), gw);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-onNewGlobalObject-14.js
@@ -0,0 +1,17 @@
+// Globals passed to onNewGlobalObject handers are ready for use immediately.
+
+var dbg = new Debugger;
+var log = '';
+dbg.onNewGlobalObject = function (global) {
+  log += 'n';
+  var gw = dbg.addDebuggee(global);
+  gw.defineProperty('x', { value: -1 });
+  // Check that the global's magic lazy properties are working.
+  assertEq(gw.evalInGlobalWithBindings('Math.atan2(y,x)', { y: 0 }).return, Math.PI);
+  // Check that the global's prototype is hooked up.
+  assertEq(gw.evalInGlobalWithBindings('x.toString()', { x: gw }).return, "[object global]");
+};
+
+newGlobal();
+
+assertEq(log, 'n');
--- a/js/src/jit-test/tests/debug/Frame-onPop-11.js
+++ b/js/src/jit-test/tests/debug/Frame-onPop-11.js
@@ -1,16 +1,17 @@
 // Setting onPop handlers from breakpoint handlers works.
 var g = newGlobal('new-compartment');
 g.eval("function f(){ return 'to normalcy'; }");
-var dbg = new Debugger(g);
+var dbg = new Debugger();
+var gw = dbg.addDebuggee(g);
 var log;
 
 // Set a breakpoint at the start of g.f
-var gf = dbg.addDebuggee(g.f); // addDebuggee used as Debugger.Object factory
+var gf = gw.makeDebuggeeValue(g.f);
 var fStartOffset = gf.script.getLineOffsets(gf.script.startLine)[0];
 gf.script.setBreakpoint(fStartOffset, {
     hit: function handleHit(frame) {
         log += 'b';
         frame.onPop = function handlePop(c) {
             log += ')';
             assertEq(c.return, "to normalcy");
         };
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Object-evalInGlobal-05.js
@@ -0,0 +1,22 @@
+// Debugger.Object.prototype.evalInGlobal throws when asked to evaluate in a CCW of a global.
+
+load(libdir + 'asserts.js');
+
+var dbg = new Debugger();
+
+var g1 = newGlobal();
+var dg1 = dbg.addDebuggee(g1);
+
+var g2 = newGlobal();
+var dg2 = dbg.addDebuggee(g2);
+
+// Generate a Debugger.Object viewing g2 from g1's compartment.
+var dg1wg2 = dg1.makeDebuggeeValue(g2);
+assertEq(dg1wg2.global, dg1);
+assertEq(dg1wg2.unwrap(), dg2);
+assertThrowsInstanceOf(function () { dg1wg2.evalInGlobal('1'); }, TypeError);
+assertThrowsInstanceOf(function () { dg1wg2.evalInGlobalWithBindings('x', { x: 1 }); }, TypeError);
+
+// These, however, should not throw.
+assertEq(dg1wg2.unwrap().evalInGlobal('1729').return, 1729);
+assertEq(dg1wg2.unwrap().evalInGlobalWithBindings('x', { x: 1729 }).return, 1729);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Object-global-01.js
@@ -0,0 +1,26 @@
+// Debugger.Object.prototype.global accessor surfaces.
+
+load(libdir + 'asserts.js');
+
+var dbg = new Debugger;
+var g = newGlobal();
+var gw = dbg.addDebuggee(g);
+
+assertEq(Object.getOwnPropertyDescriptor(gw, 'global'), undefined);
+var d = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(gw), 'global');
+assertEq(d.enumerable, false);
+assertEq(d.configurable, true);
+assertEq(typeof d.get, "function");
+assertEq(d.get.length, 0);
+assertEq(d.set, undefined);
+
+// This should not throw.
+gw.global = '';
+
+// This should throw.
+assertThrowsInstanceOf(function () { "use strict"; gw.global = {}; }, TypeError);
+assertEq(gw.global, gw);
+
+// You shouldn't be able to apply the accessor to the prototype.
+assertThrowsInstanceOf(function () { return Debugger.Object.prototype.global; },
+                       TypeError);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Object-global-02.js
@@ -0,0 +1,25 @@
+// Debugger.Object.prototype.global retrieves the correct global.
+
+var dbg = new Debugger;
+var g1 = newGlobal();
+var g1w = dbg.addDebuggee(g1);
+var g2 = newGlobal();
+var g2w = dbg.addDebuggee(g2);
+
+assertEq(g1w === g2w, false);
+assertEq(g1w.global, g1w);
+assertEq(g2w.global, g2w);
+
+var g1ow = g1w.makeDebuggeeValue(g1.Object());
+var g2ow = g2w.makeDebuggeeValue(g2.Object());
+assertEq(g1ow.global, g1w);
+assertEq(g2ow.global, g2w);
+
+// mild paranoia
+assertEq(g1ow.global === g1ow, false);
+assertEq(g2ow.global === g2ow, false);
+
+// The .global accessor doesn't unwrap.
+assertEq(g1w.makeDebuggeeValue(g2.Object()).global, g1w);
+assertEq(g2w.makeDebuggeeValue(g1.Object()).global, g2w);
+
--- a/js/src/jit-test/tests/debug/Object-preventExtensions-01.js
+++ b/js/src/jit-test/tests/debug/Object-preventExtensions-01.js
@@ -1,16 +1,17 @@
 // Basic preventExtensions test.
 
 var g = newGlobal('new-compartment');
 var obj = g.eval("({x: 1})");
 assertEq(g.Object.isExtensible(obj), true);
 
 var dbg = new Debugger;
-var objw = dbg.addDebuggee(obj);
+var gw = dbg.addDebuggee(g);
+var objw = gw.makeDebuggeeValue(obj);
 assertEq(objw.isExtensible(), true);
 
 assertEq(objw.preventExtensions(), undefined);
 assertEq(g.Object.isExtensible(obj), false);
 assertEq(objw.isExtensible(), false);
 
 // Calling preventExtensions again has no effect.
 assertEq(objw.preventExtensions(), undefined);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Object-unwrap-01.js
@@ -0,0 +1,23 @@
+// Check Debugger.Object.prototype.unwrap surfaces.
+
+load(libdir + 'asserts.js');
+
+var dbg = new Debugger();
+var g = newGlobal();
+var gw = dbg.addDebuggee(g);
+
+assertEq(Object.getOwnPropertyDescriptor(gw, 'unwrap'), undefined);
+var d = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(gw), 'unwrap');
+assertEq(d.enumerable, false);
+assertEq(d.configurable, true);
+assertEq(d.writable, true);
+
+assertEq(typeof gw.unwrap, "function");
+assertEq(gw.unwrap.length, 0);
+assertEq(gw.unwrap.name, "unwrap");
+
+// It can be called.
+gw.unwrap();
+
+// You shouldn't be able to apply the accessor to the prototype.
+assertThrowsInstanceOf(function () { Debugger.Object.prototype.unwrap(); }, TypeError);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Object-unwrap-02.js
@@ -0,0 +1,23 @@
+// Debugger.Object.prototype.unwrap unwraps Debugger.Objects referring to
+// cross-compartment wrappers.
+
+var dbg = new Debugger();
+
+var g1 = newGlobal();
+var dg1 = dbg.addDebuggee(g1);
+assertEq(dg1.unwrap(), dg1);
+
+var g2 = newGlobal();
+var dg2 = dbg.addDebuggee(g2);
+
+var dg1g2 = dg1.makeDebuggeeValue(g2);
+assertEq(dg1g2.global, dg1);
+assertEq(dg1g2.unwrap(), dg2);
+
+// Try an ordinary object, not a global.
+var g2o = g2.Object();
+var dg2o = dg2.makeDebuggeeValue(g2o);
+var dg1g2o = dg1.makeDebuggeeValue(g2o);
+assertEq(dg1g2o.global, dg1);
+assertEq(dg1g2o.unwrap(), dg2o);
+assertEq(dg1g2o.unwrap().unwrap(), dg2o);
--- a/js/src/jit-test/tests/debug/onEnterFrame-04.js
+++ b/js/src/jit-test/tests/debug/onEnterFrame-04.js
@@ -8,40 +8,41 @@
 // for at least detecting the recursion.
 
 load(libdir + 'asserts.js');
 
 var g = newGlobal('new-compartment');
 g.eval("function f(frame) { n++; return 42; }");
 g.n = 0;
 
-var dbg = Debugger(g);
+var dbg = Debugger();
+var gw = dbg.addDebuggee(g);
 
 // Register the debuggee function as the onEnterFrame handler. When we first
 // call or eval in the debuggee:
 //
 // - The onEnterFrame call reporting that frame's creation is itself an event
 //   that must be reported, so we call onEnterFrame again.
-// 
+//
 // - SpiderMonkey detects the out-of-control recursion, and generates a "too
 //   much recursion" InternalError in the youngest onEnterFrame call.
 //
 // - We don't catch it, so the onEnterFrame handler call itself throws.
 //
 // - Since the Debugger doesn't have an uncaughtExceptionHook (it can't; such a
 //   hook would itself raise a "too much recursion" exception), Spidermonkey
 //   reports the exception immediately and terminates the debuggee --- which is
 //   the next-older onEnterFrame call.
 //
 // - This termination propagates all the way out to the initial attempt to
 //   create a frame in the debuggee.
 dbg.onEnterFrame = g.f;
 
 // Get a Debugger.Object instance referring to f.
-var debuggeeF = dbg.addDebuggee(g.f);
+var debuggeeF = gw.makeDebuggeeValue(g.f);
 
 // Using f.call allows us to catch the termination.
 assertEq(debuggeeF.call(), null);
 
 // We should never actually begin execution of the function.
 assertEq(g.n, 0);
 
 // When an error is reported, the shell usually exits with a nonzero exit code.
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -370,8 +370,9 @@ MSG_DEF(JSMSG_CANT_DEFINE_INVALID,    31
 MSG_DEF(JSMSG_CANT_DEFINE_NE_AS_NC,   317, 0, JSEXN_TYPEERR, "proxy can't define a non-existent property as non-configurable")
 MSG_DEF(JSMSG_INVALID_TRAP_RESULT,    318, 2, JSEXN_TYPEERR, "trap {1} for {0} returned an invalid result")
 MSG_DEF(JSMSG_CANT_SKIP_NC,           319, 0, JSEXN_TYPEERR, "proxy can't skip a non-configurable property")
 MSG_DEF(JSMSG_MUST_REPORT_SAME_VALUE, 320, 0, JSEXN_TYPEERR, "proxy must report the same value for a non-writable, non-configurable property")
 MSG_DEF(JSMSG_MUST_REPORT_UNDEFINED,  321, 0, JSEXN_TYPEERR, "proxy must report undefined for a non-configurable accessor property without a getter")
 MSG_DEF(JSMSG_CANT_SET_NW_NC,         322, 0, JSEXN_TYPEERR, "proxy can't successfully set a non-writable, non-configurable property")
 MSG_DEF(JSMSG_CANT_SET_WO_SETTER,     323, 0, JSEXN_TYPEERR, "proxy can't succesfully set an accessor property without a setter")
 MSG_DEF(JSMSG_DEBUG_BAD_REFERENT,     324, 2, JSEXN_TYPEERR, "{0} does not refer to {1}")
+MSG_DEF(JSMSG_DEBUG_WRAPPER_IN_WAY,   325, 2, JSEXN_TYPEERR, "{0} is a wrapper around {1}, but a direct reference is required")
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -58,16 +58,17 @@
 #include "builtin/MapObject.h"
 #include "builtin/RegExp.h"
 #include "builtin/ParallelArray.h"
 #include "ds/LifoAlloc.h"
 #include "frontend/BytecodeCompiler.h"
 #include "gc/Marking.h"
 #include "gc/Memory.h"
 #include "js/MemoryMetrics.h"
+#include "vm/Debugger.h"
 #include "vm/NumericConversions.h"
 #include "vm/StringBuffer.h"
 #include "vm/Xdr.h"
 #include "yarr/BumpPointerAllocator.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsinterpinlines.h"
@@ -859,16 +860,17 @@ JSRuntime::JSRuntime()
     ionStackLimit(0),
     ionActivation(NULL),
     ionPcScriptCache(NULL),
     ionReturnOverride_(MagicValue(JS_ARG_POISON))
 {
     /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
     JS_INIT_CLIST(&contextList);
     JS_INIT_CLIST(&debuggerList);
+    JS_INIT_CLIST(&onNewGlobalObjectWatchers);
 
     PodZero(&debugHooks);
     PodZero(&atomState);
 
 #if JS_STACK_GROWTH_DIRECTION > 0
     nativeStackLimit = UINTPTR_MAX;
 #endif
 }
@@ -3376,18 +3378,23 @@ JS_NewGlobalObject(JSContext *cx, JSClas
     JSCompartment *compartment = NewCompartment(cx, principals);
     if (!compartment)
         return NULL;
 
     AutoHoldCompartment hold(compartment);
 
     JSCompartment *saved = cx->compartment;
     cx->setCompartment(compartment);
-    GlobalObject *global = GlobalObject::create(cx, Valueify(clasp));
+    Rooted<GlobalObject *> global(cx, GlobalObject::create(cx, Valueify(clasp)));
     cx->setCompartment(saved);
+    if (!global)
+        return NULL;
+
+    if (!Debugger::onNewGlobalObject(cx, global))
+        return NULL;
 
     return global;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *protoArg, JSObject *parentArg)
 {
     RootedObject proto(cx, protoArg);
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -349,17 +349,17 @@ JSRuntime::initSelfHosting(JSContext *cx
 
     /*
      * Set a temporary error reporter printing to stderr because it is too
      * early in the startup process for any other reporter to be registered
      * and we don't want errors in self-hosted code to be silently swallowed.
      */
     JSErrorReporter oldReporter = JS_SetErrorReporter(cx, selfHosting_ErrorReporter);
     Value rv;
-    bool ok;
+    bool ok = false;
 
     char *filename = getenv("MOZ_SELFHOSTEDJS");
     if (filename) {
         RootedScript script(cx, Compile(cx, shg, options, filename));
         if (script)
             ok = Execute(cx, script, *shg.get(), &rv);
     } else {
         const char *src = selfhosted::raw_sources;
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -809,16 +809,22 @@ struct JSRuntime : js::RuntimeFriendFiel
     JSBool              hadOutOfMemory;
 
     /*
      * Linked list of all js::Debugger objects. This may be accessed by the GC
      * thread, if any, or a thread that is in a request and holds gcLock.
      */
     JSCList             debuggerList;
 
+    /*
+     * Head of circular list of all enabled Debuggers that have
+     * onNewGlobalObject handler methods established.
+     */
+    JSCList             onNewGlobalObjectWatchers;
+
     /* Bookkeeping information for debug scope objects. */
     js::DebugScopes     *debugScopes;
 
     /* Linked list of live array buffers with >1 view */
     JSObject            *liveArrayBuffers;
 
     /* Client opaque pointers */
     void                *data;
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -788,16 +788,17 @@ Evaluate(JSContext *cx, unsigned argc, j
     bool newContext = false;
     bool compileAndGo = true;
     bool noScriptRval = false;
     const char *fileName = "@evaluate";
     JSAutoByteString fileNameBytes;
     jschar *sourceMapURL = NULL;
     unsigned lineNumber = 1;
     RootedObject global(cx, NULL);
+    bool catchTermination = false;
 
     global = JS_GetGlobalForObject(cx, &args.callee());
     if (!global)
         return false;
 
     if (argc == 2) {
         RootedObject options(cx, &args[1].toObject());
         jsval v;
@@ -873,16 +874,25 @@ Evaluate(JSContext *cx, unsigned argc, j
                     return false;
             }
             if (!global || !(JS_GetClass(global)->flags & JSCLASS_IS_GLOBAL)) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
                                      "\"global\" passed to evaluate()", "not a global object");
                 return false;
             }
         }
+
+        if (!JS_GetProperty(cx, options, "catchTermination", &v))
+            return false;
+        if (!JSVAL_IS_VOID(v)) {
+            JSBool b;
+            if (!JS_ValueToBoolean(cx, v, &b))
+                return false;
+            catchTermination = b;
+        }
     }
 
     RootedString code(cx, args[0].toString());
 
     size_t codeLength;
     const jschar *codeChars = JS_GetStringCharsAndLength(cx, code, &codeLength);
     if (!codeChars)
         return false;
@@ -908,18 +918,23 @@ Evaluate(JSContext *cx, unsigned argc, j
         JS_SetOptions(cx, saved);
         if (!script)
             return false;
 
         if (sourceMapURL && !script->scriptSource()->hasSourceMap()) {
             if (!script->scriptSource()->setSourceMap(cx, sourceMapURL, script->filename))
                 return false;
         }
-        if (!JS_ExecuteScript(cx, global, script, vp))
+        if (!JS_ExecuteScript(cx, global, script, vp)) {
+            if (catchTermination && !JS_IsExceptionPending(cx)) {
+                *vp = StringValue(JS_NewStringCopyZ(cx, "terminated"));
+                return true;
+            }
             return false;
+        }
     }
 
     return JS_WrapValue(cx, vp);
 }
 
 static JSString *
 FileAsString(JSContext *cx, const char *pathname)
 {
@@ -3436,17 +3451,20 @@ static JSFunctionSpecWithHelp shell_func
 "evaluate(code[, options])",
 "  Evaluate code as though it were the contents of a file.\n"
 "  options is an optional object that may have these properties:\n"
 "      compileAndGo: use the compile-and-go compiler option (default: true)\n"
 "      noScriptRval: use the no-script-rval compiler option (default: false)\n"
 "      fileName: filename for error messages and debug info\n"
 "      lineNumber: starting line number for error messages and debug info\n"
 "      global: global in which to execute the code\n"
-"      newContext: if true, create and use a new cx (default: false)\n"),
+"      newContext: if true, create and use a new cx (default: false)\n"
+"      catchTermination: if true, catch termination (failure without\n"
+"         an exception value, as for slow scripts or out-of-memory)\n"
+"          and return 'terminated'\n"),
 
     JS_FN_HELP("run", Run, 1, 0,
 "run('foo.js')",
 "  Run the file named by the first argument, returning the number of\n"
 "  of milliseconds spent compiling and executing it."),
 
     JS_FN_HELP("readline", ReadLine, 0, 0,
 "readline()",
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -11,16 +11,17 @@
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jswrapper.h"
 #include "jsarrayinlines.h"
 #include "jsgcinlines.h"
 #include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsopcodeinlines.h"
+#include "jscompartment.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "gc/Marking.h"
 #include "methodjit/Retcon.h"
 #include "js/Vector.h"
 
 #include "vm/Stack-inl.h"
@@ -361,25 +362,32 @@ Debugger::Debugger(JSContext *cx, JSObje
   : object(dbg), uncaughtExceptionHook(NULL), enabled(true),
     frames(cx), scripts(cx), objects(cx), environments(cx)
 {
     assertSameCompartment(cx, dbg);
 
     JSRuntime *rt = cx->runtime;
     JS_APPEND_LINK(&link, &rt->debuggerList);
     JS_INIT_CLIST(&breakpoints);
+    JS_INIT_CLIST(&onNewGlobalObjectWatchersLink);
 }
 
 Debugger::~Debugger()
 {
     JS_ASSERT(debuggees.empty());
 
     /* This always happens in the GC thread, so no locking is required. */
     JS_ASSERT(object->compartment()->rt->isHeapBusy());
     JS_REMOVE_LINK(&link);
+
+    /*
+     * Since the inactive state for this link is a singleton cycle, it's always
+     * safe to apply JS_REMOVE_LINK to it, regardless of whether we're in the list or not.
+     */
+    JS_REMOVE_LINK(&onNewGlobalObjectWatchersLink);
 }
 
 bool
 Debugger::init(JSContext *cx)
 {
     bool ok = debuggees.init() &&
               frames.init() &&
               scripts.init() &&
@@ -1241,16 +1249,89 @@ Debugger::onSingleStep(JSContext *cx, Va
     }
 
     vp->setUndefined();
     if (exceptionPending)
         cx->setPendingException(exception);
     return JSTRAP_CONTINUE;
 }
 
+JSTrapStatus
+Debugger::fireNewGlobalObject(JSContext *cx, Handle<GlobalObject *> global, Value *vp)
+{
+    RootedObject hook(cx, getHook(OnNewGlobalObject));
+    JS_ASSERT(hook);
+    JS_ASSERT(hook->isCallable());
+
+    Maybe<AutoCompartment> ac;
+    ac.construct(cx, object);
+
+    Value argv[1];
+    argv[0].setObject(*global);
+    if (!wrapDebuggeeValue(cx, &argv[0]))
+        return handleUncaughtException(ac, NULL, false);
+
+    Value rv;
+    bool ok = Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 1, argv, &rv);
+    return parseResumptionValue(ac, ok, rv, vp);
+}
+
+bool
+Debugger::slowPathOnNewGlobalObject(JSContext *cx, Handle<GlobalObject *> global)
+{
+    JS_ASSERT(!JS_CLIST_IS_EMPTY(&cx->runtime->onNewGlobalObjectWatchers));
+
+    /*
+     * Make a copy of the runtime's onNewGlobalObjectWatchers before running the
+     * handlers. Since one Debugger's handler can disable another's, the list
+     * can be mutated while we're walking it.
+     */
+    AutoObjectVector watchers(cx);
+    for (JSCList *link = JS_LIST_HEAD(&cx->runtime->onNewGlobalObjectWatchers);
+         link != &cx->runtime->onNewGlobalObjectWatchers;
+         link = JS_NEXT_LINK(link)) {
+        Debugger *dbg = fromOnNewGlobalObjectWatchersLink(link);
+        JS_ASSERT(dbg->observesNewGlobalObject());
+        if (!watchers.append(dbg->object))
+            return false;
+    }
+
+    JSTrapStatus status = JSTRAP_CONTINUE;
+    RootedValue value(cx);
+
+    for (size_t i = 0; i < watchers.length(); i++) {
+        Debugger *dbg = fromJSObject(watchers[i]);
+
+        // One Debugger's onNewGlobalObject handler can disable another's, so we
+        // must test this in the loop.
+        if (dbg->observesNewGlobalObject()) {
+            status = dbg->fireNewGlobalObject(cx, global, &value.get());
+            if (status != JSTRAP_CONTINUE && status != JSTRAP_RETURN)
+                break;
+        }
+    }
+
+    switch (status) {
+      case JSTRAP_CONTINUE:
+      case JSTRAP_RETURN: // Treat return like continue, ignoring the value.
+        return true;
+
+      case JSTRAP_ERROR:
+        JS_ASSERT(!cx->isExceptionPending());
+        return false;
+
+      case JSTRAP_THROW:
+        cx->setPendingException(value);
+        return false;
+
+      default:
+        JS_NOT_REACHED("bad status from Debugger::fireNewGlobalObject");
+    }
+}
+
 
 /*** Debugger JSObjects **************************************************************************/
 
 void
 Debugger::markKeysInCompartment(JSTracer *tracer)
 {
     /*
      * WeakMap::Range is deliberately private, to discourage C++ code from
@@ -1551,16 +1632,33 @@ Debugger::setEnabled(JSContext *cx, unsi
 
     if (enabled != dbg->enabled) {
         for (Breakpoint *bp = dbg->firstBreakpoint(); bp; bp = bp->nextInDebugger()) {
             if (enabled)
                 bp->site->inc(cx->runtime->defaultFreeOp());
             else
                 bp->site->dec(cx->runtime->defaultFreeOp());
         }
+
+        /*
+         * Add or remove ourselves from the runtime's list of Debuggers
+         * that care about new globals.
+         */
+        if (dbg->getHook(OnNewGlobalObject)) {
+            if (enabled) {
+                /* If we were not enabled, the link should be a singleton list. */
+                JS_ASSERT(JS_CLIST_IS_EMPTY(&dbg->onNewGlobalObjectWatchersLink));
+                JS_APPEND_LINK(&dbg->onNewGlobalObjectWatchersLink,
+                               &cx->runtime->onNewGlobalObjectWatchers);
+            } else {
+                /* If we were enabled, the link should be inserted in the list. */
+                JS_ASSERT(!JS_CLIST_IS_EMPTY(&dbg->onNewGlobalObjectWatchersLink));
+                JS_REMOVE_AND_INIT_LINK(&dbg->onNewGlobalObjectWatchersLink);
+            }
+        }
     }
 
     dbg->enabled = enabled;
     args.rval().setUndefined();
     return true;
 }
 
 JSBool
@@ -1634,16 +1732,52 @@ Debugger::getOnEnterFrame(JSContext *cx,
 
 JSBool
 Debugger::setOnEnterFrame(JSContext *cx, unsigned argc, Value *vp)
 {
     return setHookImpl(cx, argc, vp, OnEnterFrame);
 }
 
 JSBool
+Debugger::getOnNewGlobalObject(JSContext *cx, unsigned argc, Value *vp)
+{
+    return getHookImpl(cx, argc, vp, OnNewGlobalObject);
+}
+
+JSBool
+Debugger::setOnNewGlobalObject(JSContext *cx, unsigned argc, Value *vp)
+{
+    THIS_DEBUGGER(cx, argc, vp, "setOnNewGlobalObject", args, dbg);
+    JSObject *oldHook = dbg->getHook(OnNewGlobalObject);
+
+    if (!setHookImpl(cx, argc, vp, OnNewGlobalObject))
+        return false;
+
+    /*
+     * Add or remove ourselves from the runtime's list of Debuggers that
+     * care about new globals.
+     */
+    if (dbg->enabled) {
+        JSObject *newHook = dbg->getHook(OnNewGlobalObject);
+        if (!oldHook && newHook) {
+            /* If we didn't have a hook, the link should be a singleton list. */
+            JS_ASSERT(JS_CLIST_IS_EMPTY(&dbg->onNewGlobalObjectWatchersLink));
+            JS_APPEND_LINK(&dbg->onNewGlobalObjectWatchersLink,
+                           &cx->runtime->onNewGlobalObjectWatchers);
+        } else if (oldHook && !newHook) {
+            /* If we did have a hook, the link should be inserted in the list. */
+            JS_ASSERT(!JS_CLIST_IS_EMPTY(&dbg->onNewGlobalObjectWatchersLink));
+            JS_REMOVE_AND_INIT_LINK(&dbg->onNewGlobalObjectWatchersLink);
+        }
+    }
+
+    return true;
+}
+
+JSBool
 Debugger::getUncaughtExceptionHook(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGGER(cx, argc, vp, "get uncaughtExceptionHook", args, dbg);
     args.rval().setObjectOrNull(dbg->uncaughtExceptionHook);
     return true;
 }
 
 JSBool
@@ -1657,84 +1791,97 @@ Debugger::setUncaughtExceptionHook(JSCon
         return false;
     }
 
     dbg->uncaughtExceptionHook = args[0].toObjectOrNull();
     args.rval().setUndefined();
     return true;
 }
 
-JSObject *
+GlobalObject *
 Debugger::unwrapDebuggeeArgument(JSContext *cx, const Value &v)
 {
-    /*
-     * The argument to {add,remove,has}Debuggee may be
-     *   - a Debugger.Object belonging to this Debugger: return its referent
-     *   - a cross-compartment wrapper: return the wrapped object
-     *   - any other non-Debugger.Object object: return it
-     * If it is a primitive, or a Debugger.Object that belongs to some other
-     * Debugger, throw a TypeError.
-     */
-    JSObject *obj = NonNullObject(cx, v);
-    if (obj) {
-        if (obj->getClass() == &DebuggerObject_class) {
-            Value rv = v;
-            if (!unwrapDebuggeeValue(cx, &rv))
-                return NULL;
-            return &rv.toObject();
-        }
-        if (IsCrossCompartmentWrapper(obj))
-            return &GetProxyPrivate(obj).toObject();
+    if (!v.isObject()) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
+                             "argument", "not a global object");
+        return NULL;
+    }
+
+    RootedObject obj(cx, &v.toObject());
+
+    /* If it's a Debugger.Object belonging to this debugger, dereference that. */
+    if (obj->getClass() == &DebuggerObject_class) {
+        Value rv = v;
+        if (!unwrapDebuggeeValue(cx, &rv))
+            return NULL;
+        obj = &rv.toObject();
     }
-    return obj;
+
+    /* If we have a cross-compartment wrapper, dereference as far as is secure. */
+    obj = UnwrapObjectChecked(cx, obj);
+    if (!obj)
+        return NULL;
+
+    /* If that produced an outer window, innerize it. */
+    obj = GetInnerObject(cx, obj);
+    if (!obj)
+        return NULL;
+
+    /* If that didn't produce a global object, it's an error. */
+    if (!obj->isGlobal()) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
+                             "argument", "not a global object");
+        return NULL;
+    }
+
+    return &obj->asGlobal();
 }
 
 JSBool
 Debugger::addDebuggee(JSContext *cx, unsigned argc, Value *vp)
 {
     REQUIRE_ARGC("Debugger.addDebuggee", 1);
     THIS_DEBUGGER(cx, argc, vp, "addDebuggee", args, dbg);
-    RootedObject referent(cx, dbg->unwrapDebuggeeArgument(cx, args[0]));
-    if (!referent)
+    Rooted<GlobalObject*> global(cx, dbg->unwrapDebuggeeArgument(cx, args[0]));
+    if (!global)
         return false;
-    Rooted<GlobalObject*> global(cx, &referent->global());
+
     if (!dbg->addDebuggeeGlobal(cx, global))
         return false;
 
-    Value v = ObjectValue(*referent);
+    Value v = ObjectValue(*global);
     if (!dbg->wrapDebuggeeValue(cx, &v))
         return false;
     args.rval().set(v);
     return true;
 }
 
 JSBool
 Debugger::removeDebuggee(JSContext *cx, unsigned argc, Value *vp)
 {
     REQUIRE_ARGC("Debugger.removeDebuggee", 1);
     THIS_DEBUGGER(cx, argc, vp, "removeDebuggee", args, dbg);
-    JSObject *referent = dbg->unwrapDebuggeeArgument(cx, args[0]);
-    if (!referent)
+    GlobalObject *global = dbg->unwrapDebuggeeArgument(cx, args[0]);
+    if (!global)
         return false;
-    GlobalObject *global = &referent->global();
     if (dbg->debuggees.has(global))
         dbg->removeDebuggeeGlobal(cx->runtime->defaultFreeOp(), global, NULL, NULL);
     args.rval().setUndefined();
     return true;
 }
 
 JSBool
 Debugger::hasDebuggee(JSContext *cx, unsigned argc, Value *vp)
 {
     REQUIRE_ARGC("Debugger.hasDebuggee", 1);
     THIS_DEBUGGER(cx, argc, vp, "hasDebuggee", args, dbg);
-    JSObject *referent = dbg->unwrapDebuggeeArgument(cx, args[0]);
-    if (!referent)
+    GlobalObject *global = dbg->unwrapDebuggeeArgument(cx, args[0]);
+    if (!global)
         return false;
-    args.rval().setBoolean(!!dbg->debuggees.lookup(&referent->global()));
+    args.rval().setBoolean(!!dbg->debuggees.lookup(global));
     return true;
 }
 
 JSBool
 Debugger::getDebuggees(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGGER(cx, argc, vp, "getDebuggees", args, dbg);
     RootedObject arrobj(cx, NewDenseAllocatedArray(cx, dbg->debuggees.count()));
@@ -2006,20 +2153,19 @@ class Debugger::ScriptQuery {
          * scripts scoped to a particular global object.
          */
         RootedValue global(cx);
         if (!JSObject::getProperty(cx, query, query, cx->names().global, &global))
             return false;
         if (global.isUndefined()) {
             matchAllDebuggeeGlobals();
         } else {
-            JSObject *referent = debugger->unwrapDebuggeeArgument(cx, global);
-            if (!referent)
+            GlobalObject *globalObject = debugger->unwrapDebuggeeArgument(cx, global);
+            if (!globalObject)
                 return false;
-            GlobalObject *globalObject = &referent->global();
 
             /*
              * If the given global isn't a debuggee, just leave the set of
              * acceptable globals empty; we'll return no scripts.
              */
             if (debugger->debuggees.has(globalObject)) {
                 if (!matchSingleGlobal(globalObject))
                     return false;
@@ -2334,37 +2480,63 @@ Debugger::findScripts(JSContext *cx, uns
             return false;
         result->setDenseArrayElement(i, ObjectValue(*scriptObject));
     }
 
     args.rval().setObject(*result);
     return true;
 }
 
+JSBool
+Debugger::findAllGlobals(JSContext *cx, unsigned argc, Value *vp)
+{
+    THIS_DEBUGGER(cx, argc, vp, "findAllGlobals", args, dbg);
+
+    RootedObject result(cx, NewDenseEmptyArray(cx));
+    if (!result)
+        return false;
+
+    for (CompartmentsIter c(cx->runtime); !c.done(); c.next()) {
+        GlobalObject *global = c->maybeGlobal();
+        if (global) {
+            Value globalValue(ObjectValue(*global));
+            if (!dbg->wrapDebuggeeValue(cx, &globalValue))
+                return false;
+            if (!js_NewbornArrayPush(cx, result, globalValue))
+                return false;
+        }
+    }
+
+    args.rval().setObject(*result);
+    return true;
+}
+
 JSPropertySpec Debugger::properties[] = {
     JS_PSGS("enabled", Debugger::getEnabled, Debugger::setEnabled, 0),
     JS_PSGS("onDebuggerStatement", Debugger::getOnDebuggerStatement,
             Debugger::setOnDebuggerStatement, 0),
     JS_PSGS("onExceptionUnwind", Debugger::getOnExceptionUnwind,
             Debugger::setOnExceptionUnwind, 0),
     JS_PSGS("onNewScript", Debugger::getOnNewScript, Debugger::setOnNewScript, 0),
     JS_PSGS("onEnterFrame", Debugger::getOnEnterFrame, Debugger::setOnEnterFrame, 0),
+    JS_PSGS("onNewGlobalObject", Debugger::getOnNewGlobalObject, Debugger::setOnNewGlobalObject, 0),
     JS_PSGS("uncaughtExceptionHook", Debugger::getUncaughtExceptionHook,
             Debugger::setUncaughtExceptionHook, 0),
     JS_PS_END
 };
 
 JSFunctionSpec Debugger::methods[] = {
     JS_FN("addDebuggee", Debugger::addDebuggee, 1, 0),
     JS_FN("removeDebuggee", Debugger::removeDebuggee, 1, 0),
     JS_FN("hasDebuggee", Debugger::hasDebuggee, 1, 0),
     JS_FN("getDebuggees", Debugger::getDebuggees, 0, 0),
     JS_FN("getNewestFrame", Debugger::getNewestFrame, 0, 0),
     JS_FN("clearAllBreakpoints", Debugger::clearAllBreakpoints, 1, 0),
     JS_FN("findScripts", Debugger::findScripts, 1, 0),
+    JS_FN("findAllGlobals", Debugger::findAllGlobals, 0, 0),
     JS_FS_END
 };
 
 
 /*** Debugger.Script *****************************************************************************/
 
 static inline JSScript *
 GetScriptReferent(JSObject *obj)
@@ -3823,16 +3995,28 @@ DebuggerObject_getEnvironment(JSContext 
         if (!env)
             return false;
     }
 
     return dbg->wrapEnvironment(cx, env, args.rval().address());
 }
 
 static JSBool
+DebuggerObject_getGlobal(JSContext *cx, unsigned argc, Value *vp)
+{
+    THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "get global", args, dbg, obj);
+
+    Value v = ObjectValue(obj->global());
+    if (!dbg->wrapDebuggeeValue(cx, &v))
+        return false;
+    args.rval().set(v);
+    return true;
+}
+
+static JSBool
 DebuggerObject_getOwnPropertyDescriptor(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "getOwnPropertyDescriptor", args, dbg, obj);
 
     RootedId id(cx);
     if (!ValueToId(cx, argc >= 1 ? args[0] : UndefinedValue(), id.address()))
         return false;
 
@@ -4228,16 +4412,27 @@ DebuggerObject_makeDebuggeeValue(JSConte
     args.rval().set(args[0]);
     return true;
 }
 
 static bool
 RequireGlobalObject(JSContext *cx, HandleValue dbgobj, HandleObject obj)
 {
     if (!obj->isGlobal()) {
+        /* Help the poor programmer by pointing out wrappers around globals. */
+        if (obj->isWrapper()) {
+            JSObject *unwrapped = js::UnwrapObject(obj);
+            if (unwrapped->isGlobal()) {
+                js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_DEBUG_WRAPPER_IN_WAY,
+                                         JSDVG_SEARCH_STACK, dbgobj, NullPtr(),
+                                         "a global object", NULL);
+                return false;
+            }
+        }
+
         js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_DEBUG_BAD_REFERENT,
                                  JSDVG_SEARCH_STACK, dbgobj, NullPtr(),
                                  "a global object", NULL);
         return false;
     }
 
     return true;
 }
@@ -4261,25 +4456,52 @@ DebuggerObject_evalInGlobalWithBindings(
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "evalInGlobalWithBindings", args, dbg, referent);
     if (!RequireGlobalObject(cx, args.thisv(), referent))
         return false;
 
     return DebuggerGenericEval(cx, "Debugger.Object.prototype.evalInGlobalWithBindings",
                                args[0], &args[1], vp, dbg, referent, NULL);
 }
 
+static JSBool
+DebuggerObject_unwrap(JSContext *cx, unsigned argc, Value *vp)
+{
+    THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "unwrap", args, dbg, referent);
+    JSObject *unwrapped = UnwrapOneChecked(cx, referent);
+    if (!unwrapped) {
+        // If we were terminated, then pass that along.
+        if (!cx->isExceptionPending())
+            return false;
+
+        // If the unwrap operation threw an exception, assume it's a
+        // security exception, and return null. It seems like the wrappers
+        // in use in Firefox just call JS_ReportError, so we have no way to
+        // distinguish genuine should-not-unwrap errors from other kinds of
+        // errors.
+        cx->clearPendingException();
+        vp->setNull();
+        return true;
+    }
+
+    *vp = ObjectValue(*unwrapped);
+    if (!dbg->wrapDebuggeeValue(cx, vp))
+        return false;
+    return true;
+}
+
 static JSPropertySpec DebuggerObject_properties[] = {
     JS_PSG("proto", DebuggerObject_getProto, 0),
     JS_PSG("class", DebuggerObject_getClass, 0),
     JS_PSG("callable", DebuggerObject_getCallable, 0),
     JS_PSG("name", DebuggerObject_getName, 0),
     JS_PSG("displayName", DebuggerObject_getDisplayName, 0),
     JS_PSG("parameterNames", DebuggerObject_getParameterNames, 0),
     JS_PSG("script", DebuggerObject_getScript, 0),
     JS_PSG("environment", DebuggerObject_getEnvironment, 0),
+    JS_PSG("global", DebuggerObject_getGlobal, 0),
     JS_PS_END
 };
 
 static JSFunctionSpec DebuggerObject_methods[] = {
     JS_FN("getOwnPropertyDescriptor", DebuggerObject_getOwnPropertyDescriptor, 1, 0),
     JS_FN("getOwnPropertyNames", DebuggerObject_getOwnPropertyNames, 0, 0),
     JS_FN("defineProperty", DebuggerObject_defineProperty, 2, 0),
     JS_FN("defineProperties", DebuggerObject_defineProperties, 1, 0),
@@ -4290,16 +4512,17 @@ static JSFunctionSpec DebuggerObject_met
     JS_FN("isSealed", DebuggerObject_isSealed, 0, 0),
     JS_FN("isFrozen", DebuggerObject_isFrozen, 0, 0),
     JS_FN("isExtensible", DebuggerObject_isExtensible, 0, 0),
     JS_FN("apply", DebuggerObject_apply, 0, 0),
     JS_FN("call", DebuggerObject_call, 0, 0),
     JS_FN("makeDebuggeeValue", DebuggerObject_makeDebuggeeValue, 1, 0),
     JS_FN("evalInGlobal", DebuggerObject_evalInGlobal, 1, 0),
     JS_FN("evalInGlobalWithBindings", DebuggerObject_evalInGlobalWithBindings, 2, 0),
+    JS_FN("unwrap", DebuggerObject_unwrap, 0, 0),
     JS_FS_END
 };
 
 
 /*** Debugger.Environment ************************************************************************/
 
 static void
 DebuggerEnv_trace(JSTracer *trc, RawObject obj)
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -29,16 +29,17 @@ class Debugger {
     friend JSBool (::JS_DefineDebuggerObject)(JSContext *cx, JSObject *obj);
 
   public:
     enum Hook {
         OnDebuggerStatement,
         OnExceptionUnwind,
         OnNewScript,
         OnEnterFrame,
+        OnNewGlobalObject,
         HookCount
     };
 
     enum {
         JSSLOT_DEBUG_PROTO_START,
         JSSLOT_DEBUG_FRAME_PROTO = JSSLOT_DEBUG_PROTO_START,
         JSSLOT_DEBUG_ENV_PROTO,
         JSSLOT_DEBUG_OBJECT_PROTO,
@@ -50,17 +51,25 @@ class Debugger {
     };
 
   private:
     JSCList link;                       /* See JSRuntime::debuggerList. */
     HeapPtrObject object;               /* The Debugger object. Strong reference. */
     GlobalObjectSet debuggees;          /* Debuggee globals. Cross-compartment weak references. */
     js::HeapPtrObject uncaughtExceptionHook; /* Strong reference. */
     bool enabled;
-    JSCList breakpoints;                /* cyclic list of all js::Breakpoints in this debugger */
+    JSCList breakpoints;                /* Circular list of all js::Breakpoints in this debugger */
+
+    /*
+     * If this Debugger is enabled, and has a onNewGlobalObject handler, then
+     * this link is inserted into the circular list headed by
+     * JSRuntime::onNewGlobalObjectWatchers. Otherwise, this is set to a
+     * singleton cycle.
+     */
+    JSCList onNewGlobalObjectWatchersLink;
 
     /*
      * Map from stack frames that are currently on the stack to Debugger.Frame
      * instances.
      *
      * The keys are always live stack frames. We drop them from this map as
      * soon as they leave the stack (see slowPathOnLeaveFrame) and in
      * removeDebuggee.
@@ -134,17 +143,17 @@ class Debugger {
      *     null - Return JSTRAP_ERROR to terminate the debuggee with an
      *         uncatchable error.
      *     anything else - Make a new TypeError the pending exception and
      *         return handleUncaughtException(ac, vp, callHook).
      */
     JSTrapStatus parseResumptionValue(Maybe<AutoCompartment> &ac, bool ok, const Value &rv,
                                       Value *vp, bool callHook = true);
 
-    JSObject *unwrapDebuggeeArgument(JSContext *cx, const Value &v);
+    GlobalObject *unwrapDebuggeeArgument(JSContext *cx, const Value &v);
 
     static void traceObject(JSTracer *trc, RawObject obj);
     void trace(JSTracer *trc);
     static void finalize(FreeOp *fop, RawObject obj);
     void markKeysInCompartment(JSTracer *tracer);
 
     static Class jsclass;
 
@@ -156,58 +165,65 @@ class Debugger {
     static JSBool getOnDebuggerStatement(JSContext *cx, unsigned argc, Value *vp);
     static JSBool setOnDebuggerStatement(JSContext *cx, unsigned argc, Value *vp);
     static JSBool getOnExceptionUnwind(JSContext *cx, unsigned argc, Value *vp);
     static JSBool setOnExceptionUnwind(JSContext *cx, unsigned argc, Value *vp);
     static JSBool getOnNewScript(JSContext *cx, unsigned argc, Value *vp);
     static JSBool setOnNewScript(JSContext *cx, unsigned argc, Value *vp);
     static JSBool getOnEnterFrame(JSContext *cx, unsigned argc, Value *vp);
     static JSBool setOnEnterFrame(JSContext *cx, unsigned argc, Value *vp);
+    static JSBool getOnNewGlobalObject(JSContext *cx, unsigned argc, Value *vp);
+    static JSBool setOnNewGlobalObject(JSContext *cx, unsigned argc, Value *vp);
     static JSBool getUncaughtExceptionHook(JSContext *cx, unsigned argc, Value *vp);
     static JSBool setUncaughtExceptionHook(JSContext *cx, unsigned argc, Value *vp);
     static JSBool addDebuggee(JSContext *cx, unsigned argc, Value *vp);
     static JSBool removeDebuggee(JSContext *cx, unsigned argc, Value *vp);
     static JSBool hasDebuggee(JSContext *cx, unsigned argc, Value *vp);
     static JSBool getDebuggees(JSContext *cx, unsigned argc, Value *vp);
     static JSBool getNewestFrame(JSContext *cx, unsigned argc, Value *vp);
     static JSBool clearAllBreakpoints(JSContext *cx, unsigned argc, Value *vp);
     static JSBool findScripts(JSContext *cx, unsigned argc, Value *vp);
+    static JSBool findAllGlobals(JSContext *cx, unsigned argc, Value *vp);
     static JSBool wrap(JSContext *cx, unsigned argc, Value *vp);
     static JSBool construct(JSContext *cx, unsigned argc, Value *vp);
     static JSPropertySpec properties[];
     static JSFunctionSpec methods[];
 
     JSObject *getHook(Hook hook) const;
     bool hasAnyLiveHooks() const;
 
     static JSTrapStatus slowPathOnEnterFrame(JSContext *cx, Value *vp);
     static bool slowPathOnLeaveFrame(JSContext *cx, bool ok);
     static void slowPathOnNewScript(JSContext *cx, JSScript *script,
                                     GlobalObject *compileAndGoGlobal);
+    static bool slowPathOnNewGlobalObject(JSContext *cx, Handle<GlobalObject *> global);
     static JSTrapStatus dispatchHook(JSContext *cx, Value *vp, Hook which);
 
     JSTrapStatus fireDebuggerStatement(JSContext *cx, Value *vp);
     JSTrapStatus fireExceptionUnwind(JSContext *cx, Value *vp);
     JSTrapStatus fireEnterFrame(JSContext *cx, Value *vp);
+    JSTrapStatus fireNewGlobalObject(JSContext *cx, Handle<GlobalObject *> global, Value *vp);
 
     /*
      * Allocate and initialize a Debugger.Script instance whose referent is
      * |script|.
      */
     JSObject *newDebuggerScript(JSContext *cx, HandleScript script);
 
     /*
      * Receive a "new script" event from the engine. A new script was compiled
      * or deserialized.
      */
     void fireNewScript(JSContext *cx, HandleScript script);
 
     static inline Debugger *fromLinks(JSCList *links);
     inline Breakpoint *firstBreakpoint() const;
 
+    static inline Debugger *fromOnNewGlobalObjectWatchersLink(JSCList *link);
+
   public:
     Debugger(JSContext *cx, JSObject *dbg);
     ~Debugger();
 
     bool init(JSContext *cx);
     inline const js::HeapPtrObject &toJSObject() const;
     inline js::HeapPtrObject &toJSObjectRef();
     static inline Debugger *fromJSObject(JSObject *obj);
@@ -237,23 +253,25 @@ class Debugger {
                                              GlobalObjectSet::Enum *compartmentEnum);
 
     static inline JSTrapStatus onEnterFrame(JSContext *cx, Value *vp);
     static inline bool onLeaveFrame(JSContext *cx, bool ok);
     static inline JSTrapStatus onDebuggerStatement(JSContext *cx, Value *vp);
     static inline JSTrapStatus onExceptionUnwind(JSContext *cx, Value *vp);
     static inline void onNewScript(JSContext *cx, JSScript *script,
                                    GlobalObject *compileAndGoGlobal);
+    static inline bool onNewGlobalObject(JSContext *cx, Handle<GlobalObject *> global);
     static JSTrapStatus onTrap(JSContext *cx, Value *vp);
     static JSTrapStatus onSingleStep(JSContext *cx, Value *vp);
 
     /************************************* Functions for use by Debugger.cpp. */
 
     inline bool observesEnterFrame() const;
     inline bool observesNewScript() const;
+    inline bool observesNewGlobalObject() const;
     inline bool observesGlobal(GlobalObject *global) const;
     inline bool observesFrame(StackFrame *fp) const;
     bool observesScript(JSScript *script) const;
 
     /*
      * If env is NULL, call vp->setNull() and return true. Otherwise, find or
      * create a Debugger.Environment object for the given Env. On success,
      * store the Environment object in *vp and return true.
@@ -416,28 +434,34 @@ class Breakpoint {
     Breakpoint *nextInSite();
     const HeapPtrObject &getHandler() const { return handler; }
     HeapPtrObject &getHandlerRef() { return handler; }
 };
 
 Debugger *
 Debugger::fromLinks(JSCList *links)
 {
-    unsigned char *p = reinterpret_cast<unsigned char *>(links);
+    char *p = reinterpret_cast<char *>(links);
     return reinterpret_cast<Debugger *>(p - offsetof(Debugger, link));
 }
 
 Breakpoint *
 Debugger::firstBreakpoint() const
 {
     if (JS_CLIST_IS_EMPTY(&breakpoints))
         return NULL;
     return Breakpoint::fromDebuggerLinks(JS_NEXT_LINK(&breakpoints));
 }
 
+Debugger *
+Debugger::fromOnNewGlobalObjectWatchersLink(JSCList *link) {
+    char *p = reinterpret_cast<char *>(link);
+    return reinterpret_cast<Debugger *>(p - offsetof(Debugger, onNewGlobalObjectWatchersLink));
+}
+
 const js::HeapPtrObject &
 Debugger::toJSObject() const
 {
     JS_ASSERT(object);
     return object;
 }
 
 js::HeapPtrObject &
@@ -462,16 +486,22 @@ Debugger::observesEnterFrame() const
 
 bool
 Debugger::observesNewScript() const
 {
     return enabled && getHook(OnNewScript);
 }
 
 bool
+Debugger::observesNewGlobalObject() const
+{
+    return enabled && getHook(OnNewGlobalObject);
+}
+
+bool
 Debugger::observesGlobal(GlobalObject *global) const
 {
     return debuggees.has(global);
 }
 
 bool
 Debugger::observesFrame(StackFrame *fp) const
 {
@@ -517,16 +547,24 @@ void
 Debugger::onNewScript(JSContext *cx, JSScript *script, GlobalObject *compileAndGoGlobal)
 {
     JS_ASSERT_IF(script->compileAndGo, compileAndGoGlobal);
     JS_ASSERT_IF(!script->compileAndGo, !compileAndGoGlobal);
     if (!script->compartment()->getDebuggees().empty())
         slowPathOnNewScript(cx, script, compileAndGoGlobal);
 }
 
+bool
+Debugger::onNewGlobalObject(JSContext *cx, Handle<GlobalObject *> global)
+{
+    if (JS_CLIST_IS_EMPTY(&cx->runtime->onNewGlobalObjectWatchers))
+        return true;
+    return Debugger::slowPathOnNewGlobalObject(cx, global);
+}
+
 extern JSBool
 EvaluateInEnv(JSContext *cx, Handle<Env*> env, HandleValue thisv, StackFrame *fp,
               StableCharPtr chars, unsigned length, const char *filename, unsigned lineno,
               Value *rval);
 
 }
 
 #endif /* Debugger_h__ */
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -90,16 +90,17 @@ members = [
     # would shadow any quick stub.  Also, document.location is a special
     # case for security.
     #'nsIDOMDocument.location',
     'nsIDOMDocument.elementFromPoint',
     'nsIDOMDocument.activeElement',
     'nsIDOMDocument.onreadystatechange',
     'nsIDOMDocument.onmouseenter',
     'nsIDOMDocument.onmouseleave',
+    'nsIDOMDocument.URL',
     'nsIDOMElement.removeAttributeNS',
     'nsIDOMElement.removeAttribute',
     'nsIDOMElement.getAttribute',
     'nsIDOMElement.getElementsByTagName',
     'nsIDOMElement.setAttribute',
     'nsIDOMElement.getElementsByTagNameNS',
     'nsIDOMElement.hasAttributeNS',
     'nsIDOMElement.tagName',
@@ -202,17 +203,16 @@ members = [
     'nsIDOMHTMLButtonElement.form',
     'nsIDOMHTMLButtonElement.value',
     'nsIDOMHTMLButtonElement.disabled',
     'nsIDOMHTMLCommandElement.*',
     'nsIDOMHTMLDocument.body',
     'nsIDOMHTMLDocument.getElementsByName',
     'nsIDOMHTMLDocument.anchors',
     'nsIDOMHTMLDocument.links',
-    'nsIDOMHTMLDocument.URL',
     'nsIDOMHTMLDocument.forms',
     'nsIDOMHTMLDocument.cookie',
     'nsIDOMHTMLDocument.images',
     'nsIDOMHTMLDocument.write',
     'nsIDOMHTMLDocument.writeln',
     'nsIDOMHTMLDocument.domain',
     'nsIDOMHTMLDocument.getSelection',
     'nsIDOMHTMLDocument.designMode',
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -842,20 +842,26 @@ NoteGCThingXPCOMChildren(js::Class *clas
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "xpc_GetJSPrivate(obj)");
         cb.NoteXPCOMChild(static_cast<nsISupports*>(xpc_GetJSPrivate(obj)));
     } else if (oldproxybindings::instanceIsProxy(obj)) {
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "js::GetProxyPrivate(obj)");
         nsISupports *identity =
             static_cast<nsISupports*>(js::GetProxyPrivate(obj).toPrivate());
         cb.NoteXPCOMChild(identity);
     } else {
-        nsISupports *identity;
-        if (UnwrapDOMObjectToISupports(obj, identity)) {
+        const DOMClass* domClass;
+        DOMObjectSlot slot = GetDOMClass(obj, domClass);
+        if (slot != eNonDOMObject) {
             NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "UnwrapDOMObject(obj)");
-            cb.NoteXPCOMChild(identity);
+            if (domClass->mDOMObjectIsISupports) {
+                cb.NoteXPCOMChild(UnwrapDOMObject<nsISupports>(obj, slot));
+            } else if (domClass->mParticipant) {
+                cb.NoteNativeChild(UnwrapDOMObject<void>(obj, slot),
+                                   domClass->mParticipant);
+            }
         }
     }
 }
 
 enum TraverseSelect {
     TRAVERSE_CPP,
     TRAVERSE_FULL
 };
--- a/js/xpconnect/tests/mochitest/test_bug393269.html
+++ b/js/xpconnect/tests/mochitest/test_bug393269.html
@@ -11,31 +11,31 @@ https://bugzilla.mozilla.org/show_bug.cg
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=393269">Mozilla Bug 393269</a>
 <iframe id="ifr"></iframe>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 (function () {
     /** Test for Bug 393269 **/
     var doc = $("ifr").contentDocument;
-    is("UTF-8", doc.characterSet, "control, getting a property");
+    is("utf-8", doc.characterSet, "control, getting a property");
     doc.open();
     try {
-        is("UTF-8", doc.characterSet,
+        is("utf-8", doc.characterSet,
            "can get a property after 1 document.open")
     } catch (e) {
         fail("Shouldn't have thrown: " + e);
         return;
     } finally {
         doc.close();
     }
 
     doc.open();
     try {
-        is("UTF-8", doc.characterSet,
+        is("utf-8", doc.characterSet,
            "can get a property after 2 document.opens")
     } catch (e) {
         fail("Shouldn't have thrown: " + e);
     } finally {
         doc.close();
     }
 })();
 </script>
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -8047,18 +8047,16 @@ nsCSSFrameConstructor::ProcessRestyledFr
     aChangeList.ChangeAt(index, &changeData);
     if (changeData->mFrame) {
       propTable->Set(changeData->mFrame, ChangeListProperty(),
                      NS_INT32_TO_PTR(1));
     }
   }
 
   index = count;
-  bool didInvalidate = false;
-  bool didReflow = false;
 
   while (0 <= --index) {
     nsIFrame* frame;
     nsIContent* content;
     bool didReflowThisFrame = false;
     nsChangeHint hint;
     aChangeList.ChangeAt(index, frame, content, hint);
 
@@ -8105,29 +8103,26 @@ nsCSSFrameConstructor::ProcessRestyledFr
       RecreateFramesForContent(content, false);
     } else {
       NS_ASSERTION(frame, "This shouldn't happen");
       if (hint & nsChangeHint_UpdateEffects) {
         nsSVGEffects::UpdateEffects(frame);
       }
       if (hint & nsChangeHint_NeedReflow) {
         StyleChangeReflow(frame, hint);
-        didReflow = true;
         didReflowThisFrame = true;
       }
       if (hint & (nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView |
                   nsChangeHint_UpdateOpacityLayer | nsChangeHint_UpdateTransformLayer |
                   nsChangeHint_ChildrenOnlyTransform)) {
         ApplyRenderingChangeToTree(presContext, frame, hint);
-        didInvalidate = true;
       }
       if ((hint & nsChangeHint_RecomputePosition) && !didReflowThisFrame) {
         // It is possible for this to fall back to a reflow
         if (!RecomputePosition(frame)) {
-          didReflow = true;
           didReflowThisFrame = true;
         }
       }
       NS_ASSERTION(!(hint & nsChangeHint_ChildrenOnlyTransform) ||
                    (hint & nsChangeHint_UpdateOverflow),
                    "nsChangeHint_UpdateOverflow should be passed too");
       if ((hint & nsChangeHint_UpdateOverflow) && !didReflowThisFrame) {
         if (hint & nsChangeHint_ChildrenOnlyTransform) {
@@ -8190,26 +8185,16 @@ nsCSSFrameConstructor::ProcessRestyledFr
       if (hint & nsChangeHint_UpdateCursor) {
         mPresShell->SynthesizeMouseMove(false);
       }
     }
   }
 
   EndUpdate();
 
-  if (didInvalidate && !didReflow) {
-    // RepaintFrame changes can indicate changes in opacity etc which
-    // can require plugin clipping to change. If we requested a reflow,
-    // we don't need to do this since the reflow will do it for us.
-    nsRootPresContext* rootPC = presContext->GetRootPresContext();
-    if (rootPC) {
-      rootPC->RequestUpdatePluginGeometry();
-    }
-  }
-
   // cleanup references and verify the style tree.  Note that the latter needs
   // to happen once we've processed the whole list, since until then the tree
   // is not in fact in a consistent state.
   index = count;
   while (0 <= --index) {
     const nsStyleChangeData* changeData;
     aChangeList.ChangeAt(index, &changeData);
     if (changeData->mFrame) {
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -1228,31 +1228,34 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
     gfxRect shadowGfxRect =
       nsLayoutUtils::RectToGfxRect(shadowRect, twipsPerPixel);
     gfxRect shadowGfxRectPlusBlur =
       nsLayoutUtils::RectToGfxRect(shadowRectPlusBlur, twipsPerPixel);
     shadowGfxRect.Round();
     shadowGfxRectPlusBlur.RoundOut();
 
     gfxContext* renderContext = aRenderingContext.ThebesContext();
-    nsRefPtr<gfxContext> shadowContext;
     nsContextBoxBlur blurringArea;
 
     // When getting the widget shape from the native theme, we're going
     // to draw the widget into the shadow surface to create a mask.
     // We need to ensure that there actually *is* a shadow surface
     // and that we're not going to draw directly into renderContext.
-    shadowContext = 
+    gfxContext* shadowContext =
       blurringArea.Init(shadowRect, pixelSpreadRadius,
                         blurRadius, twipsPerPixel, renderContext, aDirtyRect,
                         useSkipGfxRect ? &skipGfxRect : nullptr,
                         nativeTheme ? nsContextBoxBlur::FORCE_MASK : 0);
     if (!shadowContext)
       continue;
 
+    // shadowContext is owned by either blurringArea or aRenderingContext.
+    MOZ_ASSERT(shadowContext == renderContext ||
+               shadowContext == blurringArea.GetContext());
+
     // Set the shadow color; if not specified, use the foreground color
     nscolor shadowColor;
     if (shadowItem->mHasColor)
       shadowColor = shadowItem->mColor;
     else
       shadowColor = aForFrame->GetStyleColor()->mColor;
 
     renderContext->Save();
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -435,16 +435,18 @@ nsDisplayListBuilder::nsDisplayListBuild
       mMode(aMode),
       mBuildCaret(aBuildCaret),
       mIgnoreSuppression(false),
       mHadToIgnoreSuppression(false),
       mIsAtRootOfPseudoStackingContext(false),
       mIncludeAllOutOfFlows(false),
       mSelectedFramesOnly(false),
       mAccurateVisibleRegions(false),
+      mAllowMergingAndFlattening(true),
+      mWillComputePluginGeometry(false),
       mInTransform(false),
       mSyncDecodeImages(false),
       mIsPaintingToWindow(false),
       mHasDisplayPort(false),
       mHasFixedItems(false),
       mIsInFixedPosition(false),
       mIsCompositingCheap(false)
 {
@@ -911,30 +913,32 @@ nsDisplayList::ComputeVisibilityForSubli
   FlattenTo(&elements);
 
   bool forceTransparentSurface = false;
 
   for (int32_t i = elements.Length() - 1; i >= 0; --i) {
     nsDisplayItem* item = elements[i];
     nsDisplayItem* belowItem = i < 1 ? nullptr : elements[i - 1];
 
-    if (belowItem && item->TryMerge(aBuilder, belowItem)) {
-      belowItem->~nsDisplayItem();
-      elements.ReplaceElementsAt(i - 1, 1, item);
-      continue;
-    }
-
     nsDisplayList* list = item->GetList();
-    if (list && item->ShouldFlattenAway(aBuilder)) {
-      // The elements on the list >= i no longer serve any use.
-      elements.SetLength(i);
-      list->FlattenTo(&elements);
-      i = elements.Length();
-      item->~nsDisplayItem();
-      continue;
+    if (aBuilder->AllowMergingAndFlattening()) {
+      if (belowItem && item->TryMerge(aBuilder, belowItem)) {
+        belowItem->~nsDisplayItem();
+        elements.ReplaceElementsAt(i - 1, 1, item);
+        continue;
+      }
+
+      if (list && item->ShouldFlattenAway(aBuilder)) {
+        // The elements on the list >= i no longer serve any use.
+        elements.SetLength(i);
+        list->FlattenTo(&elements);
+        i = elements.Length();
+        item->~nsDisplayItem();
+        continue;
+      }
     }
 
     nsRect bounds = item->GetBounds(aBuilder, &snap);
 
     nsRegion itemVisible;
     if (ForceVisiblityForFixedItem(aBuilder, item)) {
       itemVisible.And(GetDisplayPortBounds(aBuilder, item), bounds);
     } else {
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -124,30 +124,45 @@ public:
     PAINTING,
     EVENT_DELIVERY,
     PLUGIN_GEOMETRY,
     OTHER
   };
   nsDisplayListBuilder(nsIFrame* aReferenceFrame, Mode aMode, bool aBuildCaret);
   ~nsDisplayListBuilder();
 
+  void SetWillComputePluginGeometry(bool aWillComputePluginGeometry)
+  {
+    mWillComputePluginGeometry = aWillComputePluginGeometry;
+  }
+  void SetForPluginGeometry()
+  {
+    NS_ASSERTION(mMode == PAINTING, "Can only switch from PAINTING to PLUGIN_GEOMETRY");
+    NS_ASSERTION(mWillComputePluginGeometry, "Should have signalled this in advance");
+    mMode = PLUGIN_GEOMETRY;
+  }
+
   /**
    * @return true if the display is being built in order to determine which
    * frame is under the mouse position.
    */
   bool IsForEventDelivery() { return mMode == EVENT_DELIVERY; }
   /**
+   * Be careful with this. The display list will be built in PAINTING mode
+   * first and then switched to PLUGIN_GEOMETRY before a second call to
+   * ComputeVisibility.
    * @return true if the display list is being built to compute geometry
    * for plugins.
    */
   bool IsForPluginGeometry() { return mMode == PLUGIN_GEOMETRY; }
   /**
    * @return true if the display list is being built for painting.
    */
   bool IsForPainting() { return mMode == PAINTING; }
+  bool WillComputePluginGeometry() { return mWillComputePluginGeometry; }
   /**
    * @return true if "painting is suppressed" during page load and we
    * should paint only the background of the document.
    */
   bool IsBackgroundOnly() {
     NS_ASSERTION(mPresShellStates.Length() > 0,
                  "don't call this if we're not in a presshell");
     return CurrentPresShellState()->mIsBackgroundOnly;
@@ -259,16 +274,23 @@ public:
   bool GetHadToIgnorePaintSuppression() { return mHadToIgnoreSuppression; }
   /**
    * Call this if we're doing normal painting to the window.
    */
   void SetPaintingToWindow(bool aToWindow) { mIsPaintingToWindow = aToWindow; }
   bool IsPaintingToWindow() const { return mIsPaintingToWindow; }
 
   /**
+   * Returns true if merging and flattening of display lists should be
+   * performed while computing visibility.
+   */
+  bool AllowMergingAndFlattening() { return mAllowMergingAndFlattening; }
+  void SetAllowMergingAndFlattening(bool aAllow) { mAllowMergingAndFlattening = aAllow; }
+
+  /**
    * @return Returns if the builder is currently building an
    * nsDisplayFixedPosition sub-tree.
    */
   bool IsInFixedPosition() const { return mIsInFixedPosition; }
 
   bool SetIsCompositingCheap(bool aCompositingCheap) { 
     bool temp = mIsCompositingCheap; 
     mIsCompositingCheap = aCompositingCheap;
@@ -597,16 +619,18 @@ private:
   Mode                           mMode;
   bool                           mBuildCaret;
   bool                           mIgnoreSuppression;
   bool                           mHadToIgnoreSuppression;
   bool                           mIsAtRootOfPseudoStackingContext;
   bool                           mIncludeAllOutOfFlows;
   bool                           mSelectedFramesOnly;
   bool                           mAccurateVisibleRegions;
+  bool                           mAllowMergingAndFlattening;
+  bool                           mWillComputePluginGeometry;
   // True when we're building a display list that's directly or indirectly
   // under an nsDisplayTransform
   bool                           mInTransform;
   bool                           mSyncDecodeImages;
   bool                           mIsPaintingToWindow;
   bool                           mHasDisplayPort;
   bool                           mHasFixedItems;
   bool                           mIsInFixedPosition;
@@ -937,16 +961,17 @@ public:
    * nsDisplayItem::ComputeVisibility do not need to do these things.
    * nsDisplayList::ComputeVisibility will already have set mVisibleRect on
    * this item to the intersection of *aVisibleRegion and this item's bounds.
    * We rely on that, so this should only be called by
    * nsDisplayList::ComputeVisibility or nsDisplayItem::RecomputeVisibility.
    * aAllowVisibleRegionExpansion is a rect where we are allowed to
    * expand the visible region and is only used for making sure the
    * background behind a plugin is visible.
+   * This method needs to be idempotent.
    *
    * @return true if the item is visible, false if no part of the item
    * is visible.
    */
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion)
   { return !mVisibleRect.IsEmpty(); }
@@ -1248,37 +1273,39 @@ public:
    * This is also a good place to put ComputeVisibility-related logic
    * that must be applied to every display item. In particular, this
    * sets mVisibleRect on each display item.
    * This sets mIsOpaque if the entire visible area of this list has
    * been removed from aVisibleRegion when we return.
    * This does not remove any items from the list, so we can recompute
    * visiblity with different regions later (see
    * FrameLayerBuilder::DrawThebesLayer).
+   * This method needs to be idempotent.
    * 
    * @param aVisibleRegion the area that is visible, relative to the
    * reference frame; on return, this contains the area visible under the list.
    * I.e., opaque contents of this list are subtracted from aVisibleRegion.
    * @param aListVisibleBounds must be equal to the bounds of the intersection
    * of aVisibleRegion and GetBounds() for this list.
    * @return true if any item in the list is visible.
    */
   bool ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
-                                     nsRegion* aVisibleRegion,
-                                     const nsRect& aListVisibleBounds,
-                                     const nsRect& aAllowVisibleRegionExpansion);
+                                   nsRegion* aVisibleRegion,
+                                   const nsRect& aListVisibleBounds,
+                                   const nsRect& aAllowVisibleRegionExpansion);
 
   /**
    * As ComputeVisibilityForSublist, but computes visibility for a root
    * list (a list that does not belong to an nsDisplayItem).
+   * This method needs to be idempotent.
    *
    * @param aVisibleRegion the area that is visible
    */
   bool ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
-                                  nsRegion* aVisibleRegion);
+                                nsRegion* aVisibleRegion);
 
   /**
    * Returns true if the visible region output from ComputeVisiblity was
    * empty, i.e. everything visible in this list is opaque.
    */
   bool IsOpaque() const {
     NS_ASSERTION(mDidComputeVisibility, "Need to have called ComputeVisibility");
     return mIsOpaque;
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -109,20 +109,20 @@ typedef struct CapturingContentInfo {
   // capture should only be allowed during a mousedown event
   bool mAllowed;
   bool mPointerLock;
   bool mRetargetToElement;
   bool mPreventDrag;
   nsIContent* mContent;
 } CapturingContentInfo;
 
-// 7E29E8A8-9C77-4445-A523-41B363E0C98A
+// ebc1bbe4-5456-4c62-ba1f-c2ef7387963e
 #define NS_IPRESSHELL_IID \
-  { 0x7e29e8a8, 0x9c77, 0x4445, \
-    { 0xa5, 0x23, 0x41, 0xb3, 0x63, 0xe0, 0xc9, 0x8a } }
+{ 0xebc1bbe4, 0x5456, 0x4c62, \
+  { 0xba, 0x1f, 0xc2, 0xef, 0x73, 0x87, 0x96, 0x3e } }
 
 // debug VerifyReflow flags
 #define VERIFY_REFLOW_ON                    0x01
 #define VERIFY_REFLOW_NOISY                 0x02
 #define VERIFY_REFLOW_ALL                   0x04
 #define VERIFY_REFLOW_DUMP_COMMANDS         0x08
 #define VERIFY_REFLOW_NOISY_RC              0x10
 #define VERIFY_REFLOW_REALLY_NOISY_RC       0x20
@@ -1225,25 +1225,39 @@ public:
   virtual void Paint(nsIView* aViewToPaint, const nsRegion& aDirtyRegion,
                      PaintType aType, bool aWillSendDidPaint) = 0;
   virtual nsresult HandleEvent(nsIFrame*       aFrame,
                                nsGUIEvent*     aEvent,
                                bool            aDontRetargetEvents,
                                nsEventStatus*  aEventStatus) = 0;
   virtual bool ShouldIgnoreInvalidation() = 0;
   /**
-   * Notify that the NS_WILL_PAINT event was received. Fires on every
-   * visible presshell in the document tree.
+   * Notify that we're going to call Paint with PaintType_NoComposite
+   * or PaintType_Full on the root pres shell (which might not be this one, since
+   * WillPaint is called on all descendant presshells). This is issued at a time when
+   * it's safe to modify widget geometry.
    */
   virtual void WillPaint(bool aWillSendDidPaint) = 0;
   /**
-   * Notify that the NS_DID_PAINT event was received. Only fires on the
-   * root pres shell.
+   * Notify that we called Paint with PaintType_NoComposite. Only fires on the
+   * root pres shell. This is issued at a time when it's safe to modify
+   * widget geometry.
    */
   virtual void DidPaint() = 0;
+  /**
+   * Notify that we're going to call Paint with PaintType_Composite
+   * or PaintType_Full.  This is issued at a time when it's safe to
+   * modify widget geometry.
+   */
+  virtual void WillPaintWindow(bool aWillSendDidPaint) = 0;
+  /**
+   * Notify that we called Paint with PaintType_Composite or PaintType_Full.
+   * This is issued at a time when it's safe to modify widget geometry.
+   */
+  virtual void DidPaintWindow() = 0;
 
   /**
    * Ensures that the refresh driver is running, and schedules a view 
    * manager flush on the next tick.
    */
   virtual void ScheduleViewManagerFlush() = 0;
   virtual void ClearMouseCaptureOnView(nsIView* aView) = 0;
   virtual bool IsVisible() = 0;
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1363,72 +1363,74 @@ TransformGfxRectFromAncestor(nsIFrame *a
 {
   gfx3DMatrix ctm = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestor);
   return ctm.Inverse().ProjectRectBounds(aRect);
 }
 
 static gfxRect
 TransformGfxRectToAncestor(nsIFrame *aFrame,
                            const gfxRect &aRect,
-                           nsIFrame *aAncestor)
+                           const nsIFrame *aAncestor)
 {
   gfx3DMatrix ctm = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestor);
   return ctm.TransformBounds(aRect);
 }
 
 nsPoint
 nsLayoutUtils::TransformRootPointToFrame(nsIFrame *aFrame,
                                          const nsPoint &aPoint)
 {
     float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
     gfxPoint result(NSAppUnitsToFloatPixels(aPoint.x, factor),
                     NSAppUnitsToFloatPixels(aPoint.y, factor));
-    
+
     result = TransformGfxPointFromAncestor(aFrame, result, nullptr);
-   
+
     return nsPoint(NSFloatPixelsToAppUnits(float(result.x), factor),
                    NSFloatPixelsToAppUnits(float(result.y), factor));
 }
 
 nsRect 
 nsLayoutUtils::TransformAncestorRectToFrame(nsIFrame* aFrame,
                                             const nsRect &aRect,
                                             const nsIFrame* aAncestor)
 {
-    float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
-    gfxRect result(NSAppUnitsToFloatPixels(aRect.x, factor),
-                   NSAppUnitsToFloatPixels(aRect.y, factor),
-                   NSAppUnitsToFloatPixels(aRect.width, factor),
-                   NSAppUnitsToFloatPixels(aRect.height, factor));
+    float srcAppUnitsPerDevPixel = aAncestor->PresContext()->AppUnitsPerDevPixel();
+    gfxRect result(NSAppUnitsToFloatPixels(aRect.x, srcAppUnitsPerDevPixel),
+                   NSAppUnitsToFloatPixels(aRect.y, srcAppUnitsPerDevPixel),
+                   NSAppUnitsToFloatPixels(aRect.width, srcAppUnitsPerDevPixel),
+                   NSAppUnitsToFloatPixels(aRect.height, srcAppUnitsPerDevPixel));
 
     result = TransformGfxRectFromAncestor(aFrame, result, aAncestor);
 
-    return nsRect(NSFloatPixelsToAppUnits(float(result.x), factor),
-                  NSFloatPixelsToAppUnits(float(result.y), factor),
-                  NSFloatPixelsToAppUnits(float(result.width), factor),
-                  NSFloatPixelsToAppUnits(float(result.height), factor));
+    float destAppUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
+    return nsRect(NSFloatPixelsToAppUnits(float(result.x), destAppUnitsPerDevPixel),
+                  NSFloatPixelsToAppUnits(float(result.y), destAppUnitsPerDevPixel),
+                  NSFloatPixelsToAppUnits(float(result.width), destAppUnitsPerDevPixel),
+                  NSFloatPixelsToAppUnits(float(result.height), destAppUnitsPerDevPixel));
 }
 
 nsRect
 nsLayoutUtils::TransformFrameRectToAncestor(nsIFrame* aFrame,
                                             const nsRect& aRect,
-                                            nsIFrame* aAncestor)
+                                            const nsIFrame* aAncestor)
 {
-  float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
-  gfxRect result(NSAppUnitsToFloatPixels(aRect.x, factor),
-                 NSAppUnitsToFloatPixels(aRect.y, factor),
-                 NSAppUnitsToFloatPixels(aRect.width, factor),
-                 NSAppUnitsToFloatPixels(aRect.height, factor));
+  float srcAppUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
+  gfxRect result(NSAppUnitsToFloatPixels(aRect.x, srcAppUnitsPerDevPixel),
+                 NSAppUnitsToFloatPixels(aRect.y, srcAppUnitsPerDevPixel),
+                 NSAppUnitsToFloatPixels(aRect.width, srcAppUnitsPerDevPixel),
+                 NSAppUnitsToFloatPixels(aRect.height, srcAppUnitsPerDevPixel));
 
   result = TransformGfxRectToAncestor(aFrame, result, aAncestor);
 
-  return nsRect(NSFloatPixelsToAppUnits(float(result.x), factor),
-                NSFloatPixelsToAppUnits(float(result.y), factor),
-                NSFloatPixelsToAppUnits(float(result.width), factor),
-                NSFloatPixelsToAppUnits(float(result.height), factor));
+  float destAppUnitsPerDevPixel = aAncestor->PresContext()->AppUnitsPerDevPixel();
+  return nsRect(NSFloatPixelsToAppUnits(float(result.x), destAppUnitsPerDevPixel),
+                NSFloatPixelsToAppUnits(float(result.y), destAppUnitsPerDevPixel),
+                NSFloatPixelsToAppUnits(float(result.width), destAppUnitsPerDevPixel),
+                NSFloatPixelsToAppUnits(float(result.height), destAppUnitsPerDevPixel));
 }
 
 static nsIntPoint GetWidgetOffset(nsIWidget* aWidget, nsIWidget*& aRootWidget) {
   nsIntPoint offset(0, 0);
   nsIWidget* parent = aWidget->GetParent();
   while (parent) {
     nsIntRect bounds;
     aWidget->GetBounds(bounds);
@@ -1610,16 +1612,20 @@ nsLayoutUtils::PaintFrame(nsRenderingCon
     if (!(view && view->GetWidget() && GetDisplayRootFrame(aFrame) == aFrame)) {
       aFlags &= ~PAINT_WIDGET_LAYERS;
       NS_ASSERTION(aRenderingContext, "need a rendering context");
     }
   }
 
   nsPresContext* presContext = aFrame->PresContext();
   nsIPresShell* presShell = presContext->PresShell();
+  nsRootPresContext* rootPresContext = presContext->GetRootPresContext();
+  if (!rootPresContext) {
+    return NS_OK;
+  }
 
   nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
   bool usingDisplayPort = false;
   nsRect displayport;
   if (rootScrollFrame) {
     nsIContent* content = rootScrollFrame->GetContent();
     if (content) {
       usingDisplayPort = nsLayoutUtils::GetDisplayPort(content, &displayport);
@@ -1663,16 +1669,23 @@ nsLayoutUtils::PaintFrame(nsRenderingCon
     builder.SetSyncDecodeImages(true);
   }
   if (aFlags & (PAINT_WIDGET_LAYERS | PAINT_TO_WINDOW)) {
     builder.SetPaintingToWindow(true);
   }
   if (aFlags & PAINT_IGNORE_SUPPRESSION) {
     builder.IgnorePaintSuppression();
   }
+  // Windowed plugins aren't allowed in popups
+  if ((aFlags & PAINT_WIDGET_LAYERS) &&
+      !willFlushRetainedLayers &&
+      !(aFlags & PAINT_DOCUMENT_RELATIVE) &&
+      rootPresContext->NeedToComputePluginGeometryUpdates()) {
+    builder.SetWillComputePluginGeometry(true);
+  }
   nsRect canvasArea(nsPoint(0, 0), aFrame->GetSize());
 
 #ifdef DEBUG
   if (ignoreViewportScrolling) {
     nsIDocument* doc = aFrame->GetContent() ?
       aFrame->GetContent()->GetCurrentDoc() : nullptr;
     NS_ASSERTION(!aFrame->GetParent() ||
                  (doc && doc->IsBeingUsedAsImage()),
@@ -1829,30 +1842,16 @@ nsLayoutUtils::PaintFrame(nsRenderingCon
     flags |= nsDisplayList::PAINT_EXISTING_TRANSACTION;
   }
   if (aFlags & PAINT_NO_COMPOSITE) {
     flags |= nsDisplayList::PAINT_NO_COMPOSITE;
   }
 
   list.PaintRoot(&builder, aRenderingContext, flags);
 
-  // Update the widget's opaque region information. This sets
-  // glass boundaries on Windows.
-  if ((aFlags & PAINT_WIDGET_LAYERS) &&
-      !willFlushRetainedLayers &&
-      !(aFlags & PAINT_DOCUMENT_RELATIVE)) {
-    nsIWidget *widget = aFrame->GetNearestWidget();
-    if (widget) {
-      nsRegion excludedRegion = builder.GetExcludedGlassRegion();
-      excludedRegion.Sub(excludedRegion, visibleRegion);
-      nsIntRegion windowRegion(excludedRegion.ToNearestPixels(presContext->AppUnitsPerDevPixel()));
-      widget->UpdateOpaqueRegion(windowRegion);
-    }
-  }
-
 #ifdef MOZ_DUMP_PAINTING
   if (gfxUtils::sDumpPaintList || gfxUtils::sDumpPainting) {
     if (gfxUtils::sDumpPaintingToFile) {
       fprintf(gfxUtils::sDumpPaintFile, "</script>");
     }
     fprintf(gfxUtils::sDumpPaintFile, "Painting --- after optimization:\n");
     nsFrame::PrintDisplayList(&builder, list, gfxUtils::sDumpPaintFile, gfxUtils::sDumpPaintingToFile);
 
@@ -1869,16 +1868,34 @@ nsLayoutUtils::PaintFrame(nsRenderingCon
       fprintf(gfxUtils::sDumpPaintFile, "</body></html>");
       fclose(gfxUtils::sDumpPaintFile);
     }
     gfxUtils::sDumpPaintFile = savedDumpFile;
     gPaintCount++;
   }
 #endif
 
+  // Update the widget's opaque region information. This sets
+  // glass boundaries on Windows. Also set up plugin clip regions and bounds.
+  if ((aFlags & PAINT_WIDGET_LAYERS) &&
+      !willFlushRetainedLayers &&
+      !(aFlags & PAINT_DOCUMENT_RELATIVE)) {
+    nsIWidget *widget = aFrame->GetNearestWidget();
+    if (widget) {
+      nsRegion excludedRegion = builder.GetExcludedGlassRegion();
+      excludedRegion.Sub(excludedRegion, visibleRegion);
+      nsIntRegion windowRegion(excludedRegion.ToNearestPixels(presContext->AppUnitsPerDevPixel()));
+      widget->UpdateOpaqueRegion(windowRegion);
+    }
+  }
+
+  if (builder.WillComputePluginGeometry()) {
+    rootPresContext->ComputePluginGeometryUpdates(aFrame, &builder, &list);
+  }
+
   // Flush the list so we don't trigger the IsEmpty-on-destruction assertion
   list.DeleteAll();
   return NS_OK;
 }
 
 int32_t
 nsLayoutUtils::GetZIndex(nsIFrame* aFrame) {
   if (!aFrame->IsPositioned())
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -521,17 +521,17 @@ public:
                                              const nsIFrame* aAncestor);
 
   /**
    * Transform aRect relative to aFrame up to the coordinate system of
    * aAncestor. Computes the bounding-box of the true quadrilateral.
    */
   static nsRect TransformFrameRectToAncestor(nsIFrame* aFrame,
                                              const nsRect& aRect,
-                                             nsIFrame* aAncestor);
+                                             const nsIFrame* aAncestor);
 
 
   /**
    * Gets the transform for aFrame relative to aAncestor. Pass null for aAncestor
    * to go up to the root frame.
    */
   static gfx3DMatrix GetTransformToAncestor(nsIFrame *aFrame, const nsIFrame *aAncestor);
 
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -1075,17 +1075,17 @@ nsPresContext::SetShell(nsIPresShell* aS
     if (mAnimationManager) {
       mAnimationManager->Disconnect();
       mAnimationManager = nullptr;
     }
 
     if (IsRoot()) {
       // Have to cancel our plugin geometry timer, because the
       // callback for that depends on a non-null presshell.
-      static_cast<nsRootPresContext*>(this)->CancelUpdatePluginGeometryTimer();
+      static_cast<nsRootPresContext*>(this)->CancelApplyPluginGeometryTimer();
     }
   }
 }
 
 void
 nsPresContext::DoChangeCharSet(const nsCString& aCharSet)
 {
   UpdateCharSet(aCharSet);
@@ -2434,196 +2434,127 @@ nsPresContext::IsCrossProcessRootContent
 
   TabChild* tabChild = GetTabChildFrom(mShell);
   return (tabChild && tabChild->IsRootContentDocument());
 }
 
 nsRootPresContext::nsRootPresContext(nsIDocument* aDocument,
                                      nsPresContextType aType)
   : nsPresContext(aDocument, aType),
-    mDOMGeneration(0),
-    mNeedsToUpdatePluginGeometry(false)
+    mDOMGeneration(0)
 {
   mRegisteredPlugins.Init();
 }
 
 nsRootPresContext::~nsRootPresContext()
 {
   NS_ASSERTION(mRegisteredPlugins.Count() == 0,
                "All plugins should have been unregistered");
   CancelDidPaintTimer();
-  CancelUpdatePluginGeometryTimer();
+  CancelApplyPluginGeometryTimer();
 }
 
 void
 nsRootPresContext::RegisterPluginForGeometryUpdates(nsIContent* aPlugin)
 {
   mRegisteredPlugins.PutEntry(aPlugin);
 }
 
 void
 nsRootPresContext::UnregisterPluginForGeometryUpdates(nsIContent* aPlugin)
 {
   mRegisteredPlugins.RemoveEntry(aPlugin);
 }
 
-struct PluginGeometryClosure {
-  nsIFrame* mRootFrame;
-  int32_t   mRootAPD;
-  nsIFrame* mChangedSubtree;
-  nsRect    mChangedRect;
-  nsTHashtable<nsPtrHashKey<nsObjectFrame> > mAffectedPlugins;
-  nsRect    mAffectedPluginBounds;
-  nsTArray<nsIWidget::Configuration>* mOutputConfigurations;
-};
 static PLDHashOperator
-PluginBoundsEnumerator(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
+SetPluginHidden(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
 {
-  PluginGeometryClosure* closure = static_cast<PluginGeometryClosure*>(userArg);
+  nsIFrame* root = static_cast<nsIFrame*>(userArg);
   nsObjectFrame* f = static_cast<nsObjectFrame*>(aEntry->GetKey()->GetPrimaryFrame());
   if (!f) {
-    NS_WARNING("Null frame in PluginBoundsEnumerator");
+    NS_WARNING("Null frame in SetPluginHidden");
     return PL_DHASH_NEXT;
   }
-  nsRect fBounds = f->GetContentRect() +
-      f->GetParent()->GetOffsetToCrossDoc(closure->mRootFrame);
-  int32_t APD = f->PresContext()->AppUnitsPerDevPixel();
-  fBounds = fBounds.ConvertAppUnitsRoundOut(APD, closure->mRootAPD);
-  // We're identifying the plugins that may have been affected by changes
-  // to the frame subtree rooted at aChangedRoot. Any plugin that overlaps
-  // the overflow area of aChangedRoot could have its clip region affected
-  // because it might be covered (or uncovered) by changes to the subtree.
-  // Plugins in the subtree might have changed position and/or size, and
-  // they might not be in aChangedRoot's overflow area (because they're
-  // being clipped by an ancestor in the subtree).
-  if (fBounds.Intersects(closure->mChangedRect) ||
-      nsLayoutUtils::IsAncestorFrameCrossDoc(closure->mChangedSubtree, f)) {
-    closure->mAffectedPluginBounds.UnionRect(
-        closure->mAffectedPluginBounds, fBounds);
-    closure->mAffectedPlugins.PutEntry(f);
+  if (!nsLayoutUtils::IsAncestorFrameCrossDoc(root, f)) {
+    // f is not managed by this frame so we should ignore it.
+    return PL_DHASH_NEXT;
   }
+  f->SetEmptyWidgetConfiguration();
   return PL_DHASH_NEXT;
 }
 
-static PLDHashOperator
-PluginHideEnumerator(nsPtrHashKey<nsObjectFrame>* aEntry, void* userArg)
+void
+nsRootPresContext::ComputePluginGeometryUpdates(nsIFrame* aFrame,
+                                                nsDisplayListBuilder* aBuilder,
+                                                nsDisplayList* aList)
 {
-  PluginGeometryClosure* closure = static_cast<PluginGeometryClosure*>(userArg);
-  nsObjectFrame* f = aEntry->GetKey();
-  f->GetEmptyClipConfiguration(closure->mOutputConfigurations);
-  return PL_DHASH_NEXT;
+  if (mRegisteredPlugins.Count() == 0) {
+    return;
+  }
+
+  // Initially make the next state for each plugin descendant of aFrame be
+  // "hidden". Plugins that are visible will have their next state set to
+  // unhidden by nsDisplayPlugin::ComputeVisibility.
+  mRegisteredPlugins.EnumerateEntries(SetPluginHidden, aFrame);
+
+  nsIFrame* rootFrame = FrameManager()->GetRootFrame();
+  if (!rootFrame) {
+    return;
+  }
+
+  aBuilder->SetForPluginGeometry();
+  aBuilder->SetAccurateVisibleRegions();
+  // Merging and flattening has already been done and we should not do it
+  // again. nsDisplayScroll(Info)Layer doesn't support trying to flatten
+  // again.
+  aBuilder->SetAllowMergingAndFlattening(false);
+  nsRegion region = rootFrame->GetVisualOverflowRectRelativeToSelf();
+  // nsDisplayPlugin::ComputeVisibility will automatically set a non-hidden
+  // widget configuration for the plugin, if it's visible.
+  aList->ComputeVisibilityForRoot(aBuilder, &region);
+
+  InitApplyPluginGeometryTimer();
 }
 
 static void
-RecoverPluginGeometry(nsDisplayListBuilder* aBuilder,
-    nsDisplayList* aList, bool aInTransform, PluginGeometryClosure* aClosure)
+ApplyPluginGeometryUpdatesCallback(nsITimer *aTimer, void *aClosure)
+{
+  static_cast<nsRootPresContext*>(aClosure)->ApplyPluginGeometryUpdates();
+}
+
+void
+nsRootPresContext::InitApplyPluginGeometryTimer()
 {
-  for (nsDisplayItem* i = aList->GetBottom(); i; i = i->GetAbove()) {
-    switch (i->GetType()) {
-    case nsDisplayItem::TYPE_PLUGIN: {
-      nsDisplayPlugin* displayPlugin = static_cast<nsDisplayPlugin*>(i);
-      nsObjectFrame* f = static_cast<nsObjectFrame*>(
-          displayPlugin->GetUnderlyingFrame());
-      // Ignore plugins which aren't supposed to be affected by this
-      // operation --- their bounds will not have been included in the
-      // display list computations so the visible region computed for them
-      // would be incorrect
-      nsPtrHashKey<nsObjectFrame>* entry =
-        aClosure->mAffectedPlugins.GetEntry(f);
-      // Windowed plugins in transforms are always ignored, we don't
-      // create configurations for them
-      if (entry && (!aInTransform || f->PaintedByGecko())) {
-        displayPlugin->GetWidgetConfiguration(aBuilder,
-                                              aClosure->mOutputConfigurations);
-        // we've dealt with this plugin now
-        aClosure->mAffectedPlugins.RawRemoveEntry(entry);
-      }
-      break;
-    }
-    case nsDisplayItem::TYPE_TRANSFORM: {
-      nsDisplayList* sublist =
-          static_cast<nsDisplayTransform*>(i)->GetStoredList()->GetList();
-      RecoverPluginGeometry(aBuilder, sublist, true, aClosure);
-      break;
-    }
-    default: {
-      nsDisplayList* sublist = i->GetList();
-      if (sublist) {
-        RecoverPluginGeometry(aBuilder, sublist, aInTransform, aClosure);
-      }
-      break;
-    }
-    }
+  if (mApplyPluginGeometryTimer) {
+    return;
+  }
+
+  // We'll apply the plugin geometry updates during the next compositing paint in this
+  // presContext (either from nsPresShell::WillPaintWindow or from
+  // nsPresShell::DidPaintWindow, depending on the platform).  But paints might
+  // get optimized away if the old plugin geometry covers the invalid region,
+  // so set a backup timer to do this too.  We want to make sure this
+  // won't fire before our normal paint notifications, if those would
+  // update the geometry, so set it for double the refresh driver interval.
+  mApplyPluginGeometryTimer = do_CreateInstance("@mozilla.org/timer;1");
+  if (mApplyPluginGeometryTimer) {
+    mApplyPluginGeometryTimer->
+      InitWithFuncCallback(ApplyPluginGeometryUpdatesCallback, this,
+                           nsRefreshDriver::DefaultInterval() * 2,
+                           nsITimer::TYPE_ONE_SHOT);
   }
 }
 
-#ifdef DEBUG
-#include <stdio.h>
-
-static bool gDumpPluginList = false;
-#endif
-
 void
-nsRootPresContext::GetPluginGeometryUpdates(nsIFrame* aChangedSubtree,
-                                            nsTArray<nsIWidget::Configuration>* aConfigurations)
+nsRootPresContext::CancelApplyPluginGeometryTimer()
 {
-  if (mRegisteredPlugins.Count() == 0)
-    return;
-
-  PluginGeometryClosure closure;
-  closure.mRootFrame = mShell->FrameManager()->GetRootFrame();
-  closure.mRootAPD = closure.mRootFrame->PresContext()->AppUnitsPerDevPixel();
-  closure.mChangedSubtree = aChangedSubtree;
-  closure.mChangedRect = aChangedSubtree->GetVisualOverflowRect() +
-      aChangedSubtree->GetOffsetToCrossDoc(closure.mRootFrame);
-  int32_t subtreeAPD = aChangedSubtree->PresContext()->AppUnitsPerDevPixel();
-  closure.mChangedRect =
-    closure.mChangedRect.ConvertAppUnitsRoundOut(subtreeAPD, closure.mRootAPD);
-  closure.mAffectedPlugins.Init();
-  closure.mOutputConfigurations = aConfigurations;
-  // Fill in closure.mAffectedPlugins and closure.mAffectedPluginBounds
-  mRegisteredPlugins.EnumerateEntries(PluginBoundsEnumerator, &closure);
-
-  nsRect bounds;
-  if (bounds.IntersectRect(closure.mAffectedPluginBounds,
-                           closure.mRootFrame->GetRect())) {
-    nsDisplayListBuilder builder(closure.mRootFrame,
-    		nsDisplayListBuilder::PLUGIN_GEOMETRY, false);
-    builder.SetAccurateVisibleRegions();
-    nsDisplayList list;
-
-    builder.EnterPresShell(closure.mRootFrame, bounds);
-    closure.mRootFrame->BuildDisplayListForStackingContext(
-        &builder, bounds, &list);
-    builder.LeavePresShell(closure.mRootFrame, bounds);
-
-#ifdef DEBUG
-    if (gDumpPluginList) {
-      fprintf(stderr, "Plugins --- before optimization (bounds %d,%d,%d,%d):\n",
-          bounds.x, bounds.y, bounds.width, bounds.height);
-      nsFrame::PrintDisplayList(&builder, list);
-    }
-#endif
-
-    nsRegion visibleRegion(bounds);
-    list.ComputeVisibilityForRoot(&builder, &visibleRegion);
-
-#ifdef DEBUG
-    if (gDumpPluginList) {
-      fprintf(stderr, "Plugins --- after optimization:\n");
-      nsFrame::PrintDisplayList(&builder, list);
-    }
-#endif
-
-    RecoverPluginGeometry(&builder, &list, false, &closure);
-    list.DeleteAll();
+  if (mApplyPluginGeometryTimer) {
+    mApplyPluginGeometryTimer->Cancel();
+    mApplyPluginGeometryTimer = nullptr;
   }
-
-  // Plugins that we didn't find in the display list are not visible
-  closure.mAffectedPlugins.EnumerateEntries(PluginHideEnumerator, &closure);
 }
 
 static bool
 HasOverlap(const nsIntPoint& aOffset1, const nsTArray<nsIntRect>& aClipRects1,
            const nsIntPoint& aOffset2, const nsTArray<nsIntRect>& aClipRects2)
 {
   nsIntPoint offsetDelta = aOffset1 - aOffset2;
   for (uint32_t i = 0; i < aClipRects1.Length(); ++i) {
@@ -2684,86 +2615,59 @@ SortConfigurations(nsTArray<nsIWidget::C
     }
     // Note that we always move the last plugin in pluginsToMove, if we
     // can't find any other plugin to move
     aConfigurations->AppendElement(pluginsToMove[i]);
     pluginsToMove.RemoveElementAt(i);
   }
 }
 
-void
-nsRootPresContext::UpdatePluginGeometry()
-{
-  if (!mNeedsToUpdatePluginGeometry)
-    return;
-  mNeedsToUpdatePluginGeometry = false;
-  // Cancel out mUpdatePluginGeometryTimer so it doesn't do a random
-  // update when we don't actually want one.
-  CancelUpdatePluginGeometryTimer();
-
-  nsIFrame* f = FrameManager()->GetRootFrame();
-  nsTArray<nsIWidget::Configuration> configurations;
-  GetPluginGeometryUpdates(f, &configurations);
-  if (configurations.IsEmpty())
-    return;
-  SortConfigurations(&configurations);
-  nsIWidget* widget = f->GetNearestWidget();
-  NS_ASSERTION(widget, "Plugins must have a parent window");
-  widget->ConfigureChildren(configurations);
-  DidApplyPluginGeometryUpdates();
-}
-
-static void
-UpdatePluginGeometryCallback(nsITimer *aTimer, void *aClosure)
-{
-  static_cast<nsRootPresContext*>(aClosure)->UpdatePluginGeometry();
-}
-
-void
-nsRootPresContext::RequestUpdatePluginGeometry()
-{
-  if (mRegisteredPlugins.Count() == 0)
-    return;
-
-  if (!mNeedsToUpdatePluginGeometry) {
-    // We'll update the plugin geometry during the next paint in this
-    // presContext (either from nsPresShell::WillPaint or from
-    // nsPresShell::DidPaint, depending on the platform) or on the next
-    // layout flush, whichever comes first.  But we may not have anyone
-    // flush layout, and paints might get optimized away if the old
-    // plugin geometry covers the whole canvas, so set a backup timer to
-    // do this too.  We want to make sure this won't fire before our
-    // normal paint notifications, if those would update the geometry,
-    // so set it for double the refresh driver interval.
-    mUpdatePluginGeometryTimer = do_CreateInstance("@mozilla.org/timer;1");
-    if (mUpdatePluginGeometryTimer) {
-      mUpdatePluginGeometryTimer->
-        InitWithFuncCallback(UpdatePluginGeometryCallback, this,
-                             nsRefreshDriver::DefaultInterval() * 2,
-                             nsITimer::TYPE_ONE_SHOT);
-    }
-    mNeedsToUpdatePluginGeometry = true;
-  }
-}
-
 static PLDHashOperator
 PluginDidSetGeometryEnumerator(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
 {
   nsObjectFrame* f = static_cast<nsObjectFrame*>(aEntry->GetKey()->GetPrimaryFrame());
   if (!f) {
     NS_WARNING("Null frame in PluginDidSetGeometryEnumerator");
     return PL_DHASH_NEXT;
   }
   f->DidSetWidgetGeometry();
   return PL_DHASH_NEXT;
 }
 
+struct PluginGetGeometryUpdateClosure {
+  nsTArray<nsIWidget::Configuration> mConfigurations;
+};
+static PLDHashOperator
+PluginGetGeometryUpdate(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
+{
+  PluginGetGeometryUpdateClosure* closure =
+    static_cast<PluginGetGeometryUpdateClosure*>(userArg);
+  nsObjectFrame* f = static_cast<nsObjectFrame*>(aEntry->GetKey()->GetPrimaryFrame());
+  if (!f) {
+    NS_WARNING("Null frame in GetPluginGeometryUpdate");
+    return PL_DHASH_NEXT;
+  }
+  f->GetWidgetConfiguration(&closure->mConfigurations);
+  return PL_DHASH_NEXT;
+}
+
 void
-nsRootPresContext::DidApplyPluginGeometryUpdates()
+nsRootPresContext::ApplyPluginGeometryUpdates()
 {
+  CancelApplyPluginGeometryTimer();
+
+  PluginGetGeometryUpdateClosure closure;
+  mRegisteredPlugins.EnumerateEntries(PluginGetGeometryUpdate, &closure);
+  // Walk mRegisteredPlugins and ask each plugin for its configuration
+  if (!closure.mConfigurations.IsEmpty()) {
+    nsIWidget* widget = closure.mConfigurations[0].mChild->GetParent();
+    NS_ASSERTION(widget, "Plugins must have a parent window");
+    SortConfigurations(&closure.mConfigurations);
+    widget->ConfigureChildren(closure.mConfigurations);
+  }
   mRegisteredPlugins.EnumerateEntries(PluginDidSetGeometryEnumerator, nullptr);
 }
 
 static void
 NotifyDidPaintForSubtreeCallback(nsITimer *aTimer, void *aClosure)
 {
   nsPresContext* presContext = (nsPresContext*)aClosure;
   nsAutoScriptBlocker blockScripts;
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -1260,50 +1260,43 @@ public:
   void RegisterPluginForGeometryUpdates(nsIContent* aPlugin);
   /**
    * Stops a plugin receiving geometry updates (position and clip
    * region). If the plugin was not already registered, this does
    * nothing.
    */
   void UnregisterPluginForGeometryUpdates(nsIContent* aPlugin);
 
+  bool NeedToComputePluginGeometryUpdates()
+  {
+    return mRegisteredPlugins.Count() > 0;
+  }
   /**
-   * Iterate through all plugins that are registered for geometry updates
-   * and update their position and clip region to match the current frame
-   * tree.
+   * Compute geometry updates for each plugin given that aList is the display
+   * list for aFrame. The updates are not yet applied;
+   * ApplyPluginGeometryUpdates is responsible for that. In the meantime they
+   * are stored on each nsObjectFrame.
+   * This needs to be called even when aFrame is a popup, since although
+   * windowed plugins aren't allowed in popups, windowless plugins are
+   * and ComputePluginGeometryUpdates needs to be called for them.
    */
-  void UpdatePluginGeometry();
+  void ComputePluginGeometryUpdates(nsIFrame* aFrame,
+                                    nsDisplayListBuilder* aBuilder,
+                                    nsDisplayList* aList);
 
   /**
-   * Iterate through all plugins that are registered for geometry updates
-   * and compute their position and clip region according to the
-   * current frame tree. Only frames at or under aChangedRoot can have
-   * changed their geometry. The computed positions and clip regions are
-   * appended to aConfigurations.
+   * Apply the stored plugin geometry updates. This should normally be called
+   * in DidPaint so the plugins are moved/clipped immediately after we've
+   * updated our window, so they look in sync with our window.
    */
-  void GetPluginGeometryUpdates(nsIFrame* aChangedRoot,
-                                nsTArray<nsIWidget::Configuration>* aConfigurations);
-
-  /**
-   * When all geometry updates have been applied, call this function
-   * in case the nsObjectFrames have work to do after the widgets
-   * have been updated.
-   */
-  void DidApplyPluginGeometryUpdates();
+  void ApplyPluginGeometryUpdates();
 
   virtual bool IsRoot() MOZ_OVERRIDE { return true; }
 
   /**
-   * Call this after reflow and scrolling to ensure that the geometry
-   * of any windowed plugins is updated. aFrame is the root of the
-   * frame subtree whose geometry has changed.
-   */
-  void RequestUpdatePluginGeometry();
-
-  /**
    * Increment DOM-modification generation counter to indicate that
    * the DOM has changed in a way that might lead to style changes/
    * reflows/frame creation and destruction.
    */
   void IncrementDOMGeneration() { mDOMGeneration++; }
 
   /**
    * Get the current DOM generation counter.
@@ -1323,49 +1316,47 @@ public:
   /**
    * Run all runnables that need to get called before the next paint.
    */
   void FlushWillPaintObservers();
 
   virtual size_t SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const MOZ_OVERRIDE;
 
 protected:
+  /**
+   * Start a timer to ensure we eventually run ApplyPluginGeometryUpdates.
+   */
+  void InitApplyPluginGeometryTimer();
+  /**
+   * Cancel the timer that ensures we eventually run ApplyPluginGeometryUpdates.
+   */
+  void CancelApplyPluginGeometryTimer();
+
   class RunWillPaintObservers : public nsRunnable {
   public:
     RunWillPaintObservers(nsRootPresContext* aPresContext) : mPresContext(aPresContext) {}
     void Revoke() { mPresContext = nullptr; }
     NS_IMETHOD Run()
     {
       if (mPresContext) {
         mPresContext->FlushWillPaintObservers();
       }
       return NS_OK;
     }
     nsRootPresContext* mPresContext;
   };
 
   friend class nsPresContext;
-  void CancelUpdatePluginGeometryTimer()
-  {
-    if (mUpdatePluginGeometryTimer) {
-      mUpdatePluginGeometryTimer->Cancel();
-      mUpdatePluginGeometryTimer = nullptr;
-    }
-  }
 
   nsCOMPtr<nsITimer> mNotifyDidPaintTimer;
-  nsCOMPtr<nsITimer> mUpdatePluginGeometryTimer;
+  nsCOMPtr<nsITimer> mApplyPluginGeometryTimer;
   nsTHashtable<nsRefPtrHashKey<nsIContent> > mRegisteredPlugins;
-  // if mNeedsToUpdatePluginGeometry is set, then this is the frame to
-  // use as the root of the subtree to search for plugin updates, or
-  // null to use the root frame of this prescontext
   nsTArray<nsCOMPtr<nsIRunnable> > mWillPaintObservers;
   nsRevocableEventPtr<RunWillPaintObservers> mWillPaintFallbackEvent;
   uint32_t mDOMGeneration;
-  bool mNeedsToUpdatePluginGeometry;
 };
 
 #ifdef MOZ_REFLOW_PERF
 
 #define DO_GLOBAL_REFLOW_COUNT(_name) \
   aPresContext->CountReflows((_name), (nsIFrame*)this); 
 #else
 #define DO_GLOBAL_REFLOW_COUNT(_name)
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -3570,21 +3570,16 @@ PresShell::UnsuppressAndInvalidate()
   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
   if (rootFrame) {
     // let's assume that outline on a root frame is not supported
     rootFrame->InvalidateFrame();
 
     if (mCaretEnabled && mCaret) {
       mCaret->CheckCaretDrawingState();
     }
-
-    nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
-    if (rootPC) {
-      rootPC->RequestUpdatePluginGeometry();
-    }
   }
 
   // now that painting is unsuppressed, focus may be set on the document
   nsPIDOMWindow *win = mDocument->GetWindow();
   if (win)
     win->SetReadyForFocus();
 
   if (!mHaveShutDown)
@@ -3880,24 +3875,16 @@ PresShell::FlushPendingNotifications(moz
     } else if (!mIsDestroying && mSuppressInterruptibleReflows &&
                aType == Flush_InterruptibleLayout) {
       // We suppressed this flush, but the document thinks it doesn't
       // need to flush anymore.  Let it know what's really going on.
       mDocument->SetNeedLayoutFlush();
     }
 
     if (aType >= Flush_Layout) {
-      // Flush plugin geometry. Don't flush plugin geometry for
-      // interruptible layouts, since WillPaint does an interruptible
-      // layout.
-      nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
-      if (rootPresContext) {
-        rootPresContext->UpdatePluginGeometry();
-      }
-
       if (!mIsDestroying) {
         mViewManager->UpdateWidgetGeometry();
       }
     }
   }
 }
 
 void
@@ -6988,55 +6975,67 @@ bool
 PresShell::ShouldIgnoreInvalidation()
 {
   return mPaintingSuppressed || !mIsActive;
 }
 
 void
 PresShell::WillPaint(bool aWillSendDidPaint)
 {
+  nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
+  if (!rootPresContext) {
+    // In some edge cases, such as when we don't have a root frame yet,
+    // we can't find the root prescontext. There's nothing to do in that
+    // case.
+    return;
+  }
+
   // Don't bother doing anything if some viewmanager in our tree is painting
   // while we still have painting suppressed or we are not active.
   if (mPaintingSuppressed || !mIsActive || !IsVisible()) {
     return;
   }
 
-  nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
-  if (!rootPresContext) {
-    return;
-  }
-
-  if (!aWillSendDidPaint && rootPresContext == mPresContext) {
-    rootPresContext->UpdatePluginGeometry();
-  }
   rootPresContext->FlushWillPaintObservers();
   if (mIsDestroying)
     return;
 
   // Process reflows, if we have them, to reduce flicker due to invalidates and
   // reflow being interspersed.  Note that we _do_ allow this to be
   // interruptible; if we can't do all the reflows it's better to flicker a bit
   // than to freeze up.
   FlushPendingNotifications(Flush_InterruptibleLayout);
 }
 
 void
 PresShell::DidPaint()
 {
-  if (mPaintingSuppressed || !mIsActive || !IsVisible()) {
+}
+
+void
+PresShell::WillPaintWindow(bool aWillSendDidPaint)
+{
+  nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
+  if (rootPresContext != mPresContext) {
+    // This could be a popup's presshell. We don't allow plugins in popups
+    // so there's nothing to do here.
     return;
   }
 
-  NS_ASSERTION(mPresContext->IsRoot(), "Should only call DidPaint on root presshells");
-
+  rootPresContext->ApplyPluginGeometryUpdates();
+}
+
+void
+PresShell::DidPaintWindow()
+{
   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
-  // This should only be called on root presshells, but maybe if a document
-  // tree is torn down we might not be a root presshell...
-  if (rootPresContext == mPresContext) {
-    rootPresContext->UpdatePluginGeometry();
+  if (rootPresContext != mPresContext) {
+    // This could be a popup's presshell. No point in notifying XPConnect
+    // about compositing of popups.
+    return;
   }
 
   if (nsContentUtils::XPConnect()) {
     nsContentUtils::XPConnect()->NotifyDidPaint();
   }
 }
 
 bool
@@ -7485,21 +7484,16 @@ PresShell::DoReflow(nsIFrame* target, bo
 
     // Any FlushPendingNotifications with interruptible reflows
     // should be suppressed now. We don't want to do extra reflow work
     // before our reflow event happens.
     mSuppressInterruptibleReflows = true;
     MaybeScheduleReflow();
   }
 
-  nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
-  if (rootPC) {
-    rootPC->RequestUpdatePluginGeometry();
-  }
-
   return !interrupted;
 }
 
 #ifdef DEBUG
 void
 PresShell::DoVerifyReflow()
 {
   if (GetVerifyReflowEnable()) {
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -192,16 +192,18 @@ public:
                                                         nsEvent* aEvent,
                                                         nsEventStatus* aStatus);
   virtual NS_HIDDEN_(nsresult) HandleDOMEventWithTarget(nsIContent* aTargetContent,
                                                         nsIDOMEvent* aEvent,
                                                         nsEventStatus* aStatus);
   virtual bool ShouldIgnoreInvalidation();
   virtual void WillPaint(bool aWillSendDidPaint);
   virtual void DidPaint();
+  virtual void WillPaintWindow(bool aWillSendDidPaint);
+  virtual void DidPaintWindow();
   virtual void ScheduleViewManagerFlush();
   virtual void DispatchSynthMouseMove(nsGUIEvent *aEvent, bool aFlushOnHoverChange);
   virtual void ClearMouseCaptureOnView(nsIView* aView);
   virtual bool IsVisible();
 
   // caret handling
   virtual NS_HIDDEN_(already_AddRefed<nsCaret>) GetCaret() const;
   virtual NS_HIDDEN_(void) MaybeInvalidateCaretPosition();
--- a/layout/generic/Selection.h
+++ b/layout/generic/Selection.h
@@ -241,13 +241,12 @@ see the nsIEnumerator for more details*/
 /*END Helper Methods*/
 
   nsSelectionIterator(mozilla::Selection*);
   virtual ~nsSelectionIterator();
 
 private:
   int32_t             mIndex;
   mozilla::Selection* mDomSelection;
-  SelectionType       mType;
 };
 
 
 #endif // mozilla_Selection_h__
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1833,18 +1833,21 @@ nsIFrame::BuildDisplayListForStackingCon
   // Replaced elements have their visibility handled here, because
   // they're visually atomic
   if (IsFrameOfType(eReplaced) && !IsVisibleForPainting(aBuilder))
     return NS_OK;
 
   nsRect clipPropClip;
   const nsStyleDisplay* disp = GetStyleDisplay();
   // We can stop right away if this is a zero-opacity stacking context and
-  // we're painting, and we're not animating opacity.
+  // we're painting, and we're not animating opacity. Don't do this
+  // if we're going to compute plugin geometry, since opacity-0 plugins
+  // need to have display items built for them.
   if (disp->mOpacity == 0.0 && aBuilder->IsForPainting() &&
+      !aBuilder->WillComputePluginGeometry() &&
       !nsLayoutUtils::HasAnimationsForCompositor(mContent,
                                                  eCSSProperty_opacity)) {
     return NS_OK;
   }
 
   bool applyClipPropClipping =
       ApplyClipPropClipping(aBuilder, disp, this, &clipPropClip);
   nsRect dirtyRect = aDirtyRect;
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1778,23 +1778,16 @@ void nsGfxScrollFrameInner::MarkActive()
       gScrollFrameActivityTracker = new ScrollFrameActivityTracker();
     }
     gScrollFrameActivityTracker->AddObject(this);
   }
 }
 
 void nsGfxScrollFrameInner::ScrollVisual(nsPoint aOldScrolledFramePos)
 {
-  nsRootPresContext* rootPresContext = mOuter->PresContext()->GetRootPresContext();
-  if (!rootPresContext) {
-    return;
-  }
-
-  rootPresContext->RequestUpdatePluginGeometry();
-
   AdjustViews(mScrolledFrame);
   // We need to call this after fixing up the view positions
   // to be consistent with the frame hierarchy.
   bool invalidate = false;
   bool canScrollWithBlitting = CanScrollWithBlitting(mOuter);
   mOuter->RemoveStateBits(NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL);
   if (IsScrollingActive()) {
     if (!canScrollWithBlitting) {
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -375,23 +375,24 @@ nsObjectFrame::PrepForDrawing(nsIWidget 
   nsIView* parentWithView;
   nsPoint origin;
   nsRect r(0, 0, mRect.width, mRect.height);
 
   GetOffsetFromView(origin, &parentWithView);
   viewMan->ResizeView(view, r);
   viewMan->MoveViewTo(view, origin.x, origin.y);
 
-  nsRootPresContext* rpc = PresContext()->GetRootPresContext();
+  nsPresContext* presContext = PresContext();
+  nsRootPresContext* rpc = presContext->GetRootPresContext();
   if (!rpc) {
     return NS_ERROR_FAILURE;
   }
 
   if (mWidget) {
-    // Disallow plugins in popups
+    // Disallow windowed plugins in popups
     nsIFrame* rootFrame = rpc->PresShell()->FrameManager()->GetRootFrame();
     nsIWidget* parentWidget = rootFrame->GetNearestWidget();
     if (!parentWidget || nsLayoutUtils::GetDisplayRootFrame(this) != rootFrame) {
       return NS_ERROR_FAILURE;
     }
 
     mInnerView = viewMan->CreateView(GetContentRectRelativeToSelf(), view);
     if (!mInnerView) {
@@ -399,28 +400,28 @@ nsObjectFrame::PrepForDrawing(nsIWidget 
       return NS_ERROR_OUT_OF_MEMORY;
     }
     viewMan->InsertChild(view, mInnerView, nullptr, true);
 
     mWidget->SetParent(parentWidget);
     mWidget->Show(true);
     mWidget->Enable(true);
 
-    // Set the plugin window to have an empty cliprect. The cliprect
-    // will be reset when nsRootPresContext::UpdatePluginGeometry
-    // runs later. The plugin window does need to have the correct
-    // size here. GetEmptyClipConfiguration will probably give it the
-    // size, but just in case we haven't been reflowed or something, set
-    // the size explicitly.
-    nsAutoTArray<nsIWidget::Configuration,1> configuration;
-    GetEmptyClipConfiguration(&configuration);
-    NS_ASSERTION(configuration.Length() > 0, "Empty widget configuration array!");
-    configuration[0].mBounds.width = mRect.width;
-    configuration[0].mBounds.height = mRect.height;
-    parentWidget->ConfigureChildren(configuration);
+    // Set the plugin window to have an empty clip region until we know
+    // what our true position, size and clip region are. These
+    // will be reset when nsRootPresContext computes our true
+    // geometry. The plugin window does need to have a good size here, so
+    // set the size explicitly to a reasonable guess.
+    nsAutoTArray<nsIWidget::Configuration,1> configurations;
+    nsIWidget::Configuration* configuration = configurations.AppendElement();
+    nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
+    configuration->mChild = mWidget;
+    configuration->mBounds.width = NSAppUnitsToIntPixels(mRect.width, appUnitsPerDevPixel);
+    configuration->mBounds.height = NSAppUnitsToIntPixels(mRect.height, appUnitsPerDevPixel);
+    parentWidget->ConfigureChildren(configurations);
 
     nsRefPtr<nsDeviceContext> dx;
     viewMan->GetDeviceContext(*getter_AddRefs(dx));
     mInnerView->AttachWidgetEventHandler(mWidget);
 
 #ifdef XP_MACOSX
     // On Mac, we need to invalidate ourselves since even windowed
     // plugins are painted through Thebes and we need to ensure
@@ -756,17 +757,16 @@ nsObjectFrame::RegisterPluginForGeometry
   }
   if (mRootPresContextRegisteredWith && mRootPresContextRegisteredWith != rpc) {
     // Registered to some other root pres context. Unregister, and
     // re-register with our current one...
     UnregisterPluginForGeometryUpdates();
   }
   mRootPresContextRegisteredWith = rpc;
   mRootPresContextRegisteredWith->RegisterPluginForGeometryUpdates(mContent);
-  mRootPresContextRegisteredWith->RequestUpdatePluginGeometry();
 }
 
 void
 nsObjectFrame::UnregisterPluginForGeometryUpdates()
 {
   if (!mRootPresContextRegisteredWith) {
     // Not registered...
     return;
@@ -785,17 +785,18 @@ nsObjectFrame::SetInstanceOwner(nsPlugin
   UnregisterPluginForGeometryUpdates();
   if (mWidget && mInnerView) {
     mInnerView->DetachWidgetEventHandler(mWidget);
     // Make sure the plugin is hidden in case an update of plugin geometry
     // hasn't happened since this plugin became hidden.
     nsIWidget* parent = mWidget->GetParent();
     if (parent) {
       nsTArray<nsIWidget::Configuration> configurations;
-      this->GetEmptyClipConfiguration(&configurations);
+      nsIWidget::Configuration* configuration = configurations.AppendElement();
+      configuration->mChild = mWidget;
       parent->ConfigureChildren(configurations);
 
       mWidget->Show(false);
       mWidget->Enable(false);
       mWidget->SetParent(nullptr);
     }
   }
 }
@@ -1043,119 +1044,92 @@ nsDisplayPlugin::Paint(nsDisplayListBuil
   f->PaintPlugin(aBuilder, *aCtx, mVisibleRect, GetBounds(aBuilder, &snap));
 }
 
 bool
 nsDisplayPlugin::ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion)
 {
-  bool snap;
-  mVisibleRegion.And(*aVisibleRegion, GetBounds(aBuilder, &snap));
+  if (aBuilder->IsForPluginGeometry()) {
+    nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
+    if (!aBuilder->IsInTransform() || f->IsPaintedByGecko()) {
+      // Since transforms induce reference frames, we don't need to worry
+      // about this method fluffing out due to non-rectilinear transforms.
+      nsRect rAncestor = nsLayoutUtils::TransformFrameRectToAncestor(f,
+          f->GetContentRectRelativeToSelf(), ReferenceFrame());
+      nscoord appUnitsPerDevPixel =
+        ReferenceFrame()->PresContext()->AppUnitsPerDevPixel();
+      f->mNextConfigurationBounds = rAncestor.ToNearestPixels(appUnitsPerDevPixel);
+
+      bool snap;
+      nsRegion visibleRegion;
+      visibleRegion.And(*aVisibleRegion, GetBounds(aBuilder, &snap));
+      // Make visibleRegion relative to f
+      visibleRegion.MoveBy(-ToReferenceFrame());
+
+      f->mNextConfigurationClipRegion.Clear();
+      nsRegionRectIterator iter(visibleRegion);
+      for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
+        nsRect rAncestor =
+          nsLayoutUtils::TransformFrameRectToAncestor(f, *r, ReferenceFrame());
+        nsIntRect rPixels = rAncestor.ToNearestPixels(appUnitsPerDevPixel)
+            - f->mNextConfigurationBounds.TopLeft();
+        if (!rPixels.IsEmpty()) {
+          f->mNextConfigurationClipRegion.AppendElement(rPixels);
+        }
+      }
+    }
+
+    if (f->mInnerView) {
+      // This should produce basically the same rectangle (but not relative
+      // to the root frame). We only call this here for the side-effect of
+      // setting mViewToWidgetOffset on the view.
+      f->mInnerView->CalcWidgetBounds(eWindowType_plugin);
+    }
+  }
+
   return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
                                           aAllowVisibleRegionExpansion);
 }
 
 nsRegion
 nsDisplayPlugin::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                  bool* aSnap)
 {
   *aSnap = false;
   nsRegion result;
   nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
   if (!aBuilder->IsForPluginGeometry()) {
     nsIWidget* widget = f->GetWidget();
     if (widget) {
-      nsTArray<nsIntRect> clip;
-      widget->GetWindowClipRegion(&clip);
-      nsTArray<nsIWidget::Configuration> configuration;
-      GetWidgetConfiguration(aBuilder, &configuration);
-      NS_ASSERTION(configuration.Length() == 1, "No configuration found");
-      if (clip != configuration[0].mClipRegion) {
-        // Something has clipped us unexpectedly. Perhaps there is a translucent
-        // chrome element overlaying us that forced us to be clipped away. Treat
-        // us as non-opaque since we may have holes.
-    	return result;
-      }
+      // Be conservative and treat plugins with widgets as not opaque,
+      // because that's simple and we might need the content under the widget
+      // if the widget is unexpectedly clipped away. (As can happen when
+      // chrome content over a plugin forces us to clip out the plugin for
+      // security reasons.)
+      // We shouldn't be repainting the content under plugins much anyway
+      // since there generally shouldn't be anything to invalidate or paint
+      // in ThebesLayers there.
+  	  return result;
     }
   }
+
   if (f->IsOpaque()) {
     nsRect bounds = GetBounds(aBuilder, aSnap);
     if (aBuilder->IsForPluginGeometry() ||
         (f->GetPaintedRect(this) + ToReferenceFrame()).Contains(bounds)) {
       // We can treat this as opaque
       result = bounds;
     }
   }
+
   return result;
 }
 
-void
-nsDisplayPlugin::GetWidgetConfiguration(nsDisplayListBuilder* aBuilder,
-                                        nsTArray<nsIWidget::Configuration>* aConfigurations)
-{
-  nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
-  nsPoint pluginOrigin = mFrame->GetContentRectRelativeToSelf().TopLeft() +
-    ToReferenceFrame();
-  f->ComputeWidgetGeometry(mVisibleRegion, pluginOrigin, aConfigurations);
-}
-
-void
-nsObjectFrame::ComputeWidgetGeometry(const nsRegion& aRegion,
-                                     const nsPoint& aPluginOrigin,
-                                     nsTArray<nsIWidget::Configuration>* aConfigurations)
-{
-  if (!mWidget) {
-#ifndef XP_MACOSX
-    if (mInstanceOwner) {
-      // UpdateWindowVisibility will notify the plugin of position changes
-      // by updating the NPWindow and calling NPP_SetWindow/AsyncSetWindow.
-      mInstanceOwner->UpdateWindowVisibility(!aRegion.IsEmpty());
-    }
-#endif
-    return;
-  }
-
-  if (!mInnerView) {
-    return;
-  }
-
-  nsPresContext* presContext = PresContext();
-  nsRootPresContext* rootPC = presContext->GetRootPresContext();
-  if (!rootPC)
-    return;
-
-  nsIWidget::Configuration* configuration = aConfigurations->AppendElement();
-  if (!configuration)
-    return;
-  configuration->mChild = mWidget;
-
-  int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
-  nsIFrame* rootFrame = rootPC->PresShell()->FrameManager()->GetRootFrame();
-  nsRect bounds = GetContentRectRelativeToSelf() + GetOffsetToCrossDoc(rootFrame);
-  configuration->mBounds = bounds.ToNearestPixels(appUnitsPerDevPixel);
-
-  // This should produce basically the same rectangle (but not relative
-  // to the root frame). We only call this here for the side-effect of
-  // setting mViewToWidgetOffset on the view.
-  mInnerView->CalcWidgetBounds(eWindowType_plugin);
-
-  nsRegionRectIterator iter(aRegion);
-  nsIntPoint pluginOrigin = aPluginOrigin.ToNearestPixels(appUnitsPerDevPixel);
-  for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
-    // Snap *r to pixels while it's relative to the painted widget, to
-    // improve consistency with rectangle and image drawing
-    nsIntRect pixRect =
-      r->ToNearestPixels(appUnitsPerDevPixel) - pluginOrigin;
-    if (!pixRect.IsEmpty()) {
-      configuration->mClipRegion.AppendElement(pixRect);
-    }
-  }
-}
-
 nsresult
 nsObjectFrame::PluginEventNotifier::Run() {
   nsCOMPtr<nsIObserverService> obsSvc =
     mozilla::services::GetObserverService();
   obsSvc->NotifyObservers(nullptr, "plugin-changed-event", mEventType.get());
   return NS_OK;
 }
 
@@ -1167,16 +1141,22 @@ nsObjectFrame::NotifyPluginReflowObserve
 
 void
 nsObjectFrame::DidSetWidgetGeometry()
 {
 #if defined(XP_MACOSX)
   if (mInstanceOwner) {
     mInstanceOwner->FixUpPluginWindow(nsPluginInstanceOwner::ePluginPaintEnable);
   }
+#else
+  if (!mWidget && mInstanceOwner) {
+    // UpdateWindowVisibility will notify the plugin of position changes
+    // by updating the NPWindow and calling NPP_SetWindow/AsyncSetWindow.
+    mInstanceOwner->UpdateWindowVisibility(!mNextConfigurationBounds.IsEmpty());
+  }
 #endif
 }
 
 bool
 nsObjectFrame::IsOpaque() const
 {
 #if defined(XP_MACOSX)
   // ???
@@ -2279,17 +2259,17 @@ nsObjectFrame::EndSwapDocShells(nsIConte
 
 nsIFrame*
 NS_NewObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsObjectFrame(aContext);
 }
 
 bool
-nsObjectFrame::PaintedByGecko()
+nsObjectFrame::IsPaintedByGecko() const
 {
 #ifdef XP_MACOSX
   return true;
 #else
   return !mWidget;
 #endif
 }
 
--- a/layout/generic/nsObjectFrame.h
+++ b/layout/generic/nsObjectFrame.h
@@ -97,28 +97,47 @@ public:
   virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext);
 
   NS_METHOD GetPluginInstance(nsNPAPIPluginInstance** aPluginInstance);
 
   virtual void SetIsDocumentActive(bool aIsActive) MOZ_OVERRIDE;
 
   NS_IMETHOD GetCursor(const nsPoint& aPoint, nsIFrame::Cursor& aCursor);
 
-  // Compute the desired position of the plugin's widget, on the assumption
-  // that it is not visible (clipped out or covered by opaque content).
-  // This will only be called for plugins which have been registered
-  // with the root pres context for geometry updates.
-  // The widget, its new position, size and (empty) clip region are appended
-  // as a Configuration record to aConfigurations.
-  // If there is no widget associated with the plugin, this
-  // simply does nothing.
-  void GetEmptyClipConfiguration(nsTArray<nsIWidget::Configuration>* aConfigurations) {
-    ComputeWidgetGeometry(nsRegion(), nsPoint(0,0), aConfigurations);
+  // APIs used by nsRootPresContext to set up the widget position/size/clip
+  // region.
+  /**
+   * Set the next widget configuration for the plugin to the desired
+   * position of the plugin's widget, on the assumption that it is not visible
+   * (clipped out or covered by opaque content).
+   * This will only be called for plugins which have been registered
+   * with the root pres context for geometry updates.
+   * If there is no widget associated with the plugin, this will have no effect.
+   */
+  void SetEmptyWidgetConfiguration()
+  {
+    mNextConfigurationBounds = nsIntRect(0,0,0,0);
+    mNextConfigurationClipRegion.Clear();
   }
-
+  /**
+   * Append the desired widget configuration to aConfigurations.
+   */
+  void GetWidgetConfiguration(nsTArray<nsIWidget::Configuration>* aConfigurations)
+  {
+    if (mWidget) {
+      nsIWidget::Configuration* configuration = aConfigurations->AppendElement();
+      configuration->mChild = mWidget;
+      configuration->mBounds = mNextConfigurationBounds;
+      configuration->mClipRegion = mNextConfigurationClipRegion;
+    }
+  }
+  /**
+   * Called after all widget position/size/clip regions have been changed
+   * (even if there isn't a widget for this plugin).
+   */
   void DidSetWidgetGeometry();
 
   // accessibility support
 #ifdef ACCESSIBILITY
   virtual already_AddRefed<Accessible> CreateAccessible();
 #ifdef XP_WIN
   NS_IMETHOD GetPluginPort(HWND *aPort);
 #endif
@@ -165,18 +184,16 @@ public:
    */
   static void BeginSwapDocShells(nsIContent* aContent, void*);
   /**
    * If aContent has a nsObjectFrame, then set it up after a DocShell swap.
    * @see nsSubDocumentFrame::EndSwapDocShells.
    */
   static void EndSwapDocShells(nsIContent* aContent, void*);
 
-  bool PaintedByGecko();
-
   nsIWidget* GetWidget() MOZ_OVERRIDE { return mInnerView ? mWidget : nullptr; }
 
   /**
    * Adjust the plugin's idea of its size, using aSize as its new size.
    * (aSize must be in twips)
    */
   void FixupWindow(const nsSize& aSize);
 
@@ -199,41 +216,29 @@ protected:
 
   bool IsFocusable(int32_t *aTabIndex = nullptr, bool aWithMouse = false);
 
   // check attributes and optionally CSS to see if we should display anything
   bool IsHidden(bool aCheckVisibilityStyle = true) const;
 
   bool IsOpaque() const;
   bool IsTransparentMode() const;
+  bool IsPaintedByGecko() const;
 
   nsIntPoint GetWindowOriginInPixels(bool aWindowless);
 
   static void PaintPrintPlugin(nsIFrame* aFrame,
                                nsRenderingContext* aRenderingContext,
                                const nsRect& aDirtyRect, nsPoint aPt);
   void PrintPlugin(nsRenderingContext& aRenderingContext,
                    const nsRect& aDirtyRect);
   void PaintPlugin(nsDisplayListBuilder* aBuilder,
                    nsRenderingContext& aRenderingContext,
                    const nsRect& aDirtyRect, const nsRect& aPluginRect);
 
-  /**
-   * Get the widget geometry for the plugin. aRegion is in some appunits
-   * coordinate system whose origin is device-pixel-aligned (if possible),
-   * and aPluginOrigin gives the top-left of the plugin frame's content-rect
-   * in that coordinate system. It doesn't matter what that coordinate
-   * system actually is, as long as aRegion and aPluginOrigin are consistent.
-   * This will append a Configuration object to aConfigurations
-   * containing the widget, its desired position, size and clip region.
-   */
-  void ComputeWidgetGeometry(const nsRegion& aRegion,
-                             const nsPoint& aPluginOrigin,
-                             nsTArray<nsIWidget::Configuration>* aConfigurations);
-
   void NotifyPluginReflowObservers();
 
   friend class nsPluginInstanceOwner;
   friend class nsDisplayPlugin;
   friend class PluginBackgroundSink;
 
 private:
   // Registers the plugin for a geometry update, and requests a geometry
@@ -261,16 +266,28 @@ private:
   nsCOMPtr<nsIWidget>             mWidget;
   nsIntRect                       mWindowlessRect;
   /**
    * This is owned by the ReadbackLayer for this nsObjectFrame. It is
    * automatically cleared if the PluginBackgroundSink is destroyed.
    */
   PluginBackgroundSink*           mBackgroundSink;
 
+  /**
+   * Bounds that we should set the plugin's widget to in the next composite,
+   * for plugins with widgets. For plugins without widgets, bounds in device
+   * pixels relative to the nearest frame that's a display list reference frame.
+   */
+  nsIntRect                       mNextConfigurationBounds;
+  /**
+   * Clip region that we should set the plugin's widget to
+   * in the next composite. Only meaningful for plugins with widgets.
+   */
+  nsTArray<nsIntRect>             mNextConfigurationClipRegion;
+
   bool mReflowCallbackPosted;
 
   // A reference to the ImageContainer which contains the current frame
   // of plugin to display.
   nsRefPtr<ImageContainer> mImageContainer;
 
   // We keep this reference to ensure we can always unregister the
   // plugins we register on the root PresContext.
@@ -298,26 +315,16 @@ public:
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
 
   NS_DISPLAY_DECL_NAME("Plugin", TYPE_PLUGIN)
 
-  // Compute the desired position and clip region of the plugin's widget.
-  // This will only be called for plugins which have been registered
-  // with the root pres context for geometry updates.
-  // The widget, its new position, size and clip region are appended as
-  // a Configuration record to aConfigurations.
-  // If the plugin has no widget, no configuration is added, but
-  // the plugin visibility state may be adjusted.
-  void GetWidgetConfiguration(nsDisplayListBuilder* aBuilder,
-                              nsTArray<nsIWidget::Configuration>* aConfigurations);
-
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerParameters& aContainerParameters) MOZ_OVERRIDE
   {
     return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder,
                                                            aManager, 
                                                            this,
                                                            aContainerParameters);
@@ -325,14 +332,11 @@ public:
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerParameters& aParameters) MOZ_OVERRIDE
   {
     return static_cast<nsObjectFrame*>(mFrame)->GetLayerState(aBuilder,
                                                               aManager);
   }
-
-private:
-  nsRegion mVisibleRegion;
 };
 
 #endif /* nsObjectFrame_h___ */
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/clipPath-basic-06.svg
@@ -0,0 +1,21 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink">
+
+  <title>Testcase for non-rectilinear clipPath</title>
+
+  <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=797231 -->
+
+  <clipPath id="cp">
+    <ellipse cx="60" cy="60" rx="60" ry="60"/>
+  </clipPath>
+
+  <rect width="100%" height="100%" fill="lime"/>
+  <circle cx="60" cy="60" r="58" fill="red"/>
+  <rect width="200" height="200" fill="lime" clip-path="url(#cp)"/>
+
+</svg>
+
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -30,16 +30,17 @@ include svg-integration/reftest.list
 == clip-02b.svg clip-02-ref.svg
 == clipPath-advanced-01.svg pass.svg
 fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu),1,2) == clipPath-and-shape-rendering-01.svg clipPath-and-shape-rendering-01-ref.svg # bug 614840
 == clipPath-basic-01.svg pass.svg
 == clipPath-basic-02.svg pass.svg
 == clipPath-basic-03.svg pass.svg
 == clipPath-basic-04.svg pass.svg
 == clipPath-basic-05.svg pass.svg
+== clipPath-basic-06.svg pass.svg
 == clipPath-winding-01.svg pass.svg
 == clip-surface-clone-01.svg clip-surface-clone-01-ref.svg
 == conditions-01.svg pass.svg
 == conditions-02.svg pass.svg
 == conditions-03.svg pass.svg
 == conditions-04.svg pass.svg
 == conditions-05.svg about:blank
 == conditions-06.svg pass.svg
--- a/layout/xul/base/src/grid/nsGridRowGroupLayout.h
+++ b/layout/xul/base/src/grid/nsGridRowGroupLayout.h
@@ -39,14 +39,13 @@ public:
 protected:
   nsGridRowGroupLayout();
   virtual ~nsGridRowGroupLayout();
 
   virtual void ChildAddedOrRemoved(nsIFrame* aBox, nsBoxLayoutState& aState) MOZ_OVERRIDE;
   static void AddWidth(nsSize& aSize, nscoord aSize2, bool aIsHorizontal);
 
 private:
-  nsGridRow* mRowColumn;
   int32_t mRowCount;
 };
 
 #endif
 
--- a/media/libjpeg/MOZCHANGES
+++ b/media/libjpeg/MOZCHANGES
@@ -53,16 +53,20 @@ To upgrade to a new revision of libjpeg-
     $ patch -p0 -i mozilla.diff
 
 * Update Makefile.in to build any new files.
 
 * Finally, tell hg that we've added or removed some files:
 
     $ hg addremove
 
+== October 13, 2012 ==
+
+* Modified config.h to use MOZ_ALWAYS_INLINE (bug 800106).
+
 == July 4, 2012 (libjpeg-turbo v1.2.1 r853 2012-06-30) ==
 
 * Updated to v1.2.1 stable release.
 
 == June 5, 2012 (libjpeg-turbo v1.2.x branch, r831 2012-05-30) ==
 
 * Updated to latest version on v1.2.x branch (bug 759891).
 
--- a/media/libjpeg/config.h
+++ b/media/libjpeg/config.h
@@ -1,6 +1,7 @@
 #define VERSION "1.2.1"
 #define BUILD "2012-06-30"
 #define PACKAGE_NAME "libjpeg-turbo"
 
 /* Need to use Mozilla-specific function inlining. */
-#define INLINE NS_ALWAYS_INLINE
+#include "mozilla/Attributes.h"
+#define INLINE MOZ_ALWAYS_INLINE
--- a/memory/build/extraMallocFuncs.c
+++ b/memory/build/extraMallocFuncs.c
@@ -38,16 +38,40 @@ wrap(_ZdlPv)(void *ptr)
   wrap(free)(ptr);
 }
 /* operator delete[](void*) */
 MOZ_EXPORT_API(void)
 wrap(_ZdaPv)(void *ptr)
 {
   wrap(free)(ptr);
 }
+/*operator new(unsigned int, std::nothrow_t const&)*/
+MOZ_EXPORT_API(void *)
+wrap(_ZnwjRKSt9nothrow_t)(unsigned int size)
+{
+  return wrap(malloc)(size);
+}
+/*operator new[](unsigned int, std::nothrow_t const&)*/
+MOZ_EXPORT_API(void *)
+wrap(_ZnajRKSt9nothrow_t)(unsigned int size)
+{
+  return wrap(malloc)(size);
+}
+/* operator delete(void*, std::nothrow_t const&) */
+MOZ_EXPORT_API(void)
+wrap(_ZdlPvRKSt9nothrow_t)(void *ptr)
+{
+  wrap(free)(ptr);
+}
+/* operator delete[](void*, std::nothrow_t const&) */
+MOZ_EXPORT_API(void)
+wrap(_ZdaPvRKSt9nothrow_t)(void *ptr)
+{
+  wrap(free)(ptr);
+}
 #endif
 
 #ifdef wrap
 MOZ_EXPORT_API(char *)
 wrap(strndup)(const char *src, size_t len)
 {
   char* dst = (char*) wrap(malloc)(len + 1);
   if (dst)
--- a/memory/mozalloc/mozalloc.h
+++ b/memory/mozalloc/mozalloc.h
@@ -34,18 +34,18 @@
 /* Make sure symbols are still exported even if we're wrapped in a
  * |visibility push(hidden)| blanket. */
 #  define MOZALLOC_EXPORT __attribute__ ((visibility ("default")))
 #else
 #  define MOZALLOC_EXPORT
 #endif
 
 
-#if defined(NS_ALWAYS_INLINE)
-#  define MOZALLOC_INLINE NS_ALWAYS_INLINE inline
+#if defined(MOZ_ALWAYS_INLINE)
+#  define MOZALLOC_INLINE MOZ_ALWAYS_INLINE
 #elif defined(HAVE_FORCEINLINE)
 #  define MOZALLOC_INLINE __forceinline
 #else
 #  define MOZALLOC_INLINE inline
 #endif
 
 /* Workaround build problem with Sun Studio 12 */
 #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
--- a/parser/htmlparser/tests/mochitest/test_bug102699.html
+++ b/parser/htmlparser/tests/mochitest/test_bug102699.html
@@ -41,17 +41,17 @@ var d = p.parseFromString(
 '<noscript><div></div></noscript>"', "text/html");
 
 is(d.createElement("div").tagName, "DIV", "The created document should have HTML nature.");
 
 is(d.getElementsByTagName("div").length, 1, "There should be one div.");
 
 is(d.contentType, "text/html", "contentType should be text/html");
 
-is(d.characterSet, "UTF-8", "Expected the <meta> to be ignored.");
+is(d.characterSet, "utf-8", "Expected the <meta> to be ignored.");
 
 is(d.compatMode, "BackCompat", "Should be in the quirks mode.");
 
 var scripts = d.getElementsByTagName("script");
 is(scripts.length, 4, "Unexpected number of scripts.");
 while (scripts.length) {
   // These should not run when moved to another doc
   document.body.appendChild(scripts[0]);
--- a/storage/public/StatementCache.h
+++ b/storage/public/StatementCache.h
@@ -60,17 +60,17 @@ public:
       NS_ENSURE_TRUE(stmt, nullptr);
 
       mCachedStatements.Put(aQuery, stmt);
     }
     return stmt.forget();
   }
 
   template<int N>
-  NS_ALWAYS_INLINE already_AddRefed<StatementType>
+  MOZ_ALWAYS_INLINE already_AddRefed<StatementType>
   GetCachedStatement(const char (&aQuery)[N])
   {
     nsDependentCString query(aQuery, N - 1);
     return GetCachedStatement(query);
   }
 
   /**
    * Finalizes all cached statements so the database can be safely closed.  The
--- a/toolkit/components/places/SQLFunctions.cpp
+++ b/toolkit/components/places/SQLFunctions.cpp
@@ -39,17 +39,17 @@ namespace {
    *
    * @param aStart the beginning of the UTF-8 sequence
    * @param aNext the next character in the sequence
    * @param aEnd the first byte which is not part of the sequence
    *
    * @return a pointer to the next word boundary after aStart
    */
   static
-  NS_ALWAYS_INLINE const_char_iterator
+  MOZ_ALWAYS_INLINE const_char_iterator
   nextWordBoundary(const_char_iterator const aStart,
                    const_char_iterator const aNext,
                    const_char_iterator const aEnd) {
 
     const_char_iterator cur = aStart;
     if (('a' <= *cur && *cur <= 'z') ||
         ('A' <= *cur && *cur <= 'Z')) {
 
@@ -71,32 +71,32 @@ namespace {
     eFindOnBoundary,
     eFindAnywhere
   };
 
   /**
    * findAnywhere and findOnBoundary do almost the same thing, so it's natural
    * to implement them in terms of a single function.  They're both
    * performance-critical functions, however, and checking aBehavior makes them
-   * a bit slower.  Our solution is to define findInString as NS_ALWAYS_INLINE
+   * a bit slower.  Our solution is to define findInString as MOZ_ALWAYS_INLINE
    * and rely on the compiler to optimize out the aBehavior check.
    *
    * @param aToken
    *        The token we're searching for
    * @param aSourceString
    *        The string in which we're searching
    * @param aBehavior
    *        eFindOnBoundary if we should only consider matchines which occur on
    *        word boundaries, or eFindAnywhere if we should consider matches
    *        which appear anywhere.
    *
    * @return true if aToken was found in aSourceString, false otherwise.
    */
   static
-  NS_ALWAYS_INLINE bool
+  MOZ_ALWAYS_INLINE bool
   findInString(const nsDependentCSubstring &aToken,
                const nsACString &aSourceString,
                FindInStringBehavior aBehavior)
   {
     // CaseInsensitiveUTF8CharsEqual assumes that there's at least one byte in
     // the both strings, so don't pass an empty token here.
     NS_PRECONDITION(!aToken.IsEmpty(), "Don't search for an empty token!");
 
--- a/uriloader/prefetch/OfflineCacheUpdateChild.cpp
+++ b/uriloader/prefetch/OfflineCacheUpdateChild.cpp
@@ -39,16 +39,17 @@ using namespace mozilla::ipc;
 //    set NSPR_LOG_MODULES=nsOfflineCacheUpdate:5
 //    set NSPR_LOG_FILE=offlineupdate.log
 //
 // this enables PR_LOG_ALWAYS level information and places all output in
 // the file offlineupdate.log
 //
 extern PRLogModuleInfo *gOfflineCacheUpdateLog;
 #endif
+#undef LOG
 #define LOG(args) PR_LOG(gOfflineCacheUpdateLog, 4, args)
 #define LOG_ENABLED() PR_LOG_TEST(gOfflineCacheUpdateLog, 4)
 
 namespace mozilla {
 namespace docshell {
 
 //-----------------------------------------------------------------------------
 // OfflineCacheUpdateChild::nsISupports
--- a/uriloader/prefetch/nsOfflineCacheUpdateService.cpp
+++ b/uriloader/prefetch/nsOfflineCacheUpdateService.cpp
@@ -58,16 +58,17 @@ typedef mozilla::docshell::OfflineCacheU
 //    set NSPR_LOG_MODULES=nsOfflineCacheUpdate:5
 //    set NSPR_LOG_FILE=offlineupdate.log
 //
 // this enables PR_LOG_ALWAYS level information and places all output in
 // the file offlineupdate.log
 //
 PRLogModuleInfo *gOfflineCacheUpdateLog;
 #endif
+#undef LOG
 #define LOG(args) PR_LOG(gOfflineCacheUpdateLog, 4, args)
 #define LOG_ENABLED() PR_LOG_TEST(gOfflineCacheUpdateLog, 4)
 
 class AutoFreeArray {
 public:
     AutoFreeArray(uint32_t count, char **values)
         : mCount(count), mValues(values) {};
     ~AutoFreeArray() { NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mCount, mValues); }
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -648,45 +648,43 @@ void nsViewManager::InvalidateViews(nsVi
   while (nullptr != childView)  {
     childView->GetViewManager()->InvalidateViews(childView);
     childView = childView->GetNextSibling();
   }
 }
 
 void nsViewManager::WillPaintWindow(nsIWidget* aWidget, bool aWillSendDidPaint)
 {
-  if (IsRefreshDriverPaintingEnabled())
-    return;
-
-  if (!aWidget || !mContext)
-    return;
+  if (!IsRefreshDriverPaintingEnabled() && aWidget && mContext) {
+    // If an ancestor widget was hidden and then shown, we could
+    // have a delayed resize to handle.
+    for (nsViewManager *vm = this; vm;
+         vm = vm->mRootView->GetParent()
+                ? vm->mRootView->GetParent()->GetViewManager()
+                : nullptr) {
+      if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
+          vm->mRootView->IsEffectivelyVisible() &&
+          mPresShell && mPresShell->IsVisible()) {
+        vm->FlushDelayedResize(true);
+        vm->InvalidateView(vm->mRootView);
+      }
+    }
 
-  // If an ancestor widget was hidden and then shown, we could
-  // have a delayed resize to handle.
-  for (nsViewManager *vm = this; vm;
-       vm = vm->mRootView->GetParent()
-              ? vm->mRootView->GetParent()->GetViewManager()
-              : nullptr) {
-    if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
-        vm->mRootView->IsEffectivelyVisible() &&
-        mPresShell && mPresShell->IsVisible()) {
-      vm->FlushDelayedResize(true);
-      vm->InvalidateView(vm->mRootView);
-    }
+    // Flush things like reflows by calling WillPaint on observer presShells.
+    nsRefPtr<nsViewManager> rootVM = RootViewManager();
+    rootVM->CallWillPaintOnObservers(aWillSendDidPaint);
+
+    // Flush view widget geometry updates and invalidations.
+    rootVM->ProcessPendingUpdates();
   }
 
-  // Flush things like reflows and plugin widget geometry updates by
-  // calling WillPaint on observer presShells.
-  nsRefPtr<nsViewManager> rootVM = RootViewManager();
-  if (mPresShell) {
-    rootVM->CallWillPaintOnObservers(aWillSendDidPaint);
+  nsCOMPtr<nsIPresShell> shell = mPresShell;
+  if (shell) {
+    shell->WillPaintWindow(aWillSendDidPaint);
   }
-
-  // Flush view widget geometry updates and invalidations.
-  rootVM->ProcessPendingUpdates();
 }
 
 bool nsViewManager::PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion,
                                 bool aSentWillPaint, bool aWillSendDidPaint)
  {
   if (!aWidget || !mContext)
     return false;
 
@@ -704,16 +702,21 @@ bool nsViewManager::PaintWindow(nsIWidge
     Refresh(view, aRegion, aWillSendDidPaint);
   }
 
   return true;
 }
 
 void nsViewManager::DidPaintWindow()
 {
+  nsCOMPtr<nsIPresShell> shell = mPresShell;
+  if (shell) {
+    shell->DidPaintWindow();
+  }
+
   if (!IsRefreshDriverPaintingEnabled()) {
     mRootViewManager->CallDidPaintOnObserver();
   }
 }
 
 nsresult nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsIView* aView, nsEventStatus* aStatus)
 {
   SAMPLE_LABEL("event", "nsViewManager::DispatchEvent");
@@ -1197,18 +1200,17 @@ nsViewManager::ProcessPendingUpdates()
   if (!IsRootVM()) {
     RootViewManager()->ProcessPendingUpdates();
     return;
   }
 
   if (IsRefreshDriverPaintingEnabled()) {
     mPresShell->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush();
       
-    // Flush things like reflows and plugin widget geometry updates by
-    // calling WillPaint on observer presShells.
+    // Flush things like reflows by calling WillPaint on observer presShells.
     if (mPresShell) {
       CallWillPaintOnObservers(true);
     }
     ProcessPendingUpdatesForView(mRootView, true);
     CallDidPaintOnObserver();
   } else {
     ProcessPendingUpdatesForView(mRootView, true);
   }
--- a/widget/qt/mozqwidget.cpp
+++ b/widget/qt/mozqwidget.cpp
@@ -410,17 +410,17 @@ void MozQWidget::hideEvent(QHideEvent* a
 }
 
 void MozQWidget::showEvent(QShowEvent* aEvent)
 {
     mReceiver->showEvent(aEvent);
     QGraphicsWidget::showEvent(aEvent);
 }
 
-bool MozQWidget::SetCursor(nsCursor aCursor)
+void MozQWidget::SetCursor(nsCursor aCursor)
 {
     Qt::CursorShape cursor = Qt::ArrowCursor;
     switch(aCursor) {
     case eCursor_standard:
         cursor = Qt::ArrowCursor;
         break;
     case eCursor_wait:
         cursor = Qt::WaitCursor;
@@ -463,26 +463,22 @@ bool MozQWidget::SetCursor(nsCursor aCur
     case eCursor_zoom_in:
     case eCursor_zoom_out:
 
     default:
         break;
     }
 
     setCursor(cursor);
-
-    return NS_OK;
 }
 
-bool MozQWidget::SetCursor(const QPixmap& aCursor, int aHotX, int aHotY)
+void MozQWidget::SetCursor(const QPixmap& aCursor, int aHotX, int aHotY)
 {
     QCursor bitmapCursor(aCursor, aHotX, aHotY);
     setCursor(bitmapCursor);
-
-    return NS_OK;
 }
 
 void MozQWidget::setModal(bool modal)
 {
 #if QT_VERSION >= 0x040600
     setPanelModality(modal ? QGraphicsItem::SceneModal : QGraphicsItem::NonModal);
 #else
     LOG(("Modal QGraphicsWidgets not supported in Qt < 4.6\n"));
--- a/widget/qt/mozqwidget.h
+++ b/widget/qt/mozqwidget.h
@@ -17,17 +17,17 @@ public:
     MozQWidget(nsWindow* aReceiver, QGraphicsItem *aParent);
 
     ~MozQWidget();
 
     /**
      * Mozilla helper.
      */
     virtual void setModal(bool);
-    virtual bool SetCursor(nsCursor aCursor);
+    virtual void SetCursor(nsCursor aCursor);
     virtual void dropReceiver() { mReceiver = 0x0; };
     virtual nsWindow* getReceiver() { return mReceiver; };
 
     virtual void activate();
     virtual void deactivate();
 
     /**
      * VirtualKeyboardIntegration
@@ -70,16 +70,16 @@ protected:
     virtual void paint(QPainter* aPainter, const QStyleOptionGraphicsItem* aOption, QWidget* aWidget = 0);
     virtual void resizeEvent(QGraphicsSceneResizeEvent* aEvent);
     virtual void closeEvent(QCloseEvent* aEvent);
     virtual void hideEvent(QHideEvent* aEvent);
     virtual void showEvent(QShowEvent* aEvent);
     virtual bool event(QEvent* aEvent);
     virtual QVariant inputMethodQuery(Qt::InputMethodQuery aQuery) const;
 
-    bool SetCursor(const QPixmap& aPixmap, int, int);
+    void SetCursor(const QPixmap& aPixmap, int, int);
 
 private:
     void sendPressReleaseKeyEvent(int key, const QChar* letter = 0, bool autorep = false, ushort count = 1);
     nsWindow *mReceiver;
 };
 
 #endif
--- a/widget/tests/test_plugin_scroll_invalidation.html
+++ b/widget/tests/test_plugin_scroll_invalidation.html
@@ -27,16 +27,17 @@ var last_paint_counts;
 function initialize() {
   scrolling = document.getElementById("i").contentWindow;
   scrolling_plugins = scrolling.document.querySelectorAll("embed.scrolling");
   paint_waiter = scrolling.document.getElementById("paint-waiter");
 
   scrolling.scrollTo(50, 45);
 
   is(paint_waiter.getPaintCount(), 0, "zero-sized plugin not painted");
+
   waitForPaint(scrollAround);
 }
 
 function scrollAround() {
   var paints = getPaintCounts();
 
   for (var i = 0; i < paints.length; ++i) {
     isnot(paints[i], 0, "embed " + scrolling_plugins[i].id + " is painted"); 
@@ -61,34 +62,37 @@ function scrollAround() {
 function done() {
   var paints = getPaintCounts();
   for (var i = 0; i < paints.length; ++i) {
     is(paints[i], last_paint_counts[i], "embed " + scrolling_plugins[i].id + " is not painted on scroll");
   }
   SimpleTest.finish();  
 }
 
+// Waits for the paint_waiter plugin to be repainted and then
+// calls 'func' to continue.
 function waitForPaint(func) {
   paint_waiter.last_paint_count = paint_waiter.getPaintCount();
+
   paint_waiter.style.left = scrolling.scrollX + "px";
   paint_waiter.style.top = scrolling.scrollY + "px";
-  paint_waiter.style.width = "1px";
+
+  // Fiddle with the style in a way that should force some repainting
+  paint_waiter.style.width =
+    (paint_waiter.getBoundingClientRect().width + 1) + "px"; 
   paint_waiter.style.height = "1px";
-  waitForPaintHelper(func);
-}
 
-function waitForPaintHelper(func) {
-  if (paint_waiter.getPaintCount() != paint_waiter.last_paint_count) {
-    // hide the paint waiter
-    paint_waiter.style.width = "0px";
-    paint_waiter.style.height = "0px";
-    setTimeout(func, 0);
-    return;
+  function waitForPaintHelper() {
+    if (paint_waiter.getPaintCount() != paint_waiter.last_paint_count) {
+      setTimeout(func, 0);
+      return;
+    }
+    setTimeout(waitForPaintHelper, 0);
   }
-  setTimeout(function() { waitForPaintHelper(func); }, 100);
+  waitForPaintHelper();
 }
 
 function getPaintCounts() {
   var result = [];
   for (var i = 0; i < scrolling_plugins.length; ++i) {
     result[i] = scrolling_plugins[i].getPaintCount();
   }
   return result;
--- a/widget/xpwidgets/nsIdleService.cpp
+++ b/widget/xpwidgets/nsIdleService.cpp
@@ -144,19 +144,19 @@ nsIdleServiceDaily::Observe(nsISupports 
 
   return NS_OK;
 }
 
 nsIdleServiceDaily::nsIdleServiceDaily(nsIIdleService* aIdleService)
   : mIdleService(aIdleService)
   , mTimer(do_CreateInstance(NS_TIMER_CONTRACTID))
   , mCategoryObservers(OBSERVER_TOPIC_IDLE_DAILY)
+  , mShutdownInProgress(false)
   , mExpectedTriggerTime(0)
   , mIdleDailyTriggerWait(DAILY_SIGNIFICANT_IDLE_SERVICE_SEC)
-  , mShutdownInProgress(false)
 {
 }
 
 void
 nsIdleServiceDaily::Init()
 {
   // First check the time of the last idle-daily event notification. If it
   // has been 24 hours or higher, or if we have never sent an idle-daily,
--- a/xpcom/base/ErrorList.h
+++ b/xpcom/base/ErrorList.h
@@ -900,14 +900,11 @@
 
   /* a11y */
   /* raised when current pivot's position is needed but it's not in the tree */
   ERROR(NS_ERROR_NOT_IN_TREE,  FAILURE(38)),
 
   /* see Accessible::GetAttrValue */
   ERROR(NS_OK_NO_ARIA_VALUE,           SUCCESS(33)),
   ERROR(NS_OK_DEFUNCT_OBJECT,          SUCCESS(34)),
-  /* see Accessible::GetNameInternal */
-  ERROR(NS_OK_EMPTY_NAME,              SUCCESS(35)),
-  ERROR(NS_OK_NO_NAME_CLAUSE_HANDLED,  SUCCESS(36)),
-  /* see Accessible::GetNameInternal */
-  ERROR(NS_OK_NAME_FROM_TOOLTIP,       SUCCESS(37))
+  /* see nsTextEquivUtils */
+  ERROR(NS_OK_NO_NAME_CLAUSE_HANDLED,  SUCCESS(35))
 #undef MODULE
--- a/xpcom/string/public/nsUTF8Utils.h
+++ b/xpcom/string/public/nsUTF8Utils.h
@@ -281,17 +281,17 @@ class ConvertUTF8toUTF16
 
     ConvertUTF8toUTF16( buffer_type* aBuffer )
         : mStart(aBuffer), mBuffer(aBuffer), mErrorEncountered(false) {}
 
     size_t Length() const { return mBuffer - mStart; }
 
     bool ErrorEncountered() const { return mErrorEncountered; }
 
-    void NS_ALWAYS_INLINE write( const value_type* start, uint32_t N )
+    void MOZ_ALWAYS_INLINE write( const value_type* start, uint32_t N )
       {
         if ( mErrorEncountered )
           return;
 
         // algorithm assumes utf8 units won't
         // be spread across fragments
         const value_type* p = start;
         const value_type* end = start + N;
@@ -340,17 +340,17 @@ class CalculateUTF8Length
   {
     public:
       typedef char value_type;
 
     CalculateUTF8Length() : mLength(0), mErrorEncountered(false) { }
 
     size_t Length() const { return mLength; }
 
-    void NS_ALWAYS_INLINE write( const value_type* start, uint32_t N )
+    void MOZ_ALWAYS_INLINE write( const value_type* start, uint32_t N )
       {
           // ignore any further requests
         if ( mErrorEncountered )
             return;
 
         // algorithm assumes utf8 units won't
         // be spread across fragments
         const value_type* p = start;
@@ -444,17 +444,17 @@ class ConvertUTF16toUTF8
     // |ConvertUTF8toUTF16|, but it's that way for backwards
     // compatibility.
 
     ConvertUTF16toUTF8( buffer_type* aBuffer )
         : mStart(aBuffer), mBuffer(aBuffer) {}
 
     size_t Size() const { return mBuffer - mStart; }
 
-    void NS_ALWAYS_INLINE write( const value_type* start, uint32_t N )
+    void MOZ_ALWAYS_INLINE write( const value_type* start, uint32_t N )
       {
         buffer_type *out = mBuffer; // gcc isn't smart enough to do this!
 
         for (const value_type *p = start, *end = start + N; p < end; ++p )
           {
             value_type c = *p;
             if (! (c & 0xFF80)) // U+0000 - U+007F
               {
@@ -561,17 +561,17 @@ class CalculateUTF8Size
     public:
       typedef PRUnichar value_type;
 
     CalculateUTF8Size()
       : mSize(0) { }
 
     size_t Size() const { return mSize; }
 
-    void NS_ALWAYS_INLINE write( const value_type* start, uint32_t N )
+    void MOZ_ALWAYS_INLINE write( const value_type* start, uint32_t N )
       {
         // Assume UCS2 surrogate pairs won't be spread across fragments.
         for (const value_type *p = start, *end = start + N; p < end; ++p )
           {
             value_type c = *p;
             if (! (c & 0xFF80)) // U+0000 - U+007F
               mSize += 1;
             else if (! (c & 0xF800)) // U+0100 - U+07FF