Merge mozilla-central into mozilla-inbound
authorEhsan Akhgari <ehsan@mozilla.com>
Tue, 16 Oct 2012 20:43:47 -0400
changeset 110619 81e18ebdef919e76c4fc981fbdf2a181b8a1ed04
parent 110618 4741e1875d1b90f4687f72315f9ccf359c74b24f (current diff)
parent 110520 044d1b97438563d6a3867ec720996afc4c1a8726 (diff)
child 110620 74cdc7eda9c51c000914796320c752a535a3746f
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
milestone19.0a1
Merge mozilla-central into mozilla-inbound
dom/base/test/test_gsp-standards.html
dom/bindings/Codegen.py
dom/devicestorage/nsDeviceStorage.cpp
testing/marionette/marionette-actors.js
--- a/accessible/src/generic/DocAccessible.cpp
+++ b/accessible/src/generic/DocAccessible.cpp
@@ -1120,17 +1120,17 @@ DocAccessible::AttributeChangedImpl(nsIC
     nsRefPtr<AccEvent> editableChangeEvent =
       new AccStateChangeEvent(aContent, states::EDITABLE);
     FireDelayedAccessibleEvent(editableChangeEvent);
     return;
   }
 
   if (aAttribute == nsGkAtoms::value) {
     Accessible* accessible = GetAccessible(aContent);
-    if(accessible->IsProgress()) {
+    if(accessible && accessible->IsProgress()) {
       FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
                                  aContent);
     }
   }
 }
 
 // DocAccessible protected member
 void
--- a/browser/config/mozconfigs/linux32/l10n-mozconfig
+++ b/browser/config/mozconfigs/linux32/l10n-mozconfig
@@ -1,9 +1,12 @@
 ac_add_options --with-l10n-base=../../l10n-central
 ac_add_options --enable-official-branding
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 
+# Avoid dependency on libstdc++ 4.5
+ac_add_options --enable-stdcxx-compat
+
 . $topsrcdir/build/unix/mozconfig.linux
 
 
 . "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux64/l10n-mozconfig
+++ b/browser/config/mozconfigs/linux64/l10n-mozconfig
@@ -1,9 +1,12 @@
 ac_add_options --with-l10n-base=../../l10n-central
 ac_add_options --enable-official-branding
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 
+# Avoid dependency on libstdc++ 4.5
+ac_add_options --enable-stdcxx-compat
+
 . $topsrcdir/build/unix/mozconfig.linux
 
 
 . "$topsrcdir/build/mozconfig.common.override"
