Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Sun, 14 Oct 2012 16:39:23 -0400
changeset 110233 942ed5747b63807e625f5b692564fe31496c3117
parent 110184 57304bbf9c0e8fd5ffbfc79a43ea5ccdd53074b1 (current diff)
parent 110232 45cf07ab3a5ef5d6142c6e44f39a30e9cd3f0487 (diff)
child 110234 5f4a6a4744556201c38d0869381fe4ab1454fa0f
child 110288 1764fa8b0450ad67a1b55934a1c6f1e87606245b
child 110874 51b26b095a27eaa681c70f091567485b482d5f31
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +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