new file mode 100644
--- /dev/null
+++ b/browser/config/mozconfigs/macosx-universal/l10n-mozconfig
@@ -0,0 +1,13 @@
+. "$topsrcdir/browser/config/mozconfigs/common"
+
+ac_add_options --with-l10n-base=../../l10n-central
+
+if [ "${MOZ_UPDATE_CHANNEL}" = "release" -o "${MOZ_UPDATE_CHANNEL}" = "beta" ]; then
+ac_add_options --enable-official-branding
+fi
+
+ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
+ac_add_options --enable-update-packaging
+ac_add_options --with-ccache
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -1160,19 +1160,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Fr
   nsINode::Unlink(tmp);
 
   if (tmp->HasProperties()) {
     if (tmp->IsHTML()) {
       tmp->DeleteProperty(nsGkAtoms::microdataProperties);
       tmp->DeleteProperty(nsGkAtoms::itemtype);
       tmp->DeleteProperty(nsGkAtoms::itemref);
       tmp->DeleteProperty(nsGkAtoms::itemprop);
-    } else if (tmp->IsXUL()) {
-      tmp->DeleteProperty(nsGkAtoms::contextmenulistener);
-      tmp->DeleteProperty(nsGkAtoms::popuplistener);
     }
   }
 
   // Unlink child content (and unbind our subtree).
   if (tmp->UnoptimizableCCNode() || !nsCCUncollectableMarker::sGeneration) {
     uint32_t childCount = tmp->mAttrsAndChildren.ChildCount();
     if (childCount) {
       // Don't allow script to run while we're unbinding everything.
@@ -1703,23 +1700,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
                                          (tmp->GetProperty(nsGkAtoms::microdataProperties));
       cb.NoteXPCOMChild(property);
       property = static_cast<nsISupports*>(tmp->GetProperty(nsGkAtoms::itemref));
       cb.NoteXPCOMChild(property);
       property = static_cast<nsISupports*>(tmp->GetProperty(nsGkAtoms::itemprop));
       cb.NoteXPCOMChild(property);
       property = static_cast<nsISupports*>(tmp->GetProperty(nsGkAtoms::itemtype));
       cb.NoteXPCOMChild(property);
-    } else if (tmp->IsXUL()) {
-      nsISupports* property = static_cast<nsISupports*>
-                                         (tmp->GetProperty(nsGkAtoms::contextmenulistener));
-      cb.NoteXPCOMChild(property);
-      property = static_cast<nsISupports*>
-                            (tmp->GetProperty(nsGkAtoms::popuplistener));
-      cb.NoteXPCOMChild(property);
     }
   }
 
   // Traverse attribute names and child content.
   {
     uint32_t i;
     uint32_t attrs = tmp->mAttrsAndChildren.AttrCount();
     for (i = 0; i < attrs; i++) {
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -221,17 +221,16 @@ GK_ATOM(contenteditable, "contenteditabl
 GK_ATOM(headerContentDisposition, "content-disposition")
 GK_ATOM(headerContentLanguage, "content-language")
 GK_ATOM(contentLocation, "content-location")
 GK_ATOM(headerContentScriptType, "content-script-type")
 GK_ATOM(headerContentStyleType, "content-style-type")
 GK_ATOM(headerContentType, "content-type")
 GK_ATOM(context, "context")
 GK_ATOM(contextmenu, "contextmenu")
-GK_ATOM(contextmenulistener, "contextmenulistener")
 GK_ATOM(control, "control")
 GK_ATOM(controls, "controls")
 GK_ATOM(coords, "coords")
 GK_ATOM(copy, "copy")
 GK_ATOM(copyOf, "copy-of")
 GK_ATOM(count, "count")
 GK_ATOM(crop, "crop")
 GK_ATOM(crossorigin, "crossorigin")
@@ -828,17 +827,16 @@ GK_ATOM(pointSize, "point-size")
 GK_ATOM(poly, "poly")
 GK_ATOM(polygon, "polygon")
 GK_ATOM(popup, "popup")
 GK_ATOM(popupalign, "popupalign")
 GK_ATOM(popupanchor, "popupanchor")
 GK_ATOM(popupgroup, "popupgroup")
 GK_ATOM(popuphidden, "popuphidden")
 GK_ATOM(popuphiding, "popuphiding")
-GK_ATOM(popuplistener, "popuplistener")
 GK_ATOM(popupset, "popupset")
 GK_ATOM(popupshowing, "popupshowing")
 GK_ATOM(popupshown, "popupshown")
 GK_ATOM(popupsinherittooltip, "popupsinherittooltip")
 GK_ATOM(position, "position")
 GK_ATOM(poster, "poster")
 GK_ATOM(pre, "pre")
 GK_ATOM(preceding, "preceding")
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -1549,68 +1549,36 @@ nsXULElement::GetBindingParent() const
 }
 
 bool
 nsXULElement::IsNodeOfType(uint32_t aFlags) const
 {
     return !(aFlags & ~eCONTENT);
 }
 
-static void
-PopupListenerPropertyDtor(void* aObject, nsIAtom* aPropertyName,
-                          void* aPropertyValue, void* aData)
-{
-  nsIDOMEventListener* listener =
-    static_cast<nsIDOMEventListener*>(aPropertyValue);
-  if (!listener) {
-    return;
-  }
-  nsEventListenerManager* manager = static_cast<nsINode*>(aObject)->
-    GetListenerManager(false);
-  if (manager) {
-    manager->RemoveEventListenerByType(listener,
-                                       NS_LITERAL_STRING("mousedown"),
-                                       NS_EVENT_FLAG_BUBBLE |
-                                       NS_EVENT_FLAG_SYSTEM_EVENT);
-    manager->RemoveEventListenerByType(listener,
-                                       NS_LITERAL_STRING("contextmenu"),
-                                       NS_EVENT_FLAG_BUBBLE |
-                                       NS_EVENT_FLAG_SYSTEM_EVENT);
-  }
-  NS_RELEASE(listener);
-}
-
 nsresult
 nsXULElement::AddPopupListener(nsIAtom* aName)
 {
     // Add a popup listener to the element
     bool isContext = (aName == nsGkAtoms::context ||
                         aName == nsGkAtoms::contextmenu);
-    nsIAtom* listenerAtom = isContext ?
-                            nsGkAtoms::contextmenulistener :
-                            nsGkAtoms::popuplistener;
+    uint32_t listenerFlag = isContext ?
+                            XUL_ELEMENT_HAS_CONTENTMENU_LISTENER :
+                            XUL_ELEMENT_HAS_POPUP_LISTENER;
 
-    nsCOMPtr<nsIDOMEventListener> popupListener =
-        static_cast<nsIDOMEventListener*>(GetProperty(listenerAtom));
-    if (popupListener) {
-        // Popup listener is already installed.
+    if (HasFlag(listenerFlag)) {
         return NS_OK;
     }
 
-    popupListener = new nsXULPopupListener(this, isContext);
+    nsCOMPtr<nsIDOMEventListener> listener =
+      new nsXULPopupListener(this, isContext);
 
     // Add the popup as a listener on this element.
     nsEventListenerManager* manager = GetListenerManager(true);
-    NS_ENSURE_TRUE(manager, NS_ERROR_FAILURE);
-    nsresult rv = SetProperty(listenerAtom, popupListener,
-                              PopupListenerPropertyDtor, true);
-    NS_ENSURE_SUCCESS(rv, rv);
-    // Want the property to have a reference to the listener.
-    nsIDOMEventListener* listener = nullptr;
-    popupListener.swap(listener);
+    SetFlags(listenerFlag);
 
     if (isContext) {
       manager->AddEventListenerByType(listener,
                                       NS_LITERAL_STRING("contextmenu"),
                                       NS_EVENT_FLAG_BUBBLE |
                                       NS_EVENT_FLAG_SYSTEM_EVENT);
     } else {
       manager->AddEventListenerByType(listener,
--- a/content/xul/content/src/nsXULElement.h
+++ b/content/xul/content/src/nsXULElement.h
@@ -316,21 +316,23 @@ public:
   The XUL element.
 
  */
 
 #define XUL_ELEMENT_FLAG_BIT(n_) NODE_FLAG_BIT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + (n_))
 
 // XUL element specific bits
 enum {
-  XUL_ELEMENT_TEMPLATE_GENERATED =        XUL_ELEMENT_FLAG_BIT(0)
+  XUL_ELEMENT_TEMPLATE_GENERATED =        XUL_ELEMENT_FLAG_BIT(0),
+  XUL_ELEMENT_HAS_CONTENTMENU_LISTENER =  XUL_ELEMENT_FLAG_BIT(1),
+  XUL_ELEMENT_HAS_POPUP_LISTENER =        XUL_ELEMENT_FLAG_BIT(2)
 };
 
-// Make sure we have space for our bit
-PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET < 32);
+// Make sure we have space for our bits
+PR_STATIC_ASSERT((ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 2) < 32);
 
 #undef XUL_ELEMENT_FLAG_BIT
 
 class nsScriptEventHandlerOwnerTearoff;
 
 class nsXULElement : public nsStyledElement, public nsIDOMXULElement
 {
 public:
--- a/content/xul/content/src/nsXULPopupListener.cpp
+++ b/content/xul/content/src/nsXULPopupListener.cpp
@@ -28,17 +28,17 @@
 #include "nsServiceManagerUtils.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsLayoutUtils.h"
 #include "nsFrameManager.h"
 #include "nsHTMLReflowState.h"
 #include "nsIObjectLoadingContent.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/dom/Element.h"
+#include "mozilla/dom/FragmentOrElement.h"
 
 // for event firing in context menus
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsFocusManager.h"
 #include "nsPIDOMWindow.h"
 #include "nsIViewManager.h"
 #include "nsError.h"
@@ -47,30 +47,50 @@
 using namespace mozilla;
 
 // on win32 and os/2, context menus come up on mouse up. On other platforms,
 // they appear on mouse down. Certain bits of code care about this difference.
 #if defined(XP_WIN) || defined(XP_OS2)
 #define NS_CONTEXT_MENU_IS_MOUSEUP 1
 #endif
 
-nsXULPopupListener::nsXULPopupListener(nsIDOMElement *aElement, bool aIsContext)
+nsXULPopupListener::nsXULPopupListener(mozilla::dom::Element* aElement,
+                                       bool aIsContext)
   : mElement(aElement), mPopupContent(nullptr), mIsContext(aIsContext)
 {
 }
 
 nsXULPopupListener::~nsXULPopupListener(void)
 {
   ClosePopup();
 }
 
 NS_IMPL_CYCLE_COLLECTION_2(nsXULPopupListener, mElement, mPopupContent)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULPopupListener)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULPopupListener)
 
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsXULPopupListener)
+  // If the owner, mElement, can be skipped, so can we.
+  if (tmp->mElement) {
+    return mozilla::dom::FragmentOrElement::CanSkip(tmp->mElement, true);
+  }
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsXULPopupListener)
+  if (tmp->mElement) {
+    return mozilla::dom::FragmentOrElement::CanSkipInCC(tmp->mElement);
+  }
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsXULPopupListener)
+  if (tmp->mElement) {
+    return mozilla::dom::FragmentOrElement::CanSkipThis(tmp->mElement);
+  }
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
+
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULPopupListener)
   NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 ////////////////////////////////////////////////////////////////
 // nsIDOMEventListener
 
@@ -302,86 +322,76 @@ GetImmediateChild(nsIContent* aContent, 
 // (popup, context) and uses that attribute's value as an ID for
 // the popup content in the document.
 //
 nsresult
 nsXULPopupListener::LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent)
 {
   nsresult rv = NS_OK;
 
-  nsAutoString type(NS_LITERAL_STRING("popup"));
-  if (mIsContext)
-    type.AssignLiteral("context");
+  nsIAtom* type = mIsContext ? nsGkAtoms::context : nsGkAtoms::popup;
 
   nsAutoString identifier;
-  mElement->GetAttribute(type, identifier);
+  mElement->GetAttr(kNameSpaceID_None, type, identifier);
 
   if (identifier.IsEmpty()) {
-    if (type.EqualsLiteral("popup"))
-      mElement->GetAttribute(NS_LITERAL_STRING("menu"), identifier);
-    else if (type.EqualsLiteral("context"))
-      mElement->GetAttribute(NS_LITERAL_STRING("contextmenu"), identifier);
+    if (type == nsGkAtoms::popup) {
+      mElement->GetAttr(kNameSpaceID_None, nsGkAtoms::menu, identifier);
+    } else {
+      mElement->GetAttr(kNameSpaceID_None, nsGkAtoms::contextmenu, identifier);
+    }
     if (identifier.IsEmpty())
       return rv;
   }
 
   // Try to find the popup content and the document.
-  nsCOMPtr<nsIContent> content = do_QueryInterface(mElement);
-  nsCOMPtr<nsIDocument> document = content->GetDocument();
-
-  // Turn the document into a DOM document so we can use getElementById
-  nsCOMPtr<nsIDOMDocument> domDocument = do_QueryInterface(document);
-  if (!domDocument) {
-    NS_ERROR("Popup attached to an element that isn't in XUL!");
+  nsCOMPtr<nsIDocument> document = mElement->GetDocument();
+  if (!document) {
+    NS_WARNING("No document!");
     return NS_ERROR_FAILURE;
   }
 
   // Handle the _child case for popups and context menus
-  nsCOMPtr<nsIDOMElement> popupElement;
-
+  nsCOMPtr<nsIContent> popup;
   if (identifier.EqualsLiteral("_child")) {
-    nsCOMPtr<nsIContent> popup = GetImmediateChild(content, nsGkAtoms::menupopup);
-    if (popup)
-      popupElement = do_QueryInterface(popup);
-    else {
-      nsCOMPtr<nsIDOMDocumentXBL> nsDoc(do_QueryInterface(domDocument));
+    popup = GetImmediateChild(mElement, nsGkAtoms::menupopup);
+    if (!popup) {
+      nsCOMPtr<nsIDOMDocumentXBL> nsDoc(do_QueryInterface(document));
       nsCOMPtr<nsIDOMNodeList> list;
-      nsDoc->GetAnonymousNodes(mElement, getter_AddRefs(list));
+      nsCOMPtr<nsIDOMElement> el = do_QueryInterface(mElement);
+      nsDoc->GetAnonymousNodes(el, getter_AddRefs(list));
       if (list) {
         uint32_t ctr,listLength;
         nsCOMPtr<nsIDOMNode> node;
         list->GetLength(&listLength);
         for (ctr = 0; ctr < listLength; ctr++) {
           list->Item(ctr, getter_AddRefs(node));
           nsCOMPtr<nsIContent> childContent(do_QueryInterface(node));
 
           if (childContent->NodeInfo()->Equals(nsGkAtoms::menupopup,
                                                kNameSpaceID_XUL)) {
-            popupElement = do_QueryInterface(childContent);
+            popup.swap(childContent);
             break;
           }
         }
       }
     }
-  }
-  else if (NS_FAILED(rv = domDocument->GetElementById(identifier,
-                                              getter_AddRefs(popupElement)))) {
+  } else if (!(popup = document->GetElementById(identifier))) {
     // Use getElementById to obtain the popup content and gracefully fail if 
     // we didn't find any popup content in the document. 
     NS_ERROR("GetElementById had some kind of spasm.");
     return rv;
   }
 
   // return if no popup was found or the popup is the element itself.
-  if ( !popupElement || popupElement == mElement)
+  if (!popup || popup == mElement)
     return NS_OK;
 
   // Submenus can't be used as context menus or popups, bug 288763.
   // Similar code also in nsXULTooltipListener::GetTooltipFor.
-  nsCOMPtr<nsIContent> popup = do_QueryInterface(popupElement);
   nsIContent* parent = popup->GetParent();
   if (parent) {
     nsMenuFrame* menu = do_QueryFrame(parent->GetPrimaryFrame());
     if (menu)
       return NS_OK;
   }
 
   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
@@ -392,17 +402,17 @@ nsXULPopupListener::LaunchPopup(nsIDOMEv
   // popupanchor and popupalign attributes are used, anchor the popup to the
   // element, otherwise just open it at the screen position where the mouse
   // was clicked. Context menus always open at the mouse position.
   mPopupContent = popup;
   if (!mIsContext &&
       (mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::position) ||
        (mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popupanchor) &&
         mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popupalign)))) {
-    pm->ShowPopup(mPopupContent, content, EmptyString(), 0, 0,
+    pm->ShowPopup(mPopupContent, mElement, EmptyString(), 0, 0,
                   false, true, false, aEvent);
   }
   else {
     int32_t xPos = 0, yPos = 0;
     nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
     mouseEvent->GetScreenX(&xPos);
     mouseEvent->GetScreenY(&yPos);
 
--- a/content/xul/content/src/nsXULPopupListener.h
+++ b/content/xul/content/src/nsXULPopupListener.h
@@ -7,35 +7,35 @@
  * This is the popup listener implementation for popup menus and context menus.
  */
 
 #ifndef nsXULPopupListener_h___
 #define nsXULPopupListener_h___
 
 #include "nsCOMPtr.h"
 
-#include "nsIContent.h"
+#include "mozilla/dom/Element.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsIDOMEventListener.h"
 #include "nsCycleCollectionParticipant.h"
 
 class nsXULPopupListener : public nsIDOMEventListener
 {
 public:
     // aElement is the element that the popup is attached to. If aIsContext is
     // false, the popup opens on left click on aElement or a descendant. If
     // aIsContext is true, the popup is a context menu which opens on a
     // context menu event.
-    nsXULPopupListener(nsIDOMElement *aElement, bool aIsContext);
+    nsXULPopupListener(mozilla::dom::Element* aElement, bool aIsContext);
     virtual ~nsXULPopupListener(void);
 
     // nsISupports
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-    NS_DECL_CYCLE_COLLECTION_CLASS(nsXULPopupListener)
+    NS_DECL_CYCLE_COLLECTION_SKIPPABLE_CLASS(nsXULPopupListener)
     NS_DECL_NSIDOMEVENTLISTENER
 
 protected:
     // open the popup. aEvent is the event that triggered the popup such as
     // a mouse click and aTargetContent is the target of this event.
     virtual nsresult LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent);
 
     // close the popup when the listener goes away
@@ -43,17 +43,17 @@ protected:
 
 private:
 #ifndef NS_CONTEXT_MENU_IS_MOUSEUP
     // When a context menu is opened, focus the target of the contextmenu event.
     nsresult FireFocusOnTargetContent(nsIDOMNode* aTargetNode);
 #endif
 
     // |mElement| is the node to which this listener is attached.
-    nsCOMPtr<nsIDOMElement> mElement;
+    nsCOMPtr<mozilla::dom::Element> mElement;
 
     // The popup that is getting shown on top of mElement.
     nsCOMPtr<nsIContent> mPopupContent; 
 
     // true if a context popup
     bool mIsContext;
 };
 
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -6,16 +6,17 @@
 
 #include <stdarg.h>
 
 #include "BindingUtils.h"
 
 #include "AccessCheck.h"
 #include "WrapperFactory.h"
 #include "xpcprivate.h"
+#include "nsContentUtils.h"
 #include "XPCQuickStubs.h"
 #include "nsIXPConnect.h"
 
 namespace mozilla {
 namespace dom {
 
 JSErrorFormatString ErrorFormatString[] = {
 #define MSG_DEF(_name, _argc, _str) \
@@ -734,10 +735,32 @@ SetXrayExpandoChain(JSObject* obj, JSObj
   JS::Value v = chain ? JS::ObjectValue(*chain) : JSVAL_VOID;
   if (IsDOMProxy(obj)) {
     js::SetProxyExtra(obj, JSPROXYSLOT_XRAY_EXPANDO, v);
   } else {
     js::SetReservedSlot(obj, DOM_XRAY_EXPANDO_SLOT, v);
   }
 }
 
+JSContext*
+MainThreadDictionaryBase::ParseJSON(const nsAString& aJSON,
+                                    mozilla::Maybe<JSAutoRequest>& aAr,
+                                    mozilla::Maybe<JSAutoCompartment>& aAc,
+                                    JS::Value& aVal)
+{
+  JSContext* cx = nsContentUtils::ThreadJSContextStack()->GetSafeJSContext();
+  NS_ENSURE_TRUE(cx, nullptr);
+  JSObject* global = JS_GetGlobalObject(cx);
+  aAr.construct(cx);
+  aAc.construct(cx, global);
+  if (aJSON.IsEmpty()) {
+    return cx;
+  }
+  if (!JS_ParseJSON(cx,
+                    static_cast<const jschar*>(PromiseFlatString(aJSON).get()),
+                    aJSON.Length(), &aVal)) {
+    return nullptr;
+  }
+  return cx;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1222,12 +1222,21 @@ MustInheritFromNonRefcountedDOMObject(No
 {
 }
 
 // Set the chain of expando objects for various consumers of the given object.
 // For Paris Bindings only. See the relevant infrastructure in XrayWrapper.cpp.
 JSObject* GetXrayExpandoChain(JSObject *obj);
 void SetXrayExpandoChain(JSObject *obj, JSObject *chain);
 
+struct MainThreadDictionaryBase
+{
+protected:
+  JSContext* ParseJSON(const nsAString& aJSON,
+                       mozilla::Maybe<JSAutoRequest>& aAr,
+                       mozilla::Maybe<JSAutoCompartment>& aAc,
+                       JS::Value& aVal);
+};
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_BindingUtils_h__ */
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -5385,26 +5385,38 @@ class CGDictionary(CGThing):
             self.generatable = False
 
     def declare(self):
         if not self.generatable:
             return ""
         d = self.dictionary
         if d.parent:
             inheritance = ": public %s " % self.makeClassName(d.parent)
+        elif not self.workers:
+            inheritance = ": public MainThreadDictionaryBase "
         else:
             inheritance = ""
         memberDecls = ["  %s %s;" %
                        (self.getMemberType(m), m[0].identifier.name)
                        for m in self.memberInfo]
 
         return (string.Template(
                 "struct ${selfName} ${inheritance}{\n"
                 "  ${selfName}() {}\n"
                 "  bool Init(JSContext* cx, const JS::Value& val);\n"
+                "  \n" +
+                ("  bool Init(const nsAString& aJSON)\n"
+                 "  {\n"
+                 "    mozilla::Maybe<JSAutoRequest> ar;\n"
+                 "    mozilla::Maybe<JSAutoCompartment> ac;\n"
+                 "    jsval json = JSVAL_VOID;\n"
+                 "    JSContext* cx = ParseJSON(aJSON, ar, ac, json);\n"
+                 "    NS_ENSURE_TRUE(cx, false);\n"
+                 "    return Init(cx, json);\n"
+                 "  }\n" if not self.workers else "") +
                 "\n" +
                 "\n".join(memberDecls) + "\n"
                 "private:\n"
                 "  // Disallow copy-construction\n"
                 "  ${selfName}(const ${selfName}&) MOZ_DELETE;\n" +
                 # NOTE: jsids are per-runtime, so don't use them in workers
                 ("  static bool InitIds(JSContext* cx);\n"
                  "  static bool initedIds;\n" if not self.workers else "") +
--- a/dom/devicestorage/DeviceStorageRequestParent.cpp
+++ b/dom/devicestorage/DeviceStorageRequestParent.cpp
@@ -243,16 +243,24 @@ DeviceStorageRequestParent::WriteFileEve
   nsRefPtr<nsRunnable> r;
 
   if (!mInputStream) {
     r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
     NS_DispatchToMainThread(r);
     return NS_OK;
   }
 
+  bool check = false;
+  mFile->mFile->Exists(&check);
+  if (check) {
+    nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_EXISTS);
+    NS_DispatchToMainThread(event);
+    return NS_OK;
+  }
+
   nsresult rv = mFile->Write(mInputStream);
 
   if (NS_FAILED(rv)) {
     r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
   }
   else {
     r = new PostPathResultEvent(mParent, mFile->mPath);
   }
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -842,54 +842,30 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DeviceStorageCursorRequest)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mCursor, nsIDOMDeviceStorageCursor)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 
 class PostErrorEvent : public nsRunnable
 {
 public:
-  PostErrorEvent(nsRefPtr<DOMRequest>& aRequest, const char* aMessage, DeviceStorageFile* aFile)
+  PostErrorEvent(nsRefPtr<DOMRequest>& aRequest, const char* aMessage)
   {
     mRequest.swap(aRequest);
-    BuildErrorString(aMessage, aFile);
+    CopyASCIItoUTF16(aMessage, mError);
   }
 
-  PostErrorEvent(DOMRequest* aRequest, const char* aMessage, DeviceStorageFile* aFile)
+  PostErrorEvent(DOMRequest* aRequest, const char* aMessage)
     : mRequest(aRequest)
   {
-    BuildErrorString(aMessage, aFile);
+    CopyASCIItoUTF16(aMessage, mError);
   }
 
   ~PostErrorEvent() {}
 
-  void BuildErrorString(const char* aMessage, DeviceStorageFile* aFile)
-  {
-    nsAutoString fullPath;
-
-    if (aFile && aFile->mFile) {
-      aFile->mFile->GetPath(fullPath);
-    }
-    else {
-      fullPath.Assign(NS_LITERAL_STRING("null file"));
-    }
-
-    mError = NS_ConvertASCIItoUTF16(aMessage);
-    mError.Append(NS_LITERAL_STRING(" file path = "));
-    mError.Append(fullPath.get());
-    mError.Append(NS_LITERAL_STRING(" path = "));
-
-    if (aFile) {
-      mError.Append(aFile->mPath);
-    }
-    else {
-      mError.Append(NS_LITERAL_STRING("null path"));
-    }
-  }
-
   NS_IMETHOD Run()
   {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     mRequest->FireError(mError);
     mRequest = nullptr;
     return NS_OK;
   }
 
@@ -997,19 +973,17 @@ public:
   ~InitCursorEvent() {}
 
   NS_IMETHOD Run() {
     NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
     bool check;
     mFile->mFile->IsDirectory(&check);
     if (!check) {
-      nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mRequest,
-                                                          POST_ERROR_EVENT_FILE_NOT_ENUMERABLE,
-                                                          mFile);
+      nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mRequest, POST_ERROR_EVENT_FILE_NOT_ENUMERABLE);
       NS_DispatchToMainThread(event);
       return NS_OK;
     }
 
     nsDOMDeviceStorageCursor* cursor = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get());
     mFile->CollectFiles(cursor->mFiles, cursor->mSince);
 
     nsCOMPtr<ContinueCursorEvent> event = new ContinueCursorEvent(mRequest);
@@ -1084,30 +1058,26 @@ nsDOMDeviceStorageCursor::GetElement(nsI
 {
   *aRequestingElement = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMDeviceStorageCursor::Cancel()
 {
-  nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(this,
-                                                      POST_ERROR_EVENT_PERMISSION_DENIED,
-                                                      mFile);
+  nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(this, POST_ERROR_EVENT_PERMISSION_DENIED);
   NS_DispatchToMainThread(event);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMDeviceStorageCursor::Allow()
 {
   if (!mFile->IsSafePath()) {
-    nsCOMPtr<nsIRunnable> r = new PostErrorEvent(this,
-                                                 POST_ERROR_EVENT_ILLEGAL_FILE_NAME,
-                                                 mFile);
+    nsCOMPtr<nsIRunnable> r = new PostErrorEvent(this, POST_ERROR_EVENT_PERMISSION_DENIED);
     NS_DispatchToMainThread(r);
     return NS_OK;
   }
 
   if (XRE_GetProcessType() != GeckoProcessType_Default) {
 
     nsString fullpath;
     nsresult rv = mFile->mFile->GetPath(fullpath);
@@ -1276,24 +1246,30 @@ public:
 
   NS_IMETHOD Run()
   {
     NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
     nsCOMPtr<nsIInputStream> stream;
     mBlob->GetInternalStream(getter_AddRefs(stream));
 
+    bool check = false;
+    mFile->mFile->Exists(&check);
+    if (check) {
+      nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mRequest, POST_ERROR_EVENT_FILE_EXISTS);
+      NS_DispatchToMainThread(event);
+      return NS_OK;
+    }
+
     nsresult rv = mFile->Write(stream);
 
     if (NS_FAILED(rv)) {
       mFile->mFile->Remove(false);
 
-      nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mRequest,
-                                                          POST_ERROR_EVENT_UNKNOWN,
-                                                          mFile);
+      nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mRequest, POST_ERROR_EVENT_UNKNOWN);
       NS_DispatchToMainThread(event);
       return NS_OK;
     }
 
     nsCOMPtr<PostResultEvent> event = new PostResultEvent(mRequest, mFile->mPath);
     NS_DispatchToMainThread(event);
     return NS_OK;
   }
@@ -1320,17 +1296,17 @@ public:
   {
     NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
     nsRefPtr<nsRunnable> r;
     if (!mFile->mEditable) {
       bool check = false;
       mFile->mFile->Exists(&check);
       if (!check) {
-        r = new PostErrorEvent(mRequest, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST, mFile);
+        r = new PostErrorEvent(mRequest, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST);
       }
     }
 
     if (!r) {
       r = new PostResultEvent(mRequest, mFile);
     }
     NS_DispatchToMainThread(r);
     return NS_OK;
@@ -1357,17 +1333,17 @@ public:
   {
     NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
     mFile->Remove();
 
     nsRefPtr<nsRunnable> r;
     bool check = false;
     mFile->mFile->Exists(&check);
     if (check) {
-      r = new PostErrorEvent(mRequest, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST, mFile);
+      r = new PostErrorEvent(mRequest, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST);
     }
     else {
       r = new PostResultEvent(mRequest, mFile->mPath);
     }
     NS_DispatchToMainThread(r);
     return NS_OK;
   }
 
@@ -1518,19 +1494,17 @@ public:
   NS_IMETHOD GetElement(nsIDOMElement * *aRequestingElement)
   {
     *aRequestingElement = nullptr;
     return NS_OK;
   }
 
   NS_IMETHOD Cancel()
   {
-    nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mRequest,
-                                                        POST_ERROR_EVENT_PERMISSION_DENIED,
-                                                        mFile);
+    nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mRequest, POST_ERROR_EVENT_PERMISSION_DENIED);
     NS_DispatchToMainThread(event);
     return NS_OK;
   }
 
   NS_IMETHOD Allow()
   {
     nsCOMPtr<nsIRunnable> r;
 
@@ -1828,22 +1802,21 @@ nsDOMDeviceStorage::AddNamed(nsIDOMBlob 
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(win);
   NS_ADDREF(*_retval = request);
 
   nsCOMPtr<nsIRunnable> r;
 
   nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, mRootDirectory, aPath);
-  if (!typeChecker->Check(mStorageType, dsf->mFile) ||
+  if (!dsf->IsSafePath()) {
+    r = new PostErrorEvent(request, POST_ERROR_EVENT_PERMISSION_DENIED);
+  } else if (!typeChecker->Check(mStorageType, dsf->mFile) ||
       !typeChecker->Check(mStorageType, aBlob)) {
-    r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_TYPE, dsf);
-  }
-  else if (!dsf->IsSafePath()) {
-    r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_FILE_NAME, dsf);
+    r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_TYPE);
   }
   else {
     r = new DeviceStorageRequest(DeviceStorageRequest::DEVICE_STORAGE_REQUEST_WRITE,
                                  win, mPrincipal, dsf, request, aBlob);
   }
 
   NS_DispatchToMainThread(r);
   return NS_OK;
@@ -1879,28 +1852,25 @@ nsDOMDeviceStorage::GetInternal(const JS
   nsRefPtr<DOMRequest> request = new DOMRequest(win);
   NS_ADDREF(*_retval = request);
 
   nsCOMPtr<nsIRunnable> r;
 
   JSString* jsstr = JS_ValueToString(aCx, aPath);
   nsDependentJSString path;
   if (!path.init(aCx, jsstr)) {
-    nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, mRootDirectory);
-    r = new PostErrorEvent(request,
-                           POST_ERROR_EVENT_NON_STRING_TYPE_UNSUPPORTED,
-                           dsf);
+    r = new PostErrorEvent(request, POST_ERROR_EVENT_UNKNOWN);
     NS_DispatchToMainThread(r);
     return NS_OK;
   }
 
   nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, mRootDirectory, path);
   dsf->SetEditable(aEditable);
   if (!dsf->IsSafePath()) {
-    r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_FILE_NAME, dsf);
+    r = new PostErrorEvent(request, POST_ERROR_EVENT_PERMISSION_DENIED);
   } else {
     r = new DeviceStorageRequest(DeviceStorageRequest::DEVICE_STORAGE_REQUEST_READ,
                                  win, mPrincipal, dsf, request);
   }
   NS_DispatchToMainThread(r);
   return NS_OK;
 }
 
@@ -1915,26 +1885,25 @@ nsDOMDeviceStorage::Delete(const JS::Val
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(win);
   NS_ADDREF(*_retval = request);
 
   JSString* jsstr = JS_ValueToString(aCx, aPath);
   nsDependentJSString path;
   if (!path.init(aCx, jsstr)) {
-    nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, mRootDirectory);
-    r = new PostErrorEvent(request, POST_ERROR_EVENT_NON_STRING_TYPE_UNSUPPORTED, dsf);
+    r = new PostErrorEvent(request, POST_ERROR_EVENT_UNKNOWN);
     NS_DispatchToMainThread(r);
     return NS_OK;
   }
 
   nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, mRootDirectory, path);
 
   if (!dsf->IsSafePath()) {
-    r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_FILE_NAME, dsf);
+    r = new PostErrorEvent(request, POST_ERROR_EVENT_PERMISSION_DENIED);
   }
   else {
     r = new DeviceStorageRequest(DeviceStorageRequest::DEVICE_STORAGE_REQUEST_DELETE,
                                  win, mPrincipal, dsf, request);
   }
   NS_DispatchToMainThread(r);
   return NS_OK;
 }
--- a/dom/devicestorage/nsDeviceStorage.h
+++ b/dom/devicestorage/nsDeviceStorage.h
@@ -27,24 +27,22 @@ class nsPIDOMWindow;
 #include "nsIObserver.h"
 #include "nsIStringBundle.h"
 #include "mozilla/Mutex.h"
 #include "prtime.h"
 #include "DeviceStorage.h"
 
 #include "DeviceStorageRequestChild.h"
 
-#define POST_ERROR_EVENT_FILE_DOES_NOT_EXIST         "File location doesn't exists"
-#define POST_ERROR_EVENT_FILE_NOT_ENUMERABLE         "File location is not enumerable"
-#define POST_ERROR_EVENT_PERMISSION_DENIED           "Permission Denied"
-#define POST_ERROR_EVENT_ILLEGAL_FILE_NAME           "Illegal file name"
-#define POST_ERROR_EVENT_ILLEGAL_TYPE                "Illegal content type"
+#define POST_ERROR_EVENT_FILE_EXISTS                 "NoModificationAllowedError"
+#define POST_ERROR_EVENT_FILE_DOES_NOT_EXIST         "NotFoundError"
+#define POST_ERROR_EVENT_FILE_NOT_ENUMERABLE         "TypeMismatchError"
+#define POST_ERROR_EVENT_PERMISSION_DENIED           "SecurityError"
+#define POST_ERROR_EVENT_ILLEGAL_TYPE                "TypeMismatchError"
 #define POST_ERROR_EVENT_UNKNOWN                     "Unknown"
-#define POST_ERROR_EVENT_NON_STRING_TYPE_UNSUPPORTED "Non-string type unsupported"
-#define POST_ERROR_EVENT_NOT_IMPLEMENTED             "Not implemented"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::dom::devicestorage;
 
 class DeviceStorageTypeChecker MOZ_FINAL
 {
 public:
--- a/dom/devicestorage/test/test_addCorrectType.html
+++ b/dom/devicestorage/test/test_addCorrectType.html
@@ -38,16 +38,18 @@ var tests = [
   function () { return addNamed("music",    "kyle/smash", ".mp3")},
   function () { return addNamed("music",    "music/mp3",  ".poo")},
   function () { return addNamed("videos",   "kyle/smash", ".ogv")},
   function () { return addNamed("videos",   "video/ogv",  ".poo")},
 ];
 
 function fail(e) {
   ok(false, "addSuccess was called");
+  ok(e.target.error.name == "TypeMismatchError", "Error must be TypeMismatchError");
+
   devicestorage_cleanup();
 }
 
 function next(e) {
 
   if (e != undefined)
     ok(true, "addError was called");
   
--- a/dom/devicestorage/test/test_basic.html
+++ b/dom/devicestorage/test/test_basic.html
@@ -8,34 +8,25 @@ https://bugzilla.mozilla.org/show_bug.cg
 -->
 <head>
   <title>Test for the device storage API </title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="devicestorage_common.js"></script>
 
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
-<body onunload="unload()">
+<body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
-function unload() {
-  delete gDataBlob;
-  gDataBlob = null;
-
-  delete gFileReader;
-  gFileReader = null;
-}
-
-
 devicestorage_setup();
 
 var gFileName = "devicestorage/hi.png";
 var gData = "My name is Doug Turner.  My IRC nick is DougT.  I like Maple cookies."
 var gDataBlob = new Blob([gData], {type: 'image/png'});
 var gFileReader = new FileReader();
 
 function getAfterDeleteSuccess(e) {
--- a/dom/devicestorage/test/test_dotdot.html
+++ b/dom/devicestorage/test/test_dotdot.html
@@ -40,19 +40,21 @@ var gFileName = "../owned.png";
 function fail(e) {
   ok(false, "addSuccess was called");
   dump(request);
   devicestorage_cleanup();
 }
 
 function next(e) {
 
-  if (e != undefined)
-    ok(true, "addError was called");
-  
+  if (e != undefined) {
+    ok(true, "addError was called");  
+    ok(e.target.error.name == "SecurityError", "Error must be SecurityError");
+  }
+
   var f = tests.pop();
 
   if (f == undefined) {
     devicestorage_cleanup();
     return;
   }
 
   request = f();
--- a/dom/devicestorage/test/test_overwrite.html
+++ b/dom/devicestorage/test/test_overwrite.html
@@ -39,16 +39,17 @@ function deleteError(e) {
 
 function addOverwritingSuccess(e) {
   ok(false, "addOverwritingSuccess was called.");
   devicestorage_cleanup();
 }
 
 function addOverwritingError(e) {
   ok(true, "Adding to the same location should fail");
+  ok(e.target.error.name == "NoModificationAllowedError", "Error must be NoModificationAllowedError");
 
   var storage = navigator.getDeviceStorage("pictures");
   request = storage.delete(filename)
   request.onsuccess = deleteSuccess;
   request.onerror = deleteError;
 }
 
 function addSuccess(e) {
--- a/dom/sms/tests/marionette/manifest.ini
+++ b/dom/sms/tests/marionette/manifest.ini
@@ -1,13 +1,13 @@
 [DEFAULT]
 b2g = true
 browser = false
 qemu = true
 
-[test_between_emulators.py]
+;[test_between_emulators.py]
 [test_incoming.js]
 [test_outgoing.js]
 [test_message_classes.js]
 [test_incoming_delete.js]
 [test_outgoing_delete.js]
 [test_getmessage.js]
 [test_getmessage_notfound.js]
--- a/testing/marionette/marionette-actors.js
+++ b/testing/marionette/marionette-actors.js
@@ -36,16 +36,25 @@ Cu.import("resource://gre/modules/NetUti
 Services.prefs.setBoolPref("marionette.contentListener", false);
 let appName = Services.appinfo.name;
 
 // import logger
 Cu.import("resource:///modules/services-common/log4moz.js");
 let logger = Log4Moz.repository.getLogger("Marionette");
 logger.info('marionette-actors.js loaded');
 
+// This is used to prevent newSession from returning before the telephony
+// API's are ready; see bug 792647.  This assumes that marionette-actors.js
+// will be loaded before the 'system-message-listener-ready' message
+// is fired.  If this stops being true, this approach will have to change.
+let systemMessageListenerReady = false;
+Services.obs.addObserver(function() {
+  systemMessageListenerReady = true;
+}, "system-message-listener-ready", false);
+
 /**
  * Creates the root actor once a connection is established
  */
 
 function createRootActor(aConnection)
 {
   return new MarionetteRootActor(aConnection);
 }
@@ -433,17 +442,20 @@ MarionetteDriverActor.prototype = {
    * the client to test in.
    *
    */
   newSession: function MDA_newSession() {
 
     function waitForWindow() {
       let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
       let win = this.getCurrentWindow();
-      if (!win || (appName == "Firefox" && !win.gBrowser) || (appName == "Fennec" && !win.BrowserApp)) { 
+      if (!win ||
+          (appName == "Firefox" && !win.gBrowser) ||
+          (appName == "Fennec" && !win.BrowserApp) ||
+          (appName == "B2G" && !systemMessageListenerReady)) { 
         checkTimer.initWithCallback(waitForWindow.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
       }
       else {
         this.startBrowser(win, true);
       }
     }
 
     this.switchToGlobalMessageManager();