Merge inbound to m-c
authorWes Kocher <wkocher@mozilla.com>
Thu, 22 May 2014 17:30:30 -0700
changeset 184584 e9b2b72f4e6c59e19c705dc6c4b177c17e6a29a0
parent 184583 bbd450246fe1d93dfad3991e0eea052d6ec820e3 (current diff)
parent 184476 8ceaed67eda43cd8bd1b92e1cbd5510f3266484e (diff)
child 184585 3078d2486cab285f624e371716864a5a43700a67
child 184683 975c221719aaf2703a096425f9e6b6f85275a4c2
child 184702 a25a5c97727aa81256270b13f3033e4c74496c93
push id43874
push userkwierso@gmail.com
push dateFri, 23 May 2014 00:55:10 +0000
treeherdermozilla-inbound@3078d2486cab [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone32.0a1
first release with
nightly linux32
e9b2b72f4e6c / 32.0a1 / 20140523030202 / files
nightly linux64
e9b2b72f4e6c / 32.0a1 / 20140523030202 / files
nightly mac
e9b2b72f4e6c / 32.0a1 / 20140523030202 / files
nightly win32
e9b2b72f4e6c / 32.0a1 / 20140523030202 / files
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
Merge inbound to m-c
js/src/jsworkers.cpp
services/sync/tps/extensions/mozmill/defaults/preferences/debug.js
services/sync/tps/extensions/mozmill/resource/modules/controller.js
services/sync/tps/extensions/mozmill/resource/modules/elementslib.js
services/sync/tps/extensions/mozmill/resource/modules/init.js
services/sync/tps/extensions/mozmill/resource/modules/inspection.js
services/sync/tps/extensions/mozmill/resource/modules/jum.js
services/sync/tps/extensions/mozmill/resource/modules/mozelement.js
services/sync/tps/extensions/mozmill/resource/modules/mozmill.js
services/sync/tps/extensions/mozmill/resource/modules/utils.js
services/sync/tps/extensions/tps/resource/mozmill/sync.jsm
--- a/content/base/src/nsContentList.cpp
+++ b/content/base/src/nsContentList.cpp
@@ -564,40 +564,41 @@ nsContentList::GetSupportedNames(unsigne
     return;
   }
 
   BringSelfUpToDate(true);
 
   nsAutoTArray<nsIAtom*, 8> atoms;
   for (uint32_t i = 0; i < mElements.Length(); ++i) {
     nsIContent *content = mElements.ElementAt(i);
+    if (content->HasID()) {
+      nsIAtom* id = content->GetID();
+      MOZ_ASSERT(id != nsGkAtoms::_empty,
+                 "Empty ids don't get atomized");
+      if (!atoms.Contains(id)) {
+        atoms.AppendElement(id);
+      }
+    }
+
     nsGenericHTMLElement* el = nsGenericHTMLElement::FromContent(content);
     if (el) {
       // XXXbz should we be checking for particular tags here?  How
       // stable is this part of the spec?
       // Note: nsINode::HasName means the name is exposed on the document,
       // which is false for options, so we don't check it here.
       const nsAttrValue* val = el->GetParsedAttr(nsGkAtoms::name);
       if (val && val->Type() == nsAttrValue::eAtom) {
         nsIAtom* name = val->GetAtomValue();
         MOZ_ASSERT(name != nsGkAtoms::_empty,
                    "Empty names don't get atomized");
         if (!atoms.Contains(name)) {
           atoms.AppendElement(name);
         }
       }
     }
-    if (content->HasID()) {
-      nsIAtom* id = content->GetID();
-      MOZ_ASSERT(id != nsGkAtoms::_empty,
-                 "Empty ids don't get atomized");
-      if (!atoms.Contains(id)) {
-        atoms.AppendElement(id);
-      }
-    }
   }
 
   aNames.SetCapacity(atoms.Length());
   for (uint32_t i = 0; i < atoms.Length(); ++i) {
     aNames.AppendElement(nsDependentAtomString(atoms[i]));
   }
 }
 
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -1968,16 +1968,17 @@ nsXMLHttpRequest::OnStartRequest(nsIRequ
       (mState & XML_HTTP_REQUEST_ASYNC)) {
     if (mProgressTimerIsActive) {
       mProgressTimerIsActive = false;
       mProgressNotifier->Cancel();
     }
     if (mUploadTransferred < mUploadTotal) {
       mUploadTransferred = mUploadTotal;
       mProgressSinceLastProgressEvent = true;
+      mUploadLengthComputable = true;
       MaybeDispatchProgressEvents(true);
     }
     mUploadComplete = true;
     DispatchProgressEvent(mUpload, NS_LITERAL_STRING(LOAD_STR),
                           true, mUploadTotal, mUploadTotal);
   }
 
   mContext = ctxt;
--- a/content/base/test/test_bug435425.html
+++ b/content/base/test/test_bug435425.html
@@ -32,16 +32,19 @@ function logEvent(evt) {
          ((currentEvents[i].type != evt.type) ||
           !(evt.target instanceof currentEvents[i].target))) {
     ++i;
   }
   if (evt.target instanceof XMLHttpRequestUpload) {
     if (evt.type == "loadstart") {
       uploadTotal = evt.total
     } else {
+      if (evt.type == "progress") {
+        ok(evt.lengthComputable, "event(" + evt.type +  ").lengthComputable should be true.");
+      }
       is(evt.total, uploadTotal, "event(" + evt.type +  ").total should not change during upload.");
     }
   }
   ok(i != currentEvents.length, "Extra or wrong event?");
   is(evt.type, currentEvents[i].type, "Wrong event!")
   ok(evt.target instanceof currentEvents[i].target,
      "Wrong event target [" + evt.target + "," + evt.type + "]!");
   // If we handled non-optional event, remove all optional events before the 
--- a/content/html/content/test/test_htmlcollection.html
+++ b/content/html/content/test/test_htmlcollection.html
@@ -42,15 +42,15 @@ is(names[8], "length", "Enum entry 9")
 names = Object.getOwnPropertyNames(x);
 is(names.length, 9, "Should have 9 items");
 is(names[0], "0", "Entry 1")
 is(names[1], "1", "Entry 2")
 is(names[2], "2", "Entry 3")
 is(names[3], "3", "Entry 4")
 is(names[4], "x", "Entry 5")
 is(names[5], "y", "Entry 6")
-is(names[6], "z", "Entry 7")
-is(names[7], "w", "Entry 8")
+is(names[6], "w", "Entry 7")
+is(names[7], "z", "Entry 8")
 is(names[8], "something", "Entry 9")
 </script>
 </pre>
 </body>
 </html>
--- a/content/html/document/src/HTMLAllCollection.cpp
+++ b/content/html/document/src/HTMLAllCollection.cpp
@@ -63,42 +63,51 @@ HTMLAllCollection::Collection()
     nsIDocument* document = mDocument;
     mCollection = document->GetElementsByTagName(NS_LITERAL_STRING("*"));
     MOZ_ASSERT(mCollection);
   }
   return mCollection;
 }
 
 static bool
+IsAllNamedElement(nsIContent* aContent)
+{
+  nsIAtom* tag = aContent->Tag();
+  return
+    tag == nsGkAtoms::a ||
+    tag == nsGkAtoms::applet ||
+    tag == nsGkAtoms::button ||
+    tag == nsGkAtoms::embed ||
+    tag == nsGkAtoms::form ||
+    tag == nsGkAtoms::iframe ||
+    tag == nsGkAtoms::img ||
+    tag == nsGkAtoms::input ||
+    tag == nsGkAtoms::map ||
+    tag == nsGkAtoms::meta ||
+    tag == nsGkAtoms::object ||
+    tag == nsGkAtoms::select ||
+    tag == nsGkAtoms::textarea ||
+    tag == nsGkAtoms::frame ||
+    tag == nsGkAtoms::frameset;
+}
+
+static bool
 DocAllResultMatch(nsIContent* aContent, int32_t aNamespaceID, nsIAtom* aAtom,
                   void* aData)
 {
   if (aContent->GetID() == aAtom) {
     return true;
   }
 
   nsGenericHTMLElement* elm = nsGenericHTMLElement::FromContent(aContent);
   if (!elm) {
     return false;
   }
 
-  nsIAtom* tag = elm->Tag();
-  if (tag != nsGkAtoms::a &&
-      tag != nsGkAtoms::applet &&
-      tag != nsGkAtoms::button &&
-      tag != nsGkAtoms::embed &&
-      tag != nsGkAtoms::form &&
-      tag != nsGkAtoms::iframe &&
-      tag != nsGkAtoms::img &&
-      tag != nsGkAtoms::input &&
-      tag != nsGkAtoms::map &&
-      tag != nsGkAtoms::meta &&
-      tag != nsGkAtoms::object &&
-      tag != nsGkAtoms::select &&
-      tag != nsGkAtoms::textarea) {
+  if (!IsAllNamedElement(elm)) {
     return false;
   }
 
   const nsAttrValue* val = elm->GetParsedAttr(nsGkAtoms::name);
   return val && val->Type() == nsAttrValue::eAtom &&
          val->GetAtomValue() == aAtom;
 }
 
@@ -154,16 +163,61 @@ HTMLAllCollection::NamedGetter(const nsA
     aResult.SetValue().SetAsNode() = node;
     return;
   }
 
   aFound = false;
   aResult.SetNull();
 }
 
+void
+HTMLAllCollection::GetSupportedNames(unsigned aFlags, nsTArray<nsString>& aNames)
+{
+  if (!(aFlags & JSITER_HIDDEN)) {
+    return;
+  }
+
+  // XXXbz this is very similar to nsContentList::GetSupportedNames,
+  // but has to check IsAllNamedElement for the name case.
+  nsAutoTArray<nsIAtom*, 8> atoms;
+  for (uint32_t i = 0; i < Length(); ++i) {
+    nsIContent *content = Item(i);
+    if (content->HasID()) {
+      nsIAtom* id = content->GetID();
+      MOZ_ASSERT(id != nsGkAtoms::_empty,
+                 "Empty ids don't get atomized");
+      if (!atoms.Contains(id)) {
+        atoms.AppendElement(id);
+      }
+    }
+
+    nsGenericHTMLElement* el = nsGenericHTMLElement::FromContent(content);
+    if (el) {
+      // Note: nsINode::HasName means the name is exposed on the document,
+      // which is false for options, so we don't check it here.
+      const nsAttrValue* val = el->GetParsedAttr(nsGkAtoms::name);
+      if (val && val->Type() == nsAttrValue::eAtom &&
+          IsAllNamedElement(content)) {
+        nsIAtom* name = val->GetAtomValue();
+        MOZ_ASSERT(name != nsGkAtoms::_empty,
+                   "Empty names don't get atomized");
+        if (!atoms.Contains(name)) {
+          atoms.AppendElement(name);
+        }
+      }
+    }
+  }
+
+  aNames.SetCapacity(atoms.Length());
+  for (uint32_t i = 0; i < atoms.Length(); ++i) {
+    aNames.AppendElement(nsDependentAtomString(atoms[i]));
+  }
+}
+
+
 JSObject*
 HTMLAllCollection::WrapObject(JSContext* aCx)
 {
   return HTMLAllCollectionBinding::Wrap(aCx, this);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/html/document/src/HTMLAllCollection.h
+++ b/content/html/document/src/HTMLAllCollection.h
@@ -59,19 +59,17 @@ public:
                  Nullable<OwningNodeOrHTMLCollection>& aResult)
   {
     bool found = false;
     NamedGetter(aName, found, aResult);
   }
   void NamedGetter(const nsAString& aName,
                    bool& aFound,
                    Nullable<OwningNodeOrHTMLCollection>& aResult);
-  void GetSupportedNames(unsigned flags, nsTArray<nsString>& aNames)
-  {
-  }
+  void GetSupportedNames(unsigned aFlags, nsTArray<nsString>& aNames);
   bool NameIsEnumerable(const nsAString& aName)
   {
     return false;
   }
   void LegacyCall(JS::Handle<JS::Value>, const nsAString& aName,
                   Nullable<OwningNodeOrHTMLCollection>& aResult)
   {
     NamedItem(aName, aResult);
--- a/content/html/document/test/mochitest.ini
+++ b/content/html/document/test/mochitest.ini
@@ -73,8 +73,10 @@ skip-if = toolkit == 'android'
 [test_bug741266.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(needs control of popup window size) b2g-debug(needs control of popup window size) b2g-desktop(needs control of popup window size)
 [test_non-ascii-cookie.html]
 skip-if = buildapp == 'b2g' || e10s
 [test_bug765780.html]
 [test_bug871161.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || e10s #Bug 931116, b2g desktop specific, initial triage
 support-files = file_bug871161-1.html file_bug871161-2.html
+
+[test_bug1013316.html]
new file mode 100644
--- /dev/null
+++ b/content/html/document/test/test_bug1013316.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1013316
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1013316</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 1013316 **/
+  SimpleTest.waitForExplicitFinish();
+   addLoadEvent(function() {
+      is(Object.keys(document.all).length, 15, "We have 15 indexed props");
+      var props = Object.getOwnPropertyNames(document.all);
+      is(props.length, 20, "Should have five names");
+      is(props[15], "display", "display first");
+      is(props[16], "content", "content second");
+      is(props[17], "bar", "bar third");
+      is(props[18], "foo", "foo fourth");
+      is(props[19], "test", "test fifth");
+
+      is(Object.keys(document.images).length, 2, "We have 2 indexed props");
+      props = Object.getOwnPropertyNames(document.images);
+      is(props.length, 5, "Should have 3 names");
+      is(props[2], "display", "display first on document.images");
+      is(props[3], "bar", "bar second on document.images");
+      is(props[4], "foo", "foo third on document.images");
+      SimpleTest.finish();
+  })
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1013316">Mozilla Bug 1013316</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  <img id="display">
+  <img name="foo" id="bar">
+  <div name="baz">
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/content/html/document/test/test_documentAll.html
+++ b/content/html/document/test/test_documentAll.html
@@ -116,17 +116,17 @@ var elementNames =
    'multicol','noscript','noframes','object','spacer','table','td','td','th',
    'thead','tfoot','tr','textarea','select','option','spacer','param',
    'marquee','hr','title','hx','tt','u','ul','var','wbr','sub','sup','cite',
    'code','q','nobr','ol','p','pre','s','samp','small','body','html','map',
    'bdo','legend','listing','style','script','tbody','caption','meta',
    'optgroup','button','span','strike','strong','td'].sort();
 var hasName =
   ['applet','a','embed','form','iframe','img','input','object','textarea',
-   'select','map','meta','button'].sort();
+   'select','map','meta','button','frame','frameset'].sort();
 
 elementNames.forEach(function (name) {
   nameval = 'namefor' + name;
 
   e = document.createElement(name);
   p.appendChild(e);
   e.setAttribute('name', nameval);
 
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -425,32 +425,39 @@ AudioContext::Listener()
   return mListener;
 }
 
 void
 AudioContext::DecodeAudioData(const ArrayBuffer& aBuffer,
                               DecodeSuccessCallback& aSuccessCallback,
                               const Optional<OwningNonNull<DecodeErrorCallback> >& aFailureCallback)
 {
+  AutoJSAPI jsapi;
+  JSContext* cx = jsapi.cx();
+  JSAutoCompartment ac(cx, aBuffer.Obj());
+
+  // Neuter the array buffer
+  size_t length = aBuffer.Length();
+  JS::RootedObject obj(cx, aBuffer.Obj());
+
+  uint8_t* data = static_cast<uint8_t*>(JS_StealArrayBufferContents(cx, obj));
+
   // Sniff the content of the media.
   // Failed type sniffing will be handled by AsyncDecodeMedia.
   nsAutoCString contentType;
-  NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr,
-                  aBuffer.Data(), aBuffer.Length(),
-                  contentType);
+  NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr, data, length, contentType);
 
   nsRefPtr<DecodeErrorCallback> failureCallback;
   if (aFailureCallback.WasPassed()) {
     failureCallback = &aFailureCallback.Value();
   }
   nsRefPtr<WebAudioDecodeJob> job(
-    new WebAudioDecodeJob(contentType, this, aBuffer,
+    new WebAudioDecodeJob(contentType, this,
                           &aSuccessCallback, failureCallback));
-  mDecoder.AsyncDecodeMedia(contentType.get(),
-                            aBuffer.Data(), aBuffer.Length(), *job);
+  mDecoder.AsyncDecodeMedia(contentType.get(), data, length, *job);
   // Transfer the ownership to mDecodeJobs
   mDecodeJobs.AppendElement(job);
 }
 
 void
 AudioContext::RemoveFromDecodeQueue(WebAudioDecodeJob* aDecodeJob)
 {
   mDecodeJobs.RemoveElement(aDecodeJob);
--- a/content/media/webaudio/MediaBufferDecoder.cpp
+++ b/content/media/webaudio/MediaBufferDecoder.cpp
@@ -25,31 +25,28 @@ namespace mozilla {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(WebAudioDecodeJob)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WebAudioDecodeJob)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutput)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuccessCallback)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFailureCallback)
-  tmp->mArrayBuffer = nullptr;
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WebAudioDecodeJob)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutput)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuccessCallback)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFailureCallback)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WebAudioDecodeJob)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mArrayBuffer)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebAudioDecodeJob, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebAudioDecodeJob, Release)
 
 using namespace dom;
 
 class ReportResultTask : public nsRunnable
 {
 public:
@@ -138,16 +135,17 @@ private:
 
   void Cleanup()
   {
     MOZ_ASSERT(NS_IsMainThread());
     // MediaDecoderReader expects that BufferDecoder is alive.
     // Destruct MediaDecoderReader first.
     mDecoderReader = nullptr;
     mBufferDecoder = nullptr;
+    JS_free(nullptr, mBuffer);
   }
 
 private:
   nsCString mContentType;
   uint8_t* mBuffer;
   uint32_t mLength;
   WebAudioDecodeJob& mDecodeJob;
   PhaseEnum mPhase;
@@ -477,41 +475,34 @@ MediaBufferDecoder::EnsureThreadPoolInit
       return false;
     }
   }
   return true;
 }
 
 WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType,
                                      AudioContext* aContext,
-                                     const ArrayBuffer& aBuffer,
                                      DecodeSuccessCallback* aSuccessCallback,
                                      DecodeErrorCallback* aFailureCallback)
   : mContentType(aContentType)
   , mWriteIndex(0)
   , mContext(aContext)
   , mSuccessCallback(aSuccessCallback)
   , mFailureCallback(aFailureCallback)
 {
   MOZ_ASSERT(aContext);
   MOZ_ASSERT(aSuccessCallback);
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_COUNT_CTOR(WebAudioDecodeJob);
-
-  mArrayBuffer = aBuffer.Obj();
-
-  mozilla::HoldJSObjects(this);
 }
 
 WebAudioDecodeJob::~WebAudioDecodeJob()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_COUNT_DTOR(WebAudioDecodeJob);
-  mArrayBuffer = nullptr;
-  mozilla::DropJSObjects(this);
 }
 
 void
 WebAudioDecodeJob::OnSuccess(ErrorCode aErrorCode)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aErrorCode == NoError);
 
--- a/content/media/webaudio/MediaBufferDecoder.h
+++ b/content/media/webaudio/MediaBufferDecoder.h
@@ -27,17 +27,16 @@ class DecodeSuccessCallback;
 }
 
 struct WebAudioDecodeJob MOZ_FINAL
 {
   // You may omit both the success and failure callback, or you must pass both.
   // The callbacks are only necessary for asynchronous operation.
   WebAudioDecodeJob(const nsACString& aContentType,
                     dom::AudioContext* aContext,
-                    const dom::ArrayBuffer& aBuffer,
                     dom::DecodeSuccessCallback* aSuccessCallback = nullptr,
                     dom::DecodeErrorCallback* aFailureCallback = nullptr);
   ~WebAudioDecodeJob();
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebAudioDecodeJob)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebAudioDecodeJob)
 
   enum ErrorCode {
@@ -54,17 +53,16 @@ struct WebAudioDecodeJob MOZ_FINAL
   void OnSuccess(ErrorCode /* ignored */);
   void OnFailure(ErrorCode aErrorCode);
 
   bool AllocateBuffer();
 
   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
-  JS::Heap<JSObject*> mArrayBuffer;
   nsCString mContentType;
   uint32_t mWriteIndex;
   nsRefPtr<dom::AudioContext> mContext;
   nsRefPtr<dom::DecodeSuccessCallback> mSuccessCallback;
   nsRefPtr<dom::DecodeErrorCallback> mFailureCallback; // can be null
   nsRefPtr<dom::AudioBuffer> mOutput;
   FallibleTArray<ChannelBuffer> mChannelBuffers;
 };
--- a/content/media/webaudio/test/test_mediaDecoding.html
+++ b/content/media/webaudio/test/test_mediaDecoding.html
@@ -306,28 +306,31 @@ function runResampling(test, response, c
     checkResampledBuffer(asyncResult, test, callback);
   }, function onFailure() {
     ok(false, "Expected successful decode with resample");
     callback();
   });
 }
 
 function runTest(test, response, callback) {
+  // We need to copy the array here, because decodeAudioData is going to neuter
+  // the array.
+  var compressedAudio = response.slice(0);
   var expectCallback = false;
   var cx = new OfflineAudioContext(test.numberOfChannels || 1,
                                    test.frames || 1, test.sampleRate);
   cx.decodeAudioData(response, function onSuccess(asyncResult) {
     ok(expectCallback, "Success callback should fire asynchronously");
     ok(test.valid, "Did expect success for test " + test.url);
 
     checkAudioBuffer(asyncResult, test);
 
     test.expectedBuffer = asyncResult;
     test.nativeContext = cx;
-    runResampling(test, response, callback);
+    runResampling(test, compressedAudio, callback);
   }, function onFailure() {
     ok(expectCallback, "Failure callback should fire asynchronously");
     ok(!test.valid, "Did expect failure for test " + test.url);
     callback();
   });
   expectCallback = true;
 }
 
--- a/content/media/webrtc/LoadMonitor.cpp
+++ b/content/media/webrtc/LoadMonitor.cpp
@@ -415,28 +415,32 @@ nsresult LoadInfo::UpdateSystemLoad()
 
   UpdateCpuLoad(mTicksPerInterval,
                 total_times,
                 cpu_times,
                 &mSystemLoad);
   return NS_OK;
 #elif defined(__DragonFly__) || defined(__FreeBSD__) \
    || defined(__NetBSD__) || defined(__OpenBSD__)
+#if defined(__NetBSD__)
+  uint64_t cp_time[CPUSTATES];
+#else
   long cp_time[CPUSTATES];
+#endif // __NetBSD__
   size_t sz = sizeof(cp_time);
 #ifdef KERN_CP_TIME
   int mib[] = {
     CTL_KERN,
     KERN_CP_TIME,
   };
   size_t miblen = sizeof(mib) / sizeof(mib[0]);
   if (sysctl(mib, miblen, &cp_time, &sz, NULL, 0)) {
 #else
   if (sysctlbyname("kern.cp_time", &cp_time, &sz, NULL, 0)) {
-#endif
+#endif // KERN_CP_TIME
     LOG(("sysctl kern.cp_time failed"));
     return NS_ERROR_FAILURE;
   }
 
   const uint64_t cpu_times = cp_time[CP_NICE]
                            + cp_time[CP_SYS]
                            + cp_time[CP_INTR]
                            + cp_time[CP_USER];
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2907,26 +2907,16 @@ AsmJSCacheOpenEntryForWrite(JS::Handle<J
                             intptr_t* aHandle)
 {
   nsIPrincipal* principal =
     nsJSPrincipals::get(JS_GetCompartmentPrincipals(js::GetObjectCompartment(aGlobal)));
   return asmjscache::OpenEntryForWrite(principal, aInstalled, aBegin, aEnd,
                                        aSize, aMemory, aHandle);
 }
 
-static void
-OnLargeAllocationFailure()
-{
-  nsCOMPtr<nsIObserverService> os =
-    mozilla::services::GetObserverService();
-  if (os) {
-    os->NotifyObservers(nullptr, "memory-pressure", MOZ_UTF16("heap-minimize"));
-  }
-}
-
 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 void
 nsJSContext::EnsureStatics()
 {
   if (sIsInitialized) {
     if (!nsContentUtils::XPConnect()) {
       MOZ_CRASH();
@@ -2976,18 +2966,16 @@ nsJSContext::EnsureStatics()
     AsmJSCacheOpenEntryForRead,
     asmjscache::CloseEntryForRead,
     AsmJSCacheOpenEntryForWrite,
     asmjscache::CloseEntryForWrite,
     asmjscache::GetBuildId
   };
   JS::SetAsmJSCacheOps(sRuntime, &asmJSCacheOps);
 
-  JS::SetLargeAllocationFailureCallback(sRuntime, OnLargeAllocationFailure);
-
   // Set these global xpconnect options...
   Preferences::RegisterCallbackAndCall(ReportAllJSExceptionsPrefChangedCallback,
                                        "dom.report_all_js_exceptions");
 
   Preferences::RegisterCallbackAndCall(SetMemoryHighWaterMarkPrefChangedCallback,
                                        "javascript.options.mem.high_water_mark");
 
   Preferences::RegisterCallbackAndCall(SetMemoryMaxPrefChangedCallback,
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1339,18 +1339,28 @@ class CGAbstractMethod(CGThing):
         maybeNewline = " " if self.inline else "\n"
         return ' '.join(decorators) + maybeNewline
 
     def declare(self):
         if self.inline:
             return self._define(True)
         return "%s%s%s(%s);\n" % (self._template(), self._decorators(), self.name, self._argstring(True))
 
+    def indent_body(self, body):
+        """
+        Indent the code returned by self.definition_body(). Most classes
+        simply indent everything two spaces. This is here for
+        CGRegisterProtos, which needs custom indentation.
+        """
+        return indent(body)
+
     def _define(self, fromDeclare=False):
-        return self.definition_prologue(fromDeclare) + self.definition_body() + self.definition_epilogue()
+        return (self.definition_prologue(fromDeclare) +
+                self.indent_body(self.definition_body()) +
+                self.definition_epilogue())
 
     def define(self):
         return "" if self.inline else self._define()
 
     def definition_prologue(self, fromDeclare):
         return "%s%s%s(%s)\n{\n" % (self._template(), self._decorators(),
                                     self.name, self._argstring(fromDeclare))
 
@@ -1381,56 +1391,56 @@ class CGAbstractClassHook(CGAbstractStat
     'this' unwrapping as it assumes that the unwrapped type is always known.
     """
     def __init__(self, descriptor, name, returnType, args):
         CGAbstractStaticMethod.__init__(self, descriptor, name, returnType,
                                         args)
 
     def definition_body_prologue(self):
         return ("\n"  # BOGUS extra blank line at start of function
-                "  %s* self = UnwrapDOMObject<%s>(obj);\n" %
+                "%s* self = UnwrapDOMObject<%s>(obj);\n" %
                 (self.descriptor.nativeType, self.descriptor.nativeType))
 
     def definition_body(self):
         return self.definition_body_prologue() + self.generate_code()
 
     def generate_code(self):
         assert False  # Override me!
 
 
 class CGGetJSClassMethod(CGAbstractMethod):
     def __init__(self, descriptor):
         CGAbstractMethod.__init__(self, descriptor, 'GetJSClass', 'const JSClass*',
                                   [])
 
     def definition_body(self):
-        return "  return Class.ToJSClass();\n"
+        return "return Class.ToJSClass();\n"
 
 
 class CGAddPropertyHook(CGAbstractClassHook):
     """
     A hook for addProperty, used to preserve our wrapper from GC.
     """
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'),
                 Argument('JS::Handle<JSObject*>', 'obj'),
                 Argument('JS::Handle<jsid>', 'id'),
                 Argument('JS::MutableHandle<JS::Value>', 'vp')]
         CGAbstractClassHook.__init__(self, descriptor, ADDPROPERTY_HOOK_NAME,
                                      'bool', args)
 
     def generate_code(self):
         assert self.descriptor.wrapperCache
-        return indent(dedent("""
+        return dedent("""
             // We don't want to preserve if we don't have a wrapper.
             if (self->GetWrapperPreserveColor()) {
               PreserveWrapper(self);
             }
             return true;
-            """))
+            """)
 
 
 def DeferredFinalizeSmartPtr(descriptor):
     if descriptor.nativeOwnership == 'owned':
         smartPtr = 'nsAutoPtr'
     else:
         smartPtr = 'nsRefPtr'
     return smartPtr
@@ -1454,17 +1464,17 @@ class CGClassFinalizeHook(CGAbstractClas
     A hook for finalize, used to release our native object.
     """
     def __init__(self, descriptor):
         args = [Argument('js::FreeOp*', 'fop'), Argument('JSObject*', 'obj')]
         CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
                                      'void', args)
 
     def generate_code(self):
-        return indent(finalizeHook(self.descriptor, self.name, self.args[0].name).define())
+        return finalizeHook(self.descriptor, self.name, self.args[0].name).define()
 
 
 class CGClassConstructor(CGAbstractStaticMethod):
     """
     JS-visible constructor for our objects
     """
     def __init__(self, descriptor, ctor, name=CONSTRUCT_HOOK_NAME):
         args = [Argument('JSContext*', 'cx'),
@@ -1526,50 +1536,50 @@ class CGClassConstructor(CGAbstractStati
             chromeOnlyCheck=chromeOnlyCheck,
             ctorName=ctorName)
 
         name = self._ctor.identifier.name
         nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
         callGenerator = CGMethodCall(nativeName, True, self.descriptor,
                                      self._ctor, isConstructor=True,
                                      constructorName=ctorName)
-        return indent(preamble) + callGenerator.define()
+        return preamble + callGenerator.define()
 
 
 # Encapsulate the constructor in a helper method to share genConstructorBody with CGJSImplMethod.
 class CGConstructNavigatorObjectHelper(CGAbstractStaticMethod):
     """
     Construct a new JS-implemented WebIDL DOM object, for use on navigator.
     """
     def __init__(self, descriptor):
         name = "ConstructNavigatorObjectHelper"
         args = [Argument('JSContext*', 'cx'),
                 Argument('GlobalObject&', 'global'),
                 Argument('ErrorResult&', 'aRv')]
         rtype = 'already_AddRefed<%s>' % descriptor.name
         CGAbstractStaticMethod.__init__(self, descriptor, name, rtype, args)
 
     def definition_body(self):
-        return indent(genConstructorBody(self.descriptor))
+        return genConstructorBody(self.descriptor)
 
 
 class CGConstructNavigatorObject(CGAbstractMethod):
     """
     Wrap a JS-implemented WebIDL object into a JS value, for use on navigator.
     """
     def __init__(self, descriptor):
         name = 'ConstructNavigatorObject'
         args = [Argument('JSContext*', 'aCx'), Argument('JS::Handle<JSObject*>', 'aObj')]
         CGAbstractMethod.__init__(self, descriptor, name, 'JSObject*', args)
 
     def definition_body(self):
         if not self.descriptor.interface.isJSImplemented():
             raise TypeError("Only JS-implemented classes are currently supported "
                             "on navigator. See bug 856820.")
-        return indent(fill(
+        return fill(
             """
             GlobalObject global(aCx, aObj);
             if (global.Failed()) {
               return nullptr;
             }
             ErrorResult rv;
             nsRefPtr<mozilla::dom::${descriptorName}> result = ConstructNavigatorObjectHelper(aCx, global, rv);
             rv.WouldReportJSException();
@@ -1580,17 +1590,17 @@ class CGConstructNavigatorObject(CGAbstr
             JS::Rooted<JS::Value> v(aCx);
             if (!WrapNewBindingObject(aCx, result, &v)) {
               //XXX Assertion disabled for now, see bug 991271.
               MOZ_ASSERT(true || JS_IsExceptionPending(aCx));
               return nullptr;
             }
             return &v.toObject();
             """,
-            descriptorName=self.descriptor.name))
+            descriptorName=self.descriptor.name)
 
 
 class CGClassConstructHookHolder(CGGeneric):
     def __init__(self, descriptor):
         if descriptor.interface.ctor():
             constructHook = CONSTRUCT_HOOK_NAME
         else:
             constructHook = "ThrowingConstructor"
@@ -1679,17 +1689,17 @@ class CGClassHasInstanceHook(CGAbstractS
             if (!vp.isObject()) {
               *bp = false;
               return true;
             }
 
             JS::Rooted<JSObject*> instance(cx, &vp.toObject());
             """)
         if self.descriptor.interface.hasInterfacePrototypeObject():
-            return indent(
+            return (
                 header +
                 fill(
                     """
 
                     static_assert(IsBaseOf<nsISupports, ${nativeType}>::value,
                                   "HasInstance only works for nsISupports-based classes.");
 
                     bool ok = InterfaceHasInstance(cx, obj, instance, bp);
@@ -1731,17 +1741,17 @@ class CGClassHasInstanceHook(CGAbstractS
                 if (domClass->mInterfaceChain[PrototypeTraits<prototypes::id::${name}>::Depth] == prototypes::id::${name}) {
                   ${setBp};
                   return true;
                 }
                 """,
                 name=iface.identifier.name,
                 setBp=setBp)
         hasInstanceCode += "return true;\n"
-        return indent(header + hasInstanceCode)
+        return header + hasInstanceCode
 
 
 def isChromeOnly(m):
     return m.getExtendedAttribute("ChromeOnly")
 
 
 def getAvailableInTestFunc(obj):
     availableIn = obj.getExtendedAttribute("AvailableIn")
@@ -2519,21 +2529,20 @@ class CGCreateInterfaceObjectsMethod(CGA
                 if (proto) {
                   js::SetReservedSlot(proto, DOM_INTERFACE_PROTO_SLOTS_BASE,
                                       JS::ObjectValue(*unforgeableHolder));
                 }
                 """,
                 name=self.descriptor.name))
         else:
             setUnforgeableHolder = None
-        functionBody = CGList(
+        return CGList(
             [CGGeneric(getParentProto), CGGeneric(getConstructorProto), initIds,
              prefCache, createUnforgeableHolder, CGGeneric(call), setUnforgeableHolder],
-            "\n")
-        return CGIndenter(functionBody).define()
+            "\n").define()
 
 
 class CGGetPerInterfaceObject(CGAbstractMethod):
     """
     A method for getting a per-interface object (a prototype object or interface
     constructor object).
     """
     def __init__(self, descriptor, name, idPrefix="", extraArgs=[]):
@@ -2541,17 +2550,17 @@ class CGGetPerInterfaceObject(CGAbstract
                 Argument('JS::Handle<JSObject*>', 'aGlobal')] + extraArgs
         CGAbstractMethod.__init__(self, descriptor, name,
                                   'JS::Handle<JSObject*>', args)
         self.id = idPrefix + "id::" + self.descriptor.name
 
     def definition_body(self):
         # BOGUS extra blank line at the beginning of the code below
         # BOGUS - should be a blank line between an if-block and following comment below
-        return indent(fill(
+        return fill(
             """
 
             /* Make sure our global is sane.  Hopefully we can remove this sometime */
             if (!(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL)) {
               return JS::NullPtr();
             }
             /* Check to see whether the interface objects are already installed */
             ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(aGlobal);
@@ -2563,54 +2572,54 @@ class CGGetPerInterfaceObject(CGAbstract
              * The object might _still_ be null, but that's OK.
              *
              * Calling fromMarkedLocation() is safe because protoAndIfaceCache is
              * traced by TraceProtoAndIfaceCache() and its contents are never
              * changed after they have been set.
              */
             return JS::Handle<JSObject*>::fromMarkedLocation(protoAndIfaceCache.EntrySlotMustExist(${id}).address());
             """,
-            id=self.id))
+            id=self.id)
 
 
 class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
     """
     A method for getting the interface prototype object.
     """
     def __init__(self, descriptor):
         CGGetPerInterfaceObject.__init__(self, descriptor, "GetProtoObject",
                                          "prototypes::")
 
     def definition_body(self):
         # BOGUS extra blank line at start of method
-        return indent(dedent("""
+        return dedent("""
 
             /* Get the interface prototype object for this class.  This will create the
                object as needed. */
             bool aDefineOnGlobal = true;
-            """)) + CGGetPerInterfaceObject.definition_body(self)
+            """) + CGGetPerInterfaceObject.definition_body(self)
 
 
 class CGGetConstructorObjectMethod(CGGetPerInterfaceObject):
     """
     A method for getting the interface constructor object.
     """
     def __init__(self, descriptor):
         CGGetPerInterfaceObject.__init__(
             self, descriptor, "GetConstructorObject",
             "constructors::",
             extraArgs=[Argument("bool", "aDefineOnGlobal", "true")])
 
     def definition_body(self):
         # BOGUS extra blank line at start of method
-        return indent(dedent("""
+        return dedent("""
 
             /* Get the interface object for this class.  This will create the object as
                needed. */
-            """)) + CGGetPerInterfaceObject.definition_body(self)
+            """) + CGGetPerInterfaceObject.definition_body(self)
 
 
 class CGDefineDOMInterfaceMethod(CGAbstractMethod):
     """
     A method for resolve hooks to try to lazily define the interface object for
     a given interface.
     """
     def __init__(self, descriptor):
@@ -2627,31 +2636,31 @@ class CGDefineDOMInterfaceMethod(CGAbstr
 
     def define(self):
         if self.descriptor.workers:
             return ''
         return CGAbstractMethod.define(self)
 
     def definition_body(self):
         if len(self.descriptor.interface.namedConstructors) > 0:
-            getConstructor = indent(dedent("""
+            getConstructor = dedent("""
                 JSObject* interfaceObject = GetConstructorObject(aCx, aGlobal, aDefineOnGlobal);
                 if (!interfaceObject) {
                   return nullptr;
                 }
                 for (unsigned slot = DOM_INTERFACE_SLOTS_BASE; slot < JSCLASS_RESERVED_SLOTS(&InterfaceObjectClass.mBase); ++slot) {
                   JSObject* constructor = &js::GetReservedSlot(interfaceObject, slot).toObject();
                   if (JS_GetFunctionId(JS_GetObjectFunction(constructor)) == JSID_TO_STRING(id)) {
                     return constructor;
                   }
                 }
                 return interfaceObject;
-                """))
-        else:
-            getConstructor = "  return GetConstructorObject(aCx, aGlobal, aDefineOnGlobal);\n"
+                """)
+        else:
+            getConstructor = "return GetConstructorObject(aCx, aGlobal, aDefineOnGlobal);\n"
         return getConstructor
 
 
 class CGConstructorEnabled(CGAbstractMethod):
     """
     A method for testing whether we should be exposing this interface
     object or navigator property.  This can perform various tests
     depending on what conditions are specified on the interface.
@@ -2675,20 +2684,19 @@ class CGConstructorEnabled(CGAbstractMet
         if func:
             assert isinstance(func, list) and len(func) == 1
             conditions.append("%s(aCx, aObj)" % func[0])
         availableIn = getAvailableInTestFunc(iface)
         if availableIn:
             conditions.append("%s(aCx, aObj)" % availableIn)
         # We should really have some conditions
         assert len(conditions)
-        body = CGWrapper(CGList((CGGeneric(cond) for cond in conditions),
+        return CGWrapper(CGList((CGGeneric(cond) for cond in conditions),
                                 " &&\n"),
-                         pre="return ", post=";\n", reindent=True)
-        return CGIndenter(body).define()
+                         pre="return ", post=";\n", reindent=True).define()
 
 
 def CreateBindingJSObject(descriptor, properties, parent):
     # We don't always need to root obj, but there are a variety
     # of cases where we do, so for simplicity, just always root it.
     objDecl = "JS::Rooted<JSObject*> obj(aCx);\n"
     if descriptor.proxy:
         create = fill(
@@ -2792,21 +2800,21 @@ def InitUnforgeableProperties(descriptor
 
 
 def AssertInheritanceChain(descriptor):
     asserts = ""
     iface = descriptor.interface
     while iface:
         desc = descriptor.getDescriptor(iface.identifier.name)
         asserts += (
-            "  MOZ_ASSERT(static_cast<%s*>(aObject) == \n"
-            "             reinterpret_cast<%s*>(aObject));\n" %
+            "MOZ_ASSERT(static_cast<%s*>(aObject) == \n"
+            "           reinterpret_cast<%s*>(aObject));\n" %
             (desc.nativeType, desc.nativeType))
         iface = iface.parent
-    asserts += "  MOZ_ASSERT(ToSupportsIsCorrect(aObject));\n"
+    asserts += "MOZ_ASSERT(ToSupportsIsCorrect(aObject));\n"
     return asserts
 
 
 def InitMemberSlots(descriptor, wrapperCache):
     """
     Initialize member slots on our JS object if we're supposed to have some.
 
     Note that this is called after the SetWrapper() call in the
@@ -2838,51 +2846,52 @@ class CGWrapWithCacheMethod(CGAbstractMe
                 Argument(descriptor.nativeType + '*', 'aObject'),
                 Argument('nsWrapperCache*', 'aCache')]
         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
         self.properties = properties
 
     def definition_body(self):
         return fill(
             """
-            ${assertion}
-              MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
-                         "nsISupports must be on our primary inheritance chain");
-
-              JS::Rooted<JSObject*> parent(aCx,
-                GetRealParentObject(aObject,
-                                    WrapNativeParent(aCx, aObject->GetParentObject())));
-              if (!parent) {
-                return nullptr;
+            $*{assertion}
+
+            MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
+                       "nsISupports must be on our primary inheritance chain");
+
+            JS::Rooted<JSObject*> parent(aCx,
+              GetRealParentObject(aObject,
+                                  WrapNativeParent(aCx, aObject->GetParentObject())));
+            if (!parent) {
+              return nullptr;
+            }
+
+            // That might have ended up wrapping us already, due to the wonders
+            // of XBL.  Check for that, and bail out as needed.  Scope so we don't
+            // collide with the "obj" we declare in CreateBindingJSObject.
+            {
+              JSObject* obj = aCache->GetWrapper();
+              if (obj) {
+                return obj;
               }
-
-              // That might have ended up wrapping us already, due to the wonders
-              // of XBL.  Check for that, and bail out as needed.  Scope so we don't
-              // collide with the "obj" we declare in CreateBindingJSObject.
-              {
-                JSObject* obj = aCache->GetWrapper();
-                if (obj) {
-                  return obj;
-                }
-              }
-
-              JSAutoCompartment ac(aCx, parent);
-              JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, parent));
-              JS::Handle<JSObject*> proto = GetProtoObject(aCx, global);
-              if (!proto) {
-                return nullptr;
-              }
-
-              $*{parent}
-
-              $*{unforgeable}
-
-              aCache->SetWrapper(obj);
-              $*{slots}
-              return obj;
+            }
+
+            JSAutoCompartment ac(aCx, parent);
+            JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, parent));
+            JS::Handle<JSObject*> proto = GetProtoObject(aCx, global);
+            if (!proto) {
+              return nullptr;
+            }
+
+            $*{parent}
+
+            $*{unforgeable}
+
+            aCache->SetWrapper(obj);
+            $*{slots}
+            return obj;
             """,
             assertion=AssertInheritanceChain(self.descriptor),
             parent=CreateBindingJSObject(self.descriptor, self.properties,
                                          "parent"),
             unforgeable=InitUnforgeableProperties(self.descriptor, self.properties),
             slots=InitMemberSlots(self.descriptor, True))
 
 
@@ -2891,17 +2900,17 @@ class CGWrapMethod(CGAbstractMethod):
         # XXX can we wrap if we don't have an interface prototype object?
         assert descriptor.interface.hasInterfacePrototypeObject()
         args = [Argument('JSContext*', 'aCx'),
                 Argument('T*', 'aObject')]
         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args,
                                   inline=True, templateArgs=["class T"])
 
     def definition_body(self):
-        return "  return Wrap(aCx, aObject, aObject);\n"
+        return "return Wrap(aCx, aObject, aObject);\n"
 
 
 class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
     """
     Create a wrapper JSObject for a given native that does not implement
     nsWrapperCache.
 
     properties should be a PropertyArrays instance.
@@ -2914,29 +2923,30 @@ class CGWrapNonWrapperCacheMethod(CGAbst
         if descriptor.nativeOwnership == 'owned':
             args.append(Argument('bool*', 'aTookOwnership'))
         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
         self.properties = properties
 
     def definition_body(self):
         return fill(
             """
-            ${assertions}
-              JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
-              JS::Handle<JSObject*> proto = GetProtoObject(aCx, global);
-              if (!proto) {
-                return nullptr;
-              }
-
-              $*{global_}
-
-              $*{unforgeable}
-
-              $*{slots}
-              return obj;
+            $*{assertions}
+
+            JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
+            JS::Handle<JSObject*> proto = GetProtoObject(aCx, global);
+            if (!proto) {
+              return nullptr;
+            }
+
+            $*{global_}
+
+            $*{unforgeable}
+
+            $*{slots}
+            return obj;
             """,
             assertions=AssertInheritanceChain(self.descriptor),
             global_=CreateBindingJSObject(self.descriptor, self.properties,
                                           "global"),
             unforgeable=InitUnforgeableProperties(self.descriptor, self.properties),
             slots=InitMemberSlots(self.descriptor, False))
 
 
@@ -2973,46 +2983,46 @@ class CGWrapGlobalMethod(CGAbstractMetho
             fireOnNewGlobal = """// XXXkhuey can't do this yet until workers can lazy resolve.
 // JS_FireOnNewGlobalObject(aCx, obj);
 """
         else:
             fireOnNewGlobal = ""
 
         return fill(
             """
-            ${assertions}
-              MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
-                         "nsISupports must be on our primary inheritance chain");
-
-              JS::Rooted<JSObject*> obj(aCx);
-              CreateGlobal<${nativeType}, GetProtoObject>(aCx,
-                                               aObject,
-                                               aCache,
-                                               Class.ToJSClass(),
-                                               aOptions,
-                                               aPrincipal,
-                                               aInitStandardClasses,
-                                               &obj);
-              if (!obj) {
-                return nullptr;
-              }
-
-              // obj is a new global, so has a new compartment.  Enter it
-              // before doing anything with it.
-              JSAutoCompartment ac(aCx, obj);
-
-              if (!DefineProperties(aCx, obj, ${properties}, ${chromeProperties})) {
-                return nullptr;
-              }
-              $*{unforgeable}
-
-              $*{slots}
-              $*{fireOnNewGlobal}
-
-              return obj;
+            $*{assertions}
+            MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
+                       "nsISupports must be on our primary inheritance chain");
+
+            JS::Rooted<JSObject*> obj(aCx);
+            CreateGlobal<${nativeType}, GetProtoObject>(aCx,
+                                             aObject,
+                                             aCache,
+                                             Class.ToJSClass(),
+                                             aOptions,
+                                             aPrincipal,
+                                             aInitStandardClasses,
+                                             &obj);
+            if (!obj) {
+              return nullptr;
+            }
+
+            // obj is a new global, so has a new compartment.  Enter it
+            // before doing anything with it.
+            JSAutoCompartment ac(aCx, obj);
+
+            if (!DefineProperties(aCx, obj, ${properties}, ${chromeProperties})) {
+              return nullptr;
+            }
+            $*{unforgeable}
+
+            $*{slots}
+            $*{fireOnNewGlobal}
+
+            return obj;
             """,
             assertions=AssertInheritanceChain(self.descriptor),
             nativeType=self.descriptor.nativeType,
             properties=properties,
             chromeProperties=chromeProperties,
             unforgeable=InitUnforgeableProperties(self.descriptor, self.properties),
             slots=InitMemberSlots(self.descriptor, True),
             fireOnNewGlobal=fireOnNewGlobal)
@@ -3040,17 +3050,17 @@ class CGUpdateMemberSlotsMethod(CGAbstra
                     }
                     // Getter handled setting our reserved slots
                     """,
                     slot=memberReservedSlot(m),
                     interface=self.descriptor.interface.identifier.name,
                     member=m.identifier.name)
 
         body += "\nreturn true;\n"
-        return indent(body)
+        return body
 
 
 class CGClearCachedValueMethod(CGAbstractMethod):
     def __init__(self, descriptor, member):
         self.member = member
         # If we're StoreInSlot, we'll need to call the getter
         if member.getExtendedAttribute("StoreInSlot"):
             args = [Argument('JSContext*', 'aCx')]
@@ -3087,32 +3097,32 @@ class CGClearCachedValueMethod(CGAbstrac
                 name=self.member.identifier.name,
                 slotIndex=slotIndex)
         else:
             declObj = "JSObject* obj;\n"
             noopRetval = ""
             saveMember = ""
             regetMember = ""
 
-        return indent(fill(
+        return fill(
             """
             $*{declObj}
             obj = aObject->GetWrapper();
             if (!obj) {
               return${noopRetval};
             }
             $*{saveMember}
             js::SetReservedSlot(obj, ${slotIndex}, JS::UndefinedValue());
             $*{regetMember}
             """,
             declObj=declObj,
             noopRetval=noopRetval,
             saveMember=saveMember,
             slotIndex=slotIndex,
-            regetMember=regetMember))
+            regetMember=regetMember)
 
 
 class CGIsPermittedMethod(CGAbstractMethod):
     """
     crossOriginGetters/Setters/Methods are sets of names of the relevant members.
     """
     def __init__(self, descriptor, crossOriginGetters, crossOriginSetters,
                  crossOriginMethods):
@@ -3144,17 +3154,17 @@ class CGIsPermittedMethod(CGAbstractMeth
             case.append(CGGeneric("if (%s) {\n"
                                   "  return true;\n"
                                   "}\n" % cond))
             cases[firstLetter] = case
         caseList = []
         for firstLetter in sorted(cases.keys()):
             caseList.append(CGCase("'%s'" % firstLetter, cases[firstLetter]))
         switch = CGSwitch("propFirstChar", caseList)
-        return indent(switch.define() + "\nreturn false;\n")
+        return switch.define() + "\nreturn false;\n"
 
 builtinNames = {
     IDLType.Tags.bool: 'bool',
     IDLType.Tags.int8: 'int8_t',
     IDLType.Tags.int16: 'int16_t',
     IDLType.Tags.int32: 'int32_t',
     IDLType.Tags.int64: 'int64_t',
     IDLType.Tags.uint8: 'uint8_t',
@@ -6110,29 +6120,29 @@ class CGMethodCall(CGThing):
                                       isConstructor=isConstructor)
 
         signatures = method.signatures()
         if len(signatures) == 1:
             # Special case: we can just do a per-signature method call
             # here for our one signature and not worry about switching
             # on anything.
             signature = signatures[0]
-            self.cgRoot = CGList([CGIndenter(getPerSignatureCall(signature))])
+            self.cgRoot = CGList([getPerSignatureCall(signature)])
             requiredArgs = requiredArgCount(signature)
 
             if requiredArgs > 0:
-                code = indent(fill(  # BOGUS extra blank line
+                code = fill(  # BOGUS extra blank line
                     """
 
                     if (args.length() < ${requiredArgs}) {
                       return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${methodName}");
                     }
                     """,
                     requiredArgs=requiredArgs,
-                    methodName=methodName))
+                    methodName=methodName)
                 self.cgRoot.prepend(CGGeneric(code))
             return
 
         # Need to find the right overload
         maxArgCount = method.maxArgCount
         allowedArgCounts = method.allowedArgCounts
 
         argCountCases = []
@@ -6465,18 +6475,17 @@ class CGMethodCall(CGThing):
             CGSwitch("argcount",
                      argCountCases,
                      # BOGUS extra blank line at end of default block
                      CGGeneric('return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "%s");\n\n' %
                                methodName)))
         overloadCGThings.append(
             CGGeneric('MOZ_CRASH("We have an always-returning default case");\n'
                       'return false;\n'))
-        self.cgRoot = CGWrapper(CGIndenter(CGList(overloadCGThings)),
-                                pre="\n")
+        self.cgRoot = CGWrapper(CGList(overloadCGThings), pre="\n")
 
     def define(self):
         return self.cgRoot.define()
 
 
 class CGGetterCall(CGPerSignatureCall):
     """
     A class to generate a native object getter call for a particular IDL
@@ -6607,17 +6616,17 @@ class CGAbstractBindingMethod(CGAbstract
         # we're someone's consequential interface.  But for this-unwrapping, we
         # know that we're the real deal.  So fake a descriptor here for
         # consumption by CastableObjectUnwrapper.
         body += str(CastableObjectUnwrapper(
             self.descriptor,
             "obj", "self", self.unwrapFailureCode,
             allowCrossOriginObj=self.allowCrossOriginThis))
 
-        return indent(body) + self.generate_code().define()
+        return body + self.generate_code().define()
 
     def generate_code(self):
         assert False  # Override me
 
 
 class CGAbstractStaticBindingMethod(CGAbstractStaticMethod):
     """
     Common class to generate the JSNatives for all our static methods, getters
@@ -6630,21 +6639,21 @@ class CGAbstractStaticBindingMethod(CGAb
         args = [Argument('JSContext*', 'cx'),
                 Argument('unsigned', 'argc'),
                 Argument('JS::Value*', 'vp')]
         CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
 
     def definition_body(self):
         # Make sure that "obj" is in the same compartment as "cx", since we'll
         # later use it to wrap return values.
-        unwrap = indent(dedent("""
+        unwrap = dedent("""
             JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
             JS::Rooted<JSObject*> obj(cx, &args.callee());
 
-            """))
+            """)
         return unwrap + self.generate_code().define()
 
     def generate_code(self):
         assert False  # Override me
 
 
 def MakeNativeName(name):
     return name[0].upper() + name[1:]
@@ -6666,28 +6675,28 @@ class CGGenericMethod(CGAbstractBindingM
             descriptor.interface.identifier.name)
         name = "genericCrossOriginMethod" if allowCrossOriginThis else "genericMethod"
         CGAbstractBindingMethod.__init__(self, descriptor, name,
                                          args,
                                          unwrapFailureCode=unwrapFailureCode,
                                          allowCrossOriginThis=allowCrossOriginThis)
 
     def generate_code(self):
-        return CGGeneric(indent(dedent("""
+        return CGGeneric(dedent("""
             const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
             MOZ_ASSERT(info->type() == JSJitInfo::Method);
             JSJitMethodOp method = info->method;
             bool ok = method(cx, obj, self, JSJitMethodCallArgs(args));
             #ifdef DEBUG
             if (ok) {
               AssertReturnTypeMatchesJitinfo(info, args.rval());
             }
             #endif
             return ok;
-            """)))
+            """))
 
 
 class CGSpecializedMethod(CGAbstractStaticMethod):
     """
     A class for generating the C++ code for a specialized method that the JIT
     can call with lower overhead.
     """
     def __init__(self, descriptor, method):
@@ -6718,30 +6727,30 @@ class CGMethodPromiseWrapper(CGAbstractS
     """
     def __init__(self, descriptor, methodToWrap):
         self.method = methodToWrap
         name = self.makeName(methodToWrap.name)
         args = list(methodToWrap.args)
         CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool', args)
 
     def definition_body(self):
-        return indent(fill(
+        return fill(
             """
             // Make sure to save the callee before someone maybe messes
             // with rval().
             JS::Rooted<JSObject*> callee(cx, &args.callee());
             bool ok = ${methodName}(${args});
             if (ok) {
               return true;
             }
             return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
                                              args.rval());
             """,
             methodName=self.method.name,
-            args=", ".join(arg.name for arg in self.args)))
+            args=", ".join(arg.name for arg in self.args))
 
     @staticmethod
     def makeName(methodName):
         return methodName + "_promiseWrapper"
 
 
 class CGJsonifierMethod(CGSpecializedMethod):
     def __init__(self, descriptor, method):
@@ -6768,17 +6777,17 @@ class CGJsonifierMethod(CGSpecializedMet
                         return false;
                       }
                     }
                     """,
                     name=m.identifier.name)
 
         ret += ('args.rval().setObject(*result);\n'
                 'return true;\n')
-        return indent(ret)
+        return ret
 
 
 class CGLegacyCallHook(CGAbstractBindingMethod):
     """
     Call hook for our object
     """
     def __init__(self, descriptor):
         self._legacycaller = descriptor.operations["LegacyCaller"]
@@ -6814,17 +6823,17 @@ class CGNewResolveHook(CGAbstractBinding
                 Argument('JS::Handle<jsid>', 'id'),
                 Argument('JS::MutableHandle<JSObject*>', 'objp')]
         # Our "self" is actually the "obj" argument in this case, not the thisval.
         CGAbstractBindingMethod.__init__(
             self, descriptor, NEWRESOLVE_HOOK_NAME,
             args, getThisObj="", callArgs="")
 
     def generate_code(self):
-        return CGGeneric(indent(dedent("""
+        return CGGeneric(dedent("""
             JS::Rooted<JSPropertyDescriptor> desc(cx);
             if (!self->DoNewResolve(cx, obj, id, &desc)) {
               return false;
             }
             if (!desc.object()) {
               return true;
             }
             // If desc.value() is undefined, then the DoNewResolve call
@@ -6833,30 +6842,30 @@ class CGNewResolveHook(CGAbstractBinding
             if (!desc.value().isUndefined() &&
                 !JS_DefinePropertyById(cx, obj, id, desc.value(),
                                        desc.attributes(),
                                        desc.getter(), desc.setter())) {
               return false;
             }
             objp.set(obj);
             return true;
-            """)))
+            """))
 
     def definition_body(self):
         if self.descriptor.interface.getExtendedAttribute("Global"):
             # Resolve standard classes
-            prefix = indent(dedent("""
+            prefix = dedent("""
                 if (!ResolveGlobal(cx, obj, id, objp)) {
                   return false;
                 }
                 if (objp) {
                   return true;
                 }
 
-                """))
+                """)
         else:
             prefix = ""
         return prefix + CGAbstractBindingMethod.definition_body(self)
 
 
 class CGEnumerateHook(CGAbstractBindingMethod):
     """
     Enumerate hook for objects with custom hooks.
@@ -6867,42 +6876,42 @@ class CGEnumerateHook(CGAbstractBindingM
         args = [Argument('JSContext*', 'cx'),
                 Argument('JS::Handle<JSObject*>', 'obj')]
         # Our "self" is actually the "obj" argument in this case, not the thisval.
         CGAbstractBindingMethod.__init__(
             self, descriptor, ENUMERATE_HOOK_NAME,
             args, getThisObj="", callArgs="")
 
     def generate_code(self):
-        return CGGeneric(indent(dedent("""
+        return CGGeneric(dedent("""
             nsAutoTArray<nsString, 8> names;
             ErrorResult rv;
             self->GetOwnPropertyNames(cx, names, rv);
             rv.WouldReportJSException();
             if (rv.Failed()) {
               return ThrowMethodFailedWithDetails(cx, rv, "%s", "enumerate");
             }
             JS::Rooted<JS::Value> dummy(cx);
             for (uint32_t i = 0; i < names.Length(); ++i) {
               if (!JS_LookupUCProperty(cx, obj, names[i].get(), names[i].Length(), &dummy)) {
                 return false;
               }
             }
             return true;
-            """)))
+            """))
 
     def definition_body(self):
         if self.descriptor.interface.getExtendedAttribute("Global"):
             # Enumerate standard classes
-            prefix = indent(dedent("""
+            prefix = dedent("""
                 if (!EnumerateGlobal(cx, obj)) {
                   return false;
                 }
 
-                """))
+                """)
         else:
             prefix = ""
         return prefix + CGAbstractBindingMethod.definition_body(self)
 
 
 class CppKeywords():
     """
     A class for checking if method names declared in webidl
@@ -6970,28 +6979,28 @@ class CGGenericGetter(CGAbstractBindingM
             unwrapFailureCode = (
                 'return ThrowInvalidThis(cx, args, GetInvalidThisErrorForGetter(%%(securityError)s), "%s");\n' %
                 descriptor.interface.identifier.name)
         CGAbstractBindingMethod.__init__(self, descriptor, name, args,
                                          unwrapFailureCode,
                                          allowCrossOriginThis=allowCrossOriginThis)
 
     def generate_code(self):
-        return CGGeneric(indent(dedent("""
+        return CGGeneric(dedent("""
             const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
             MOZ_ASSERT(info->type() == JSJitInfo::Getter);
             JSJitGetterOp getter = info->getter;
             bool ok = getter(cx, obj, self, JSJitGetterCallArgs(args));
             #ifdef DEBUG
             if (ok) {
               AssertReturnTypeMatchesJitinfo(info, args.rval());
             }
             #endif
             return ok;
-            """)))
+            """))
 
 
 class CGSpecializedGetter(CGAbstractStaticMethod):
     """
     A class for generating the code for a specialized attribute getter
     that the JIT can call with lower overhead.
     """
     def __init__(self, descriptor, attr):
@@ -7011,17 +7020,17 @@ class CGSpecializedGetter(CGAbstractStat
         if self.attr.slotIndex is not None:
             if (self.descriptor.hasXPConnectImpls and
                 (self.descriptor.interface.identifier.name != 'Window' or
                  self.attr.identifier.name != 'document')):
                 raise TypeError("Interface '%s' has XPConnect impls, so we "
                                 "can't use our slot for property '%s'!" %
                                 (self.descriptor.interface.identifier.name,
                                  self.attr.identifier.name))
-            prefix = indent(fill(
+            prefix = fill(
                 """
                 // Have to either root across the getter call or reget after.
                 JS::Rooted<JSObject*> reflector(cx);
                 // Safe to do an unchecked unwrap, since we've gotten this far.
                 // Also make sure to unwrap outer windows, since we want the
                 // real DOM object.
                 reflector = IsDOMObject(obj) ? obj : js::UncheckedUnwrap(obj, /* stopAtOuter = */ false);
                 {
@@ -7032,23 +7041,23 @@ class CGSpecializedGetter(CGAbstractStat
                     // The cached value is in the compartment of reflector,
                     // so wrap into the caller compartment as needed.
                     return ${maybeWrap}(cx, args.rval());
                   }
                 }
 
                 """,
                 slot=memberReservedSlot(self.attr),
-                maybeWrap=getMaybeWrapValueFuncForType(self.attr.type)))
+                maybeWrap=getMaybeWrapValueFuncForType(self.attr.type))
         else:
             prefix = ""
 
         return (prefix +
-                indent(CGGetterCall(self.attr.type, nativeName,
-                                    self.descriptor, self.attr).define()))
+                CGGetterCall(self.attr.type, nativeName,
+                             self.descriptor, self.attr).define())
 
     @staticmethod
     def makeNativeName(descriptor, attr):
         name = attr.identifier.name
         nativeName = MakeNativeName(descriptor.binaryNames.get(name, name))
         # resultOutParam does not depend on whether resultAlreadyAddRefed is set
         _, resultOutParam, _, _ = getRetvalDeclarationForType(attr.type,
                                                               descriptor,
@@ -7067,18 +7076,18 @@ class CGStaticGetter(CGAbstractStaticBin
     def __init__(self, descriptor, attr):
         self.attr = attr
         name = 'get_' + attr.identifier.name
         CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
 
     def generate_code(self):
         nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
                                                         self.attr)
-        return CGIndenter(CGGetterCall(self.attr.type, nativeName,
-                                       self.descriptor, self.attr))
+        return CGGetterCall(self.attr.type, nativeName, self.descriptor,
+                            self.attr)
 
 
 class CGGenericSetter(CGAbstractBindingMethod):
     """
     A class for generating the C++ code for an IDL attribute setter.
     """
     def __init__(self, descriptor, lenientThis=False, allowCrossOriginThis=False):
         args = [Argument('JSContext*', 'cx'),
@@ -7103,34 +7112,34 @@ class CGGenericSetter(CGAbstractBindingM
                 'return ThrowInvalidThis(cx, args, GetInvalidThisErrorForSetter(%%(securityError)s), "%s");\n' %
                 descriptor.interface.identifier.name)
 
         CGAbstractBindingMethod.__init__(self, descriptor, name, args,
                                          unwrapFailureCode,
                                          allowCrossOriginThis=allowCrossOriginThis)
 
     def generate_code(self):
-        return CGGeneric(indent(fill(
+        return CGGeneric(fill(
             """
             if (args.length() == 0) {
               return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${name} attribute setter");
             }
             const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
             MOZ_ASSERT(info->type() == JSJitInfo::Setter);
             JSJitSetterOp setter = info->setter;
             if (!setter(cx, obj, self, JSJitSetterCallArgs(args))) {
               return false;
             }
             args.rval().set(JSVAL_VOID);
             #ifdef DEBUG
             AssertReturnTypeMatchesJitinfo(info, args.rval());
             #endif
             return true;
             """,
-            name=self.descriptor.interface.identifier.name)))
+            name=self.descriptor.interface.identifier.name))
 
 
 class CGSpecializedSetter(CGAbstractStaticMethod):
     """
     A class for generating the code for a specialized attribute setter
     that the JIT can call with lower overhead.
     """
     def __init__(self, descriptor, attr):
@@ -7140,18 +7149,18 @@ class CGSpecializedSetter(CGAbstractStat
                 Argument('JS::Handle<JSObject*>', 'obj'),
                 Argument('%s*' % descriptor.nativeType, 'self'),
                 Argument('JSJitSetterCallArgs', 'args')]
         CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
 
     def definition_body(self):
         nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
                                                         self.attr)
-        return CGIndenter(CGSetterCall(self.attr.type, nativeName,
-                                       self.descriptor, self.attr)).define()
+        return CGSetterCall(self.attr.type, nativeName, self.descriptor,
+                            self.attr).define()
 
     @staticmethod
     def makeNativeName(descriptor, attr):
         name = attr.identifier.name
         return "Set" + MakeNativeName(descriptor.binaryNames.get(name, name))
 
 
 class CGStaticSetter(CGAbstractStaticBindingMethod):
@@ -7170,66 +7179,66 @@ class CGStaticSetter(CGAbstractStaticBin
             """
             if (args.length() == 0) {
               return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${name} setter");
             }
             """,
             name=self.attr.identifier.name))
         call = CGSetterCall(self.attr.type, nativeName, self.descriptor,
                             self.attr)
-        return CGIndenter(CGList([checkForArg, call]))
+        return CGList([checkForArg, call])
 
 
 class CGSpecializedForwardingSetter(CGSpecializedSetter):
     """
     A class for generating the code for a specialized attribute setter with
     PutForwards that the JIT can call with lower overhead.
     """
     def __init__(self, descriptor, attr):
         CGSpecializedSetter.__init__(self, descriptor, attr)
 
     def definition_body(self):
         attrName = self.attr.identifier.name
         forwardToAttrName = self.attr.getExtendedAttribute("PutForwards")[0]
         # JS_GetProperty and JS_SetProperty can only deal with ASCII
         assert all(ord(c) < 128 for c in attrName)
         assert all(ord(c) < 128 for c in forwardToAttrName)
-        return indent(fill(
+        return fill(
             """
             JS::Rooted<JS::Value> v(cx);
             if (!JS_GetProperty(cx, obj, "${attr}", &v)) {
               return false;
             }
 
             if (!v.isObject()) {
               return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "${interface}.${attr}");
             }
 
             JS::Rooted<JSObject*> targetObj(cx, &v.toObject());
             return JS_SetProperty(cx, targetObj, "${forwardToAttrName}", args[0]);
             """,
             attr=attrName,
             interface=self.descriptor.interface.identifier.name,
-            forwardToAttrName=forwardToAttrName))
+            forwardToAttrName=forwardToAttrName)
 
 
 class CGSpecializedReplaceableSetter(CGSpecializedSetter):
     """
     A class for generating the code for a specialized attribute setter with
     Replaceable that the JIT can call with lower overhead.
     """
     def __init__(self, descriptor, attr):
         CGSpecializedSetter.__init__(self, descriptor, attr)
 
     def definition_body(self):
         attrName = self.attr.identifier.name
         # JS_DefineProperty can only deal with ASCII
         assert all(ord(c) < 128 for c in attrName)
-        return indent('return JS_DefineProperty(cx, obj, "%s", args[0], JSPROP_ENUMERATE);\n' %
-                      attrName)
+        return ('return JS_DefineProperty(cx, obj, "%s", args[0], JSPROP_ENUMERATE);\n' %
+                attrName)
 
 
 def memberReturnsNewObject(member):
     return member.getExtendedAttribute("NewObject") is not None
 
 
 class CGMemberJITInfo(CGThing):
     """
@@ -8704,17 +8713,17 @@ class CGResolveOwnProperty(CGAbstractSta
                 Argument('JS::Handle<jsid>', 'id'),
                 Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc'),
                 ]
         CGAbstractStaticMethod.__init__(self, descriptor, "ResolveOwnProperty",
                                         "bool", args)
 
     def definition_body(self):
         # BOGUS extra blank line at end of function
-        return "  return js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, desc);\n\n"
+        return "return js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, desc);\n\n"
 
 
 class CGResolveOwnPropertyViaNewresolve(CGAbstractBindingMethod):
     """
     An implementation of Xray ResolveOwnProperty stuff for things that have a
     newresolve hook.
     """
     def __init__(self, descriptor):
@@ -8724,17 +8733,17 @@ class CGResolveOwnPropertyViaNewresolve(
                 Argument('JS::Handle<jsid>', 'id'),
                 Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc')]
         CGAbstractBindingMethod.__init__(self, descriptor,
                                          "ResolveOwnPropertyViaNewresolve",
                                          args, getThisObj="",
                                          callArgs="")
 
     def generate_code(self):
-        return CGGeneric(indent(dedent("""
+        return CGGeneric(dedent("""
             {
               // Since we're dealing with an Xray, do the resolve on the
               // underlying object first.  That gives it a chance to
               // define properties on the actual object as needed, and
               // then use the fact that it created the objects as a flag
               // to avoid re-resolving the properties if someone deletes
               // them.
               JSAutoCompartment ac(cx, obj);
@@ -8749,31 +8758,31 @@ class CGResolveOwnPropertyViaNewresolve(
                   !objDesc.value().isUndefined() &&
                   !JS_DefinePropertyById(cx, obj, id, objDesc.value(),
                                          objDesc.attributes(),
                                          objDesc.getter(), objDesc.setter())) {
                 return false;
               }
             }
             return self->DoNewResolve(cx, wrapper, id, desc);
-            """)))
+            """))
 
 
 class CGEnumerateOwnProperties(CGAbstractStaticMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'),
                 Argument('JS::Handle<JSObject*>', 'wrapper'),
                 Argument('JS::Handle<JSObject*>', 'obj'),
                 Argument('JS::AutoIdVector&', 'props')]
         CGAbstractStaticMethod.__init__(self, descriptor,
                                         "EnumerateOwnProperties", "bool", args)
 
     def definition_body(self):
         # BOGUS extra newline
-        return "  return js::GetProxyHandler(obj)->getOwnPropertyNames(cx, wrapper, props);\n\n"
+        return "return js::GetProxyHandler(obj)->getOwnPropertyNames(cx, wrapper, props);\n\n"
 
 
 class CGEnumerateOwnPropertiesViaGetOwnPropertyNames(CGAbstractBindingMethod):
     """
     An implementation of Xray EnumerateOwnProperties stuff for things
     that have a newresolve hook.
     """
     def __init__(self, descriptor):
@@ -8782,28 +8791,28 @@ class CGEnumerateOwnPropertiesViaGetOwnP
                 Argument('JS::Handle<JSObject*>', 'obj'),
                 Argument('JS::AutoIdVector&', 'props')]
         CGAbstractBindingMethod.__init__(self, descriptor,
                                          "EnumerateOwnPropertiesViaGetOwnPropertyNames",
                                          args, getThisObj="",
                                          callArgs="")
 
     def generate_code(self):
-        return CGIndenter(CGGeneric(dedent("""
+        return CGGeneric(dedent("""
             nsAutoTArray<nsString, 8> names;
             ErrorResult rv;
             self->GetOwnPropertyNames(cx, names, rv);
             rv.WouldReportJSException();
             if (rv.Failed()) {
               return ThrowMethodFailedWithDetails(cx, rv, "%s", "enumerate");
             }
             // OK to pass null as "proxy" because it's ignored if
             // shadowPrototypeProperties is true
             return AppendNamedPropertyIds(cx, JS::NullPtr(), names, true, 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()])]
@@ -9092,39 +9101,39 @@ class CGProxyIsProxy(CGAbstractMethod):
     def __init__(self, descriptor):
         args = [Argument('JSObject*', 'obj')]
         CGAbstractMethod.__init__(self, descriptor, "IsProxy", "bool", args, alwaysInline=True)
 
     def declare(self):
         return ""
 
     def definition_body(self):
-        return "  return js::IsProxy(obj) && js::GetProxyHandler(obj) == DOMProxyHandler::getInstance();\n"
+        return "return js::IsProxy(obj) && js::GetProxyHandler(obj) == DOMProxyHandler::getInstance();\n"
 
 
 class CGProxyUnwrap(CGAbstractMethod):
     def __init__(self, descriptor):
         args = [Argument('JSObject*', 'obj')]
         CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", descriptor.nativeType + '*', args, alwaysInline=True)
 
     def declare(self):
         return ""
 
     def definition_body(self):
-        return indent(fill(
+        return fill(
             """
             MOZ_ASSERT(js::IsProxy(obj));
             if (js::GetProxyHandler(obj) != DOMProxyHandler::getInstance()) {
               MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(obj));
               obj = js::UncheckedUnwrap(obj);
             }
             MOZ_ASSERT(IsProxy(obj));
             return static_cast<${type}*>(js::GetProxyPrivate(obj).toPrivate());
             """,
-            type=self.descriptor.nativeType))
+            type=self.descriptor.nativeType)
 
 
 class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'),
                 Argument('JS::Handle<JSObject*>', 'proxy'),
                 Argument('JS::Handle<jsid>', 'id'),
                 Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc')]
@@ -10801,16 +10810,20 @@ class CGRegisterProtos(CGAbstractMethod)
             lines.extend("REGISTER_CONSTRUCTOR(%s, %s, %s);\n" % (n.identifier.name, desc.name, getCheck(desc))
                          for n in desc.interface.namedConstructors)
         for desc in self.config.getDescriptors(isNavigatorProperty=True, register=True):
             propName = desc.interface.getNavigatorProperty()
             assert propName
             lines.append('REGISTER_NAVIGATOR_CONSTRUCTOR("%s", %s, %s);\n' % (propName, desc.name, getCheck(desc)))
         return ''.join(lines)
 
+    def indent_body(self, body):
+        # Don't indent the body of this method, as it's all preprocessor gunk.
+        return body
+
     def definition_body(self):
         return "\n" + self._defineMacro() + "\n" + self._registerProtos() + "\n" + self._undefineMacro()
 
 
 def dependencySortObjects(objects, dependencyGetter, nameGetter):
     """
     Sort IDL objects with dependencies on each other such that if A
     depends on B then B will come before A.  This is needed for
--- a/dom/datastore/DataStoreService.js
+++ b/dom/datastore/DataStoreService.js
@@ -484,27 +484,32 @@ function DataStoreServiceChild(aWindow, 
 
 DataStoreServiceChild.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
   init: function(aWindow, aName, aSuccessCb, aErrorCb) {
     debug("DataStoreServiceChild init");
     this._successCb = aSuccessCb;
     this._errorCb = aErrorCb;
+    this._name = aName;
 
     this.initDOMRequestHelper(aWindow, [ "DataStore:Get:Return:OK",
                                          "DataStore:Get:Return:KO" ]);
 
     cpmm.sendAsyncMessage("DataStore:Get",
                           { name: aName }, null, aWindow.document.nodePrincipal );
   },
 
   receiveMessage: function(aMessage) {
     debug("DataStoreServiceChild receiveMessage");
 
+    if (aMessage.data.name != this._name) {
+      return;
+    }
+
     switch (aMessage.name) {
       case 'DataStore:Get:Return:OK':
         this.destroyDOMRequestHelper();
         this._successCb(aMessage.data.stores);
         break;
 
       case 'DataStore:Get:Return:KO':
         this.destroyDOMRequestHelper();
new file mode 100644
--- /dev/null
+++ b/dom/datastore/tests/file_bug1008044.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for DataStore - bug 1008044</title>
+</head>
+<body>
+<div id="container"></div>
+  <script type="application/javascript;version=1.7">
+
+function ok(a, msg) {
+  alert((!!a ? 'OK' : 'KO') + ' ' + msg)
+}
+
+function cbError() {
+  alert('KO error');
+}
+
+function finish() {
+  alert('DONE');
+}
+
+navigator.getDataStores('foo').then(function(stores) {
+  if (stores[0].name != 'foo') {
+    ok(false, "Wrong name is received! Expected 'foo'");
+  }
+  runTest();
+});
+
+navigator.getDataStores('bar').then(function(stores) {
+  if (stores[0].name != 'bar') {
+    ok(false, "Wrong name is received! Expected 'bar'");
+  }
+  runTest();
+});
+
+var pending = 2;
+function runTest() {
+  if (--pending == 0) {
+    ok(true, "Test passed!");
+    finish();
+  }
+}
+  </script>
+</body>
+</html>
--- a/dom/datastore/tests/mochitest.ini
+++ b/dom/datastore/tests/mochitest.ini
@@ -23,16 +23,17 @@ support-files =
   file_bug976311.template.webapp
   file_bug986056.html
   file_bug986056.template.webapp
   file_event_maker.html
   file_event_receiver.html
   file_transactions.html
   file_basic_common.js
   file_sync_common.js
+  file_bug1008044.html
 
 [test_app_install.html]
 [test_readonly.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(debug-only failure; time out) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_basic.html]
 [test_basic_worker.html]
 [test_changes.html]
 skip-if = (toolkit == 'gonk' && debug) #intermittent failures, bug 961021
@@ -47,8 +48,9 @@ skip-if = (buildapp == 'b2g' && (toolkit
 [test_certifiedApp.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure; time out
 [test_keys.html]
 [test_duplicate.html]
 [test_bug976311.html]
 [test_bug986056.html]
 [test_oop_events.html]
 [test_transactions.html]
+[test_bug1008044.html]
copy from dom/datastore/tests/test_oop.html
copy to dom/datastore/tests/test_bug1008044.html
--- a/dom/datastore/tests/test_oop.html
+++ b/dom/datastore/tests/test_bug1008044.html
@@ -1,21 +1,21 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset="utf-8">
-  <title>Test for DataStore - basic operation on a readonly db</title>
+  <title>Test for DataStore - bug 1008044</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <div id="container"></div>
   <script type="application/javascript;version=1.7">
 
-  var gHostedManifestURL = 'http://test/tests/dom/datastore/tests/file_app.sjs?testToken=file_basic.html';
+  var gHostedManifestURL = 'http://test/tests/dom/datastore/tests/file_app.sjs?testToken=file_bug1008044.html';
   var gApp;
 
   function cbError() {
     ok(false, "Error callback invoked");
     finish();
   }
 
   function installApp() {
--- a/dom/events/JSEventHandler.cpp
+++ b/dom/events/JSEventHandler.cpp
@@ -13,16 +13,17 @@
 #include "nsVariant.h"
 #include "nsIDOMBeforeUnloadEvent.h"
 #include "nsGkAtoms.h"
 #include "xpcpublic.h"
 #include "nsJSEnvironment.h"
 #include "nsDOMJSUtils.h"
 #include "WorkerPrivate.h"
 #include "mozilla/ContentEvents.h"
+#include "mozilla/HoldDropJSObjects.h"
 #include "mozilla/JSEventHandler.h"
 #include "mozilla/Likely.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/UnionTypes.h"
 
 namespace mozilla {
 
 using namespace dom;
@@ -30,16 +31,24 @@ using namespace dom;
 JSEventHandler::JSEventHandler(nsISupports* aTarget,
                                nsIAtom* aType,
                                const TypedEventHandler& aTypedHandler)
   : mEventName(aType)
   , mTypedHandler(aTypedHandler)
 {
   nsCOMPtr<nsISupports> base = do_QueryInterface(aTarget);
   mTarget = base.get();
+  // Note, we call HoldJSObjects to get CanSkip called before CC.
+  HoldJSObjects(this);
+}
+
+JSEventHandler::~JSEventHandler()
+{
+  NS_ASSERTION(!mTarget, "Should have called Disconnect()!");
+  DropJSObjects(this);
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(JSEventHandler)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(JSEventHandler)
   tmp->mTypedHandler.ForgetHandler();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(JSEventHandler)
--- a/dom/events/JSEventHandler.h
+++ b/dom/events/JSEventHandler.h
@@ -176,20 +176,17 @@ private:
 class JSEventHandler : public nsIDOMEventListener
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_JSEVENTHANDLER_IID)
 
   JSEventHandler(nsISupports* aTarget, nsIAtom* aType,
                  const TypedEventHandler& aTypedHandler);
 
-  virtual ~JSEventHandler()
-  {
-    NS_ASSERTION(!mTarget, "Should have called Disconnect()!");
-  }
+  virtual ~JSEventHandler();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   // nsIDOMEventListener interface
   NS_DECL_NSIDOMEVENTLISTENER
 
   nsISupports* GetEventTarget() const
   {
--- a/gfx/gl/DecomposeIntoNoRepeatTriangles.cpp
+++ b/gfx/gl/DecomposeIntoNoRepeatTriangles.cpp
@@ -32,35 +32,16 @@ RectTriangles::addRect(GLfloat x0, GLflo
 {
     if (flip_y) {
         std::swap(ty0, ty1);
     }
     AppendRectToCoordArray(mVertexCoords, x0, y0, x1, y1);
     AppendRectToCoordArray(mTexCoords, tx0, ty0, tx1, ty1);
 }
 
-bool
-RectTriangles::isSimpleQuad(gfx3DMatrix& aOutTextureTransform) const
-{
-    if (mVertexCoords.Length() == 6 &&
-        mVertexCoords[0].x == 0.0f &&
-        mVertexCoords[0].y == 0.0f &&
-        mVertexCoords[5].x == 1.0f &&
-        mVertexCoords[5].y == 1.0f)
-    {
-        GLfloat tx0 = mTexCoords[0].x;
-        GLfloat ty0 = mTexCoords[0].y;
-        GLfloat tx1 = mTexCoords[5].x;
-        GLfloat ty1 = mTexCoords[5].y;
-        aOutTextureTransform = gfx3DMatrix::From2D(gfxMatrix(tx1 - tx0, 0, 0, ty1 - ty0, tx0, ty0));
-        return true;
-    }
-    return false;
-}
-
 static GLfloat
 WrapTexCoord(GLfloat v)
 {
     // fmodf gives negative results for negative numbers;
     // that is, fmodf(0.75, 1.0) == 0.75, but
     // fmodf(-0.75, 1.0) == -0.75.  For the negative case,
     // the result we need is 0.25, so we add 1.0f.
     if (v < 0.0f) {
--- a/gfx/gl/DecomposeIntoNoRepeatTriangles.h
+++ b/gfx/gl/DecomposeIntoNoRepeatTriangles.h
@@ -23,23 +23,16 @@ public:
 
     // Always pass texture coordinates upright. If you want to flip the
     // texture coordinates emitted to the tex_coords array, set flip_y to
     // true.
     void addRect(GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1,
                  GLfloat tx0, GLfloat ty0, GLfloat tx1, GLfloat ty1,
                  bool flip_y = false);
 
-    // Returns whether this object is made of only one rect that can be drawn
-    // with a pre-buffered unity quad which has 0,0,1,1 as both vertex
-    // positions and texture coordinates.
-    // aOutTextureTransform returns the transform that maps 0,0,1,1 texture
-    // coordinates to the correct ones.
-    bool isSimpleQuad(gfx3DMatrix& aOutTextureTransform) const;
-
     /**
       * these return a float pointer to the start of each array respectively.
       * Use it for glVertexAttribPointer calls.
       * We can return nullptr if we choose to use Vertex Buffer Objects here.
       */
     InfallibleTArray<coord>& vertCoords() {
         return mVertexCoords;
     }
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -38,22 +38,22 @@
 #include <CoreServices/CoreServices.h>
 #include "gfxColor.h"
 #endif
 
 #if defined(MOZ_WIDGET_COCOA)
 #include "nsCocoaFeatures.h"
 #endif
 
+namespace mozilla {
+namespace gl {
+
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
-namespace mozilla {
-namespace gl {
-
 #ifdef DEBUG
 unsigned GLContext::sCurrentGLContextTLS = -1;
 #endif
 
 uint32_t GLContext::sDebugMode = 0;
 
 
 #define MAX_SYMBOL_LENGTH 128
--- a/gfx/gl/GLContextProviderCGL.mm
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -11,21 +11,21 @@
 #include <OpenGL/gl.h>
 #include "gfxPrefs.h"
 #include "gfxFailure.h"
 #include "prenv.h"
 #include "mozilla/Preferences.h"
 #include "GeckoProfiler.h"
 #include "mozilla/gfx/MacIOSurface.h"
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace gl {
 
+using namespace mozilla::gfx;
+
 static bool gUseDoubleBufferedWindows = true;
 
 class CGLLibrary
 {
 public:
     CGLLibrary()
       : mInitialized(false),
         mOGLLibrary(nullptr),
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -32,21 +32,21 @@
 #include "gfx2DGlue.h"
 
 #include "gfxCrashReporterUtils.h"
 
 #ifdef MOZ_WIDGET_GTK
 #include "gfxPlatformGtk.h"
 #endif
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace gl {
 
+using namespace mozilla::gfx;
+
 GLXLibrary sGLXLibrary;
 
 // Check that we have at least version aMajor.aMinor .
 bool
 GLXLibrary::GLXVersionCheck(int aMajor, int aMinor)
 {
     return aMajor < mGLXMajorVersion ||
            (aMajor == mGLXMajorVersion && aMinor <= mGLXMinorVersion);
--- a/gfx/gl/GLContextProviderWGL.cpp
+++ b/gfx/gl/GLContextProviderWGL.cpp
@@ -12,21 +12,21 @@
 #include "gfxWindowsSurface.h"
 
 #include "gfxCrashReporterUtils.h"
 
 #include "prenv.h"
 
 #include "mozilla/Preferences.h"
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace gl {
 
+using namespace mozilla::gfx;
+
 WGLLibrary sWGLLib;
 
 HWND
 WGLLibrary::CreateDummyWindow(HDC *aWindowDC)
 {
     WNDCLASSW wc;
     if (!GetClassInfoW(GetModuleHandle(nullptr), L"GLContextWGLClass", &wc)) {
         ZeroMemory(&wc, sizeof(WNDCLASSW));
--- a/gfx/gl/GLReadTexImageHelper.cpp
+++ b/gfx/gl/GLReadTexImageHelper.cpp
@@ -9,21 +9,21 @@
 #include "OGLShaderProgram.h"
 #include "gfxTypes.h"
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
 #include "ScopedGLHelpers.h"
 #include "mozilla/gfx/2D.h"
 #include "gfx2DGlue.h"
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace gl {
 
+using namespace mozilla::gfx;
+
 GLReadTexImageHelper::GLReadTexImageHelper(GLContext* gl)
     : mGL(gl)
 {
     mPrograms[0] = 0;
     mPrograms[1] = 0;
     mPrograms[2] = 0;
     mPrograms[3] = 0;
 }
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -17,21 +17,21 @@
 #include "nsXULAppAPI.h"
 #endif
 #ifdef XP_MACOSX
 #include "SharedSurfaceIO.h"
 #endif
 #include "ScopedGLHelpers.h"
 #include "gfx2DGlue.h"
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace gl {
 
+using namespace mozilla::gfx;
+
 GLScreenBuffer*
 GLScreenBuffer::Create(GLContext* gl,
                      const gfx::IntSize& size,
                      const SurfaceCaps& caps)
 {
     if (caps.antialias &&
         !gl->IsSupported(GLFeature::framebuffer_multisample))
     {
--- a/gfx/gl/SharedSurfaceANGLE.cpp
+++ b/gfx/gl/SharedSurfaceANGLE.cpp
@@ -2,21 +2,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SharedSurfaceANGLE.h"
 
 #include "GLContextEGL.h"
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace gl {
 
+using namespace mozilla::gfx;
+
 SurfaceFactory_ANGLEShareHandle*
 SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl,
                                         ID3D10Device1* d3d,
                                         const SurfaceCaps& caps)
 {
     GLLibraryEGL* egl = &sEGLLibrary;
     if (!egl)
         return nullptr;
--- a/gfx/gl/SharedSurfaceGralloc.cpp
+++ b/gfx/gl/SharedSurfaceGralloc.cpp
@@ -24,20 +24,21 @@
 
 #define DEBUG_GRALLOC
 #ifdef DEBUG_GRALLOC
 #define DEBUG_PRINT(...) do { printf_stderr(__VA_ARGS__); } while (0)
 #else
 #define DEBUG_PRINT(...) do { } while (0)
 #endif
 
-using namespace mozilla;
+namespace mozilla {
+namespace gl {
+
 using namespace mozilla::gfx;
-using namespace gl;
-using namespace layers;
+using namespace mozilla::layers;
 using namespace android;
 
 SurfaceFactory_Gralloc::SurfaceFactory_Gralloc(GLContext* prodGL,
                                                const SurfaceCaps& caps,
                                                layers::ISurfaceAllocator* allocator)
     : SurfaceFactory_GL(prodGL, SharedSurfaceType::Gralloc, caps)
 {
     if (caps.surfaceAllocator) {
@@ -206,8 +207,11 @@ SharedSurface_Gralloc::WaitSync()
     return true;
 }
 
 void
 SharedSurface_Gralloc::WaitForBufferOwnership()
 {
     mTextureClient->WaitReleaseFence();
 }
+
+}
+}
--- a/gfx/layers/CopyableCanvasLayer.cpp
+++ b/gfx/layers/CopyableCanvasLayer.cpp
@@ -19,22 +19,22 @@
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Tools.h"
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
 #include "nsISupportsImpl.h"            // for gfxContext::AddRef, etc
 #include "nsRect.h"                     // for nsIntRect
 #include "nsSize.h"                     // for nsIntSize
 #include "gfxUtils.h"
 
+namespace mozilla {
+namespace layers {
+
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
-namespace mozilla {
-namespace layers {
-
 CopyableCanvasLayer::CopyableCanvasLayer(LayerManager* aLayerManager, void *aImplData) :
   CanvasLayer(aLayerManager, aImplData)
   , mStream(nullptr)
 {
   MOZ_COUNT_CTOR(CopyableCanvasLayer);
 }
 
 CopyableCanvasLayer::~CopyableCanvasLayer()
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -31,25 +31,23 @@
 #ifdef XP_WIN
 #include "gfxD2DSurface.h"
 #include "gfxWindowsPlatform.h"
 #include <d3d10_1.h>
 #include "d3d10/ImageLayerD3D10.h"
 #include "D3D9SurfaceImage.h"
 #endif
 
+namespace mozilla {
+namespace layers {
+
 using namespace mozilla::ipc;
 using namespace android;
 using namespace mozilla::gfx;
 
-
-namespace mozilla {
-namespace layers {
-
-
 Atomic<int32_t> Image::sSerialCounter(0);
 
 already_AddRefed<Image>
 ImageFactory::CreateImage(ImageFormat aFormat,
                           const gfx::IntSize &,
                           BufferRecycleBin *aRecycleBin)
 {
   nsRefPtr<Image> img;
--- a/gfx/layers/LayerSorter.cpp
+++ b/gfx/layers/LayerSorter.cpp
@@ -18,21 +18,21 @@
 #include "gfxRect.h"                    // for gfxRect
 #include "gfxTypes.h"                   // for gfxFloat
 #include "mozilla/gfx/BasePoint3D.h"    // for BasePoint3D
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsTArray, etc
 #include "limits.h"
 #include "mozilla/Assertions.h"
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 enum LayerSortOrder {
   Undefined,
   ABeforeB,
   BBeforeA,
 };
 
 /**
  * Recover the z component from a 2d transformed point by finding the intersection
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -28,32 +28,31 @@
 #include "mozilla/layers/LayerManagerComposite.h"  // for LayerComposite
 #include "mozilla/layers/LayersMessages.h"  // for TransformFunction, etc
 #include "nsAString.h"
 #include "nsCSSValue.h"                 // for nsCSSValue::Array, etc
 #include "nsPrintfCString.h"            // for nsPrintfCString
 #include "nsStyleStruct.h"              // for nsTimingFunction, etc
 #include "gfxPrefs.h"
 
-using namespace mozilla::layers;
-using namespace mozilla::gfx;
+uint8_t gLayerManagerLayerBuilder;
 
-typedef FrameMetrics::ViewID ViewID;
-const ViewID FrameMetrics::NULL_SCROLL_ID = 0;
-
-uint8_t gLayerManagerLayerBuilder;
+namespace mozilla {
+namespace layers {
 
 FILE*
 FILEOrDefault(FILE* aFile)
 {
   return aFile ? aFile : stderr;
 }
 
-namespace mozilla {
-namespace layers {
+typedef FrameMetrics::ViewID ViewID;
+const ViewID FrameMetrics::NULL_SCROLL_ID = 0;
+
+using namespace mozilla::gfx;
 
 //--------------------------------------------------
 // LayerManager
 Layer*
 LayerManager::GetPrimaryScrollableLayer()
 {
   if (!mRoot) {
     return nullptr;
@@ -1342,17 +1341,17 @@ Layer::LogSelf(const char* aPrefix)
 }
 
 nsACString&
 Layer::PrintInfo(nsACString& aTo, const char* aPrefix)
 {
   aTo += aPrefix;
   aTo += nsPrintfCString("%s%s (0x%p)", mManager->Name(), Name(), this);
 
-  ::PrintInfo(aTo, AsLayerComposite());
+  layers::PrintInfo(aTo, AsLayerComposite());
 
   if (mUseClipRect) {
     AppendToString(aTo, mClipRect, " [clip=", "]");
   }
   if (1.0 != mPostXScale || 1.0 != mPostYScale) {
     aTo.AppendPrintf(" [postScale=%g, %g]", mPostXScale, mPostYScale);
   }
   if (!mTransform.IsIdentity()) {
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -121,21 +121,21 @@ WidgetModifiersToDOMModifiers(mozilla::M
   if (aModifiers & mozilla::MODIFIER_OS) {
     result |= nsIDOMWindowUtils::MODIFIER_OS;
   }
   return result;
 }
 
 }
 
-using namespace mozilla::css;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::css;
+
 typedef mozilla::layers::AllowedTouchBehavior AllowedTouchBehavior;
 typedef GeckoContentController::APZStateChange APZStateChange;
 
 /*
  * The following prefs are used to control the behaviour of the APZC.
  * The default values are provided in gfxPrefs.h.
  *
  * "apz.allow-checkerboarding"
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -46,22 +46,21 @@
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion, etc
 #include "nsTArray.h"                   // for nsAutoTArray
 #define PIXMAN_DONT_DEFINE_STDINT
 #include "pixman.h"                     // for pixman_f_transform, etc
 
 class nsIWidget;
 
-using namespace mozilla::dom;
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 /**
  * Clips to the smallest device-pixel-aligned rectangle containing aRect
  * in user space.
  * Returns true if the clip is "perfect", i.e. we actually clipped exactly to
  * aRect.
  */
 static bool
 ClipToContain(gfxContext* aContext, const nsIntRect& aRect)
--- a/gfx/layers/basic/BasicLayersImpl.cpp
+++ b/gfx/layers/basic/BasicLayersImpl.cpp
@@ -8,21 +8,21 @@
 #include "Layers.h"                     // for Layer, etc
 #include "basic/BasicImplData.h"        // for BasicImplData
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/DebugOnly.h"          // for DebugOnly
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "AutoMaskData.h"
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 bool
 GetMaskData(Layer* aMaskLayer,
             const Point& aDeviceOffset,
             AutoMoz2DMaskData* aMaskData)
 {
   if (aMaskLayer) {
     RefPtr<SourceSurface> surface =
       static_cast<BasicImplData*>(aMaskLayer->ImplData())->GetAsSourceSurface();
--- a/gfx/layers/basic/BasicThebesLayer.cpp
+++ b/gfx/layers/basic/BasicThebesLayer.cpp
@@ -23,21 +23,21 @@
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsISupportsImpl.h"            // for gfxContext::Release, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl
 #include "AutoMaskData.h"
 #include "gfx2DGlue.h"
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 static nsIntRegion
 IntersectWithClip(const nsIntRegion& aRegion, gfxContext* aContext)
 {
   gfxRect clip = aContext->GetClipExtents();
   clip.RoundOut();
   nsIntRect r(clip.X(), clip.Y(), clip.Width(), clip.Height());
   nsIntRegion result;
   result.And(aRegion, r);
--- a/gfx/layers/basic/X11TextureSourceBasic.cpp
+++ b/gfx/layers/basic/X11TextureSourceBasic.cpp
@@ -3,18 +3,19 @@
  * 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 "X11TextureSourceBasic.h"
 #include "mozilla/layers/BasicCompositor.h"
 #include "gfxXlibSurface.h"
 #include "gfx2DGlue.h"
 
-using namespace mozilla;
-using namespace mozilla::layers;
+namespace mozilla {
+namespace layers {
+
 using namespace mozilla::gfx;
 
 X11TextureSourceBasic::X11TextureSourceBasic(BasicCompositor* aCompositor, gfxXlibSurface* aSurface)
   : mCompositor(aCompositor),
     mSurface(aSurface)
 {
 }
 
@@ -62,8 +63,11 @@ X11TextureSourceBasic::ContentTypeToSurf
     case gfxContentType::ALPHA:
       return SurfaceFormat::A8;
     case gfxContentType::COLOR_ALPHA:
       return SurfaceFormat::B8G8R8A8;
     default:
       return SurfaceFormat::UNKNOWN;
   }
 }
+
+}
+}
--- a/gfx/layers/client/ClientColorLayer.cpp
+++ b/gfx/layers/client/ClientColorLayer.cpp
@@ -8,21 +8,21 @@
 #include "mozilla/layers/LayersMessages.h"  // for ColorLayerAttributes, etc
 #include "mozilla/mozalloc.h"           // for operator new
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsRegion.h"                   // for nsIntRegion
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 class ClientColorLayer : public ColorLayer, 
                          public ClientLayer {
 public:
   ClientColorLayer(ClientLayerManager* aLayerManager) :
     ColorLayer(aLayerManager,
                static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()))
   {
     MOZ_COUNT_CTOR(ClientColorLayer);
--- a/gfx/layers/client/ClientImageLayer.cpp
+++ b/gfx/layers/client/ClientImageLayer.cpp
@@ -13,21 +13,21 @@
 #include "mozilla/layers/LayersMessages.h"  // for ImageLayerAttributes, etc
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr, getter_AddRefs, etc
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsRegion.h"                   // for nsIntRegion
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 class ClientImageLayer : public ImageLayer, 
                          public ClientLayer {
 public:
   ClientImageLayer(ClientLayerManager* aLayerManager)
     : ImageLayer(aLayerManager,
                  static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()))
     , mImageClientTypeContainer(CompositableType::BUFFER_UNKNOWN)
   {
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -27,22 +27,21 @@
 #include "nsTArray.h"                   // for AutoInfallibleTArray
 #include "nsXULAppAPI.h"                // for XRE_GetProcessType, etc
 #include "TiledLayerBuffer.h"
 #include "mozilla/dom/WindowBinding.h"  // for Overfill Callback
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
 #endif
 
-using namespace mozilla::dom;
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
   : mPhase(PHASE_NONE)
   , mWidget(aWidget)
   , mTargetRotation(ROTATION_0)
   , mRepeatTransaction(false)
   , mIsRepeatTransaction(false)
   , mTransactionIncomplete(false)
   , mCompositorMightResample(false)
@@ -126,18 +125,18 @@ ClientLayerManager::BeginTransactionWith
   mPhase = PHASE_CONSTRUCTION;
 
   NS_ABORT_IF_FALSE(mKeepAlive.IsEmpty(), "uncommitted txn?");
   nsRefPtr<gfxContext> targetContext = aTarget;
 
   // If the last transaction was incomplete (a failed DoEmptyTransaction),
   // don't signal a new transaction to ShadowLayerForwarder. Carry on adding
   // to the previous transaction.
-  ScreenOrientation orientation;
-  if (TabChild* window = mWidget->GetOwningTabChild()) {
+  dom::ScreenOrientation orientation;
+  if (dom::TabChild* window = mWidget->GetOwningTabChild()) {
     orientation = window->GetOrientation();
   } else {
     hal::ScreenConfiguration currentConfig;
     hal::GetCurrentScreenConfiguration(&currentConfig);
     orientation = currentConfig.orientation();
   }
   nsIntRect clientBounds;
   mWidget->GetClientBounds(clientBounds);
@@ -145,17 +144,17 @@ ClientLayerManager::BeginTransactionWith
   mForwarder->BeginTransaction(mTargetBounds, mTargetRotation, clientBounds, orientation);
 
   // If we're drawing on behalf of a context with async pan/zoom
   // enabled, then the entire buffer of thebes layers might be
   // composited (including resampling) asynchronously before we get
   // a chance to repaint, so we have to ensure that it's all valid
   // and not rotated.
   if (mWidget) {
-    if (TabChild* window = mWidget->GetOwningTabChild()) {
+    if (dom::TabChild* window = mWidget->GetOwningTabChild()) {
       mCompositorMightResample = window->IsAsyncPanZoomEnabled();
     }
   }
 
   // If we have a non-default target, we need to let our shadow manager draw
   // to it. This will happen at the end of the transaction.
   if (aTarget && XRE_GetProcessType() == GeckoProcessType_Default) {
     mShadowTarget = aTarget;
--- a/gfx/layers/client/ClientThebesLayer.cpp
+++ b/gfx/layers/client/ClientThebesLayer.cpp
@@ -20,21 +20,21 @@
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/Preferences.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsRect.h"                     // for nsIntRect
 #include "gfx2DGlue.h"
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 void
 ClientThebesLayer::PaintThebes()
 {
   PROFILER_LABEL("ClientThebesLayer", "PaintThebes");
   NS_ASSERTION(ClientManager()->InDrawing(),
                "Can only draw in drawing phase");
   
   uint32_t flags = RotatedContentBuffer::PAINT_CAN_DRAW_ROTATED;
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -13,21 +13,21 @@
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "mozilla/layers/PCompositableChild.h"
 #ifdef XP_WIN
 #include "gfxWindowsPlatform.h"         // for gfxWindowsPlatform
 #include "mozilla/layers/TextureD3D11.h"
 #include "mozilla/layers/TextureD3D9.h"
 #endif
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 /**
  * IPDL actor used by CompositableClient to match with its corresponding
  * CompositableHost on the compositor side.
  *
  * CompositableChild is owned by a CompositableClient.
  */
 class CompositableChild : public PCompositableChild
                         , public AsyncTransactionTrackersHolder
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -31,21 +31,21 @@
 #include "nsDebug.h"                    // for NS_WARNING, NS_ASSERTION
 #include "nsISupportsImpl.h"            // for Image::Release, etc
 #include "nsRect.h"                     // for nsIntRect
 #include "mozilla/gfx/2D.h"
 #ifdef MOZ_WIDGET_GONK
 #include "GrallocImages.h"
 #endif
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 /**
  * Handle RemoveTextureFromCompositableAsync() transaction.
  */
 class RemoveTextureFromCompositableTracker : public AsyncTransactionTracker {
 public:
   RemoveTextureFromCompositableTracker(CompositableClient* aCompositableClient)
     : mCompositableClient(aCompositableClient)
   {
--- a/gfx/layers/client/SimpleTiledContentClient.cpp
+++ b/gfx/layers/client/SimpleTiledContentClient.cpp
@@ -27,21 +27,21 @@
 #include "nsISupportsImpl.h"            // for gfxContext::AddRef, etc
 #include "nsSize.h"                     // for nsIntSize
 #include "gfxReusableSharedImageSurfaceWrapper.h"
 #include "nsMathUtils.h"               // for NS_roundf
 #include "gfx2DGlue.h"
 
 #define ALOG(...)  __android_log_print(ANDROID_LOG_INFO, "SimpleTiles", __VA_ARGS__)
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 void
 SimpleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
                                     const nsIntRegion& aPaintRegion,
                                     LayerManager::DrawThebesLayerCallback aCallback,
                                     void* aCallbackData)
 {
   mCallback = aCallback;
   mCallbackData = aCallbackData;
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -53,22 +53,23 @@
 #endif
 
 #if 0
 #define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__)
 #else
 #define RECYCLE_LOG(...) do { } while (0)
 #endif
 
+namespace mozilla {
+namespace layers {
+
+using namespace mozilla::ipc;
 using namespace mozilla::gl;
 using namespace mozilla::gfx;
 
-namespace mozilla {
-namespace layers {
-
 /**
  * TextureChild is the content-side incarnation of the PTexture IPDL actor.
  *
  * TextureChild is used to synchronize a texture client and its corresponding
  * TextureHost if needed (a TextureClient that is not shared with the compositor
  * does not have a TextureChild)
  *
  * During the deallocation phase, a TextureChild may hold its recently destroyed
@@ -434,17 +435,17 @@ ShmemTextureClient::ToSurfaceDescriptor(
 
   return true;
 }
 
 bool
 ShmemTextureClient::Allocate(uint32_t aSize)
 {
   MOZ_ASSERT(mValid);
-  ipc::SharedMemory::SharedMemoryType memType = OptimalShmemType();
+  SharedMemory::SharedMemoryType memType = OptimalShmemType();
   mAllocated = GetAllocator()->AllocUnsafeShmem(aSize, memType, &mShmem);
   return mAllocated;
 }
 
 uint8_t*
 ShmemTextureClient::GetBuffer() const
 {
   MOZ_ASSERT(IsValid());
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -36,29 +36,28 @@
 #if defined(MOZ_WIDGET_ANDROID)
 # include <android/log.h>
 # include "AndroidBridge.h"
 #endif
 #include "GeckoProfiler.h"
 
 struct nsCSSValueSharedList;
 
-using namespace mozilla::dom;
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 enum Op { Resolve, Detach };
 
 static bool
-IsSameDimension(ScreenOrientation o1, ScreenOrientation o2)
+IsSameDimension(dom::ScreenOrientation o1, dom::ScreenOrientation o2)
 {
-  bool isO1portrait = (o1 == eScreenOrientation_PortraitPrimary || o1 == eScreenOrientation_PortraitSecondary);
-  bool isO2portrait = (o2 == eScreenOrientation_PortraitPrimary || o2 == eScreenOrientation_PortraitSecondary);
+  bool isO1portrait = (o1 == dom::eScreenOrientation_PortraitPrimary || o1 == dom::eScreenOrientation_PortraitSecondary);
+  bool isO2portrait = (o2 == dom::eScreenOrientation_PortraitPrimary || o2 == dom::eScreenOrientation_PortraitSecondary);
   return !(isO1portrait ^ isO2portrait);
 }
 
 static bool
 ContentMightReflowOnOrientationChange(const nsIntRect& rect)
 {
   return rect.width != rect.height;
 }
@@ -68,18 +67,18 @@ static void
 WalkTheTree(Layer* aLayer,
             bool& aReady,
             const TargetConfig& aTargetConfig)
 {
   if (RefLayer* ref = aLayer->AsRefLayer()) {
     if (const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(ref->GetReferentId())) {
       if (Layer* referent = state->mRoot) {
         if (!ref->GetVisibleRegion().IsEmpty()) {
-          ScreenOrientation chromeOrientation = aTargetConfig.orientation();
-          ScreenOrientation contentOrientation = state->mTargetConfig.orientation();
+          dom::ScreenOrientation chromeOrientation = aTargetConfig.orientation();
+          dom::ScreenOrientation contentOrientation = state->mTargetConfig.orientation();
           if (!IsSameDimension(chromeOrientation, contentOrientation) &&
               ContentMightReflowOnOrientationChange(aTargetConfig.clientBounds())) {
             aReady = false;
           }
         }
 
         if (OP == Resolve) {
           ref->ConnectReferentLayer(referent);
--- a/gfx/layers/composite/CanvasLayerComposite.cpp
+++ b/gfx/layers/composite/CanvasLayerComposite.cpp
@@ -15,18 +15,19 @@
 #include "mozilla/layers/Effects.h"     // for EffectChain
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAString.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsString.h"                   // for nsAutoCString
 
-using namespace mozilla;
-using namespace mozilla::layers;
+namespace mozilla {
+namespace layers {
+
 using namespace mozilla::gfx;
 
 CanvasLayerComposite::CanvasLayerComposite(LayerManagerComposite* aManager)
   : CanvasLayer(aManager, nullptr)
   , LayerComposite(aManager)
   , mImageHost(nullptr)
 {
   MOZ_COUNT_CTOR(CanvasLayerComposite);
@@ -139,8 +140,10 @@ CanvasLayerComposite::PrintInfo(nsACStri
   if (mImageHost && mImageHost->IsAttached()) {
     nsAutoCString pfx(aPrefix);
     pfx += "  ";
     mImageHost->PrintInfo(aTo, pfx.get());
   }
   return aTo;
 }
 
+}
+}
--- a/gfx/layers/composite/ImageLayerComposite.cpp
+++ b/gfx/layers/composite/ImageLayerComposite.cpp
@@ -20,21 +20,21 @@
 #include "nsAString.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsString.h"                   // for nsAutoCString
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 ImageLayerComposite::ImageLayerComposite(LayerManagerComposite* aManager)
   : ImageLayer(aManager, nullptr)
   , LayerComposite(aManager)
   , mImageHost(nullptr)
 {
   MOZ_COUNT_CTOR(ImageLayerComposite);
   mImplData = static_cast<LayerComposite*>(this);
 }
--- a/gfx/layers/composite/X11TextureHost.cpp
+++ b/gfx/layers/composite/X11TextureHost.cpp
@@ -8,18 +8,19 @@
 #include "mozilla/layers/X11TextureSourceBasic.h"
 #ifdef GL_PROVIDER_GLX
 #include "mozilla/layers/CompositorOGL.h"
 #include "mozilla/layers/X11TextureSourceOGL.h"
 #endif
 #include "gfxXlibSurface.h"
 #include "gfx2DGlue.h"
 
-using namespace mozilla;
-using namespace mozilla::layers;
+namespace mozilla {
+namespace layers {
+
 using namespace mozilla::gfx;
 
 X11TextureHost::X11TextureHost(TextureFlags aFlags,
                                const SurfaceDescriptorX11& aDescriptor)
  : TextureHost(aFlags)
 {
   nsRefPtr<gfxXlibSurface> surface = aDescriptor.OpenForeign();
   mSurface = surface.get();
@@ -79,8 +80,11 @@ X11TextureHost::GetFormat() const
   return X11TextureSourceBasic::ContentTypeToSurfaceFormat(type);
 }
 
 IntSize
 X11TextureHost::GetSize() const
 {
   return ToIntSize(mSurface->GetSize());
 }
+
+}
+}
--- a/gfx/layers/d3d10/CanvasLayerD3D10.cpp
+++ b/gfx/layers/d3d10/CanvasLayerD3D10.cpp
@@ -10,22 +10,22 @@
 #include "gfxWindowsPlatform.h"
 #include "SurfaceStream.h"
 #include "SharedSurfaceANGLE.h"
 #include "SharedSurfaceGL.h"
 #include "gfxContext.h"
 #include "GLContext.h"
 #include "gfxPrefs.h"
 
+namespace mozilla {
+namespace layers {
+
 using namespace mozilla::gl;
 using namespace mozilla::gfx;
 
-namespace mozilla {
-namespace layers {
-
 CanvasLayerD3D10::CanvasLayerD3D10(LayerManagerD3D10 *aManager)
   : CanvasLayer(aManager, nullptr)
   , LayerD3D10(aManager)
   , mDataIsPremultiplied(false)
   , mNeedsYFlip(false)
   , mHasAlpha(true)
 {
     mImplData = static_cast<LayerD3D10*>(this);
--- a/gfx/layers/d3d10/ImageLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ImageLayerD3D10.cpp
@@ -9,21 +9,21 @@
 #include "yuv_convert.h"
 #include "../d3d9/Nv3DVUtils.h"
 #include "D3D9SurfaceImage.h"
 #include "mozilla/gfx/Point.h"
 #include "gfx2DGlue.h"
 
 #include "gfxWindowsPlatform.h"
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 static already_AddRefed<ID3D10Texture2D>
 DataToTexture(ID3D10Device *aDevice,
               unsigned char *data,
               int stride,
               const IntSize &aSize)
 {
   D3D10_SUBRESOURCE_DATA srdata;
 
--- a/gfx/layers/d3d10/LayerManagerD3D10.cpp
+++ b/gfx/layers/d3d10/LayerManagerD3D10.cpp
@@ -26,23 +26,22 @@
 #include "../d3d9/Nv3DVUtils.h"
 
 #include "gfxCrashReporterUtils.h"
 #include "nsWindowsHelpers.h"
 #ifdef MOZ_METRO
 #include "DXGI1_2.h"
 #endif
 
-using namespace std;
-using namespace mozilla::dom;
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace std;
+using namespace mozilla::gfx;
+
 struct Vertex
 {
     float position[2];
 };
 
 // {592BF306-0EED-4F76-9D03-A0846450F472}
 static const GUID sDeviceAttachments = 
 { 0x592bf306, 0xeed, 0x4f76, { 0x9d, 0x3, 0xa0, 0x84, 0x64, 0x50, 0xf4, 0x72 } };
--- a/gfx/layers/d3d10/ThebesLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ThebesLayerD3D10.cpp
@@ -21,21 +21,21 @@
 #include "gfxTeeSurface.h"
 #include "gfxUtils.h"
 #include "ReadbackLayer.h"
 #include "ReadbackProcessor.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/gfx/2D.h"
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 ThebesLayerD3D10::ThebesLayerD3D10(LayerManagerD3D10 *aManager)
   : ThebesLayer(aManager, nullptr)
   , LayerD3D10(aManager)
   , mCurrentSurfaceMode(SurfaceMode::SURFACE_OPAQUE)
 {
   mImplData = static_cast<LayerD3D10*>(this);
 }
 
--- a/gfx/layers/d3d9/CompositorD3D9.cpp
+++ b/gfx/layers/d3d9/CompositorD3D9.cpp
@@ -12,21 +12,21 @@
 #include "mozilla/layers/Effects.h"
 #include "nsWindowsHelpers.h"
 #include "Nv3DVUtils.h"
 #include "gfxFailure.h"
 #include "mozilla/layers/PCompositorParent.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "gfxPrefs.h"
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 CompositorD3D9::CompositorD3D9(PCompositorParent* aParent, nsIWidget *aWidget)
   : Compositor(aParent)
   , mWidget(aWidget)
   , mDeviceResetCount(0)
 {
   Compositor::SetBackend(LayersBackend::LAYERS_D3D9);
 }
 
--- a/gfx/layers/d3d9/DeviceManagerD3D9.cpp
+++ b/gfx/layers/d3d9/DeviceManagerD3D9.cpp
@@ -13,21 +13,21 @@
 #include "plstr.h"
 #include <algorithm>
 #include "gfx2DGlue.h"
 #include "gfxPlatform.h"
 #include "gfxWindowsPlatform.h"
 #include "TextureD3D9.h"
 #include "mozilla/gfx/Point.h"
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 const LPCWSTR kClassName       = L"D3D9WindowClass";
 
 #define USE_D3D9EX
 
 struct vertex {
   float x, y;
 };
 
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -49,25 +49,24 @@
 #include "mozilla/layers/CompositorD3D9.h"
 #endif
 #include "GeckoProfiler.h"
 #include "mozilla/ipc/ProtocolTypes.h"
 #include "mozilla/unused.h"
 #include "mozilla/Hal.h"
 #include "mozilla/HalTypes.h"
 
+namespace mozilla {
+namespace layers {
+
 using namespace base;
-using namespace mozilla;
 using namespace mozilla::ipc;
 using namespace mozilla::gfx;
 using namespace std;
 
-namespace mozilla {
-namespace layers {
-
 CompositorParent::LayerTreeState::LayerTreeState()
   : mParent(nullptr)
   , mLayerManager(nullptr)
   , mCrossProcessParent(nullptr)
 {
 }
 
 typedef map<uint64_t, CompositorParent::LayerTreeState> LayerTreeMap;
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -36,28 +36,28 @@
 #include "nsTArrayForwardDeclare.h"     // for AutoInfallibleTArray
 #include "nsThreadUtils.h"              // for NS_IsMainThread
 #include "nsXULAppAPI.h"                // for XRE_GetIOMessageLoop
 #include "mozilla/StaticPtr.h"          // for StaticRefPtr
 #include "mozilla/layers/TextureClient.h"
 
 struct nsIntRect;
 
-using base::Thread;
-using base::ProcessHandle;
-using namespace mozilla::ipc;
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace ipc {
 class Shmem;
 }
 
 namespace layers {
 
+using base::Thread;
+using base::ProcessHandle;
+using namespace mozilla::ipc;
+using namespace mozilla::gfx;
+
 typedef std::vector<CompositableOperation> OpVector;
 
 struct CompositableTransaction
 {
   CompositableTransaction()
   : mSwapRequired(false)
   , mFinished(true)
   {}
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -30,22 +30,22 @@
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT, etc
 #include "nsISupportsImpl.h"            // for ImageBridgeParent::Release, etc
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl
 #include "nsTArrayForwardDeclare.h"     // for InfallibleTArray
 #include "nsXULAppAPI.h"                // for XRE_GetIOMessageLoop
 #include "mozilla/layers/TextureHost.h"
 #include "nsThreadUtils.h"
 
+namespace mozilla {
+namespace layers {
+
 using namespace mozilla::ipc;
 using namespace mozilla::gfx;
 
-namespace mozilla {
-namespace layers {
-
 ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop, Transport* aTransport)
   : mMessageLoop(aLoop)
   , mTransport(aTransport)
 {
   // creates the map only if it has not been created already, so it is safe
   // with several bridges
   CompositableMap::Create();
 }
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -31,27 +31,26 @@
 #include "nsDebug.h"                    // for NS_ABORT_IF_FALSE, etc
 #include "nsRect.h"                     // for nsIntRect
 #include "nsSize.h"                     // for nsIntSize
 #include "nsTArray.h"                   // for nsAutoTArray, nsTArray, etc
 #include "nsXULAppAPI.h"                // for XRE_GetProcessType, etc
 
 struct nsIntPoint;
 
-using namespace mozilla::ipc;
-using namespace mozilla::gl;
-using namespace mozilla::dom;
-
 namespace mozilla {
 namespace ipc {
 class Shmem;
 }
 
 namespace layers {
 
+using namespace mozilla::ipc;
+using namespace mozilla::gl;
+
 class ClientTiledLayerBuffer;
 
 typedef nsTArray<SurfaceDescriptor> BufferArray;
 typedef std::vector<Edit> EditVector;
 typedef std::set<ShadowableLayer*> ShadowableLayerSet;
 
 class Transaction
 {
@@ -59,17 +58,17 @@ public:
   Transaction()
     : mTargetRotation(ROTATION_0)
     , mSwapRequired(false)
     , mOpen(false)
     , mRotationChanged(false)
   {}
 
   void Begin(const nsIntRect& aTargetBounds, ScreenRotation aRotation,
-             const nsIntRect& aClientBounds, ScreenOrientation aOrientation)
+             const nsIntRect& aClientBounds, dom::ScreenOrientation aOrientation)
   {
     mOpen = true;
     mTargetBounds = aTargetBounds;
     if (aRotation != mTargetRotation) {
       // the first time this is called, mRotationChanged will be false if
       // aRotation is 0, but we should be OK because for the first transaction
       // we should only compose if it is non-empty. See the caller(s) of
       // RotationChanged.
@@ -137,17 +136,17 @@ public:
   bool Finished() const { return !mOpen && Empty(); }
 
   EditVector mCset;
   EditVector mPaints;
   ShadowableLayerSet mMutants;
   nsIntRect mTargetBounds;
   ScreenRotation mTargetRotation;
   nsIntRect mClientBounds;
-  ScreenOrientation mTargetOrientation;
+  dom::ScreenOrientation mTargetOrientation;
   bool mSwapRequired;
 
 private:
   bool mOpen;
   bool mRotationChanged;
 
   // disabled
   Transaction(const Transaction&);
@@ -182,17 +181,17 @@ ShadowLayerForwarder::~ShadowLayerForwar
     mShadowManager->Destroy();
   }
 }
 
 void
 ShadowLayerForwarder::BeginTransaction(const nsIntRect& aTargetBounds,
                                        ScreenRotation aRotation,
                                        const nsIntRect& aClientBounds,
-                                       ScreenOrientation aOrientation)
+                                       dom::ScreenOrientation aOrientation)
 {
   NS_ABORT_IF_FALSE(HasShadowManager(), "no manager to forward to");
   NS_ABORT_IF_FALSE(mTxn->Finished(), "uncommitted txn?");
   mTxn->Begin(aTargetBounds, aRotation, aClientBounds, aOrientation);
 }
 
 static PLayerChild*
 Shadow(ShadowableLayer* aLayer)
--- a/gfx/layers/ipc/SharedBufferManagerChild.cpp
+++ b/gfx/layers/ipc/SharedBufferManagerChild.cpp
@@ -17,21 +17,21 @@
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "SBMChild", ## args)
 #endif
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace layers {
 
+using namespace mozilla::gfx;
+
 // Singleton
 SharedBufferManagerChild* SharedBufferManagerChild::sSharedBufferManagerChildSingleton = nullptr;
 SharedBufferManagerParent* SharedBufferManagerChild::sSharedBufferManagerParentSingleton = nullptr;
 base::Thread* SharedBufferManagerChild::sSharedBufferManagerChildThread = nullptr;
 
 SharedBufferManagerChild::SharedBufferManagerChild()
 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
   : mBufferMutex("BufferMonitor")
--- a/gfx/layers/opengl/CompositingRenderTargetOGL.cpp
+++ b/gfx/layers/opengl/CompositingRenderTargetOGL.cpp
@@ -3,20 +3,21 @@
  * 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 "CompositingRenderTargetOGL.h"
 #include "GLContext.h"
 #include "GLReadTexImageHelper.h"
 #include "mozilla/gfx/2D.h"
 
-using namespace mozilla;
+namespace mozilla {
+namespace layers {
+
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
-using namespace mozilla::layers;
 
 CompositingRenderTargetOGL::~CompositingRenderTargetOGL()
 {
   mGL->fDeleteTextures(1, &mTextureHandle);
   mGL->fDeleteFramebuffers(1, &mFBO);
 }
 
 void
@@ -95,8 +96,11 @@ CompositingRenderTargetOGL::InitializeIm
   mGL->fScissor(0, 0, mInitParams.mSize.width, mInitParams.mSize.height);
   if (mInitParams.mInit == INIT_MODE_CLEAR) {
     mGL->fClearColor(0.0, 0.0, 0.0, 0.0);
     mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
   }
 
   mInitParams.mStatus = InitParams::INITIALIZED;
 }
+
+}
+}
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -35,17 +35,16 @@
 #include "nsAString.h"
 #include "nsIConsoleService.h"          // for nsIConsoleService, etc
 #include "nsIWidget.h"                  // for nsIWidget
 #include "nsLiteralString.h"            // for NS_LITERAL_STRING
 #include "nsMathUtils.h"                // for NS_roundf
 #include "nsRect.h"                     // for nsIntRect
 #include "nsServiceManagerUtils.h"      // for do_GetService
 #include "nsString.h"                   // for nsString, nsAutoCString, etc
-#include "DecomposeIntoNoRepeatTriangles.h"
 #include "ScopedGLHelpers.h"
 #include "GLReadTexImageHelper.h"
 #include "TiledLayerBuffer.h"           // for TiledLayerComposer
 #include "HeapCopyOfStackArray.h"
 
 #if MOZ_ANDROID_OMTC
 #include "TexturePoolOGL.h"
 #endif
@@ -77,75 +76,16 @@ BindMaskForProgram(ShaderProgramOGL* aPr
                    GLenum aTexUnit, const gfx::Matrix4x4& aTransform)
 {
   MOZ_ASSERT(LOCAL_GL_TEXTURE0 <= aTexUnit && aTexUnit <= LOCAL_GL_TEXTURE31);
   aSourceMask->BindTexture(aTexUnit, gfx::Filter::LINEAR);
   aProgram->SetMaskTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0);
   aProgram->SetMaskLayerTransform(aTransform);
 }
 
-// Draw the given quads with the already selected shader. Texture coordinates
-// are supplied if the shader requires them.
-static void
-DrawQuads(GLContext *aGLContext,
-          VBOArena &aVBOs,
-          ShaderProgramOGL *aProg,
-          GLenum aMode,
-          RectTriangles &aRects)
-{
-  NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
-  GLuint vertAttribIndex =
-    aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
-  GLuint texCoordAttribIndex =
-    aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
-  bool texCoords = (texCoordAttribIndex != GLuint(-1));
-
-  GLsizei bytes = aRects.elements() * 2 * sizeof(GLfloat);
-
-  GLsizei total = bytes;
-  if (texCoords) {
-    total *= 2;
-  }
-
-  aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER,
-                          aVBOs.Allocate(aGLContext));
-  aGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
-                          total,
-                          nullptr,
-                          LOCAL_GL_STREAM_DRAW);
-
-  aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
-                             0,
-                             bytes,
-                             aRects.vertCoords().Elements());
-  aGLContext->fEnableVertexAttribArray(vertAttribIndex);
-  aGLContext->fVertexAttribPointer(vertAttribIndex,
-                                   2, LOCAL_GL_FLOAT,
-                                   LOCAL_GL_FALSE,
-                                   0, BUFFER_OFFSET(0));
-
-  if (texCoords) {
-    aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
-                               bytes,
-                               bytes,
-                               aRects.texCoords().Elements());
-    aGLContext->fEnableVertexAttribArray(texCoordAttribIndex);
-    aGLContext->fVertexAttribPointer(texCoordAttribIndex,
-                                     2, LOCAL_GL_FLOAT,
-                                     LOCAL_GL_FALSE,
-                                     0, BUFFER_OFFSET(bytes));
-  } else {
-    aGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
-  }
-
-  aGLContext->fDrawArrays(aMode, 0, aRects.elements());
-
-  aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
-}
-
 CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
                              int aSurfaceHeight, bool aUseExternalSurfaceSize)
   : mWidget(aWidget)
   , mWidgetSize(-1, -1)
   , mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
   , mHasBGRA(0)
   , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
   , mFrameInProgress(false)
@@ -402,98 +342,187 @@ CompositorOGL::Initialize()
       msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE");
     console->LogStringMessage(msg.get());
   }
 
   reporter.SetSuccessful();
   return true;
 }
 
-// |aTextureTransform| is the texture transform that will be set on
-// aProg, possibly multiplied with another texture transform of our
-// own.
-// |aTexCoordRect| is the rectangle from the texture that we want to
-// draw using the given program.  The program already has a necessary
-// offset and scale, so the geometry that needs to be drawn is a unit
-// square from 0,0 to 1,1.
-//
-// |aTexture| is the texture we are drawing. Its actual size can be
-// larger than the rectangle given by |aTexCoordRect|.
-void
-CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
-                                              const Rect& aRect,
-                                              const gfx3DMatrix& aTextureTransform,
-                                              const Rect& aTexCoordRect,
-                                              TextureSource *aTexture)
+static GLfloat
+WrapTexCoord(GLfloat v)
 {
-  // Given what we know about these textures and coordinates, we can
-  // compute fmod(t, 1.0f) to get the same texture coordinate out.  If
-  // the texCoordRect dimension is < 0 or > width/height, then we have
-  // wraparound that we need to deal with by drawing multiple quads,
-  // because we can't rely on full non-power-of-two texture support
-  // (which is required for the REPEAT wrap mode).
+    // fmodf gives negative results for negative numbers;
+    // that is, fmodf(0.75, 1.0) == 0.75, but
+    // fmodf(-0.75, 1.0) == -0.75.  For the negative case,
+    // the result we need is 0.25, so we add 1.0f.
+    if (v < 0.0f) {
+        return 1.0f + fmodf(v, 1.0f);
+    }
 
-  RectTriangles rects;
-
-  GLenum wrapMode = aTexture->AsSourceOGL()->GetWrapMode();
+    return fmodf(v, 1.0f);
+}
 
-  IntSize realTexSize = aTexture->GetSize();
-  if (!CanUploadNonPowerOfTwo(mGLContext)) {
-    realTexSize = IntSize(NextPowerOfTwo(realTexSize.width),
-                          NextPowerOfTwo(realTexSize.height));
+static void
+SetRects(int n,
+         Rect* aLayerRects,
+         Rect* aTextureRects,
+         GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1,
+         GLfloat tx0, GLfloat ty0, GLfloat tx1, GLfloat ty1,
+         bool flip_y /* = false */)
+{
+  if (flip_y) {
+    std::swap(ty0, ty1);
   }
+  aLayerRects[n] = Rect(x0, y0, x1 - x0, y1 - y0);
+  aTextureRects[n] = Rect(tx0, ty0, tx1 - tx0, ty1 - ty0);
+}
 
-  // We need to convert back to actual texels here to get proper behaviour with
-  // our GL helper functions. Should fix this sometime.
-  // I want to vomit.
-  IntRect texCoordRect = IntRect(NS_roundf(aTexCoordRect.x * aTexture->GetSize().width),
-                                 NS_roundf(aTexCoordRect.y * aTexture->GetSize().height),
-                                 NS_roundf(aTexCoordRect.width * aTexture->GetSize().width),
-                                 NS_roundf(aTexCoordRect.height * aTexture->GetSize().height));
+static int
+DecomposeIntoNoRepeatRects(const Rect& aRect,
+                           const Rect& aTexCoordRect,
+                           Rect* aLayerRects,
+                           Rect* aTextureRects)
+{
+  Rect texCoordRect = aTexCoordRect;
 
-  // This is fairly disgusting - if the texture should be flipped it will have a
-  // negative height, in which case we un-invert the texture coords and pass the
-  // flipped 'flag' to the functions below. We can't just use the inverted coords
-  // because our GL funtions use an explicit flag.
+  // If the texture should be flipped, it will have negative height. Detect that
+  // here and compensate for it. We will flip each rect as we emit it.
   bool flipped = false;
   if (texCoordRect.height < 0) {
     flipped = true;
     texCoordRect.y = texCoordRect.YMost();
     texCoordRect.height = -texCoordRect.height;
   }
 
-  if (wrapMode == LOCAL_GL_REPEAT) {
-    rects.addRect(/* dest rectangle */
-                  0.0f, 0.0f, 1.0f, 1.0f,
-                  /* tex coords */
-                  texCoordRect.x / GLfloat(realTexSize.width),
-                  texCoordRect.y / GLfloat(realTexSize.height),
-                  texCoordRect.XMost() / GLfloat(realTexSize.width),
-                  texCoordRect.YMost() / GLfloat(realTexSize.height),
-                  flipped);
-  } else {
-    nsIntRect tcRect(texCoordRect.x, texCoordRect.y,
-                     texCoordRect.width, texCoordRect.height);
-    DecomposeIntoNoRepeatTriangles(tcRect,
-                                   nsIntSize(realTexSize.width, realTexSize.height),
-                                   rects, flipped);
+  Point tl = texCoordRect.TopLeft();
+  Point br = texCoordRect.BottomRight();
+
+  // Chen check if we wrap in either the x or y axis; if we do,
+  // then also use fmod to figure out the "true" non-wrapping
+  // texture coordinates.
+  bool xwrap = false, ywrap = false;
+
+  if (texCoordRect.x < 0 ||
+      texCoordRect.x > 1.0f ||
+      texCoordRect.XMost() < 0 ||
+      texCoordRect.XMost() > 1.0f) {
+    xwrap = true;
+    tl = Point(WrapTexCoord(tl.x), tl.y);
+    br = Point(WrapTexCoord(br.x), br.y);
+  }
+
+  if (texCoordRect.y < 0 ||
+      texCoordRect.y > 1.0f ||
+      texCoordRect.YMost() < 0 ||
+      texCoordRect.YMost() > 1.0f) {
+    ywrap = true;
+    tl = Point(tl.x, WrapTexCoord(tl.y));
+    br = Point(br.x, WrapTexCoord(br.y));
+  }
+
+  NS_ASSERTION(tl.x >= 0.0f && tl.x <= 1.0f &&
+               tl.y >= 0.0f && tl.y <= 1.0f &&
+               br.x >= 0.0f && br.x <= 1.0f &&
+               br.y >= 0.0f && br.y <= 1.0f,
+               "Somehow generated invalid texture coordinates");
+
+  // If xwrap is false, the texture will be sampled from tl.x
+  // .. br.x.  If xwrap is true, then it will be split into tl.x
+  // .. 1.0, and 0.0 .. br.x.  Same for the Y axis.  The
+  // destination rectangle is also split appropriately, according
+  // to the calculated xmid/ymid values.
+
+  // There isn't a 1:1 mapping between tex coords and destination coords;
+  // when computing midpoints, we have to take that into account.  We
+  // need to map the texture coords, which are (in the wrap case):
+  // |tl->1| and |0->br| to the |0->1| range of the vertex coords.  So
+  // we have the length (1-tl)+(br) that needs to map into 0->1.
+  // These are only valid if there is wrap involved, they won't be used
+  // otherwise.
+  GLfloat xlen = (1.0f - tl.x) + br.x;
+  GLfloat ylen = (1.0f - tl.y) + br.y;
+
+  NS_ASSERTION(!xwrap || xlen > 0.0f, "xlen isn't > 0, what's going on?");
+  NS_ASSERTION(!ywrap || ylen > 0.0f, "ylen isn't > 0, what's going on?");
+
+  if (!xwrap && !ywrap) {
+    SetRects(0, aLayerRects, aTextureRects,
+             aRect.x, aRect.y, aRect.XMost(), aRect.YMost(),
+             tl.x, tl.y, br.x, br.y,
+             flipped);
+    return 1;
   }
 
-  gfx3DMatrix textureTransform;
-  if (rects.isSimpleQuad(textureTransform)) {
-    Matrix4x4 transform;
-    ToMatrix4x4(aTextureTransform * textureTransform, transform);
-    aProg->SetTextureTransform(transform);
-    BindAndDrawQuad(aProg, aRect);
-  } else {
-    Matrix4x4 transform;
-    ToMatrix4x4(aTextureTransform, transform);
-    aProg->SetTextureTransform(transform);
-    aProg->SetLayerQuadRect(aRect);
-    DrawQuads(mGLContext, mVBOs, aProg, LOCAL_GL_TRIANGLES, rects);
+  GLfloat xmid = aRect.x + (1.0f - tl.x) / xlen * aRect.width;
+  GLfloat ymid = aRect.y + (1.0f - tl.y) / ylen * aRect.height;
+
+  if (!xwrap && ywrap) {
+    SetRects(0, aLayerRects, aTextureRects,
+             aRect.x, aRect.y, aRect.XMost(), ymid,
+             tl.x, tl.y, br.x, 1.0f,
+             flipped);
+    SetRects(1, aLayerRects, aTextureRects,
+             aRect.x, ymid, aRect.XMost(), aRect.YMost(),
+             tl.x, 0.0f, br.x, br.y,
+             flipped);
+    return 2;
+  }
+
+  if (xwrap && !ywrap) {
+    SetRects(0, aLayerRects, aTextureRects,
+             aRect.x, aRect.y, xmid, aRect.YMost(),
+             tl.x, tl.y, 1.0f, br.y,
+             flipped);
+    SetRects(1, aLayerRects, aTextureRects,
+             xmid, aRect.y, aRect.XMost(), aRect.YMost(),
+             0.0f, tl.y, br.x, br.y,
+             flipped);
+    return 2;
+  }
+
+  SetRects(0, aLayerRects, aTextureRects,
+           aRect.x, aRect.y, xmid, ymid,
+           tl.x, tl.y, 1.0f, 1.0f,
+           flipped);
+  SetRects(1, aLayerRects, aTextureRects,
+           xmid, aRect.y, aRect.XMost(), ymid,
+           0.0f, tl.y, br.x, 1.0f,
+           flipped);
+  SetRects(2, aLayerRects, aTextureRects,
+           aRect.x, ymid, xmid, aRect.YMost(),
+           tl.x, 0.0f, 1.0f, br.y,
+           flipped);
+  SetRects(3, aLayerRects, aTextureRects,
+           xmid, ymid, aRect.XMost(), aRect.YMost(),
+           0.0f, 0.0f, br.x, br.y,
+           flipped);
+  return 4;
+}
+
+// |aRect| is the rectangle we want to draw to. We will draw it with
+// up to 4 draw commands if necessary to avoid wrapping.
+// |aTexCoordRect| is the rectangle from the texture that we want to
+// draw using the given program.
+// |aTexture| is the texture we are drawing. Its actual size can be
+// larger than the rectangle given by |texCoordRect|.
+void
+CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
+                                              const Rect& aRect,
+                                              const Rect& aTexCoordRect,
+                                              TextureSource *aTexture)
+{
+  Rect layerRects[4];
+  Rect textureRects[4];
+  int rects = DecomposeIntoNoRepeatRects(aRect,
+                                         aTexCoordRect,
+                                         layerRects,
+                                         textureRects);
+  for (int n = 0; n < rects; ++n) {
+    BindAndDrawQuad(aProg, layerRects[n], textureRects[n]);
   }
 }
 
 void
 CompositorOGL::PrepareViewport(const gfx::IntSize& aSize,
                                const Matrix& aWorldTransform)
 {
   // Set the viewport correctly.
@@ -1050,23 +1079,25 @@ CompositorOGL::DrawQuad(const Rect& aRec
         // pixel-aligned compositing operations. This works around them. This
         // code should not be needed!
         filter = gfx::Filter::POINT;
       }
 #endif
       source->AsSourceOGL()->BindTexture(LOCAL_GL_TEXTURE0, filter);
 
       program->SetTextureUnit(0);
+      Matrix4x4 transform;
+      ToMatrix4x4(textureTransform, transform);
+      program->SetTextureTransform(transform);
 
       if (maskType != MaskType::MaskNone) {
         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
       }
 
-      BindAndDrawQuadWithTextureRect(program, aRect, textureTransform,
-                                     texturedEffect->mTextureCoords, source);
+      BindAndDrawQuadWithTextureRect(program, aRect, texturedEffect->mTextureCoords, source);
     }
     break;
   case EffectTypes::YCBCR: {
       EffectYCbCr* effectYCbCr =
         static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());
       TextureSource* sourceYCbCr = effectYCbCr->mTexture;
       const int Y = 0, Cb = 1, Cr = 2;
       TextureSourceOGL* sourceY =  sourceYCbCr->GetSubSource(Y)->AsSourceOGL();
@@ -1078,24 +1109,24 @@ CompositorOGL::DrawQuad(const Rect& aRec
         return;
       }
 
       sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectYCbCr->mFilter);
       sourceCb->BindTexture(LOCAL_GL_TEXTURE1, effectYCbCr->mFilter);
       sourceCr->BindTexture(LOCAL_GL_TEXTURE2, effectYCbCr->mFilter);
 
       program->SetYCbCrTextureUnits(Y, Cb, Cr);
+      program->SetTextureTransform(Matrix4x4());
 
       if (maskType != MaskType::MaskNone) {
         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE3, maskQuadTransform);
       }
       didSetBlendMode = SetBlendMode(gl(), blendMode);
       BindAndDrawQuadWithTextureRect(program,
                                      aRect,
-                                     gfx3DMatrix(),
                                      effectYCbCr->mTextureCoords,
                                      sourceYCbCr->GetSubSource(Y));
     }
     break;
   case EffectTypes::RENDER_TARGET: {
       EffectRenderTarget* effectRenderTarget =
         static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get());
       RefPtr<CompositingRenderTargetOGL> surface
@@ -1143,38 +1174,36 @@ CompositorOGL::DrawQuad(const Rect& aRec
         return;
       }
 
       sourceOnBlack->BindTexture(LOCAL_GL_TEXTURE0, effectComponentAlpha->mFilter);
       sourceOnWhite->BindTexture(LOCAL_GL_TEXTURE1, effectComponentAlpha->mFilter);
 
       program->SetBlackTextureUnit(0);
       program->SetWhiteTextureUnit(1);
-      program->SetTextureTransform(gfx::Matrix4x4());
+      program->SetTextureTransform(Matrix4x4());
 
       if (maskType != MaskType::MaskNone) {
         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform);
       }
       // Pass 1.
       gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR,
                                LOCAL_GL_ONE, LOCAL_GL_ONE);
       program->SetTexturePass2(false);
       BindAndDrawQuadWithTextureRect(program,
                                      aRect,
-                                     gfx3DMatrix(),
                                      effectComponentAlpha->mTextureCoords,
                                      effectComponentAlpha->mOnBlack);
 
       // Pass 2.
       gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE,
                                LOCAL_GL_ONE, LOCAL_GL_ONE);
       program->SetTexturePass2(true);
       BindAndDrawQuadWithTextureRect(program,
                                      aRect,
-                                     gfx3DMatrix(),
                                      effectComponentAlpha->mTextureCoords,
                                      effectComponentAlpha->mOnBlack);
 
       mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
                                      LOCAL_GL_ONE, LOCAL_GL_ONE);
     }
     break;
   default:
@@ -1461,31 +1490,35 @@ CompositorOGL::QuadVBOVerticesAttrib(GLu
 void
 CompositorOGL::QuadVBOTexCoordsAttrib(GLuint aAttribIndex) {
   mGLContext->fVertexAttribPointer(aAttribIndex, 2,
                                     LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
                                     (GLvoid*) QuadVBOTexCoordOffset());
 }
 
 void
-CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg, const Rect& aRect)
+CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg,
+                               const Rect& aLayerRect,
+                               const Rect& aTextureRect)
 {
   NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
 
-  aProg->SetLayerQuadRect(aRect);
+  aProg->SetLayerRect(aLayerRect);
 
   GLuint vertAttribIndex = aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
   GLuint texCoordAttribIndex = aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
 
   BindQuadVBO();
   QuadVBOVerticesAttrib(vertAttribIndex);
 
   if (texCoordAttribIndex != GLuint(-1)) {
     QuadVBOTexCoordsAttrib(texCoordAttribIndex);
     mGLContext->fEnableVertexAttribArray(texCoordAttribIndex);
+
+    aProg->SetTextureRect(aTextureRect);
   }
 
   mGLContext->fEnableVertexAttribArray(vertAttribIndex);
   mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
 }
 
 GLuint
 CompositorOGL::GetTemporaryTexture(GLenum aTarget, GLenum aUnit)
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -364,20 +364,20 @@ private:
 
   GLintptr QuadVBOVertexOffset() { return 0; }
   GLintptr QuadVBOTexCoordOffset() { return sizeof(float)*4*2; }
 
   void BindQuadVBO();
   void QuadVBOVerticesAttrib(GLuint aAttribIndex);
   void QuadVBOTexCoordsAttrib(GLuint aAttribIndex);
   void BindAndDrawQuad(ShaderProgramOGL *aProg,
-                       const gfx::Rect& aRect);
+                       const gfx::Rect& aLayerRect,
+                       const gfx::Rect& aTextureRect = gfx::Rect(0.0f, 0.0f, 1.0f, 1.0f));
   void BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
                                       const gfx::Rect& aRect,
-                                      const gfx3DMatrix& aTextureTransform,
                                       const gfx::Rect& aTexCoordRect,
                                       TextureSource *aTexture);
 
   void CleanupResources();
 
   /**
    * Copies the content of our backbuffer to the set transaction target.
    * Does not restore the target FBO, so only call from EndFrame.
--- a/gfx/layers/opengl/GLManager.cpp
+++ b/gfx/layers/opengl/GLManager.cpp
@@ -38,19 +38,21 @@ public:
     return mImpl->GetShaderProgramFor(config);
   }
 
   virtual const gfx::Matrix4x4& GetProjMatrix() const MOZ_OVERRIDE
   {
     return mImpl->GetProjMatrix();
   }
 
-  virtual void BindAndDrawQuad(ShaderProgramOGL *aProg, const gfx::Rect& aRect) MOZ_OVERRIDE
+  virtual void BindAndDrawQuad(ShaderProgramOGL *aProg,
+                               const gfx::Rect& aLayerRect,
+                               const gfx::Rect& aTextureRect) MOZ_OVERRIDE
   {
-    mImpl->BindAndDrawQuad(aProg, aRect);
+    mImpl->BindAndDrawQuad(aProg, aLayerRect, aTextureRect);
   }
 
 private:
   RefPtr<CompositorOGL> mImpl;
 };
 
 /* static */ GLManager*
 GLManager::CreateGLManager(LayerManagerComposite* aManager)
--- a/gfx/layers/opengl/GLManager.h
+++ b/gfx/layers/opengl/GLManager.h
@@ -28,14 +28,15 @@ class GLManager
 public:
   static GLManager* CreateGLManager(LayerManagerComposite* aManager);
 
   virtual ~GLManager() {}
 
   virtual gl::GLContext* gl() const = 0;
   virtual ShaderProgramOGL* GetProgram(GLenum aTarget, gfx::SurfaceFormat aFormat) = 0;
   virtual const gfx::Matrix4x4& GetProjMatrix() const = 0;
-  virtual void BindAndDrawQuad(ShaderProgramOGL *aProg, const gfx::Rect& aRect) = 0;
+  virtual void BindAndDrawQuad(ShaderProgramOGL *aProg, const gfx::Rect& aLayerRect,
+                               const gfx::Rect& aTextureRect) = 0;
 };
 
 }
 }
 #endif
--- a/gfx/layers/opengl/OGLShaderProgram.cpp
+++ b/gfx/layers/opengl/OGLShaderProgram.cpp
@@ -26,20 +26,21 @@ typedef ProgramProfileOGL::Argument Argu
 #define GAUSSIAN_KERNEL_HALF_WIDTH 11
 #define GAUSSIAN_KERNEL_STEP 0.2
 
 void
 AddUniforms(ProgramProfileOGL& aProfile)
 {
     static const char *sKnownUniformNames[] = {
         "uLayerTransform",
-        "uMaskQuadTransform",
-        "uLayerQuadRect",
+        "uMaskTransform",
+        "uLayerRect",
         "uMatrixProj",
         "uTextureTransform",
+        "uTextureRect",
         "uRenderTargetOffset",
         "uLayerOpacity",
         "uTexture",
         "uYTexture",
         "uCbTexture",
         "uCrTexture",
         "uBlackTexture",
         "uWhiteTexture",
@@ -140,54 +141,56 @@ ShaderConfigOGL::SetPremultiply(bool aEn
 ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
 {
   ProgramProfileOGL result;
   ostringstream fs, vs;
 
   AddUniforms(result);
 
   vs << "uniform mat4 uMatrixProj;" << endl;
-  vs << "uniform vec4 uLayerQuadRect;" << endl;
+  vs << "uniform vec4 uLayerRect;" << endl;
   vs << "uniform mat4 uLayerTransform;" << endl;
   vs << "uniform vec4 uRenderTargetOffset;" << endl;
 
   vs << "attribute vec4 aVertexCoord;" << endl;
 
   if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
     vs << "uniform mat4 uTextureTransform;" << endl;
+    vs << "uniform vec4 uTextureRect;" << endl;
     vs << "attribute vec2 aTexCoord;" << endl;
     vs << "varying vec2 vTexCoord;" << endl;
   }
 
   if (aConfig.mFeatures & ENABLE_MASK_2D ||
       aConfig.mFeatures & ENABLE_MASK_3D) {
-    vs << "uniform mat4 uMaskQuadTransform;" << endl;
+    vs << "uniform mat4 uMaskTransform;" << endl;
     vs << "varying vec3 vMaskCoord;" << endl;
   }
 
   vs << "void main() {" << endl;
-  vs << "  vec4 finalPosition = vec4(aVertexCoord.xy * uLayerQuadRect.zw + uLayerQuadRect.xy, 0.0, 1.0);" << endl;
+  vs << "  vec4 finalPosition = vec4(aVertexCoord.xy * uLayerRect.zw + uLayerRect.xy, 0.0, 1.0);" << endl;
   vs << "  finalPosition = uLayerTransform * finalPosition;" << endl;
   vs << "  finalPosition.xyz /= finalPosition.w;" << endl;
 
   if (aConfig.mFeatures & ENABLE_MASK_3D) {
-    vs << "  vMaskCoord.xy = (uMaskQuadTransform * vec4(finalPosition.xyz, 1.0)).xy;" << endl;
+    vs << "  vMaskCoord.xy = (uMaskTransform * vec4(finalPosition.xyz, 1.0)).xy;" << endl;
     // correct for perspective correct interpolation, see comment in D3D10 shader
     vs << "  vMaskCoord.z = 1.0;" << endl;
     vs << "  vMaskCoord *= finalPosition.w;" << endl;
   } else if (aConfig.mFeatures & ENABLE_MASK_2D) {
-    vs << "  vMaskCoord.xy = (uMaskQuadTransform * finalPosition).xy;" << endl;
+    vs << "  vMaskCoord.xy = (uMaskTransform * finalPosition).xy;" << endl;
   }
 
   vs << "  finalPosition = finalPosition - uRenderTargetOffset;" << endl;
   vs << "  finalPosition.xyz *= finalPosition.w;" << endl;
   vs << "  finalPosition = uMatrixProj * finalPosition;" << endl;
 
   if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
-    vs << "  vTexCoord = (uTextureTransform * vec4(aTexCoord.x, aTexCoord.y, 0.0, 1.0)).xy;" << endl;
+    vs << "  vec2 texCoord = aTexCoord * uTextureRect.zw + uTextureRect.xy;" << endl;
+    vs << "  vTexCoord = (uTextureTransform * vec4(texCoord, 0.0, 1.0)).xy;" << endl;
   }
 
   vs << "  gl_Position = finalPosition;" << endl;
   vs << "}" << endl;
 
   if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
     fs << "#extension GL_ARB_texture_rectangle : require" << endl;
   }
--- a/gfx/layers/opengl/OGLShaderProgram.h
+++ b/gfx/layers/opengl/OGLShaderProgram.h
@@ -46,20 +46,21 @@ enum ShaderFeatures {
 };
 
 class KnownUniform {
 public:
   enum KnownUniformName {
     NotAKnownUniform = -1,
 
     LayerTransform = 0,
-    MaskQuadTransform,
-    LayerQuadRect,
+    MaskTransform,
+    LayerRect,
     MatrixProj,
     TextureTransform,
+    TextureRect,
     RenderTargetOffset,
     LayerOpacity,
     Texture,
     YTexture,
     CbTexture,
     CrTexture,
     BlackTexture,
     WhiteTexture,
@@ -313,33 +314,38 @@ public:
    * Not all uniforms may be set for all programs, and such uses will throw
    * an assertion.
    */
   void SetLayerTransform(const gfx::Matrix4x4& aMatrix) {
     SetMatrixUniform(KnownUniform::LayerTransform, aMatrix);
   }
 
   void SetMaskLayerTransform(const gfx::Matrix4x4& aMatrix) {
-    SetMatrixUniform(KnownUniform::MaskQuadTransform, aMatrix);
+    SetMatrixUniform(KnownUniform::MaskTransform, aMatrix);
   }
 
-  void SetLayerQuadRect(const gfx::Rect& aRect) {
+  void SetLayerRect(const gfx::Rect& aRect) {
     float vals[4] = { float(aRect.x), float(aRect.y), float(aRect.width), float(aRect.height) };
-    SetUniform(KnownUniform::LayerQuadRect, 4, vals);
+    SetUniform(KnownUniform::LayerRect, 4, vals);
   }
 
   void SetProjectionMatrix(const gfx::Matrix4x4& aMatrix) {
     SetMatrixUniform(KnownUniform::MatrixProj, aMatrix);
   }
 
   // sets this program's texture transform, if it uses one
   void SetTextureTransform(const gfx::Matrix4x4& aMatrix) {
     SetMatrixUniform(KnownUniform::TextureTransform, aMatrix);
   }
 
+  void SetTextureRect(const gfx::Rect& aRect) {
+    float vals[4] = { float(aRect.x), float(aRect.y), float(aRect.width), float(aRect.height) };
+    SetUniform(KnownUniform::TextureRect, 4, vals);
+  }
+
   void SetRenderOffset(const nsIntPoint& aOffset) {
     float vals[4] = { float(aOffset.x), float(aOffset.y), 0.0f, 0.0f };
     SetUniform(KnownUniform::RenderTargetOffset, 4, vals);
   }
 
   void SetRenderOffset(float aX, float aY) {
     float vals[4] = { aX, aY, 0.0f, 0.0f };
     SetUniform(KnownUniform::RenderTargetOffset, 4, vals);
--- a/gfx/layers/opengl/X11TextureSourceOGL.cpp
+++ b/gfx/layers/opengl/X11TextureSourceOGL.cpp
@@ -5,18 +5,19 @@
 
 #ifdef GL_PROVIDER_GLX
 
 #include "X11TextureSourceOGL.h"
 #include "mozilla/layers/CompositorOGL.h"
 #include "gfxXlibSurface.h"
 #include "gfx2DGlue.h"
 
-using namespace mozilla;
-using namespace mozilla::layers;
+namespace mozilla {
+namespace layers {
+
 using namespace mozilla::gfx;
 
 X11TextureSourceOGL::X11TextureSourceOGL(CompositorOGL* aCompositor, gfxXlibSurface* aSurface)
   : mCompositor(aCompositor)
   , mSurface(aSurface)
   , mTexture(0)
 {
 }
@@ -97,8 +98,11 @@ X11TextureSourceOGL::ContentTypeToSurfac
     case gfxContentType::COLOR_ALPHA:
       return SurfaceFormat::R8G8B8A8;
     default:
       return SurfaceFormat::UNKNOWN;
   }
 }
 
 #endif
+
+}
+}
--- a/gfx/src/nsRegion.cpp
+++ b/gfx/src/nsRegion.cpp
@@ -308,16 +308,21 @@ MergeRects(pixman_box32_t *topRects, pix
 }
 
 void nsRegion::SimplifyOutwardByArea(uint32_t aThreshold)
 {
 
   pixman_box32_t *boxes;
   int n;
   boxes = pixman_region32_rectangles(&mImpl, &n);
+
+  // if we have no rectangles then we're done
+  if (!n)
+    return;
+
   pixman_box32_t *end = boxes + n;
   pixman_box32_t *topRectsEnd = boxes+1;
   pixman_box32_t *topRects = boxes;
 
   // we need some temporary storage for merging both rows of rectangles
   nsAutoTArray<pixman_box32_t, 10> tmpStorage;
   tmpStorage.SetCapacity(n);
   pixman_box32_t *tmpRect = tmpStorage.Elements();
--- a/gfx/tests/gtest/TestRegion.cpp
+++ b/gfx/tests/gtest/TestRegion.cpp
@@ -271,10 +271,15 @@ TEST(Gfx, RegionSimplify) {
 
     nsRegion result(nsRect(0,100,200,100));
     result.Or(result, nsRect(0,200,300,200));
 
     EXPECT_TRUE(r.IsEqual(result)) <<
       "regions not merged";
   }
 
+  { // empty region
+    // just make sure this doesn't crash.
+    nsRegion r;
+    r.SimplifyOutwardByArea(100);
+  }
 
 }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5e018590c3757d591f799b0987f523dd5ee27f2a
GIT binary patch
literal 195
zc%17D@N?(olHy`uVBq!ia0vp^-XP4u0wgE7Z%PDGOiAAEE)4(M`_JqL@;D1TB8wRq
zxP?KOkzv*x37{Z*iKnkC`#n|;VJ0byhHo2zLLr_mjv*QM-rm~C%V5C4Z1CX!{M-By
z3s-GU+i0YothHQQJB*E+0C?>l_AOpKI}rl*9^Tbd!8F;Wpy4dgd<IWfKbLh*2~7YH
CK`|Bp
new file mode 100644
--- /dev/null
+++ b/image/test/reftest/downscaling/downscale-1-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html>
+<body>
+  <img src="downscale-1-smallimage.png">
+</body>
+</html>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..588e6b78df68b1552716823473bbfec2f1cb562c
GIT binary patch
literal 88
zc%17D@N?(olHy`uVBq!ia0vp^A|TAc0wmQNuC@Uwc~2L|5RLQ6DGDtAoHf+gln$;q
l6xjMiJEdjmcE>kv44);LRK-?>7Xg(rc)I$ztaD0e0svbx7h?bb
new file mode 100644
--- /dev/null
+++ b/image/test/reftest/downscaling/downscale-1.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html class="reftest-wait">
+<head>
+  <script>
+    function snapshot() {
+      document.documentElement.removeAttribute('class');
+    }
+  </script>
+</head>
+<!-- NOTE: Using setTimeout to wait for high-quality downscaled version of
+     image to be ready, because there's nothing better we can do. If we fix
+     Bug 1006883, we can do away with this setTimeout.
+
+     For now, the setTimeout is just here to increase the likelihood that we
+     actually test the high-quality downscaled version of the image. If the
+     setTimeout happens to fire before the high-quality downscaled rendering is
+     ready, then this the test will pass without testing what it's trying to
+     test, which is fine as long as that's rare.  -->
+<body onload="setTimeout(snapshot, 50)">
+  <img src="downscale-1-bigimage.png" style="height: 20px; width: 20px">
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/image/test/reftest/downscaling/reftest.list
@@ -0,0 +1,28 @@
+# Reftests for downscaling
+#
+# Downscaling can be a lossy process, so a bit of mismatch is acceptable here,
+# as long as it's barely noticable visually. When necessary, this can be
+# explicitly allowed via 'fuzzy'/'fuzzy-if' annotations.
+#
+# IMPORTANT: For robustness, each test should be listed *twice* in this
+# manifest -- once with the high quality downscaling pref disabled, and once
+# with this pref enabled. The pref is set via "default-preferences", so
+# simply appending a new test to the lists below each of those lines should be
+# sufficient.
+#
+# Also note that Mac OS X has its own system-level downscaling algorithm, so
+# tests here may need Mac-specific "fuzzy-if(cocoaWidget,...)" annotations.
+
+# RUN TESTS WITH HIGH QUALITY DOWNSCALING DISABLED:
+# =================================================
+default-preferences pref(image.high_quality_downscaling.enabled,false)
+
+fuzzy-if(cocoaWidget,106,31) == downscale-1.html downscale-1-ref.html
+
+
+# RUN TESTS WITH HIGH QUALITY DOWNSCALING ENABLED:
+# ================================================
+# High-quality downscaling enabled:
+default-preferences pref(image.high_quality_downscaling.enabled,true)
+
+fuzzy(31,127) == downscale-1.html downscale-1-ref.html
--- a/image/test/reftest/reftest.list
+++ b/image/test/reftest/reftest.list
@@ -38,10 +38,13 @@ include apng/reftest.list
 include icon/win/reftest.list
 
 # Generic image tests
 include generic/reftest.list
 
 # Color management test
 include color-management/reftest.list
 
+# Downscaling tests
+include downscaling/reftest.list
+
 # Lossless encoders
 skip-if(Android||B2G) include encoders-lossless/reftest.list # bug 783621
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1617,16 +1617,36 @@ DumpObject(JSContext *cx, unsigned argc,
 
     js_DumpObject(obj);
 
     args.rval().setUndefined();
     return true;
 }
 #endif
 
+static bool
+ReportOutOfMemory(JSContext *cx, unsigned argc, jsval *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JS_ReportOutOfMemory(cx);
+    cx->clearPendingException();
+    args.rval().setUndefined();
+    return true;
+}
+
+static bool
+ReportLargeAllocationFailure(JSContext *cx, unsigned argc, jsval *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    void *buf = cx->runtime()->onOutOfMemoryCanGC(NULL, JSRuntime::LARGE_ALLOCATION);
+    js_free(buf);
+    args.rval().setUndefined();
+    return true;
+}
+
 static const JSFunctionSpecWithHelp TestingFunctions[] = {
     JS_FN_HELP("gc", ::GC, 0, 0,
 "gc([obj] | 'compartment')",
 "  Run the garbage collector. When obj is given, GC only its compartment.\n"
 "  If 'compartment' is given, GC any compartments that were scheduled for\n"
 "  GC via schedulegc."),
 
     JS_FN_HELP("minorgc", ::MinorGC, 0, 0,
@@ -1887,16 +1907,26 @@ static const JSFunctionSpecWithHelp Test
 "  Start logging the mainThread.\n"
 "  Note: tracelogging starts automatically. Disable it by setting environment variable\n"
 "  TLOPTIONS=disableMainThread"),
 
     JS_FN_HELP("stopTraceLogger", DisableTraceLogger, 0, 0,
 "stopTraceLogger()",
 "  Stop logging the mainThread."),
 
+    JS_FN_HELP("reportOutOfMemory", ReportOutOfMemory, 0, 0,
+"reportOutOfMemory()",
+"  Report OOM, then clear the exception and return undefined. For crash testing."),
+
+    JS_FN_HELP("reportLargeAllocationFailure", ReportLargeAllocationFailure, 0, 0,
+"reportLargeAllocationFailure()",
+"  Call the large allocation failure callback, as though a large malloc call failed,\n"
+"  then return undefined. In Gecko, this sends a memory pressure notification, which\n"
+"  can free up some memory."),
+
 #ifdef DEBUG
     JS_FN_HELP("dumpObject", DumpObject, 1, 0,
 "dumpObject()",
 "  Dump an internal representation of an object."),
 #endif
 
     JS_FS_HELP_END
 };
--- a/js/src/gdb/mozilla/JSString.py
+++ b/js/src/gdb/mozilla/JSString.py
@@ -6,45 +6,48 @@ from mozilla.prettyprinters import prett
 
 # Forget any printers from previous loads of this module.
 mozilla.prettyprinters.clear_module_printers(__name__)
 
 # Cache information about the JSString type for this objfile.
 class JSStringTypeCache(object):
     def __init__(self, cache):
         dummy = gdb.Value(0).cast(cache.JSString_ptr_t)
-        self.LENGTH_SHIFT = dummy['LENGTH_SHIFT']
-        self.FLAGS_MASK   = dummy['FLAGS_MASK']
-        self.ROPE_FLAGS   = dummy['ROPE_FLAGS']
-        self.ATOM_BIT     = dummy['ATOM_BIT']
+        self.ROPE_FLAGS = dummy['ROPE_FLAGS']
+        self.ATOM_BIT = dummy['ATOM_BIT']
+        self.INLINE_CHARS_BIT = dummy['INLINE_CHARS_BIT']
 
 class Common(mozilla.prettyprinters.Pointer):
     def __init__(self, value, cache):
         super(Common, self).__init__(value, cache)
         if not cache.mod_JSString:
             cache.mod_JSString = JSStringTypeCache(cache)
         self.stc = cache.mod_JSString
 
 @ptr_pretty_printer("JSString")
 class JSStringPtr(Common):
     def display_hint(self):
         return "string"
 
     def jschars(self):
         d = self.value['d']
-        lengthAndFlags = d['lengthAndFlags']
-        length = lengthAndFlags >> self.stc.LENGTH_SHIFT
-        is_rope = (lengthAndFlags & self.stc.FLAGS_MASK) == self.stc.ROPE_FLAGS
+        length = d['u1']['length']
+        flags = d['u1']['flags']
+        is_rope = (flags == self.stc.ROPE_FLAGS)
         if is_rope:
-            for c in JSStringPtr(d['u1']['left'], self.cache).jschars():
+            for c in JSStringPtr(d['s']['u2']['left'], self.cache).jschars():
                 yield c
-            for c in JSStringPtr(d['s']['u2']['right'], self.cache).jschars():
+            for c in JSStringPtr(d['s']['u3']['right'], self.cache).jschars():
                 yield c
         else:
-            chars = d['u1']['chars']
+            is_inline = (flags & self.stc.INLINE_CHARS_BIT) != 0
+            if is_inline:
+                chars = d['inlineStorage']
+            else:
+                chars = d['s']['u2']['nonInlineChars']
             for i in xrange(length):
                 yield chars[i]
 
     def to_string(self):
         s = u''
         for c in self.jschars():
             s += unichr(c)
         return s
--- a/js/src/irregexp/NativeRegExpMacroAssembler.cpp
+++ b/js/src/irregexp/NativeRegExpMacroAssembler.cpp
@@ -444,18 +444,19 @@ NativeRegExpMacroAssembler::GenerateCode
 #ifdef JS_ION_PERF
     writePerfSpewerJitCodeProfile(code, "RegExp");
 #endif
 
     for (size_t i = 0; i < labelPatches.length(); i++) {
         LabelPatch &v = labelPatches[i];
         JS_ASSERT(!v.label);
         v.patchOffset.fixup(&masm);
+        uintptr_t offset = masm.actualOffset(v.labelOffset);
         Assembler::patchDataWithValueCheck(CodeLocationLabel(code, v.patchOffset),
-                                           ImmPtr(code->raw() + v.labelOffset),
+                                           ImmPtr(code->raw() + offset),
                                            ImmPtr(0));
     }
 
     IonSpew(IonSpew_Codegen, "Created RegExp (raw %p length %d)",
             (void *) code->raw(), (int) masm.bytesNeeded());
 
     RegExpCode res;
     res.jitCode = code;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/ceil.js
@@ -0,0 +1,59 @@
+setJitCompilerOption("baseline.usecount.trigger", 10);
+setJitCompilerOption("ion.usecount.trigger", 20);
+
+//var log = print;
+var log = function(x){}
+
+function ceil(x) {
+    // A nice but not always efficient polyfill.
+    return -Math.floor(-x);
+}
+
+function doubleCheck(g) {
+    for (var j = 0; j < 200; j++) {
+        var i = j;
+        assertEq(g(i), i);
+        assertEq(g(i+.5), i+1);
+        assertEq(g(-i), -i);
+        assertEq(g(-i-.5), -i);
+    }
+}
+
+function floatCheck(g, val) {
+    for (var j = 0; j < 200; j++) {
+        var i = Math.fround(j);
+        assertEq(g(i), i);
+        assertEq(g(i+.5), i+1);
+        assertEq(g(-i), -i);
+        assertEq(g(-i-.5), -i);
+    }
+}
+
+function testBailout(value) {
+    var dceil = eval('(function(x) { return Math.ceil(x) })');
+    log('start double');
+    doubleCheck(dceil);
+    log('bailout');
+    // At this point, the compiled code should bailout, if 'value' is in the
+    // edge case set.
+    assertEq(dceil(value), ceil(value));
+
+    var fceil = eval('(function(x) { return Math.ceil(Math.fround(x)) })');
+    log('start float');
+    floatCheck(fceil, value);
+    log('bailout');
+    assertEq(fceil(Math.fround(value)), ceil(Math.fround(value)));
+}
+
+var INT_MAX = Math.pow(2, 31) - 1;
+var INT_MIN = INT_MAX + 1 | 0;
+
+// Values in ]-1; -0]
+testBailout(-0);
+testBailout(-.5);
+// Values outside the INT32 range, when represented in either double or
+// single precision
+testBailout(INT_MAX + .5);
+testBailout(INT_MIN - 129);
+// BatNaN
+testBailout(NaN);
--- a/js/src/jit/BaselineFrame.h
+++ b/js/src/jit/BaselineFrame.h
@@ -73,18 +73,24 @@ class BaselineFrame
         // we will resume execution on the frame, such as in a catch or
         // finally block.
         HAS_UNWOUND_SCOPE_OVERRIDE_PC = 1 << 11
     };
 
   protected: // Silence Clang warning about unused private fields.
     // We need to split the Value into 2 fields of 32 bits, otherwise the C++
     // compiler may add some padding between the fields.
-    uint32_t loScratchValue_;
-    uint32_t hiScratchValue_;
+
+    union {
+        struct {
+            uint32_t loScratchValue_;
+            uint32_t hiScratchValue_;
+        };
+        BaselineDebugModeOSRInfo *debugModeOSRInfo_;
+    };
     uint32_t loReturnValue_;              // If HAS_RVAL, the frame's return value.
     uint32_t hiReturnValue_;
     uint32_t frameSize_;
     JSObject *scopeChain_;                // Scope chain (always initialized).
     JSScript *evalScript_;                // If isEvalFrame(), the current eval script.
     ArgumentsObject *argsObj_;            // If HAS_ARGS_OBJ, the arguments object.
     void *hookData_;                      // If HAS_HOOK_DATA, debugger call hook data.
     uint32_t unwoundScopeOverrideOffset_; // If HAS_UNWOUND_SCOPE_OVERRIDE_PC.
@@ -306,28 +312,28 @@ class BaselineFrame
     }
 
     void setOverRecursed() {
         flags_ |= OVER_RECURSED;
     }
 
     BaselineDebugModeOSRInfo *debugModeOSRInfo() {
         MOZ_ASSERT(flags_ & HAS_DEBUG_MODE_OSR_INFO);
-        return *reinterpret_cast<BaselineDebugModeOSRInfo **>(&loScratchValue_);
+        return debugModeOSRInfo_;
     }
 
     BaselineDebugModeOSRInfo *getDebugModeOSRInfo() {
         if (flags_ & HAS_DEBUG_MODE_OSR_INFO)
             return debugModeOSRInfo();
         return nullptr;
     }
 
     void setDebugModeOSRInfo(BaselineDebugModeOSRInfo *info) {
         flags_ |= HAS_DEBUG_MODE_OSR_INFO;
-        *reinterpret_cast<BaselineDebugModeOSRInfo **>(&loScratchValue_) = info;
+        debugModeOSRInfo_ = info;
     }
 
     void deleteDebugModeOSRInfo();
 
     jsbytecode *unwoundScopeOverridePc() {
         MOZ_ASSERT(flags_ & HAS_UNWOUND_SCOPE_OVERRIDE_PC);
         return script()->offsetToPC(unwoundScopeOverrideOffset_);
     }
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -3111,21 +3111,23 @@ IonBuilder::filterTypesAtTest(MTest *tes
         if (!replace) {
             types::TemporaryTypeSet *type =
                 subject->resultTypeSet()->filter(alloc_->lifoAlloc(), removeUndefined,
                                                                       removeNull);
             if (!type)
                 return false;
 
             replace = ensureDefiniteTypeSet(subject, type);
-            // Make sure we don't hoist it above the MTest, we can use the
-            // 'dependency' of an MInstruction. This is normally used by
-            // Alias Analysis, but won't get overwritten, since this
-            // instruction doesn't have an AliasSet.
-            replace->setDependency(test);
+            if (replace != subject) {
+                // Make sure we don't hoist it above the MTest, we can use the
+                // 'dependency' of an MInstruction. This is normally used by
+                // Alias Analysis, but won't get overwritten, since this
+                // instruction doesn't have an AliasSet.
+                replace->setDependency(test);
+            }
         }
 
         current->setSlot(i, replace);
     }
 
    return true;
 }
 
@@ -6403,16 +6405,22 @@ IonBuilder::ensureDefiniteTypeSet(MDefin
     // Use ensureDefiniteType to do unboxing. If that happened the type can
     // be added on the newly created unbox operation.
     MDefinition *replace = ensureDefiniteType(def, types->getKnownMIRType());
     if (replace != def) {
         replace->setResultTypeSet(types);
         return replace;
     }
 
+    // Don't replace if input type is more accurate than given typeset.
+    if (def->type() != types->getKnownMIRType()) {
+        MOZ_ASSERT(types->getKnownMIRType() == MIRType_Value);
+        return def;
+    }
+
     // Create a NOP mir instruction to filter the typeset.
     MFilterTypeSet *filter = MFilterTypeSet::New(alloc(), def, types);
     current->add(filter);
     return filter;
 }
 
 static size_t
 NumFixedSlots(JSObject *object)
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -4807,16 +4807,38 @@ class LFloorF : public LInstructionHelpe
   public:
     LIR_HEADER(FloorF)
 
     LFloorF(const LAllocation &num) {
         setOperand(0, num);
     }
 };
 
+// Take the ceiling of a double precision number. Implements Math.ceil().
+class LCeil : public LInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(Ceil)
+
+    LCeil(const LAllocation &num) {
+        setOperand(0, num);
+    }
+};
+
+// Take the ceiling of a single precision number. Implements Math.ceil().
+class LCeilF : public LInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(CeilF)
+
+    LCeilF(const LAllocation &num) {
+        setOperand(0, num);
+    }
+};
+
 // Round a double precision number. Implements Math.round().
 class LRound : public LInstructionHelper<1, 1, 1>
 {
   public:
     LIR_HEADER(Round)
 
     LRound(const LAllocation &num, const LDefinition &temp) {
         setOperand(0, num);
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -229,17 +229,17 @@
     _(GetNameCache)                 \
     _(CallGetIntrinsicValue)        \
     _(CallsiteCloneCache)           \
     _(CallGetElement)               \
     _(CallSetElement)               \
     _(CallInitElementArray)         \
     _(CallSetProperty)              \
     _(CallDeleteProperty)           \
-    _(CallDeleteElement)           \
+    _(CallDeleteElement)            \
     _(SetPropertyCacheV)            \
     _(SetPropertyCacheT)            \
     _(SetElementCacheV)             \
     _(SetElementCacheT)             \
     _(SetPropertyPolymorphicV)      \
     _(SetPropertyPolymorphicT)      \
     _(CallIteratorStart)            \
     _(IteratorStart)                \
@@ -260,33 +260,35 @@
     _(SetFrameArgumentV)            \
     _(RunOncePrologue)              \
     _(Rest)                         \
     _(RestPar)                      \
     _(TypeOfV)                      \
     _(ToIdV)                        \
     _(Floor)                        \
     _(FloorF)                       \
+    _(Ceil)                         \
+    _(CeilF)                        \
     _(Round)                        \
     _(RoundF)                       \
     _(In)                           \
     _(InArray)                      \
     _(InstanceOfO)                  \
     _(InstanceOfV)                  \
     _(CallInstanceOf)               \
     _(InterruptCheck)               \
     _(InterruptCheckImplicit)       \
     _(ProfilerStackOp)              \
     _(GetDOMProperty)               \
     _(GetDOMMember)                 \
     _(SetDOMProperty)               \
     _(CallDOMNative)                \
     _(IsCallable)                   \
     _(HaveSameClass)                \
-    _(HasClass)                      \
+    _(HasClass)                     \
     _(AsmJSLoadHeap)                \
     _(AsmJSStoreHeap)               \
     _(AsmJSLoadGlobalVar)           \
     _(AsmJSStoreGlobalVar)          \
     _(AsmJSLoadFFIFunc)             \
     _(AsmJSParameter)               \
     _(AsmJSReturn)                  \
     _(AsmJSVoidReturn)              \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -1184,16 +1184,35 @@ LIRGenerator::visitFloor(MFloor *ins)
 
     LFloorF *lir = new(alloc()) LFloorF(useRegister(ins->num()));
     if (!assignSnapshot(lir))
         return false;
     return define(lir, ins);
 }
 
 bool
+LIRGenerator::visitCeil(MCeil *ins)
+{
+    MIRType type = ins->num()->type();
+    JS_ASSERT(IsFloatingPointType(type));
+
+    if (type == MIRType_Double) {
+        LCeil *lir = new(alloc()) LCeil(useRegister(ins->num()));
+        if (!assignSnapshot(lir))
+            return false;
+        return define(lir, ins);
+    }
+
+    LCeilF *lir = new(alloc()) LCeilF(useRegister(ins->num()));
+    if (!assignSnapshot(lir))
+        return false;
+    return define(lir, ins);
+}
+
+bool
 LIRGenerator::visitRound(MRound *ins)
 {
     MIRType type = ins->num()->type();
     JS_ASSERT(IsFloatingPointType(type));
 
     if (type == MIRType_Double) {
         LRound *lir = new (alloc()) LRound(useRegister(ins->num()), tempDouble());
         if (!assignSnapshot(lir))
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -114,16 +114,17 @@ class LIRGenerator : public LIRGenerator
     bool visitBitNot(MBitNot *ins);
     bool visitBitAnd(MBitAnd *ins);
     bool visitBitOr(MBitOr *ins);
     bool visitBitXor(MBitXor *ins);
     bool visitLsh(MLsh *ins);
     bool visitRsh(MRsh *ins);
     bool visitUrsh(MUrsh *ins);
     bool visitFloor(MFloor *ins);
+    bool visitCeil(MCeil *ins);
     bool visitRound(MRound *ins);
     bool visitMinMax(MMinMax *ins);
     bool visitAbs(MAbs *ins);
     bool visitSqrt(MSqrt *ins);
     bool visitAtan2(MAtan2 *ins);
     bool visitHypot(MHypot *ins);
     bool visitPow(MPow *ins);
     bool visitRandom(MRandom *ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -702,16 +702,24 @@ IonBuilder::inlineMathCeil(CallInfo &cal
         // fully truncated.
         MLimitedTruncate *ins = MLimitedTruncate::New(alloc(), callInfo.getArg(0),
                                                       MDefinition::IndirectTruncate);
         current->add(ins);
         current->push(ins);
         return InliningStatus_Inlined;
     }
 
+    if (IsFloatingPointType(argType) && returnType == MIRType_Int32) {
+        callInfo.setImplicitlyUsedUnchecked();
+        MCeil *ins = MCeil::New(alloc(), callInfo.getArg(0));
+        current->add(ins);
+        current->push(ins);
+        return InliningStatus_Inlined;
+    }
+
     if (IsFloatingPointType(argType) && returnType == MIRType_Double) {
         callInfo.setImplicitlyUsedUnchecked();
         MMathFunction *ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Ceil, nullptr);
         current->add(ins);
         current->push(ins);
         return InliningStatus_Inlined;
     }
 
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -810,46 +810,50 @@ MStringLength::foldsTo(TempAllocator &al
         Value value = string()->toConstant()->value();
         JSAtom *atom = &value.toString()->asAtom();
         return MConstant::New(alloc, Int32Value(atom->length()));
     }
 
     return this;
 }
 
+static bool
+EnsureFloatInputOrConvert(MUnaryInstruction *owner, TempAllocator &alloc)
+{
+    MDefinition *input = owner->input();
+    if (!input->canProduceFloat32()) {
+        if (input->type() == MIRType_Float32)
+            ConvertDefinitionToDouble<0>(alloc, input, owner);
+        return false;
+    }
+    return true;
+}
+
 void
 MFloor::trySpecializeFloat32(TempAllocator &alloc)
 {
-    // No need to look at the output, as it's an integer (see IonBuilder::inlineMathFloor)
-    if (!input()->canProduceFloat32()) {
-        if (input()->type() == MIRType_Float32)
-            ConvertDefinitionToDouble<0>(alloc, input(), this);
-        return;
-    }
-
-    if (type() == MIRType_Double)
-        setResultType(MIRType_Float32);
-
-    setPolicyType(MIRType_Float32);
+    JS_ASSERT(type() == MIRType_Int32);
+    if (EnsureFloatInputOrConvert(this, alloc))
+        setPolicyType(MIRType_Float32);
+}
+
+void
+MCeil::trySpecializeFloat32(TempAllocator &alloc)
+{
+    JS_ASSERT(type() == MIRType_Int32);
+    if (EnsureFloatInputOrConvert(this, alloc))
+        setPolicyType(MIRType_Float32);
 }
 
 void
 MRound::trySpecializeFloat32(TempAllocator &alloc)
 {
-    // No need to look at the output, as it's an integer (unique way to have
-    // this instruction in IonBuilder::inlineMathRound)
     JS_ASSERT(type() == MIRType_Int32);
-
-    if (!input()->canProduceFloat32()) {
-        if (input()->type() == MIRType_Float32)
-            ConvertDefinitionToDouble<0>(alloc, input(), this);
-        return;
-    }
-
-    setPolicyType(MIRType_Float32);
+    if (EnsureFloatInputOrConvert(this, alloc))
+        setPolicyType(MIRType_Float32);
 }
 
 MCompare *
 MCompare::New(TempAllocator &alloc, MDefinition *left, MDefinition *right, JSOp op)
 {
     return new(alloc) MCompare(left, right, op);
 }
 
@@ -936,45 +940,32 @@ void
 MPhi::removeAllOperands()
 {
     for (size_t i = 0; i < inputs_.length(); i++)
         inputs_[i].discardProducer();
     inputs_.clear();
 }
 
 MDefinition *
-MPhi::operandIfRedundant()
+MPhi::foldsTo(TempAllocator &alloc, bool useValueNumbers)
 {
-    JS_ASSERT(inputs_.length() != 0);
-
-    // If this phi is redundant (e.g., phi(a,a) or b=phi(a,this)),
-    // returns the operand that it will always be equal to (a, in
-    // those two cases).
+    JS_ASSERT(!inputs_.empty());
+
     MDefinition *first = getOperand(0);
-    for (size_t i = 1, e = numOperands(); i < e; i++) {
+
+    for (size_t i = 1; i < inputs_.length(); i++) {
         // Phis need dominator information to fold based on value numbers. For
         // simplicity, we only compare SSA names right now (bug 714727).
-        if (!EqualValues(false, getOperand(i), first) &&
-            !EqualValues(false, getOperand(i), this))
-        {
-            return nullptr;
-        }
+        if (!EqualValues(false, getOperand(i), first))
+            return this;
     }
+
     return first;
 }
 
-MDefinition *
-MPhi::foldsTo(TempAllocator &alloc, bool useValueNumbers)
-{
-    if (MDefinition *def = operandIfRedundant())
-        return def;
-
-    return this;
-}
-
 bool
 MPhi::congruentTo(const MDefinition *ins) const
 {
     if (!ins->isPhi())
         return false;
 
     // Phis in different blocks may have different control conditions.
     // For example, these phis:
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -4887,17 +4887,27 @@ class MPhi MOZ_FINAL : public MDefinitio
         isIterator_ = true;
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void computeRange(TempAllocator &alloc);
 
-    MDefinition *operandIfRedundant();
+    MDefinition *operandIfRedundant() {
+        // If this phi is redundant (e.g., phi(a,a) or b=phi(a,this)),
+        // returns the operand that it will always be equal to (a, in
+        // those two cases).
+        MDefinition *first = getOperand(0);
+        for (size_t i = 1, e = numOperands(); i < e; i++) {
+            if (getOperand(i) != first && getOperand(i) != this)
+                return nullptr;
+        }
+        return first;
+    }
 
     bool canProduceFloat32() const {
         return canProduceFloat32_;
     }
 
     void setCanProduceFloat32(bool can) {
         canProduceFloat32_ = can;
     }
@@ -8791,16 +8801,60 @@ class MFloor
 #ifdef DEBUG
     bool isConsistentFloat32Use(MUse *use) const {
         return true;
     }
 #endif
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
+    void computeRange(TempAllocator &alloc);
+};
+
+// Inlined version of Math.ceil().
+class MCeil
+  : public MUnaryInstruction,
+    public FloatingPointPolicy<0>
+{
+    MCeil(MDefinition *num)
+      : MUnaryInstruction(num)
+    {
+        setResultType(MIRType_Int32);
+        setPolicyType(MIRType_Double);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(Ceil)
+
+    static MCeil *New(TempAllocator &alloc, MDefinition *num) {
+        return new(alloc) MCeil(num);
+    }
+
+    MDefinition *num() const {
+        return getOperand(0);
+    }
+    AliasSet getAliasSet() const {
+        return AliasSet::None();
+    }
+    TypePolicy *typePolicy() {
+        return this;
+    }
+    bool isFloat32Commutative() const {
+        return true;
+    }
+    void trySpecializeFloat32(TempAllocator &alloc);
+#ifdef DEBUG
+    bool isConsistentFloat32Use(MUse *use) const {
+        return true;
+    }
+#endif
+    bool congruentTo(const MDefinition *ins) const {
+        return congruentIfOperandsEqual(ins);
+    }
 };
 
 // Inlined version of Math.round().
 class MRound
   : public MUnaryInstruction,
     public FloatingPointPolicy<0>
 {
     MRound(MDefinition *num)
@@ -9341,17 +9395,18 @@ class MGuardThreadExclusive
 };
 
 class MFilterTypeSet
   : public MUnaryInstruction
 {
     MFilterTypeSet(MDefinition *def, types::TemporaryTypeSet *types)
       : MUnaryInstruction(def)
     {
-        JS_ASSERT(!types->unknown());
+        MOZ_ASSERT(!types->unknown());
+        MOZ_ASSERT(def->type() == types->getKnownMIRType());
         setResultType(types->getKnownMIRType());
         setResultTypeSet(types);
     }
 
   public:
     INSTRUCTION_HEADER(FilterTypeSet)
 
     static MFilterTypeSet *New(TempAllocator &alloc, MDefinition *def, types::TemporaryTypeSet *types) {
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -180,28 +180,29 @@ namespace jit {
     _(IteratorEnd)                                                          \
     _(StringLength)                                                         \
     _(ArgumentsLength)                                                      \
     _(GetFrameArgument)                                                     \
     _(SetFrameArgument)                                                     \
     _(RunOncePrologue)                                                      \
     _(Rest)                                                                 \
     _(Floor)                                                                \
+    _(Ceil)                                                                 \
     _(Round)                                                                \
     _(In)                                                                   \
     _(InstanceOf)                                                           \
     _(CallInstanceOf)                                                       \
     _(InterruptCheck)                                                       \
     _(ProfilerStackOp)                                                      \
     _(GetDOMProperty)                                                       \
     _(GetDOMMember)                                                         \
     _(SetDOMProperty)                                                       \
     _(IsCallable)                                                           \
     _(HaveSameClass)                                                        \
-    _(HasClass)                                                              \
+    _(HasClass)                                                             \
     _(AsmJSNeg)                                                             \
     _(AsmJSUnsignedToDouble)                                                \
     _(AsmJSUnsignedToFloat32)                                               \
     _(AsmJSLoadHeap)                                                        \
     _(AsmJSStoreHeap)                                                       \
     _(AsmJSLoadGlobalVar)                                                   \
     _(AsmJSStoreGlobalVar)                                                  \
     _(AsmJSLoadFuncPtr)                                                     \
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -266,16 +266,17 @@ class ParallelSafetyVisitor : public MIn
     SAFE_OP(StringLength)
     SAFE_OP(ArgumentsLength)
     SAFE_OP(GetFrameArgument)
     UNSAFE_OP(SetFrameArgument)
     UNSAFE_OP(RunOncePrologue)
     CUSTOM_OP(Rest)
     SAFE_OP(RestPar)
     SAFE_OP(Floor)
+    SAFE_OP(Ceil)
     SAFE_OP(Round)
     UNSAFE_OP(InstanceOf)
     CUSTOM_OP(InterruptCheck)
     SAFE_OP(ForkJoinContext)
     SAFE_OP(ForkJoinGetSlice)
     SAFE_OP(NewPar)
     SAFE_OP(NewDenseArrayPar)
     SAFE_OP(NewCallObjectPar)
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -1171,16 +1171,25 @@ MAbs::computeRange(TempAllocator &alloc)
     Range other(getOperand(0));
     Range *next = Range::abs(alloc, &other);
     if (implicitTruncate_)
         next->wrapAroundToInt32();
     setRange(next);
 }
 
 void
+MFloor::computeRange(TempAllocator &alloc)
+{
+    Range other(getOperand(0));
+    Range *copy = new(alloc) Range(other);
+    copy->resetFractionalPart();
+    setRange(copy);
+}
+
+void
 MMinMax::computeRange(TempAllocator &alloc)
 {
     if (specialization_ != MIRType_Int32 && specialization_ != MIRType_Double)
         return;
 
     Range left(getOperand(0));
     Range right(getOperand(1));
     setRange(isMax() ? Range::max(alloc, &left, &right) : Range::min(alloc, &left, &right));
--- a/js/src/jit/RangeAnalysis.h
+++ b/js/src/jit/RangeAnalysis.h
@@ -583,14 +583,19 @@ class Range : public TempObject {
     }
 
     void setSymbolicLower(SymbolicBound *bound) {
         symbolicLower_ = bound;
     }
     void setSymbolicUpper(SymbolicBound *bound) {
         symbolicUpper_ = bound;
     }
+
+    void resetFractionalPart() {
+        canHaveFractionalPart_ = false;
+        optimize();
+    }
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_RangeAnalysis_h */
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -1234,16 +1234,40 @@ CodeGeneratorARM::visitFloorF(LFloorF *l
     Label bail;
     masm.floorf(input, output, &bail);
     if (!bailoutFrom(&bail, lir->snapshot()))
         return false;
     return true;
 }
 
 bool
+CodeGeneratorARM::visitCeil(LCeil *lir)
+{
+    FloatRegister input = ToFloatRegister(lir->input());
+    Register output = ToRegister(lir->output());
+    Label bail;
+    masm.ceil(input, output, &bail);
+    if (!bailoutFrom(&bail, lir->snapshot()))
+        return false;
+    return true;
+}
+
+bool
+CodeGeneratorARM::visitCeilF(LCeilF *lir)
+{
+    FloatRegister input = ToFloatRegister(lir->input());
+    Register output = ToRegister(lir->output());
+    Label bail;
+    masm.ceilf(input, output, &bail);
+    if (!bailoutFrom(&bail, lir->snapshot()))
+        return false;
+    return true;
+}
+
+bool
 CodeGeneratorARM::visitRound(LRound *lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
     Register output = ToRegister(lir->output());
     FloatRegister tmp = ToFloatRegister(lir->temp());
     Label bail;
     // Output is either correct, or clamped.  All -0 cases have been translated to a clamped
     // case.a
--- a/js/src/jit/arm/CodeGenerator-arm.h
+++ b/js/src/jit/arm/CodeGenerator-arm.h
@@ -140,16 +140,18 @@ class CodeGeneratorARM : public CodeGene
     virtual bool visitNotI(LNotI *ins);
     virtual bool visitNotD(LNotD *ins);
     virtual bool visitNotF(LNotF *ins);
 
     virtual bool visitMathD(LMathD *math);
     virtual bool visitMathF(LMathF *math);
     virtual bool visitFloor(LFloor *lir);
     virtual bool visitFloorF(LFloorF *lir);
+    virtual bool visitCeil(LCeil *lir);
+    virtual bool visitCeilF(LCeilF *lir);
     virtual bool visitRound(LRound *lir);
     virtual bool visitRoundF(LRoundF *lir);
     virtual bool visitTruncateDToInt32(LTruncateDToInt32 *ins);
     virtual bool visitTruncateFToInt32(LTruncateFToInt32 *ins);
 
     // Out of line visitors.
     bool visitOutOfLineBailout(OutOfLineBailout *ool);
     bool visitOutOfLineTableSwitch(OutOfLineTableSwitch *ool);
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -4194,16 +4194,118 @@ MacroAssemblerARMCompat::floorf(FloatReg
     // the int range, and special handling is required.
     // zero is also caught by this case, but floor of a negative number
     // should never be zero.
     ma_b(bail, NotSigned);
 
     bind(&fin);
 }
 
+void
+MacroAssemblerARMCompat::ceil(FloatRegister input, Register output, Label *bail)
+{
+    Label handleZero;
+    Label handlePos;
+    Label fin;
+
+    compareDouble(input, InvalidFloatReg);
+    // NaN is always a bail condition, just bail directly.
+    ma_b(bail, Assembler::Overflow);
+    ma_b(&handleZero, Assembler::Equal);
+    ma_b(&handlePos, Assembler::NotSigned);
+
+    // We are in the ]-Inf; 0[ range
+    // If we are in the ]-1; 0[ range => bailout
+    ma_vimm(-1.0, ScratchFloatReg);
+    compareDouble(input, ScratchFloatReg);
+    ma_b(bail, Assembler::GreaterThan);
+
+    // We are in the ]-Inf; -1] range: ceil(x) == -floor(-x) and floor can
+    // be computed with direct truncation here (x > 0).
+    ma_vneg(input, ScratchFloatReg);
+    ma_vcvt_F64_U32(ScratchFloatReg, ScratchFloatReg);
+    ma_vxfer(VFPRegister(ScratchFloatReg).uintOverlay(), output);
+    ma_neg(output, output, SetCond);
+    ma_b(bail, NotSigned);
+    ma_b(&fin);
+
+    // Test for 0.0 / -0.0: if the top word of the input double is not zero,
+    // then it was -0 and we need to bail out.
+    bind(&handleZero);
+    as_vxfer(output, InvalidReg, input, FloatToCore, Always, 1);
+    ma_cmp(output, Imm32(0));
+    ma_b(bail, NonZero);
+    ma_b(&fin);
+
+    // We are in the ]0; +inf] range: truncate integer values, maybe add 1 for
+    // non integer values, maybe bail if overflow.
+    bind(&handlePos);
+    ma_vcvt_F64_U32(input, ScratchFloatReg);
+    ma_vxfer(VFPRegister(ScratchFloatReg).uintOverlay(), output);
+    ma_vcvt_U32_F64(ScratchFloatReg, ScratchFloatReg);
+    compareDouble(ScratchFloatReg, input);
+    ma_add(output, Imm32(1), output, NoSetCond, NotEqual);
+    // Bail out if the add overflowed or the result is negative
+    ma_mov(output, output, SetCond);
+    ma_b(bail, Signed);
+
+    bind(&fin);
+}
+
+void
+MacroAssemblerARMCompat::ceilf(FloatRegister input, Register output, Label *bail)
+{
+    Label handleZero;
+    Label handlePos;
+    Label fin;
+
+    compareFloat(input, InvalidFloatReg);
+    // NaN is always a bail condition, just bail directly.
+    ma_b(bail, Assembler::Overflow);
+    ma_b(&handleZero, Assembler::Equal);
+    ma_b(&handlePos, Assembler::NotSigned);
+
+    // We are in the ]-Inf; 0[ range
+    // If we are in the ]-1; 0[ range => bailout
+    ma_vimm_f32(-1.f, ScratchFloatReg);
+    compareFloat(input, ScratchFloatReg);
+    ma_b(bail, Assembler::GreaterThan);
+
+    // We are in the ]-Inf; -1] range: ceil(x) == -floor(-x) and floor can
+    // be computed with direct truncation here (x > 0).
+    ma_vneg_f32(input, ScratchFloatReg);
+    ma_vcvt_F32_U32(ScratchFloatReg, ScratchFloatReg);
+    ma_vxfer(VFPRegister(ScratchFloatReg).uintOverlay(), output);
+    ma_neg(output, output, SetCond);
+    ma_b(bail, NotSigned);
+    ma_b(&fin);
+
+    // Test for 0.0 / -0.0: if the top word of the input double is not zero,
+    // then it was -0 and we need to bail out.
+    bind(&handleZero);
+    as_vxfer(output, InvalidReg, VFPRegister(input).singleOverlay(), FloatToCore, Always, 0);
+    ma_cmp(output, Imm32(0));
+    ma_b(bail, NonZero);
+    ma_b(&fin);
+
+    // We are in the ]0; +inf] range: truncate integer values, maybe add 1 for
+    // non integer values, maybe bail if overflow.
+    bind(&handlePos);
+    ma_vcvt_F32_U32(input, ScratchFloatReg);
+    ma_vxfer(VFPRegister(ScratchFloatReg).uintOverlay(), output);
+    ma_vcvt_U32_F32(ScratchFloatReg, ScratchFloatReg);
+    compareFloat(ScratchFloatReg, input);
+    ma_add(output, Imm32(1), output, NoSetCond, NotEqual);
+    // Bail out if the add overflowed or the result is negative
+    ma_mov(output, output, SetCond);
+    ma_b(bail, Signed);
+
+    bind(&fin);
+}
+
 CodeOffsetLabel
 MacroAssemblerARMCompat::toggledJump(Label *label)
 {
     // Emit a B that can be toggled to a CMP. See ToggleToJmp(), ToggleToCmp().
     CodeOffsetLabel ret(nextOffset().getOffset());
     ma_b(label, Always, true);
     return ret;
 }
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -952,23 +952,17 @@ class MacroAssemblerARMCompat : public M
     template <typename T>
     void branchTestMagic(Condition cond, const T &t, Label *label) {
         cond = testMagic(cond, t);
         ma_b(label, cond);
     }
     void branchTestMagicValue(Condition cond, const ValueOperand &val, JSWhyMagic why,
                               Label *label) {
         JS_ASSERT(cond == Equal || cond == NotEqual);
-        // Test for magic
-        Label notmagic;
-        Condition testCond = testMagic(cond, val);
-        ma_b(&notmagic, InvertCondition(testCond));
-        // Test magic value
-        branch32(cond, val.payloadReg(), Imm32(static_cast<int32_t>(why)), label);
-        bind(&notmagic);
+        branchTestValue(cond, val, MagicValue(why), label);
     }
     void branchTestInt32Truthy(bool truthy, const ValueOperand &operand, Label *label) {
         Condition c = testInt32Truthy(truthy, operand);
         ma_b(label, c);
     }
     void branchTestBooleanTruthy(bool truthy, const ValueOperand &operand, Label *label) {
         Condition c = testBooleanTruthy(truthy, operand);
         ma_b(label, c);
@@ -1547,16 +1541,18 @@ class MacroAssemblerARMCompat : public M
     }
     void computeEffectiveAddress(const BaseIndex &address, Register dest) {
         ma_alu(address.base, lsl(address.index, address.scale), dest, op_add, NoSetCond);
         if (address.offset)
             ma_add(dest, Imm32(address.offset), dest, NoSetCond);
     }
     void floor(FloatRegister input, Register output, Label *handleNotAnInt);
     void floorf(FloatRegister input, Register output, Label *handleNotAnInt);
+    void ceil(FloatRegister input, Register output, Label *handleNotAnInt);
+    void ceilf(FloatRegister input, Register output, Label *handleNotAnInt);
     void round(FloatRegister input, Register output, Label *handleNotAnInt, FloatRegister tmp);
     void roundf(FloatRegister input, Register output, Label *handleNotAnInt, FloatRegister tmp);
 
     void clampCheck(Register r, Label *handleNotAnInt) {
         // check explicitly for r == INT_MIN || r == INT_MAX
         // this is the instruction sequence that gcc generated for this
         // operation.
         ma_sub(r, Imm32(0x80000001), ScratchRegister);
--- a/js/src/jit/mips/MacroAssembler-mips.h
+++ b/js/src/jit/mips/MacroAssembler-mips.h
@@ -671,22 +671,17 @@ class MacroAssemblerMIPSCompat : public 
     void branchTestMagic(Condition cond, const ValueOperand &value, Label *label);
     void branchTestMagic(Condition cond, Register tag, Label *label);
     void branchTestMagic(Condition cond, const Address &address, Label *label);
     void branchTestMagic(Condition cond, const BaseIndex &src, Label *label);
 
     void branchTestMagicValue(Condition cond, const ValueOperand &val, JSWhyMagic why,
                               Label *label) {
         MOZ_ASSERT(cond == Equal || cond == NotEqual);
-        // Test for magic
-        Label notmagic;
-        branchTestMagic(cond, val, &notmagic);
-        // Test magic value
-        branch32(cond, val.payloadReg(), Imm32(static_cast<int32_t>(why)), label);
-        bind(&notmagic);
+        branchTestValue(cond, val, MagicValue(why), label);
     }
 
     void branchTestInt32Truthy(bool b, const ValueOperand &value, Label *label);
 
     void branchTestStringTruthy(bool b, const ValueOperand &value, Label *label);
 
     void branchTestDoubleTruthy(bool b, FloatRegister value, Label *label);
 
--- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp
@@ -1585,50 +1585,44 @@ CodeGeneratorX86Shared::visitFloor(LFloo
         // Bail on negative-zero.
         masm.branchNegativeZero(input, output, &bailout);
         if (!bailoutFrom(&bailout, lir->snapshot()))
             return false;
 
         // Round toward -Infinity.
         masm.roundsd(input, scratch, JSC::X86Assembler::RoundDown);
 
-        masm.cvttsd2si(scratch, output);
-        masm.cmp32(output, Imm32(INT_MIN));
-        if (!bailoutIf(Assembler::Equal, lir->snapshot()))
+        if (!bailoutCvttsd2si(scratch, output, lir->snapshot()))
             return false;
     } else {
         Label negative, end;
 
         // Branch to a slow path for negative inputs. Doesn't catch NaN or -0.
         masm.xorpd(scratch, scratch);
         masm.branchDouble(Assembler::DoubleLessThan, input, scratch, &negative);
 
         // Bail on negative-zero.
         masm.branchNegativeZero(input, output, &bailout);
         if (!bailoutFrom(&bailout, lir->snapshot()))
             return false;
 
         // Input is non-negative, so truncation correctly rounds.
-        masm.cvttsd2si(input, output);
-        masm.cmp32(output, Imm32(INT_MIN));
-        if (!bailoutIf(Assembler::Equal, lir->snapshot()))
+        if (!bailoutCvttsd2si(input, output, lir->snapshot()))
             return false;
 
         masm.jump(&end);
 
         // Input is negative, but isn't -0.
         // Negative values go on a comparatively expensive path, since no
         // native rounding mode matches JS semantics. Still better than callVM.
         masm.bind(&negative);
         {
             // Truncate and round toward zero.
             // This is off-by-one for everything but integer-valued inputs.
-            masm.cvttsd2si(input, output);
-            masm.cmp32(output, Imm32(INT_MIN));
-            if (!bailoutIf(Assembler::Equal, lir->snapshot()))
+            if (!bailoutCvttsd2si(input, output, lir->snapshot()))
                 return false;
 
             // Test whether the input double was integer-valued.
             masm.convertInt32ToDouble(output, scratch);
             masm.branchDouble(Assembler::DoubleEqualOrUnordered, input, scratch, &end);
 
             // Input is not integer-valued, so we rounded off-by-one in the
             // wrong direction. Correct by subtraction.
@@ -1654,50 +1648,44 @@ CodeGeneratorX86Shared::visitFloorF(LFlo
         // Bail on negative-zero.
         masm.branchNegativeZeroFloat32(input, output, &bailout);
         if (!bailoutFrom(&bailout, lir->snapshot()))
             return false;
 
         // Round toward -Infinity.
         masm.roundss(input, scratch, JSC::X86Assembler::RoundDown);
 
-        masm.cvttss2si(scratch, output);
-        masm.cmp32(output, Imm32(INT_MIN));
-        if (!bailoutIf(Assembler::Equal, lir->snapshot()))
+        if (!bailoutCvttss2si(scratch, output, lir->snapshot()))
             return false;
     } else {
         Label negative, end;
 
         // Branch to a slow path for negative inputs. Doesn't catch NaN or -0.
         masm.xorps(scratch, scratch);
         masm.branchFloat(Assembler::DoubleLessThan, input, scratch, &negative);
 
         // Bail on negative-zero.
         masm.branchNegativeZeroFloat32(input, output, &bailout);
         if (!bailoutFrom(&bailout, lir->snapshot()))
             return false;
 
         // Input is non-negative, so truncation correctly rounds.
-        masm.cvttss2si(input, output);
-        masm.cmp32(output, Imm32(INT_MIN));
-        if (!bailoutIf(Assembler::Equal, lir->snapshot()))
+        if (!bailoutCvttss2si(input, output, lir->snapshot()))
             return false;
 
         masm.jump(&end);
 
         // Input is negative, but isn't -0.
         // Negative values go on a comparatively expensive path, since no
         // native rounding mode matches JS semantics. Still better than callVM.
         masm.bind(&negative);
         {
             // Truncate and round toward zero.
             // This is off-by-one for everything but integer-valued inputs.
-            masm.cvttss2si(input, output);
-            masm.cmp32(output, Imm32(INT_MIN));
-            if (!bailoutIf(Assembler::Equal, lir->snapshot()))
+            if (!bailoutCvttss2si(input, output, lir->snapshot()))
                 return false;
 
             // Test whether the input double was integer-valued.
             masm.convertInt32ToFloat32(output, scratch);
             masm.branchFloat(Assembler::DoubleEqualOrUnordered, input, scratch, &end);
 
             // Input is not integer-valued, so we rounded off-by-one in the
             // wrong direction. Correct by subtraction.
@@ -1706,16 +1694,128 @@ CodeGeneratorX86Shared::visitFloorF(LFlo
         }
 
         masm.bind(&end);
     }
     return true;
 }
 
 bool
+CodeGeneratorX86Shared::visitCeil(LCeil *lir)
+{
+    FloatRegister input = ToFloatRegister(lir->input());
+    FloatRegister scratch = ScratchFloatReg;
+    Register output = ToRegister(lir->output());
+
+    Label bailout, lessThanMinusOne;
+
+    // Bail on ]-1; -0] range
+    masm.loadConstantDouble(-1, scratch);
+    masm.branchDouble(Assembler::DoubleLessThanOrEqualOrUnordered, input,
+                      scratch, &lessThanMinusOne);
+
+    // Test for remaining values with the sign bit set, i.e. ]-1; -0]
+    masm.movmskpd(input, output);
+    masm.branchTest32(Assembler::NonZero, output, Imm32(1), &bailout);
+    if (!bailoutFrom(&bailout, lir->snapshot()))
+        return false;
+
+    if (AssemblerX86Shared::HasSSE41()) {
+        // x <= -1 or x > -0
+        masm.bind(&lessThanMinusOne);
+        // Round toward +Infinity.
+        masm.roundsd(input, scratch, JSC::X86Assembler::RoundUp);
+        return bailoutCvttsd2si(scratch, output, lir->snapshot());
+    }
+
+    // No SSE4.1
+    Label end;
+
+    // x >= 0 and x is not -0.0, we can truncate (resp. truncate and add 1) for
+    // integer (resp. non-integer) values.
+    // Will also work for values >= INT_MAX + 1, as the truncate
+    // operation will return INT_MIN and there'll be a bailout.
+    if (!bailoutCvttsd2si(input, output, lir->snapshot()))
+        return false;
+    masm.convertInt32ToDouble(output, scratch);
+    masm.branchDouble(Assembler::DoubleEqualOrUnordered, input, scratch, &end);
+
+    // Input is not integer-valued, add 1 to obtain the ceiling value
+    masm.addl(Imm32(1), output);
+    // if input > INT_MAX, output == INT_MAX so adding 1 will overflow.
+    if (!bailoutIf(Assembler::Overflow, lir->snapshot()))
+        return false;
+    masm.jump(&end);
+
+    // x <= -1, truncation is the way to go.
+    masm.bind(&lessThanMinusOne);
+    if (!bailoutCvttsd2si(input, output, lir->snapshot()))
+        return false;
+
+    masm.bind(&end);
+    return true;
+}
+
+bool
+CodeGeneratorX86Shared::visitCeilF(LCeilF *lir)
+{
+    FloatRegister input = ToFloatRegister(lir->input());
+    FloatRegister scratch = ScratchFloatReg;
+    Register output = ToRegister(lir->output());
+
+    Label bailout, lessThanMinusOne;
+
+    // Bail on ]-1; -0] range
+    masm.loadConstantFloat32(-1.f, scratch);
+    masm.branchFloat(Assembler::DoubleLessThanOrEqualOrUnordered, input,
+                     scratch, &lessThanMinusOne);
+
+    // Test for remaining values with the sign bit set, i.e. ]-1; -0]
+    masm.movmskps(input, output);
+    masm.branchTest32(Assembler::NonZero, output, Imm32(1), &bailout);
+    if (!bailoutFrom(&bailout, lir->snapshot()))
+        return false;
+
+    if (AssemblerX86Shared::HasSSE41()) {
+        // x <= -1 or x > -0
+        masm.bind(&lessThanMinusOne);
+        // Round toward +Infinity.
+        masm.roundss(input, scratch, JSC::X86Assembler::RoundUp);
+        return bailoutCvttss2si(scratch, output, lir->snapshot());
+    }
+
+    // No SSE4.1
+    Label end;
+
+    // x >= 0 and x is not -0.0, we can truncate (resp. truncate and add 1) for
+    // integer (resp. non-integer) values.
+    // Will also work for values >= INT_MAX + 1, as the truncate
+    // operation will return INT_MIN and there'll be a bailout.
+    if (!bailoutCvttss2si(input, output, lir->snapshot()))
+        return false;
+    masm.convertInt32ToFloat32(output, scratch);
+    masm.branchFloat(Assembler::DoubleEqualOrUnordered, input, scratch, &end);
+
+    // Input is not integer-valued, add 1 to obtain the ceiling value
+    masm.addl(Imm32(1), output);
+    // if input > INT_MAX, output == INT_MAX so adding 1 will overflow.
+    if (!bailoutIf(Assembler::Overflow, lir->snapshot()))
+        return false;
+    masm.jump(&end);
+
+    // x <= -1, truncation is the way to go.
+    masm.bind(&lessThanMinusOne);
+    if (!bailoutCvttss2si(input, output, lir->snapshot()))
+        return false;
+
+    masm.bind(&end);
+    return true;
+}
+
+bool
 CodeGeneratorX86Shared::visitRound(LRound *lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
     FloatRegister temp = ToFloatRegister(lir->temp());
     FloatRegister scratch = ScratchFloatReg;
     Register output = ToRegister(lir->output());
 
     Label negative, end, bailout;
@@ -1731,38 +1831,33 @@ CodeGeneratorX86Shared::visitRound(LRoun
     masm.branchNegativeZero(input, output, &bailout);
     if (!bailoutFrom(&bailout, lir->snapshot()))
         return false;
 
     // Input is non-negative. Add 0.5 and truncate, rounding down. Note that we
     // have to add the input to the temp register (which contains 0.5) because
     // we're not allowed to modify the input register.
     masm.addsd(input, temp);
-
-    masm.cvttsd2si(temp, output);
-    masm.cmp32(output, Imm32(INT_MIN));
-    if (!bailoutIf(Assembler::Equal, lir->snapshot()))
+    if (!bailoutCvttsd2si(temp, output, lir->snapshot()))
         return false;
 
     masm.jump(&end);
 
 
     // Input is negative, but isn't -0.
     masm.bind(&negative);
 
     if (AssemblerX86Shared::HasSSE41()) {
         // Add 0.5 and round toward -Infinity. The result is stored in the temp
         // register (currently contains 0.5).
         masm.addsd(input, temp);
         masm.roundsd(temp, scratch, JSC::X86Assembler::RoundDown);
 
         // Truncate.
-        masm.cvttsd2si(scratch, output);
-        masm.cmp32(output, Imm32(INT_MIN));
-        if (!bailoutIf(Assembler::Equal, lir->snapshot()))
+        if (!bailoutCvttsd2si(scratch, output, lir->snapshot()))
             return false;
 
         // If the result is positive zero, then the actual result is -0. Bail.
         // Otherwise, the truncation will have produced the correct negative integer.
         masm.testl(output, output);
         if (!bailoutIf(Assembler::Zero, lir->snapshot()))
             return false;
 
@@ -1773,19 +1868,17 @@ CodeGeneratorX86Shared::visitRound(LRoun
         {
             // If input + 0.5 >= 0, input is a negative number >= -0.5 and the result is -0.
             masm.compareDouble(Assembler::DoubleGreaterThanOrEqual, temp, scratch);
             if (!bailoutIf(Assembler::DoubleGreaterThanOrEqual, lir->snapshot()))
                 return false;
 
             // Truncate and round toward zero.
             // This is off-by-one for everything but integer-valued inputs.
-            masm.cvttsd2si(temp, output);
-            masm.cmp32(output, Imm32(INT_MIN));
-            if (!bailoutIf(Assembler::Equal, lir->snapshot()))
+            if (!bailoutCvttsd2si(temp, output, lir->snapshot()))
                 return false;
 
             // Test whether the truncated double was integer-valued.
             masm.convertInt32ToDouble(output, scratch);
             masm.branchDouble(Assembler::DoubleEqualOrUnordered, temp, scratch, &end);
 
             // Input is not integer-valued, so we rounded off-by-one in the
             // wrong direction. Correct by subtraction.
@@ -1820,37 +1913,33 @@ CodeGeneratorX86Shared::visitRoundF(LRou
     if (!bailoutFrom(&bailout, lir->snapshot()))
         return false;
 
     // Input is non-negative. Add 0.5 and truncate, rounding down. Note that we
     // have to add the input to the temp register (which contains 0.5) because
     // we're not allowed to modify the input register.
     masm.addss(input, temp);
 
-    masm.cvttss2si(temp, output);
-    masm.cmp32(output, Imm32(INT_MIN));
-    if (!bailoutIf(Assembler::Equal, lir->snapshot()))
+    if (!bailoutCvttss2si(temp, output, lir->snapshot()))
         return false;
 
     masm.jump(&end);
 
 
     // Input is negative, but isn't -0.
     masm.bind(&negative);
 
     if (AssemblerX86Shared::HasSSE41()) {
         // Add 0.5 and round toward -Infinity. The result is stored in the temp
         // register (currently contains 0.5).
         masm.addss(input, temp);
         masm.roundss(temp, scratch, JSC::X86Assembler::RoundDown);
 
         // Truncate.
-        masm.cvttss2si(scratch, output);
-        masm.cmp32(output, Imm32(INT_MIN));
-        if (!bailoutIf(Assembler::Equal, lir->snapshot()))
+        if (!bailoutCvttss2si(scratch, output, lir->snapshot()))
             return false;
 
         // If the result is positive zero, then the actual result is -0. Bail.
         // Otherwise, the truncation will have produced the correct negative integer.
         masm.testl(output, output);
         if (!bailoutIf(Assembler::Zero, lir->snapshot()))
             return false;
 
@@ -1860,19 +1949,17 @@ CodeGeneratorX86Shared::visitRoundF(LRou
         {
             // If input + 0.5 >= 0, input is a negative number >= -0.5 and the result is -0.
             masm.compareFloat(Assembler::DoubleGreaterThanOrEqual, temp, scratch);
             if (!bailoutIf(Assembler::DoubleGreaterThanOrEqual, lir->snapshot()))
                 return false;
 
             // Truncate and round toward zero.
             // This is off-by-one for everything but integer-valued inputs.
-            masm.cvttss2si(temp, output);
-            masm.cmp32(output, Imm32(INT_MIN));
-            if (!bailoutIf(Assembler::Equal, lir->snapshot()))
+            if (!bailoutCvttss2si(temp, output, lir->snapshot()))
                 return false;
 
             // Test whether the truncated double was integer-valued.
             masm.convertInt32ToFloat32(output, scratch);
             masm.branchFloat(Assembler::DoubleEqualOrUnordered, temp, scratch, &end);
 
             // Input is not integer-valued, so we rounded off-by-one in the
             // wrong direction. Correct by subtraction.
--- a/js/src/jit/shared/CodeGenerator-x86-shared.h
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.h
@@ -70,16 +70,31 @@ class CodeGeneratorX86Shared : public Co
         masm.cmp32(lhs, rhs);
         return bailoutIf(c, snapshot);
     }
     template <typename T1, typename T2>
     bool bailoutTest32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot *snapshot) {
         masm.test32(lhs, rhs);
         return bailoutIf(c, snapshot);
     }
+    bool bailoutCvttsd2si(FloatRegister src, Register dest, LSnapshot *snapshot) {
+        // cvttsd2si returns 0x80000000 on failure. Test for it by
+        // subtracting 1 and testing overflow. The other possibility is to test
+        // equality for INT_MIN after a comparison, but 1 costs fewer bytes to
+        // materialize.
+        masm.cvttsd2si(src, dest);
+        masm.cmp32(dest, Imm32(1));
+        return bailoutIf(Assembler::Overflow, snapshot);
+    }
+    bool bailoutCvttss2si(FloatRegister src, Register dest, LSnapshot *snapshot) {
+        // Same trick as explained in the above comment.
+        masm.cvttss2si(src, dest);
+        masm.cmp32(dest, Imm32(1));
+        return bailoutIf(Assembler::Overflow, snapshot);
+    }
 
   protected:
     bool generatePrologue();
     bool generateAsmJSPrologue(Label *stackOverflowLabe);
     bool generateEpilogue();
     bool generateOutOfLineCode();
 
     Operand createArrayElementOperand(Register elements, const LAllocation *index);
@@ -144,16 +159,18 @@ class CodeGeneratorX86Shared : public Co
     virtual bool visitBitAndAndBranch(LBitAndAndBranch *baab);
     virtual bool visitNotI(LNotI *comp);
     virtual bool visitNotD(LNotD *comp);
     virtual bool visitNotF(LNotF *comp);
     virtual bool visitMathD(LMathD *math);
     virtual bool visitMathF(LMathF *math);
     virtual bool visitFloor(LFloor *lir);
     virtual bool visitFloorF(LFloorF *lir);
+    virtual bool visitCeil(LCeil *lir);
+    virtual bool visitCeilF(LCeilF *lir);
     virtual bool visitRound(LRound *lir);
     virtual bool visitRoundF(LRoundF *lir);
     virtual bool visitGuardShape(LGuardShape *guard);
     virtual bool visitGuardObjectType(LGuardObjectType *guard);
     virtual bool visitGuardClass(LGuardClass *guard);
     virtual bool visitEffectiveAddress(LEffectiveAddress *ins);
     virtual bool visitUDivOrMod(LUDivOrMod *ins);
     virtual bool visitAsmJSPassStackArg(LAsmJSPassStackArg *ins);
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -960,24 +960,17 @@ class MacroAssemblerX64 : public MacroAs
     void branchTestMagic(Condition cond, const T &t, Label *label) {
         cond = testMagic(cond, t);
         j(cond, label);
     }
     void branchTestMagicValue(Condition cond, const ValueOperand &val, JSWhyMagic why,
                               Label *label)
     {
         JS_ASSERT(cond == Equal || cond == NotEqual);
-        // Test for magic
-        Label notmagic;
-        Condition testCond = testMagic(cond, val);
-        j(InvertCondition(testCond), &notmagic);
-        // Test magic value
-        unboxMagic(val, ScratchReg);
-        branch32(cond, ScratchReg, Imm32(static_cast<int32_t>(why)), label);
-        bind(&notmagic);
+        branchTestValue(cond, val, MagicValue(why), label);
     }
     Condition testMagic(Condition cond, const ValueOperand &src) {
         splitTag(src, ScratchReg);
         return testMagic(cond, ScratchReg);
     }
     Condition testError(Condition cond, const ValueOperand &src) {
         return testMagic(cond, src);
     }
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -775,29 +775,17 @@ class MacroAssemblerX86 : public MacroAs
     void branchTestMagic(Condition cond, const T &t, Label *label) {
         cond = testMagic(cond, t);
         j(cond, label);
     }
     void branchTestMagicValue(Condition cond, const ValueOperand &val, JSWhyMagic why,
                               Label *label)
     {
         JS_ASSERT(cond == Equal || cond == NotEqual);
-        if (cond == Equal) {
-            // Test for magic
-            Label notmagic;
-            Condition testCond = testMagic(Equal, val);
-            j(InvertCondition(testCond), &notmagic);
-            // Test magic value
-            branch32(Equal, val.payloadReg(), Imm32(static_cast<int32_t>(why)), label);
-            bind(&notmagic);
-        } else {
-            Condition testCond = testMagic(NotEqual, val);
-            j(testCond, label);
-            branch32(NotEqual, val.payloadReg(), Imm32(static_cast<int32_t>(why)), label);
-        }
+        branchTestValue(cond, val, MagicValue(why), label);
     }
 
     // Note: this function clobbers the source register.
     void boxDouble(FloatRegister src, const ValueOperand &dest) {
         movd(src, dest.payloadReg());
         psrldq(Imm32(4), src);
         movd(src, dest.typeReg());
     }
--- a/js/src/jsapi-tests/README
+++ b/js/src/jsapi-tests/README
@@ -30,22 +30,22 @@ To run the tests in a debugger:
 --- Writing test code
 
 Here is a sample test:
 
     #include "tests.h"
 
     BEGIN_TEST(testIntString_bug515273)
     {
-        jsval v;
-        EVAL("'42';", &v);
+        RootedValue v(cx);
 
-        JSString *str = JSVAL_TO_STRING(v);
-        const char *bytes = JS_GetStringBytes(str);
-        CHECK(strcmp(bytes, "42") == 0);
+        EVAL("'42';", &v);
+        JSString *str = v.toString();
+        CHECK(JS_StringHasBeenInterned(cx, str));
+        CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "42"));
         return true;
     }
     END_TEST(testIntString_bug515273)
 
 The BEGIN_TEST and END_TEST macros bracket each test. By convention, the test
 name is <testFilename>_<detail>. (The above test is in testIntString.cpp.)
 
 The curly braces are required. This block is the body of a C++ member function
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6571,19 +6571,22 @@ JSAutoByteString::encodeLatin1(Exclusive
     if (!linear)
         return nullptr;
 
     mBytes = LossyTwoByteCharsToNewLatin1CharsZ(cx, linear->range()).c_str();
     return mBytes;
 }
 
 JS_PUBLIC_API(void)
-JS::SetLargeAllocationFailureCallback(JSRuntime *rt, JS::LargeAllocationFailureCallback lafc)
+JS::SetLargeAllocationFailureCallback(JSRuntime *rt, JS::LargeAllocationFailureCallback lafc,
+                                      void *data)
 {
     rt->largeAllocationFailureCallback = lafc;
+    rt->largeAllocationFailureCallbackData = data;
 }
 
 JS_PUBLIC_API(void)
-JS::SetOutOfMemoryCallback(JSRuntime *rt, OutOfMemoryCallback cb)
+JS::SetOutOfMemoryCallback(JSRuntime *rt, OutOfMemoryCallback cb, void *data)
 {
     rt->oomCallback = cb;
-}
-
+    rt->oomCallbackData = data;
+}
+
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5054,33 +5054,33 @@ class MOZ_STACK_CLASS JS_PUBLIC_API(ForO
  * If a large allocation fails, the JS engine may call the large-allocation-
  * failure callback, if set, to allow the embedding to flush caches, possibly
  * perform shrinking GCs, etc. to make some room so that the allocation will
  * succeed if retried. After the callback returns, the JS engine will try to
  * allocate again and may be succesful.
  */
 
 typedef void
-(* LargeAllocationFailureCallback)();
+(* LargeAllocationFailureCallback)(void *data);
 
 extern JS_PUBLIC_API(void)
-SetLargeAllocationFailureCallback(JSRuntime *rt, LargeAllocationFailureCallback afc);
+SetLargeAllocationFailureCallback(JSRuntime *rt, LargeAllocationFailureCallback afc, void *data);
 
 /*
  * Unlike the error reporter, which is only called if the exception for an OOM
  * bubbles up and is not caught, the OutOfMemoryCallback is called immediately
  * at the OOM site to allow the embedding to capture the current state of heap
  * allocation before anything is freed. If the large-allocation-failure callback
  * is called at all (not all allocation sites call the large-allocation-failure
  * callback on failure), it is called before the out-of-memory callback; the
  * out-of-memory callback is only called if the allocation still fails after the
  * large-allocation-failure callback has returned.
  */
 
 typedef void
-(* OutOfMemoryCallback)(JSContext *cx);
+(* OutOfMemoryCallback)(JSContext *cx, void *data);
 
 extern JS_PUBLIC_API(void)
-SetOutOfMemoryCallback(JSRuntime *rt, OutOfMemoryCallback cb);
+SetOutOfMemoryCallback(JSRuntime *rt, OutOfMemoryCallback cb, void *data);
 
 } /* namespace JS */
 
 #endif /* jsapi_h */
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -371,17 +371,17 @@ js_ReportOutOfMemory(ThreadSafeContext *
         return;
 
     JSContext *cx = cxArg->asJSContext();
     cx->runtime()->hadOutOfMemory = true;
 
     /* Report the oom. */
     if (JS::OutOfMemoryCallback oomCallback = cx->runtime()->oomCallback) {
         AutoSuppressGC suppressGC(cx);
-        oomCallback(cx);
+        oomCallback(cx, cx->runtime()->oomCallbackData);
     }
 
     if (JS_IsRunning(cx)) {
         cx->setPendingException(StringValue(cx->names().outOfMemory));
         return;
     }
 
     /* Get the message for this error, but we don't expand any arguments. */
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -938,18 +938,21 @@ WorkerThread::handleCompressionWorkload(
 
 bool
 js::StartOffThreadCompression(ExclusiveContext *cx, SourceCompressionTask *task)
 {
     EnsureWorkerThreadsInitialized(cx);
 
     AutoLockWorkerThreadState lock;
 
-    if (!WorkerThreadState().compressionWorklist().append(task))
+    if (!WorkerThreadState().compressionWorklist().append(task)) {
+        if (JSContext *maybecx = cx->maybeJSContext())
+            js_ReportOutOfMemory(maybecx);
         return false;
+    }
 
     WorkerThreadState().notifyOne(GlobalWorkerThreadState::PRODUCER);
     return true;
 }
 
 bool
 GlobalWorkerThreadState::compressionInProgress(SourceCompressionTask *task)
 {
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -795,43 +795,36 @@ Options(JSContext *cx, unsigned argc, js
 
         if (strcmp(opt.ptr(), "strict") == 0)
             JS::ContextOptionsRef(cx).toggleExtraWarnings();
         else if (strcmp(opt.ptr(), "werror") == 0)
             JS::ContextOptionsRef(cx).toggleWerror();
         else if (strcmp(opt.ptr(), "strict_mode") == 0)
             JS::ContextOptionsRef(cx).toggleStrictMode();
         else {
-            char* msg = JS_sprintf_append(nullptr,
-                                          "unknown option name '%s'."
-                                          " The valid names are strict,"
-                                          " werror, and strict_mode.",
-                                          opt.ptr());
-            if (!msg) {
-                JS_ReportOutOfMemory(cx);
-                return false;
-            }
-
-            JS_ReportError(cx, msg);
-            free(msg);
+            JS_ReportError(cx,
+                           "unknown option name '%s'."
+                           " The valid names are strict,"
+                           " werror, and strict_mode.",
+                           opt.ptr());
             return false;
         }
     }
 
     char *names = strdup("");
     bool found = false;
-    if (!names && oldContextOptions.extraWarnings()) {
+    if (names && oldContextOptions.extraWarnings()) {
         names = JS_sprintf_append(names, "%s%s", found ? "," : "", "strict");
         found = true;
     }
-    if (!names && oldContextOptions.werror()) {
+    if (names && oldContextOptions.werror()) {
         names = JS_sprintf_append(names, "%s%s", found ? "," : "", "werror");
         found = true;
     }
-    if (!names && oldContextOptions.strictMode()) {
+    if (names && oldContextOptions.strictMode()) {
         names = JS_sprintf_append(names, "%s%s", found ? "," : "", "strict_mode");
         found = true;
     }
     if (!names) {
         JS_ReportOutOfMemory(cx);
         return false;
     }
 
@@ -2434,17 +2427,17 @@ DisassWithSrc(JSContext *cx, unsigned ar
 }
 
 static bool
 DumpHeap(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     JSAutoByteString fileName;
-    if (args.hasDefined(0)) {
+    if (args.hasDefined(0) && !args[0].isNull()) {
         RootedString str(cx, JS::ToString(cx, args[0]));
         if (!str)
             return false;
 
         if (!fileName.encodeLatin1(cx, str))
             return false;
     }
 
@@ -5011,17 +5004,17 @@ my_ErrorReporter(JSContext *cx, const ch
             gExitCode = EXITCODE_OUT_OF_MEMORY;
         } else {
             gExitCode = EXITCODE_RUNTIME_ERROR;
         }
     }
 }
 
 static void
-my_OOMCallback(JSContext *cx)
+my_OOMCallback(JSContext *cx, void *data)
 {
     // If a script is running, the engine is about to throw the string "out of
     // memory", which may or may not be caught. Otherwise the engine will just
     // unwind and return null/false, with no exception set.
     if (!JS_IsRunning(cx))
         gGotError = true;
 }
 
@@ -6258,17 +6251,17 @@ main(int argc, char **argv, char **envp)
     if (!JS_Init())
         return 1;
 
     /* Use the same parameters as the browser in xpcjsruntime.cpp. */
     rt = JS_NewRuntime(32L * 1024L * 1024L, JS_USE_HELPER_THREADS);
     if (!rt)
         return 1;
 
-    JS::SetOutOfMemoryCallback(rt, my_OOMCallback);
+    JS::SetOutOfMemoryCallback(rt, my_OOMCallback, nullptr);
     if (!SetRuntimeOptions(rt, op))
         return 1;
 
     gInterruptFunc.construct(rt, NullValue());
 
     JS_SetGCParameter(rt, JSGC_MAX_BYTES, 0xffffffff);
 #ifdef JSGC_GENERATIONAL
     Maybe<JS::AutoDisableGenerationalGC> noggc;
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -754,24 +754,33 @@ JSRuntime::onOutOfMemory(void *p, size_t
      */
     JS::ShrinkGCBuffers(this);
     gc.waitBackgroundSweepOrAllocEnd();
     if (!p)
         p = js_malloc(nbytes);
     else if (p == reinterpret_cast<void *>(1))
         p = js_calloc(nbytes);
     else
-      p = js_realloc(p, nbytes);
+        p = js_realloc(p, nbytes);
     if (p)
         return p;
     if (cx)
         js_ReportOutOfMemory(cx);
     return nullptr;
 }
 
+void *
+JSRuntime::onOutOfMemoryCanGC(void *p, size_t bytes)
+{
+    if (!largeAllocationFailureCallback || bytes < LARGE_ALLOCATION)
+        return nullptr;
+    largeAllocationFailureCallback(largeAllocationFailureCallbackData);
+    return onOutOfMemory(p, bytes);
+}
+
 bool
 JSRuntime::activeGCInAtomsZone()
 {
     Zone *zone = atomsCompartment_->zone();
     return zone->needsBarrier() || zone->isGCScheduled() || zone->wasGCStarted();
 }
 
 #ifdef JS_THREADSAFE
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -1311,16 +1311,19 @@ struct JSRuntime : public JS::shadow::Ru
      * calloc are signaled by p == null and p == reinterpret_cast<void *>(1).
      * Other values of p mean a realloc failure.
      *
      * The function must be called outside the GC lock.
      */
     JS_FRIEND_API(void *) onOutOfMemory(void *p, size_t nbytes);
     JS_FRIEND_API(void *) onOutOfMemory(void *p, size_t nbytes, JSContext *cx);
 
+    /*  onOutOfMemory but can call the largeAllocationFailureCallback. */
+    JS_FRIEND_API(void *) onOutOfMemoryCanGC(void *p, size_t bytes);
+
     // Ways in which the interrupt callback on the runtime can be triggered,
     // varying based on which thread is triggering the callback.
     enum InterruptMode {
         RequestInterruptMainThread,
         RequestInterruptAnyThread,
         RequestInterruptAnyThreadDontStopIon,
         RequestInterruptAnyThreadForkJoin
     };
@@ -1387,44 +1390,41 @@ struct JSRuntime : public JS::shadow::Ru
 
 #ifdef DEBUG
   public:
     js::AutoEnterPolicy *enteredPolicy;
 #endif
 
     /* See comment for JS::SetLargeAllocationFailureCallback in jsapi.h. */
     JS::LargeAllocationFailureCallback largeAllocationFailureCallback;
+    void *largeAllocationFailureCallbackData;
+
     /* See comment for JS::SetOutOfMemoryCallback in jsapi.h. */
     JS::OutOfMemoryCallback oomCallback;
+    void *oomCallbackData;
 
     /*
      * These variations of malloc/calloc/realloc will call the
      * large-allocation-failure callback on OOM and retry the allocation.
      */
 
     static const unsigned LARGE_ALLOCATION = 25 * 1024 * 1024;
 
     void *callocCanGC(size_t bytes) {
         void *p = calloc_(bytes);
         if (MOZ_LIKELY(!!p))
             return p;
-        if (!largeAllocationFailureCallback || bytes < LARGE_ALLOCATION)
-            return nullptr;
-        largeAllocationFailureCallback();
-        return onOutOfMemory(reinterpret_cast<void *>(1), bytes);
+        return onOutOfMemoryCanGC(reinterpret_cast<void *>(1), bytes);
     }
 
     void *reallocCanGC(void *p, size_t bytes) {
         void *p2 = realloc_(p, bytes);
         if (MOZ_LIKELY(!!p2))
             return p2;
-        if (!largeAllocationFailureCallback || bytes < LARGE_ALLOCATION)
-            return nullptr;
-        largeAllocationFailureCallback();
-        return onOutOfMemory(p, bytes);
+        return onOutOfMemoryCanGC(p, bytes);
     }
 };
 
 namespace js {
 
 // When entering JIT code, the calling JSContext* is stored into the thread's
 // PerThreadData. This function retrieves the JSContext with the pre-condition
 // that the caller is JIT code or C++ called directly from JIT code. This
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1431,34 +1431,43 @@ XPCJSRuntime::InterruptCallback(JSContex
     // machinery with a pref of the user opted out of future slow-script dialogs.
     self->mSlowScriptCheckpoint = TimeStamp::NowLoRes();
     if (response == nsGlobalWindow::AlwaysContinueSlowScript)
         Preferences::SetInt(prefName, 0);
 
     return true;
 }
 
-/* static */ void
-XPCJSRuntime::OutOfMemoryCallback(JSContext *cx)
+void
+XPCJSRuntime::CustomOutOfMemoryCallback()
 {
     if (!Preferences::GetBool("memory.dump_reports_on_oom")) {
         return;
     }
 
     nsCOMPtr<nsIMemoryInfoDumper> dumper =
         do_GetService("@mozilla.org/memory-info-dumper;1");
     if (!dumper) {
         return;
     }
 
     // If this fails, it fails silently.
     dumper->DumpMemoryInfoToTempDir(NS_LITERAL_STRING("due-to-JS-OOM"),
                                     /* minimizeMemoryUsage = */ false);
 }
 
+void
+XPCJSRuntime::CustomLargeAllocationFailureCallback()
+{
+    nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
+    if (os) {
+        os->NotifyObservers(nullptr, "memory-pressure", MOZ_UTF16("heap-minimize"));
+    }
+}
+
 size_t
 XPCJSRuntime::SizeOfIncludingThis(MallocSizeOf mallocSizeOf)
 {
     size_t n = 0;
     n += mallocSizeOf(this);
     n += mWrappedJSMap->SizeOfIncludingThis(mallocSizeOf);
     n += mIID2NativeInterfaceMap->SizeOfIncludingThis(mallocSizeOf);
     n += mClassInfo2NativeSetMap->ShallowSizeOfIncludingThis(mallocSizeOf);
@@ -3173,17 +3182,16 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
     if (PseudoStack *stack = mozilla_get_pseudo_stack())
         stack->sampleRuntime(runtime);
 #endif
     JS_SetAccumulateTelemetryCallback(runtime, AccumulateTelemetryCallback);
     js::SetDefaultJSContextCallback(runtime, DefaultJSContextCallback);
     js::SetActivityCallback(runtime, ActivityCallback, this);
     js::SetCTypesActivityCallback(runtime, CTypesActivityCallback);
     JS_SetInterruptCallback(runtime, InterruptCallback);
-    JS::SetOutOfMemoryCallback(runtime, OutOfMemoryCallback);
 
     // The JS engine needs to keep the source code around in order to implement
     // Function.prototype.toSource(). It'd be nice to not have to do this for
     // chrome code and simply stub out requests for source on it. Life is not so
     // easy, unfortunately. Nobody relies on chrome toSource() working in core
     // browser code, but chrome tests use it. The worst offenders are addons,
     // which like to monkeypatch chrome functions by calling toSource() on them
     // and using regular expressions to modify them. We avoid keeping most browser
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -505,16 +505,18 @@ public:
     void TraverseAdditionalNativeRoots(nsCycleCollectionNoteRootCallback& cb) MOZ_OVERRIDE;
     void UnmarkSkippableJSHolders();
     void PrepareForForgetSkippable() MOZ_OVERRIDE;
     void BeginCycleCollectionCallback() MOZ_OVERRIDE;
     void EndCycleCollectionCallback(mozilla::CycleCollectorResults &aResults) MOZ_OVERRIDE;
     void DispatchDeferredDeletion(bool continuation) MOZ_OVERRIDE;
 
     void CustomGCCallback(JSGCStatus status) MOZ_OVERRIDE;
+    void CustomOutOfMemoryCallback() MOZ_OVERRIDE;
+    void CustomLargeAllocationFailureCallback() MOZ_OVERRIDE;
     bool CustomContextCallback(JSContext *cx, unsigned operation) MOZ_OVERRIDE;
     static void GCSliceCallback(JSRuntime *rt,
                                 JS::GCProgress progress,
                                 const JS::GCDescription &desc);
     static void FinalizeCallback(JSFreeOp *fop,
                                  JSFinalizeStatus status,
                                  bool isCompartmentGC,
                                  void *data);
@@ -542,17 +544,16 @@ public:
     void AddContextCallback(xpcContextCallback cb);
     void RemoveContextCallback(xpcContextCallback cb);
 
     static JSContext* DefaultJSContextCallback(JSRuntime *rt);
     static void ActivityCallback(void *arg, bool active);
     static void CTypesActivityCallback(JSContext *cx,
                                        js::CTypesActivityType type);
     static bool InterruptCallback(JSContext *cx);
-    static void OutOfMemoryCallback(JSContext *cx);
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
     AutoMarkingPtr**  GetAutoRootsAdr() {return &mAutoRoots;}
 
     JSObject* GetJunkScope();
     JSObject* GetCompilationScope();
     void DeleteSingletonScopes();
--- a/media/mtransport/nricectx.cpp
+++ b/media/mtransport/nricectx.cpp
@@ -515,16 +515,20 @@ void NrIceCtx::destroy_peer_ctx() {
 nsresult NrIceCtx::SetControlling(Controlling controlling) {
   peer_->controlling = (controlling == ICE_CONTROLLING)? 1 : 0;
 
   MOZ_MTLOG(ML_DEBUG, "ICE ctx " << name_ << " setting controlling to" <<
             controlling);
   return NS_OK;
 }
 
+NrIceCtx::Controlling NrIceCtx::GetControlling() {
+  return (peer_->controlling) ? ICE_CONTROLLING : ICE_CONTROLLED;
+}
+
 nsresult NrIceCtx::SetStunServers(const std::vector<NrIceStunServer>&
                                   stun_servers) {
   if (stun_servers.empty())
     return NS_OK;
 
   ScopedDeleteArray<nr_ice_stun_server> servers(
       new nr_ice_stun_server[stun_servers.size()]);
 
--- a/media/mtransport/nricectx.h
+++ b/media/mtransport/nricectx.h
@@ -220,16 +220,18 @@ class NrIceCtx {
   std::vector<std::string> GetGlobalAttributes();
 
   // Set the other side's global attributes
   nsresult ParseGlobalAttributes(std::vector<std::string> attrs);
 
   // Set whether we are controlling or not.
   nsresult SetControlling(Controlling controlling);
 
+  Controlling GetControlling();
+
   // Set the STUN servers. Must be called before StartGathering
   // (if at all).
   nsresult SetStunServers(const std::vector<NrIceStunServer>& stun_servers);
 
   // Set the TURN servers. Must be called before StartGathering
   // (if at all).
   nsresult SetTurnServers(const std::vector<NrIceTurnServer>& turn_servers);
 
--- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
+++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
@@ -795,35 +795,39 @@ short vcmGetIceParams(const char *peerco
 }
 
 
 /* Set remote ICE global parameters.
  *
  *  @param[in]  peerconnection - the peerconnection in use
  *  @param[in]  ufrag - the ufrag
  *  @param[in]  pwd - the pwd
+ *  @param[in]  icelite - is peer ice lite
  *
  *  @return 0 for success; VCM_ERROR for failure
  */
 static short vcmSetIceSessionParams_m(const char *peerconnection,
                                       char *ufrag,
-                                      char *pwd)
+                                      char *pwd,
+                                      cc_boolean icelite)
 {
   CSFLogDebug( logTag, "%s: PC = %s", __FUNCTION__, peerconnection);
 
   sipcc::PeerConnectionWrapper pc(peerconnection);
   ENSURE_PC(pc, VCM_ERROR);
 
   std::vector<std::string> attributes;
 
   if (ufrag)
     attributes.push_back(ufrag);
   if (pwd)
     attributes.push_back(pwd);
-
+  if (icelite) {
+    attributes.push_back("ice-lite");
+  }
   nsresult res = pc.impl()->media()->ice_ctx()->
     ParseGlobalAttributes(attributes);
 
   if (!NS_SUCCEEDED(res)) {
     CSFLogError( logTag, "%s: couldn't parse global parameters", __FUNCTION__ );
     return VCM_ERROR;
   }
 
@@ -832,30 +836,33 @@ static short vcmSetIceSessionParams_m(co
 
 /* Set remote ICE global parameters.
  *
  * This is a thunk to vcmSetIceSessionParams_m.
  *
  *  @param[in]  peerconnection - the peerconnection in use
  *  @param[in]  ufrag - the ufrag
  *  @param[in]  pwd - the pwd
+ *  @param[in]  icelite - is peer using ice-lite
  *
  *  @return 0 success, error failure
  */
 short vcmSetIceSessionParams(const char *peerconnection,
                              char *ufrag,
-                             char *pwd)
+                             char *pwd,
+                             cc_boolean icelite)
 {
   short ret;
 
   mozilla::SyncRunnable::DispatchToThread(VcmSIPCCBinding::getMainThread(),
       WrapRunnableNMRet(&vcmSetIceSessionParams_m,
                         peerconnection,
                         ufrag,
                         pwd,
+                        icelite,
                         &ret));
 
   return ret;
 }
 
 /* Set ice candidate for trickle ICE.
  *
  *  @param[in]  peerconnection - the peerconnection in use
--- a/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c
@@ -1309,16 +1309,17 @@ fsmdef_init_dcb (fsmdef_dcb_t *dcb, call
 
     gsmsdp_init_media_list(dcb);
 
     dcb->join_call_id = CC_NO_CALL_ID;
     dcb->callref = 0;
 
     dcb->ice_ufrag = NULL;
     dcb->ice_pwd = NULL;
+    dcb->peer_ice_lite = FALSE;
     dcb->ice_default_candidate_addr[0] = '\0';
 
     dcb->digest_alg[0] = '\0';
     dcb->digest[0] = '\0';
 
     sll_lite_init(&dcb->candidate_list);
 }
 
--- a/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
@@ -7106,18 +7106,23 @@ gsmsdp_install_peer_ice_attributes(fsm_f
     if (sdp_res != SDP_SUCCESS)
       ufrag = NULL;
 
     sdp_res = sdp_attr_get_ice_attribute(sdp_p->dest_sdp, SDP_SESSION_LEVEL, 0,
       SDP_ATTR_ICE_PWD, 1, &pwd);
     if (sdp_res != SDP_SUCCESS)
       pwd = NULL;
 
-    if (ufrag && pwd) {
-        vcm_res = vcmSetIceSessionParams(dcb_p->peerconnection, ufrag, pwd);
+    /* ice-lite is a session level attribute only, RFC 5245 15.3 */
+    dcb_p->peer_ice_lite = sdp_attr_is_present(sdp_p->dest_sdp,
+      SDP_ATTR_ICE_LITE, SDP_SESSION_LEVEL, 0);
+
+    if ((ufrag && pwd) || dcb_p->peer_ice_lite) {
+        vcm_res = vcmSetIceSessionParams(dcb_p->peerconnection, ufrag, pwd,
+                                         dcb_p->peer_ice_lite);
         if (vcm_res)
             return (CC_CAUSE_SETTING_ICE_SESSION_PARAMETERS_FAILED);
     }
 
     /* Now process all the media lines */
     GSMSDP_FOR_ALL_MEDIA(media, dcb_p) {
       if (!GSMSDP_MEDIA_ENABLED(media))
         continue;
--- a/media/webrtc/signaling/src/sipcc/core/gsm/h/fsm.h
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/h/fsm.h
@@ -423,16 +423,17 @@ typedef struct {
     sdp_direction_e  video_pref;
     unsigned int callref;      /* Callref (CI) from CUCM */
 
     char peerconnection[PC_HANDLE_SIZE];  /* A handle to the peerconnection */
     boolean peerconnection_set;
 
     char *ice_ufrag;
     char *ice_pwd;
+    boolean peer_ice_lite;
     char ice_default_candidate_addr[MAX_IPADDR_STR_LEN];
 
     char digest_alg[FSMDEF_MAX_DIGEST_ALG_LEN];
     char digest[FSMDEF_MAX_DIGEST_LEN];
 
     sll_lite_list_t candidate_list;
 } fsmdef_dcb_t;
 
--- a/media/webrtc/signaling/src/sipcc/core/gsm/lsm.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/lsm.c
@@ -3921,17 +3921,18 @@ lsm_connected (lsm_lcb_t *lcb, cc_state_
 
     if (!sdpmode) {
         if (tone_stop_bool == TRUE)
             (void) lsm_stop_tone(lcb, NULL);
     }
 
     /* Start ICE */
     if (start_ice) {
-      short res = vcmStartIceChecks(dcb->peerconnection, !dcb->inbound);
+      short res = vcmStartIceChecks(dcb->peerconnection,
+                                    !dcb->inbound || dcb->peer_ice_lite);
 
       /* TODO(emannion): Set state to dead here. */
       if (res)
         return CC_RC_SUCCESS;
     }
 
     /*
      * Open the RTP receive channel.
--- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp.h
+++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp.h
@@ -1254,16 +1254,18 @@ extern u32 sdp_attr_get_simple_u32(void 
 extern sdp_result_e sdp_attr_set_simple_u32(void *sdp_ptr,
                                       sdp_attr_e attr_type, u16 level,
                                       u8 cap_num, u16 inst_num, u32 num_parm);
 extern tinybool sdp_attr_get_simple_boolean(void *sdp_ptr,
                    sdp_attr_e attr_type, u16 level, u8 cap_num, u16 inst_num);
 extern sdp_result_e sdp_attr_set_simple_boolean(void *sdp_ptr,
                    sdp_attr_e attr_type, u16 level, u8 cap_num,
                    u16 inst_num, u32 bool_parm);
+extern tinybool sdp_attr_is_present (void *sdp_ptr, sdp_attr_e attr_type,
+                                     u16 level, u8 cap_num);
 extern const char* sdp_attr_get_maxprate(void *sdp_ptr, u16 level,
                                          u16 inst_num);
 extern sdp_result_e sdp_attr_set_maxprate(void *sdp_ptr, u16 level,
                                        u16 inst_num, const char *string_parm);
 extern sdp_t38_ratemgmt_e sdp_attr_get_t38ratemgmt(void *sdp_ptr, u16 level,
                                                    u8 cap_num, u16 inst_num);
 extern sdp_result_e sdp_attr_set_t38ratemgmt(void *sdp_ptr, u16 level,
                                              u8 cap_num, u16 inst_num,
--- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr.c
+++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr.c
@@ -4745,16 +4745,37 @@ sdp_result_e sdp_parse_attr_ice_attr (sd
 
     if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
       SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str, sdp_get_attr_name(attr_p->type), tmp);
     }
     return (SDP_SUCCESS);
 }
 
 
+sdp_result_e sdp_build_attr_simple_flag (sdp_t *sdp_p, sdp_attr_t *attr_p,
+                                         flex_string *fs) {
+    flex_string_sprintf(fs, "a=%s\r\n", sdp_get_attr_name(attr_p->type));
+
+    return SDP_SUCCESS;
+}
+
+
+sdp_result_e sdp_parse_attr_simple_flag (sdp_t *sdp_p, sdp_attr_t *attr_p,
+                                      const char *ptr) {
+    /* No parameters to parse. */
+
+    if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+        SDP_PRINT("%s Parsed a=%s", sdp_p->debug_str,
+                  sdp_get_attr_name(attr_p->type));
+    }
+
+    return (SDP_SUCCESS);
+}
+
+
 sdp_result_e sdp_parse_attr_fingerprint_attr (sdp_t *sdp_p, sdp_attr_t *attr_p,
                                            const char *ptr)
 {
     sdp_result_e  result;
 
     ptr = sdp_getnextstrtok(ptr, attr_p->attr.string_val, sizeof(attr_p->attr.string_val), "\r\n", &result);
 
     if (result != SDP_SUCCESS) {
--- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr_access.c
+++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr_access.c
@@ -4005,16 +4005,53 @@ sdp_result_e sdp_attr_set_ice_attribute(
     if (!ice_attrib) {
       return (SDP_INVALID_PARAMETER);
     }
 
     sstrncpy(attr_p->attr.ice_attr, ice_attrib, sizeof(attr_p->attr.ice_attr));
     return (SDP_SUCCESS);
 }
 
+/* Function:    sdp_attr_is_present
+ * Description: Returns a boolean value based on attribute being present or
+ *              not
+ *
+ * Parameters:  sdp_ptr     The SDP handle returned by sdp_init_description.
+ *              attr_type   The attribute type.
+ *              level       The level to check for the attribute.
+ *              cap_num     The capability number associated with the
+ *                          attribute if any.  If none, should be zero.
+ * Returns:
+ *              Boolean value.
+ */
+
+tinybool sdp_attr_is_present (void *sdp_ptr, sdp_attr_e attr_type, u16 level,
+                              u8 cap_num)
+{
+    sdp_t       *sdp_p = (sdp_t *)sdp_ptr;
+    sdp_attr_t  *attr_p;
+
+    if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
+        return (FALSE);
+    }
+
+    attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, 1);
+    if (attr_p != NULL) {
+        return (TRUE);
+    }
+    if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+        CSFLogDebug(logTag, "%s Attribute %s, level %u not found.",
+                    sdp_p->debug_str, sdp_get_attr_name(attr_type), level);
+    }
+
+    return (FALSE);
+}
+
+
+
 /* Function:    sdp_attr_get_rtcp_mux_attribute
  * Description: Returns the value of an rtcp-mux attribute at a given level
  *
  * Parameters:  sdp_ptr     The SDP handle returned by sdp_init_description.
  *              level       The level to check for the attribute.
  *              cap_num     The capability number associated with the
  *                          attribute if any.  If none, should be zero.
  *              inst_num    The attribute instance number to check.
--- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp_main.c
+++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp_main.c
@@ -159,16 +159,18 @@ const sdp_attrarray_t sdp_attr[SDP_MAX_A
     {"framerate", sizeof("framerate"),
       sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
     {"candidate", sizeof("candidate"),
       sdp_parse_attr_ice_attr, sdp_build_attr_ice_attr },
     {"ice-ufrag", sizeof("ice-ufrag"),
       sdp_parse_attr_ice_attr, sdp_build_attr_ice_attr },
     {"ice-pwd", sizeof("ice-pwd"),
       sdp_parse_attr_ice_attr, sdp_build_attr_ice_attr},
+    {"ice-lite", sizeof("ice-lite"),
+      sdp_parse_attr_simple_flag, sdp_build_attr_simple_flag},
     {"rtcp-mux", sizeof("rtcp-mux"),
       sdp_parse_attr_rtcp_mux_attr, sdp_build_attr_rtcp_mux_attr},
     {"fingerprint", sizeof("fingerprint"),
       sdp_parse_attr_fingerprint_attr, sdp_build_attr_simple_string},
     {"maxptime", sizeof("maxptime"),
       sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32},
     {"rtcp-fb", sizeof("rtcp-fb"),
       sdp_parse_attr_rtcp_fb, sdp_build_attr_rtcp_fb},
--- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp_private.h
+++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp_private.h
@@ -207,16 +207,21 @@ extern sdp_result_e sdp_parse_attr_rtcp_
 extern sdp_result_e sdp_build_attr_rtcp_unicast(
     sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
 
 extern sdp_result_e sdp_build_attr_ice_attr (
 	sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
 extern sdp_result_e sdp_parse_attr_ice_attr (
 	sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
 
+extern sdp_result_e sdp_build_attr_simple_flag (
+    sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+extern sdp_result_e sdp_parse_attr_simple_flag (
+    sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+
 extern sdp_result_e sdp_build_attr_rtcp_mux_attr (
 	sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
 extern sdp_result_e sdp_parse_attr_rtcp_mux_attr (
 	sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
 extern sdp_result_e sdp_parse_attr_fingerprint_attr (
     sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
 
 /* sdp_attr_access.c */
--- a/media/webrtc/signaling/src/sipcc/include/ccsdp.h
+++ b/media/webrtc/signaling/src/sipcc/include/ccsdp.h
@@ -235,16 +235,17 @@ typedef enum {
     SDP_ATTR_CPAR,
     SDP_ATTR_SPRTMAP,
     SDP_ATTR_SDESCRIPTIONS,  /* version 9 sdescriptions */
     SDP_ATTR_LABEL,
     SDP_ATTR_FRAMERATE,
     SDP_ATTR_ICE_CANDIDATE,
     SDP_ATTR_ICE_UFRAG,
     SDP_ATTR_ICE_PWD,
+    SDP_ATTR_ICE_LITE,
     SDP_ATTR_RTCP_MUX,
     SDP_ATTR_DTLS_FINGERPRINT,
     SDP_ATTR_MAXPTIME,
     SDP_ATTR_RTCP_FB,  /* RFC 4585 */
     SDP_ATTR_SETUP,
     SDP_ATTR_CONNECTION,
     SDP_ATTR_EXTMAP,  /* RFC 5285 */
     SDP_ATTR_IDENTITY,
--- a/media/webrtc/signaling/src/sipcc/include/vcm.h
+++ b/media/webrtc/signaling/src/sipcc/include/vcm.h
@@ -461,20 +461,22 @@ short vcmRxAllocICE(cc_mcapid_t mcap_id,
  */
 short vcmGetIceParams(const char *peerconnection, char **ufragp, char **pwdp);
 
 /* Set remote ICE global parameters.
  *
  *  @param[in]  peerconnection - the peerconnection in use
  *  @param[in]  ufrag - the ufrag
  *  @param[in]  pwd - the pwd
+ *  @param[in]  icelite - is peer ice lite
  *
  *  @return 0 success, error failure
  */
-short vcmSetIceSessionParams(const char *peerconnection, char *ufrag, char *pwd);
+short vcmSetIceSessionParams(const char *peerconnection, char *ufrag, char *pwd,
+                             cc_boolean icelite);
 
 /* Set ice candidate for trickle ICE.
  *
  *  @param[in]  peerconnection - the peerconnection in use
  *  @param[in]  icecandidate - the icecandidate
  *  @param[in]  level - the m line level
  *
  *  @return 0 success, error failure
--- a/media/webrtc/signaling/test/sdp_unittests.cpp
+++ b/media/webrtc/signaling/test/sdp_unittests.cpp
@@ -784,16 +784,37 @@ TEST_F(SdpTest, addFmtpMaxFsFr) {
   InitLocalSdp();
   int level = AddNewMedia(SDP_MEDIA_VIDEO);
   AddNewFmtpMaxFsFr(level, 300, 30);
   std::string body = SerializeSdp();
   ASSERT_NE(body.find("a=fmtp:120 max-fs=300;max-fr=30\r\n"),
             std::string::npos);
 }
 
+TEST_F(SdpTest, addIceLite) {
+    InitLocalSdp();
+    u16 inst_num = 0;
+    EXPECT_EQ(sdp_add_new_attr(sdp_ptr_, SDP_SESSION_LEVEL, 0,
+                               SDP_ATTR_ICE_LITE, &inst_num), SDP_SUCCESS);
+    std::string body = SerializeSdp();
+    ASSERT_NE(body.find("a=ice-lite\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, parseIceLite) {
+    std::string sdp =
+        "v=0\r\n"
+        "o=- 137331303 2 IN IP4 127.0.0.1\r\n"
+        "s=SIP Call\r\n"
+        "t=0 0\r\n"
+        "a=ice-lite\r\n";
+  ParseSdp(sdp);
+  ASSERT_TRUE(sdp_attr_is_present(sdp_ptr_, SDP_ATTR_ICE_LITE,
+                                  SDP_SESSION_LEVEL, 0));
+}
+
 } // End namespace test.
 
 int main(int argc, char **argv) {
   test_utils = new MtransportTestUtils();
   NSS_NoDB_Init(nullptr);
   NSS_SetDomesticPolicy();
 
   ::testing::InitGoogleTest(&argc, argv);
--- a/media/webrtc/signaling/test/signaling_unittests.cpp
+++ b/media/webrtc/signaling/test/signaling_unittests.cpp
@@ -40,16 +40,19 @@
 #include "nricectx.h"
 #include "rlogringbuffer.h"
 #include "mozilla/SyncRunnable.h"
 #include "logging.h"
 #include "stunserver.h"
 #include "stunserver.cpp"
 #include "PeerConnectionImplEnumsBinding.cpp"
 
+#include "ice_ctx.h"
+#include "ice_peer_ctx.h"
+
 #include "mtransport_test_utils.h"
 #include "gtest_ringbuffer_dumper.h"
 MtransportTestUtils *test_utils;
 nsCOMPtr<nsIThread> gMainThread;
 nsCOMPtr<nsIThread> gGtestThread;
 bool gTestsComplete = false;
 
 #ifndef USE_FAKE_MEDIA_STREAMS
@@ -2496,16 +2499,54 @@ TEST_F(SignalingTest, AudioOnlyG711Call)
   ASSERT_NE(answer.find(" PCMU/8000"), std::string::npos);
   ASSERT_NE(answer.find(" telephone-event/8000"), std::string::npos);
 
   // Double-check the directionality
   ASSERT_NE(answer.find("\r\na=sendrecv"), std::string::npos);
 
 }
 
+TEST_F(SignalingTest, IncomingOfferIceLite)
+{
+  EnsureInit();
+
+  sipcc::MediaConstraints constraints;
+  std::string offer =
+    "v=0\r\n"
+    "o=- 1936463 1936463 IN IP4 148.147.200.251\r\n"
+    "s=-\r\n"
+    "c=IN IP4 148.147.200.251\r\n"
+    "t=0 0\r\n"
+    "a=ice-lite\r\n"
+    "a=fingerprint:sha-1 "
+      "E7:FA:17:DA:3F:3C:1E:D8:E4:9C:8C:4C:13:B9:2E:D5:C6:78:AB:B3\r\n"
+    "m=audio 40014 RTP/SAVPF 8 0 101\r\n"
+    "a=rtpmap:8 PCMA/8000\r\n"
+    "a=rtpmap:0 PCMU/8000\r\n"
+    "a=rtpmap:101 telephone-event/8000\r\n"
+    "a=fmtp:101 0-15\r\n"
+    "a=ptime:20\r\n"
+    "a=sendrecv\r\n"
+    "a=ice-ufrag:bf2LAgqBZdiWFR2r\r\n"
+    "a=ice-pwd:ScxgaNzdBOYScR0ORleAvt1x\r\n"
+    "a=candidate:1661181211 1 udp 10 148.147.200.251 40014 typ host\r\n"
+    "a=candidate:1661181211 2 udp 9 148.147.200.251 40015 typ host\r\n"
+    "a=setup:actpass\r\n";
+
+  std::cout << "Setting offer to:" << std::endl << indent(offer) << std::endl;
+  a2_->SetRemote(TestObserver::OFFER, offer);
+
+  std::cout << "Creating answer:" << std::endl;
+  a2_->CreateAnswer(constraints, offer, OFFER_AUDIO | ANSWER_AUDIO);
+  a2_->SetLocal(TestObserver::ANSWER, a2_->answer());
+
+  ASSERT_EQ(a2_->pc->media()->ice_ctx()->GetControlling(),
+            NrIceCtx::ICE_CONTROLLING);
+}
+
 // This test comes from Bug814038
 TEST_F(SignalingTest, ChromeOfferAnswer)
 {
   EnsureInit();
 
   sipcc::MediaConstraints constraints;
 
   // This is captured SDP from an early interop attempt with Chrome.
--- a/mfbt/Attributes.h
+++ b/mfbt/Attributes.h
@@ -479,17 +479,17 @@
  *   class uses this class, or if another class inherits from this class, then
  *   it is considered to be a non-heap class as well, although this attribute
  *   need not be provided in such cases.
  * MOZ_HEAP_ALLOCATOR: Applies to any function. This indicates that the return
  *   value is allocated on the heap, and will as a result check such allocations
  *   during MOZ_STACK_CLASS and MOZ_NONHEAP_CLASS annotation checking.
  * MOZ_IMPLICIT: Applies to constructors. Implicit conversion constructors
  *   are disallowed by default unless they are marked as MOZ_IMPLICIT. This
- *   attribute must be used for constructors which intent to provide implicit
+ *   attribute must be used for constructors which intend to provide implicit
  *   conversions.
  */
 #ifdef MOZ_CLANG_PLUGIN
 #  define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override")))
 #  define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class")))
 #  define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class")))
 #  define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
 /*
--- a/mobile/android/components/NSSDialogService.js
+++ b/mobile/android/components/NSSDialogService.js
@@ -136,18 +136,18 @@ NSSDialogs.prototype = {
      .addLabel({ label: this.certInfoSection("certmgr.issuerinfo.label",
                           ["certmgr.certdetail.cn", aCert.issuerCommonName,
                            "certmgr.certdetail.o", aCert.issuerOrganization,
                            "certmgr.certdetail.ou", aCert.issuerOrganizationUnit])})
      .addLabel({ label: this.certInfoSection("certmgr.periodofvalidity.label",
                           ["certmgr.begins", aCert.validity.notBeforeLocalDay,
                            "certmgr.expires", aCert.validity.notAfterLocalDay])})
      .addLabel({ label: this.certInfoSection("certmgr.fingerprints.label",
-                          ["certmgr.certdetail.sha1fingerprint", aCert.sha1Fingerprint,
-                           "certmgr.certdetail.md5fingerprint", aCert.md5Fingerprint], false) });
+                          ["certmgr.certdetail.sha256fingerprint", aCert.sha256Fingerprint,
+                           "certmgr.certdetail.sha1fingerprint", aCert.sha1Fingerprint], false) });
     this.showPrompt(p);
   },
 
   viewCertDetails: function(details) {
     let p = this.getPrompt(this.getString("clientAuthAsk.message3"),
                     '',
                     [ this.getString("nssdialogs.ok.label") ]);
     p.addLabel({ label: details });
--- a/mobile/android/locales/en-US/chrome/pippki.properties
+++ b/mobile/android/locales/en-US/chrome/pippki.properties
@@ -30,12 +30,12 @@ certmgr.title=Certificate Details
 certmgr.subjectinfo.label=Issued To
 certmgr.issuerinfo.label=Issued By
 certmgr.periodofvalidity.label=Period of Validity
 certmgr.fingerprints.label=Fingerprints
 certmgr.certdetail.cn=Common Name (CN)
 certmgr.certdetail.o=Organization (O)
 certmgr.certdetail.ou=Organizational Unit (OU)
 certmgr.certdetail.serialnumber=Serial Number
+certmgr.certdetail.sha256fingerprint=SHA-256 Fingerprint
 certmgr.certdetail.sha1fingerprint=SHA1 Fingerprint
-certmgr.certdetail.md5fingerprint=MD5 Fingerprint
 certmgr.begins=Begins On
 certmgr.expires=Expires On
--- a/security/manager/locales/en-US/chrome/pippki/certManager.dtd
+++ b/security/manager/locales/en-US/chrome/pippki/certManager.dtd
@@ -29,18 +29,18 @@
 <!ENTITY certmgr.issuerinfo.label             "Issued By">
 <!ENTITY certmgr.periodofvalidity.label       "Period of Validity" >
 <!ENTITY certmgr.fingerprints.label           "Fingerprints">
 <!ENTITY certmgr.certdetail.title             "Certificate Detail">
 <!ENTITY certmgr.certdetail.cn                "Common Name (CN)">
 <!ENTITY certmgr.certdetail.o                 "Organization (O)">
 <!ENTITY certmgr.certdetail.ou                "Organizational Unit (OU)">
 <!ENTITY certmgr.certdetail.serialnumber      "Serial Number">
+<!ENTITY certmgr.certdetail.sha256fingerprint "SHA-256 Fingerprint">
 <!ENTITY certmgr.certdetail.sha1fingerprint   "SHA1 Fingerprint">
-<!ENTITY certmgr.certdetail.md5fingerprint    "MD5 Fingerprint">
 
 <!ENTITY certmgr.editcert.title               "Edit Security Certificate Settings">
 <!ENTITY certmgr.editcacert.title             "Edit CA certificate trust settings">
 <!ENTITY certmgr.editcert.edittrust           "Edit trust settings:">
 <!ENTITY certmgr.editcert.trustssl            "This certificate can identify websites.">
 <!ENTITY certmgr.editcert.trustemail          "This certificate can identify mail users.">
 <!ENTITY certmgr.editcert.trustobjsign        "This certificate can identify software makers.">
 <!ENTITY certmgr.editemailcert.title          "Edit email certificate trust settings">
--- a/security/manager/pki/resources/content/viewCertDetails.js
+++ b/security/manager/pki/resources/content/viewCertDetails.js
@@ -236,20 +236,20 @@ function DisplayGeneralDataFromCert(cert
   //  Common Name
   addAttributeFromCert('commonname', cert.commonName);
   //  Organization
   addAttributeFromCert('organization', cert.organization);
   //  Organizational Unit
   addAttributeFromCert('orgunit', cert.organizationalUnit);
   //  Serial Number
   addAttributeFromCert('serialnumber',cert.serialNumber);
+  // SHA-256 Fingerprint
+  addAttributeFromCert('sha256fingerprint', cert.sha256Fingerprint);
   //  SHA1 Fingerprint
   addAttributeFromCert('sha1fingerprint',cert.sha1Fingerprint);
-  //  MD5 Fingerprint
-  addAttributeFromCert('md5fingerprint',cert.md5Fingerprint);
   // Validity start
   addAttributeFromCert('validitystart', cert.validity.notBeforeLocalDay);
   // Validity end
   addAttributeFromCert('validityend', cert.validity.notAfterLocalDay);
   
   //Now to populate the fields that correspond to the issuer.
   var issuerCommonname, issuerOrg, issuerOrgUnit;
   issuerCommonname = cert.issuerCommonName;
--- a/security/manager/pki/resources/content/viewCertDetails.xul
+++ b/security/manager/pki/resources/content/viewCertDetails.xul
@@ -82,20 +82,23 @@
           <separator class="thin"/>
           <spacer/>
         </row>
         <row>
           <label class="header" value="&certmgr.fingerprints.label;"/>
           <spacer/>
         </row>
         <row>
+          <label value="&certmgr.certdetail.sha256fingerprint;"/>
+          <hbox>
+            <textbox id="sha256fingerprint" class="plain" readonly="true" multiline="true"
+                     style="height: 6ex; width: 48ch; font-family: monospace;"/>
+          </hbox>
+        </row>
+        <row>
           <label value="&certmgr.certdetail.sha1fingerprint;"/>
           <textbox id="sha1fingerprint" class="plain" readonly="true" style="min-width:34em;"/>
         </row>
-        <row>
-          <label value="&certmgr.certdetail.md5fingerprint;"/>
-          <textbox id="md5fingerprint" class="plain" readonly="true"/>
-        </row>
       </rows>
     </grid>
   </vbox>
 </vbox>
 </overlay>
--- a/security/manager/ssl/public/nsIX509Cert.idl
+++ b/security/manager/ssl/public/nsIX509Cert.idl
@@ -8,17 +8,17 @@
 
 interface nsIArray;
 interface nsIX509CertValidity;
 interface nsIASN1Object;
 
 /**
  * This represents a X.509 certificate.
  */
-[scriptable, uuid(6286dd8c-c1a1-11e3-941d-180373d97f24)]
+[scriptable, uuid(900d6442-d8bc-11e3-aa51-0800273c564f)]
 interface nsIX509Cert : nsISupports {
 
   /**
    *  A nickname for the certificate.
    */
   readonly attribute AString nickname;
 
   /**
@@ -63,28 +63,28 @@ interface nsIX509Cert : nsISupports {
   readonly attribute AString organization;
 
   /**
    *  The subject's organizational unit.
    */
   readonly attribute AString organizationalUnit;
 
   /**
+   *  The fingerprint of the certificate's DER encoding,
+   *  calculated using the SHA-256 algorithm.
+   */
+  readonly attribute AString sha256Fingerprint;
+
+  /**
    *  The fingerprint of the certificate's public key,
    *  calculated using the SHA1 algorithm.
    */
   readonly attribute AString sha1Fingerprint;
 
   /**
-   *  The fingerprint of the certificate's public key,
-   *  calculated using the MD5 algorithm.
-   */
-  readonly attribute AString md5Fingerprint;
-
-  /**
    *  A human readable name identifying the hardware or
    *  software token the certificate is stored on.
    */
   readonly attribute AString tokenName;
 
   /**
    *  The subject identifying the issuer certificate.
    */
--- a/security/manager/ssl/src/nsNSSCertificate.cpp
+++ b/security/manager/ssl/src/nsNSSCertificate.cpp
@@ -992,62 +992,53 @@ nsNSSCertificate::GetSerialNumber(nsAStr
   if (tmpstr) {
     _serialNumber = NS_ConvertASCIItoUTF16(tmpstr);
     PORT_Free(tmpstr);
     return NS_OK;
   }
   return NS_ERROR_FAILURE;
 }
 
+nsresult
+nsNSSCertificate::GetCertificateHash(nsAString& aFingerprint, SECOidTag aHashAlg)
+{
+  nsNSSShutDownPreventionLock locker;
+  if (isAlreadyShutDown()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  aFingerprint.Truncate();
+  Digest digest;
+  nsresult rv = digest.DigestBuf(aHashAlg, mCert->derCert.data,
+                                 mCert->derCert.len);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  // CERT_Hexify's second argument is an int that is interpreted as a boolean
+  char* fpStr = CERT_Hexify(const_cast<SECItem*>(&digest.get()), 1);
+  if (!fpStr) {
+    return NS_ERROR_FAILURE;
+  }
+
+  aFingerprint.AssignASCII(fpStr);
+  PORT_Free(fpStr);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsNSSCertificate::GetSha256Fingerprint(nsAString& aSha256Fingerprint)
+{
+  return GetCertificateHash(aSha256Fingerprint, SEC_OID_SHA256);
+}
+
 NS_IMETHODIMP
 nsNSSCertificate::GetSha1Fingerprint(nsAString& _sha1Fingerprint)
 {
-  nsNSSShutDownPreventionLock locker;
-  if (isAlreadyShutDown())
-    return NS_ERROR_NOT_AVAILABLE;
-
-  _sha1Fingerprint.Truncate();
-  unsigned char fingerprint[20];
-  SECItem fpItem;
-  memset(fingerprint, 0, sizeof fingerprint);
-  PK11_HashBuf(SEC_OID_SHA1, fingerprint,
-               mCert->derCert.data, mCert->derCert.len);
-  fpItem.data = fingerprint;
-  fpItem.len = SHA1_LENGTH;
-  char* fpStr = CERT_Hexify(&fpItem, 1);
-  if (fpStr) {
-    _sha1Fingerprint = NS_ConvertASCIItoUTF16(fpStr);
-    PORT_Free(fpStr);
-    return NS_OK;
-  }
-  return NS_ERROR_FAILURE;
-}
-
-NS_IMETHODIMP
-nsNSSCertificate::GetMd5Fingerprint(nsAString& _md5Fingerprint)
-{
-  nsNSSShutDownPreventionLock locker;
-  if (isAlreadyShutDown())
-    return NS_ERROR_NOT_AVAILABLE;
-
-  _md5Fingerprint.Truncate();
-  unsigned char fingerprint[20];
-  SECItem fpItem;
-  memset(fingerprint, 0, sizeof fingerprint);
-  PK11_HashBuf(SEC_OID_MD5, fingerprint,
-               mCert->derCert.data, mCert->derCert.len);
-  fpItem.data = fingerprint;
-  fpItem.len = MD5_LENGTH;
-  char* fpStr = CERT_Hexify(&fpItem, 1);
-  if (fpStr) {
-    _md5Fingerprint = NS_ConvertASCIItoUTF16(fpStr);
-    PORT_Free(fpStr);
-    return NS_OK;
-  }
-  return NS_ERROR_FAILURE;
+  return GetCertificateHash(_sha1Fingerprint, SEC_OID_SHA1);
 }
 
 NS_IMETHODIMP
 nsNSSCertificate::GetTokenName(nsAString& aTokenName)
 {
   static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
 
   nsNSSShutDownPreventionLock locker;
--- a/security/manager/ssl/src/nsNSSCertificate.h
+++ b/security/manager/ssl/src/nsNSSCertificate.h
@@ -60,16 +60,18 @@ private:
   nsresult CreateASN1Struct(nsIASN1Object** aRetVal);
   nsresult CreateTBSCertificateASN1Struct(nsIASN1Sequence** retSequence,
                                           nsINSSComponent* nssComponent);
   nsresult GetSortableDate(PRTime aTime, nsAString& _aSortableDate);
   virtual void virtualDestroyNSSReference();
   void destructorSafeDestroyNSSReference();
   bool InitFromDER(char* certDER, int derLen);  // return false on failure
 
+  nsresult GetCertificateHash(nsAString& aFingerprint, SECOidTag aHashAlg);
+
   enum {
     ev_status_unknown = -1, ev_status_invalid = 0, ev_status_valid = 1
   } mCachedEVStatus;
   SECOidTag mCachedEVOidTag;
   nsresult hasValidEVOidTag(SECOidTag& resultOidTag, bool& validEV);
   nsresult getValidEVOidTag(SECOidTag& resultOidTag, bool& validEV);
 };
 
--- a/security/manager/ssl/src/nsNSSCertificateFakeTransport.cpp
+++ b/security/manager/ssl/src/nsNSSCertificateFakeTransport.cpp
@@ -157,24 +157,24 @@ nsNSSCertificateFakeTransport::GetIssuer
 NS_IMETHODIMP
 nsNSSCertificateFakeTransport::GetSerialNumber(nsAString &_serialNumber)
 {
   NS_NOTREACHED("Unimplemented on content process");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetSha1Fingerprint(nsAString &_sha1Fingerprint)
+nsNSSCertificateFakeTransport::GetSha256Fingerprint(nsAString& aSha256Fingerprint)
 {
   NS_NOTREACHED("Unimplemented on content process");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
-nsNSSCertificateFakeTransport::GetMd5Fingerprint(nsAString &_md5Fingerprint)
+nsNSSCertificateFakeTransport::GetSha1Fingerprint(nsAString& aSha1Fingerprint)
 {
   NS_NOTREACHED("Unimplemented on content process");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsNSSCertificateFakeTransport::GetTokenName(nsAString &aTokenName)
 {
--- a/services/sync/tests/tps/mozmill_sanity.js
+++ b/services/sync/tests/tps/mozmill_sanity.js
@@ -1,28 +1,29 @@
 /* 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/. */
 
-Components.utils.import('resource://tps/mozmill/sync.jsm');
+Components.utils.import('resource://tps/tps.jsm');
 
 var setupModule = function(module) {
-  controller = mozmill.getBrowserController();
+  module.controller = mozmill.getBrowserController();
   assert.ok(true, "SetupModule passes");
 }
 
 var setupTest = function(module) {
   assert.ok(true, "SetupTest passes");
 }
 
 var testTestStep = function() {
   assert.ok(true, "test Passes");
   controller.open("http://www.mozilla.org");
-  TPS.SetupSyncAccount();
-  assert.equal(TPS.Sync(SYNC_WIPE_SERVER), 0, "sync succeeded");
+
+  TPS.Login();
+  TPS.Sync(ACTIONS.ACTION_SYNC_WIPE_CLIENT);
 }
 
 var teardownTest = function () {
   assert.ok(true, "teardownTest passes");
 }
 
 var teardownModule = function() {
   assert.ok(true, "teardownModule passes");
--- a/services/sync/tests/tps/mozmill_sanity2.js
+++ b/services/sync/tests/tps/mozmill_sanity2.js
@@ -1,53 +1,15 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-var jum = {}; Components.utils.import('resource://mozmill/modules/jum.js', jum);
+/* 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 setupModule = function(module) {
   module.controller = mozmill.getBrowserController();
 };
 
 var testGetNode = function() {
   controller.open("about:support");
   controller.waitForPageLoad();
 
-  var appbox = new elementslib.ID(controller.tabs.activeTab, "application-box");
-  jum.assert(appbox.getNode().innerHTML == 'Firefox', 'correct app name');
+  var appbox = findElement.ID(controller.tabs.activeTab, "application-box");
+  assert.waitFor(() => appbox.getNode().textContent == 'Firefox', 'correct app name');
 };
-
-const NAV_BAR             = '/id("main-window")/id("tab-view-deck")/{"flex":"1"}' +
-                            '/id("navigator-toolbox")/id("nav-bar")';
-const SEARCH_BAR          = NAV_BAR + '/id("search-container")/id("searchbar")';
-const SEARCH_TEXTBOX      = SEARCH_BAR      + '/anon({"anonid":"searchbar-textbox"})';
-const SEARCH_DROPDOWN     = SEARCH_TEXTBOX  + '/[0]/anon({"anonid":"searchbar-engine-button"})';
-const SEARCH_POPUP        = SEARCH_DROPDOWN + '/anon({"anonid":"searchbar-popup"})';
-const SEARCH_INPUT        = SEARCH_TEXTBOX  + '/anon({"class":"autocomplete-textbox-container"})' +
-                                              '/anon({"anonid":"textbox-input-box"})' +
-                                              '/anon({"anonid":"input"})';
-const SEARCH_CONTEXT      = SEARCH_TEXTBOX  + '/anon({"anonid":"textbox-input-box"})' +
-                                              '/anon({"anonid":"input-box-contextmenu"})';
-const SEARCH_GO_BUTTON    = SEARCH_TEXTBOX  + '/anon({"class":"search-go-container"})' +
-                                              '/anon({"class":"search-go-button"})';
-const SEARCH_AUTOCOMPLETE = '/id("main-window")/id("mainPopupSet")/id("PopupAutoComplete")';
-
-var testLookupExpressions = function() {
-  var item;
-  item = new elementslib.Lookup(controller.window.document, NAV_BAR);
-  controller.click(item);
-  item = new elementslib.Lookup(controller.window.document, SEARCH_BAR);
-  controller.click(item);
-  item = new elementslib.Lookup(controller.window.document, SEARCH_TEXTBOX);
-  controller.click(item);
-  item = new elementslib.Lookup(controller.window.document, SEARCH_DROPDOWN);
-  controller.click(item);
-  item = new elementslib.Lookup(controller.window.document, SEARCH_POPUP);
-  controller.click(item);
-  item = new elementslib.Lookup(controller.window.document, SEARCH_INPUT);
-  controller.click(item);
-  item = new elementslib.Lookup(controller.window.document, SEARCH_CONTEXT);
-  controller.click(item);
-  item = new elementslib.Lookup(controller.window.document, SEARCH_GO_BUTTON);
-  controller.click(item);
-  item = new elementslib.Lookup(controller.window.document, SEARCH_AUTOCOMPLETE);
-  controller.click(item);
-};
old mode 100644
new mode 100755
deleted file mode 100644
--- a/services/sync/tps/extensions/mozmill/defaults/preferences/debug.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/* 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/. */
-
-/* debugging prefs */
-pref("browser.dom.window.dump.enabled", true);
-pref("javascript.options.showInConsole", true);
old mode 100644
new mode 100755
--- a/services/sync/tps/extensions/mozmill/install.rdf
+++ b/services/sync/tps/extensions/mozmill/install.rdf
@@ -1,63 +1,28 @@
 <?xml version="1.0"?>
 <!-- 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/. -->
 
 <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
      xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
    <Description about="urn:mozilla:install-manifest">
      <em:id>mozmill@mozilla.com</em:id>
-     <em:name>MozMill</em:name>
-     <em:version>2.0b1</em:version>
-     <em:creator>Adam Christian</em:creator>
-     <em:description>A testing extension based on the Windmill Testing Framework client source</em:description>
+     <em:name>Mozmill</em:name>
+     <em:version>2.0.6</em:version>
+     <em:description>UI Automation tool for Mozilla applications</em:description>
      <em:unpack>true</em:unpack>
+
+     <em:creator>Mozilla Automation and Testing Team</em:creator>
+     <em:contributor>Adam Christian</em:contributor>
+     <em:contributor>Mikeal Rogers</em:contributor>
+
      <em:targetApplication>
-       <!-- Firefox -->
-       <Description>
-         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
-         <em:minVersion>3.5</em:minVersion>
-         <em:maxVersion>12.*</em:maxVersion>
-       </Description>
-     </em:targetApplication>
-     <em:targetApplication>
-       <!-- Thunderbird -->
-       <Description>
-         <em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id>
-         <em:minVersion>3.0a1pre</em:minVersion>
-         <em:maxVersion>9.*</em:maxVersion>
-       </Description>
-     </em:targetApplication>
-     <em:targetApplication>
-       <!-- Sunbird -->
        <Description>
-         <em:id>{718e30fb-e89b-41dd-9da7-e25a45638b28}</em:id>
-         <em:minVersion>0.6a1</em:minVersion>
-         <em:maxVersion>1.0pre</em:maxVersion>
-       </Description>
-     </em:targetApplication>
-     <em:targetApplication>
-       <!-- SeaMonkey -->
-       <Description>
-         <em:id>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</em:id>
-         <em:minVersion>2.0a1</em:minVersion>
-         <em:maxVersion>9.*</em:maxVersion>
+         <em:id>toolkit@mozilla.org</em:id>
+         <em:minVersion>10.0</em:minVersion>
+         <em:maxVersion>31.*</em:maxVersion>
        </Description>
      </em:targetApplication>
-	   <em:targetApplication>
-	      <!-- Songbird -->
-	      <Description>
-	        <em:id>songbird@songbirdnest.com</em:id>
-	        <em:minVersion>0.3pre</em:minVersion>
-	        <em:maxVersion>1.3.0a</em:maxVersion>
-	      </Description>
-	   </em:targetApplication>
-	   <em:targetApplication>
-         <Description>
-          <em:id>toolkit@mozilla.org</em:id>
-          <em:minVersion>1.9.1</em:minVersion>
-          <em:maxVersion>9.*</em:maxVersion>
-         </Description>
-     </em:targetApplication>
    </Description>
 </RDF>
new file mode 100644
--- /dev/null
+++ b/services/sync/tps/extensions/mozmill/resource/driver/controller.js
@@ -0,0 +1,1150 @@
+/* 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 EXPORTED_SYMBOLS = ["MozMillController", "globalEventRegistry",
+                        "sleep", "windowMap"];
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+var EventUtils = {}; Cu.import('resource://mozmill/stdlib/EventUtils.js', EventUtils);
+
+var assertions = {}; Cu.import('resource://mozmill/modules/assertions.js', assertions);
+var broker = {}; Cu.import('resource://mozmill/driver/msgbroker.js', broker);
+var elementslib = {}; Cu.import('resource://mozmill/driver/elementslib.js', elementslib);
+var errors = {}; Cu.import('resource://mozmill/modules/errors.js', errors);
+var mozelement = {}; Cu.import('resource://mozmill/driver/mozelement.js', mozelement);
+var utils = {}; Cu.import('resource://mozmill/stdlib/utils.js', utils);
+var windows = {}; Cu.import('resource://mozmill/modules/windows.js', windows);
+
+// Declare most used utils functions in the controller namespace
+var assert = new assertions.Assert();
+var waitFor = assert.waitFor;
+
+var sleep = utils.sleep;
+
+// For Mozmill 1.5 backward compatibility
+var windowMap = windows.map;
+
+waitForEvents = function () {
+}
+
+waitForEvents.prototype = {
+  /**
+   * Initialize list of events for given node
+   */
+  init: function waitForEvents_init(node, events) {
+    if (node.getNode != undefined)
+      node = node.getNode();
+
+    this.events = events;
+    this.node = node;
+    node.firedEvents = {};
+    this.registry = {};
+
+    for each (var e in events) {
+      var listener = function (event) {
+        this.firedEvents[event.type] = true;
+      }
+
+      this.registry[e] = listener;
+      this.registry[e].result = false;
+      this.node.addEventListener(e, this.registry[e], true);
+    }
+  },
+
+  /**
+   * Wait until all assigned events have been fired
+   */
+  wait: function waitForEvents_wait(timeout, interval) {
+    for (var e in this.registry) {
+      assert.waitFor(function () {
+        return this.node.firedEvents[e] == true;
+      }, "waitForEvents.wait(): Event '" + ex + "' has been fired.", timeout, interval);
+
+      this.node.removeEventListener(e, this.registry[e], true);
+    }
+  }
+}
+
+/**
+ * Class to handle menus and context menus
+ *
+ * @constructor
+ * @param {MozMillController} controller
+ *        Mozmill controller of the window under test
+ * @param {string} menuSelector
+ *        jQuery like selector string of the element
+ * @param {object} document
+ *        Document to use for finding the menu
+ *        [optional - default: aController.window.document]
+ */
+var Menu = function (controller, menuSelector, document) {
+  this._controller = controller;
+  this._menu = null;
+
+  document = document || controller.window.document;
+  var node = document.querySelector(menuSelector);
+  if (node) {
+    // We don't unwrap nodes automatically yet (Bug 573185)
+    node = node.wrappedJSObject || node;
+    this._menu = new mozelement.Elem(node);
+  } else {
+    throw new Error("Menu element '" + menuSelector + "' not found.");
+  }
+}
+
+Menu.prototype = {
+
+  /**
+   * Open and populate the menu
+   *
+   * @param {ElemBase} contextElement
+   *        Element whose context menu has to be opened
+   * @returns {Menu} The Menu instance
+   */
+  open: function Menu_open(contextElement) {
+    // We have to open the context menu
+    var menu = this._menu.getNode();
+    if ((menu.localName == "popup" || menu.localName == "menupopup") &&
+        contextElement && contextElement.exists()) {
+      this._controller.rightClick(contextElement);
+      assert.waitFor(function () {
+        return menu.state == "open";
+      }, "Context menu has been opened.");
+    }
+
+    // Run through the entire menu and populate with dynamic entries
+    this._buildMenu(menu);
+
+    return this;
+  },
+
+  /**
+   * Close the menu
+   *
+   * @returns {Menu} The Menu instance
+   */
+  close: function Menu_close() {
+    var menu = this._menu.getNode();
+
+    this._controller.keypress(this._menu, "VK_ESCAPE", {});
+    assert.waitFor(function () {
+      return menu.state == "closed";
+    }, "Context menu has been closed.");
+
+    return this;
+  },
+
+  /**
+   * Retrieve the specified menu entry
+   *
+   * @param {string} itemSelector
+   *        jQuery like selector string of the menu item
+   * @returns {ElemBase} Menu element
+   * @throws Error If menu element has not been found
+   */
+  getItem: function Menu_getItem(itemSelector) {
+    // Run through the entire menu and populate with dynamic entries
+    this._buildMenu(this._menu.getNode());
+
+    var node = this._menu.getNode().querySelector(itemSelector);
+
+    if (!node) {
+      throw new Error("Menu entry '" + itemSelector + "' not found.");
+    }
+
+    return new mozelement.Elem(node);
+  },
+
+  /**
+   * Click the specified menu entry
+   *
+   * @param {string} itemSelector
+   *        jQuery like selector string of the menu item
+   *
+   * @returns {Menu} The Menu instance
+   */
+  click: function Menu_click(itemSelector) {
+    this._controller.click(this.getItem(itemSelector));
+
+    return this;
+  },
+
+  /**
+   * Synthesize a keypress against the menu
+   *
+   * @param {string} key
+   *        Key to press
+   * @param {object} modifier
+   *        Key modifiers
+   * @see MozMillController#keypress
+   *
+   * @returns {Menu} The Menu instance
+   */
+  keypress: function Menu_keypress(key, modifier) {
+    this._controller.keypress(this._menu, key, modifier);
+
+    return this;
+  },
+
+  /**
+   * Opens the context menu, click the specified entry and
+   * make sure that the menu has been closed.
+   *
+   * @param {string} itemSelector
+   *        jQuery like selector string of the element
+   * @param {ElemBase} contextElement
+   *        Element whose context menu has to be opened
+   *
+   * @returns {Menu} The Menu instance
+   */
+  select: function Menu_select(itemSelector, contextElement) {
+    this.open(contextElement);
+    this.click(itemSelector);
+    this.close();
+  },
+
+  /**
+   * Recursive function which iterates through all menu elements and
+   * populates the menus with dynamic menu entries.
+   *
+   * @param {node} menu
+   *        Top menu node whose elements have to be populated
+   */
+  _buildMenu: function Menu__buildMenu(menu) {
+    var items = menu ? menu.childNodes : null;
+
+    Array.forEach(items, function (item) {
+      // When we have a menu node, fake a click onto it to populate
+      // the sub menu with dynamic entries
+      if (item.tagName == "menu") {
+        var popup = item.querySelector("menupopup");
+
+        if (popup) {
+          var popupEvent = this._controller.window.document.createEvent("MouseEvent");
+          popupEvent.initMouseEvent("popupshowing", true, true,
+                                    this._controller.window, 0, 0, 0, 0, 0,
+                                    false, false, false, false, 0, null);
+          popup.dispatchEvent(popupEvent);
+
+          this._buildMenu(popup);
+        }
+      }
+    }, this);
+  }
+};
+
+var MozMillController = function (window) {
+  this.window = window;
+
+  this.mozmillModule = {};
+  Cu.import('resource://mozmill/driver/mozmill.js', this.mozmillModule);
+
+  var self = this;
+  assert.waitFor(function () {
+    return window != null && self.isLoaded();
+  }, "controller(): Window has been initialized.");
+
+  // Ensure to focus the window which will move it virtually into the foreground
+  // when focusmanager.testmode is set enabled.
+  this.window.focus();
+
+  var windowType = window.document.documentElement.getAttribute('windowtype');
+  if (controllerAdditions[windowType] != undefined ) {
+    this.prototype = new utils.Copy(this.prototype);
+    controllerAdditions[windowType](this);
+    this.windowtype = windowType;
+  }
+}
+
+/**
+ * Returns the global browser object of the window
+ *
+ * @returns {Object} The browser object
+ */
+MozMillController.prototype.__defineGetter__("browserObject", function () {
+  return utils.getBrowserObject(this.window);
+});
+
+// constructs a MozMillElement from the controller's window
+MozMillController.prototype.__defineGetter__("rootElement", function () {
+  if (this._rootElement == undefined) {
+    let docElement = this.window.document.documentElement;
+    this._rootElement = new mozelement.MozMillElement("Elem", docElement);
+  }
+
+  return this._rootElement;
+});
+
+MozMillController.prototype.sleep = utils.sleep;
+MozMillController.prototype.waitFor = assert.waitFor;
+
+// Open the specified url in the current tab
+MozMillController.prototype.open = function (url) {
+  switch (this.mozmillModule.Application) {
+    case "Firefox":
+    case "MetroFirefox":
+      // Stop a running page load to not overlap requests
+      if (this.browserObject.selectedBrowser) {
+        this.browserObject.selectedBrowser.stop();
+      }
+
+      this.browserObject.loadURI(url);
+      break;
+
+    default:
+      throw new Error("MozMillController.open not supported.");
+  }
+
+  broker.pass({'function':'Controller.open()'});
+}
+
+/**
+ * Take a screenshot of specified node
+ *
+ * @param {Element} node
+ *        The window or DOM element to capture
+ * @param {String} name
+ *        The name of the screenshot used in reporting and as filename
+ * @param {Boolean} save
+ *        If true saves the screenshot as 'name.jpg' in tempdir,
+ *        otherwise returns a dataURL
+ * @param {Element[]} highlights
+ *        A list of DOM elements to highlight by drawing a red rectangle around them
+ *
+ * @returns {Object} Object which contains properties like filename, dataURL,
+ *          name and timestamp of the screenshot
+ */
+MozMillController.prototype.screenshot = function (node, name, save, highlights) {
+  if (!node) {
+    throw new Error("node is undefined");
+  }
+
+  // Unwrap the node and highlights
+  if ("getNode" in node) {
+    node = node.getNode();
+  }
+
+  if (highlights) {
+    for (var i = 0; i < highlights.length; ++i) {
+      if ("getNode" in highlights[i]) {
+        highlights[i] = highlights[i].getNode();
+      }
+    }
+  }
+
+  // If save is false, a dataURL is used
+  // Include both in the report anyway to avoid confusion and make the report easier to parse
+  var screenshot = {"filename": undefined,
+                    "dataURL": utils.takeScreenshot(node, highlights),
+                    "name": name,
+                    "timestamp": new Date().toLocaleString()};
+
+  if (!save) {
+    return screenshot;
+  }
+
+  // Save the screenshot to disk
+
+  let {filename, failure} = utils.saveDataURL(screenshot.dataURL, name);
+  screenshot.filename = filename;
+  screenshot.failure = failure;
+
+  if (failure) {
+    broker.log({'function': 'controller.screenshot()',
+                'message': 'Error writing to file: ' + screenshot.filename});
+  } else {
+    // Send the screenshot object to python over jsbridge
+    broker.sendMessage("screenshot", screenshot);
+    broker.pass({'function': 'controller.screenshot()'});
+  }
+
+  return screenshot;
+}
+
+/**
+ * Checks if the specified window has been loaded
+ *
+ * @param {DOMWindow} [aWindow=this.window] Window object to check for loaded state
+ */
+MozMillController.prototype.isLoaded = function (aWindow) {
+  var win = aWindow || this.window;
+
+  return windows.map.getValue(utils.getWindowId(win), "loaded") || false;
+};
+
+MozMillController.prototype.__defineGetter__("waitForEvents", function () {
+  if (this._waitForEvents == undefined) {
+    this._waitForEvents = new waitForEvents();
+  }
+
+  return this._waitForEvents;
+});
+
+/**
+ * Wrapper function to create a new instance of a menu
+ * @see Menu
+ */
+MozMillController.prototype.getMenu = function (menuSelector, document) {
+  return new Menu(this, menuSelector, document);
+};
+
+MozMillController.prototype.__defineGetter__("mainMenu", function () {
+  return this.getMenu("menubar");
+});
+
+MozMillController.prototype.__defineGetter__("menus", function () {
+  logDeprecated('controller.menus', 'Use controller.mainMenu instead');
+});
+
+MozMillController.prototype.waitForImage = function (aElement, timeout, interval) {
+  this.waitFor(function () {
+    return aElement.getNode().complete == true;
+  }, "timeout exceeded for waitForImage " + aElement.getInfo(), timeout, interval);
+
+  broker.pass({'function':'Controller.waitForImage()'});
+}
+
+MozMillController.prototype.startUserShutdown = function (timeout, restart, next, resetProfile) {
+  if (restart && resetProfile) {
+    throw new Error("You can't have a user-restart and reset the profile; there is a race condition");
+  }
+
+  let shutdownObj = {
+    'user': true,
+    'restart': Boolean(restart),
+    'next': next,
+    'resetProfile': Boolean(resetProfile),
+    'timeout': timeout
+  };
+
+  broker.sendMessage('shutdown', shutdownObj);
+}
+
+/**
+ * Restart the application
+ *
+ * @param {string} aNext
+ *        Name of the next test function to run after restart
+ * @param {boolean} [aFlags=undefined]
+ *        Additional flags how to handle the shutdown or restart. The attributes
+ *        eRestarti386 (0x20) and eRestartx86_64 (0x30) have not been documented yet.
+ * @see https://developer.mozilla.org/nsIAppStartup#Attributes
+ */
+MozMillController.prototype.restartApplication = function (aNext, aFlags) {
+  var flags = Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart;
+
+  if (aFlags) {
+    flags |= aFlags;
+  }
+
+  broker.sendMessage('shutdown', {'user': false,
+                                  'restart': true,
+                                  'flags': flags,
+                                  'next': aNext,
+                                  'timeout': 0 });
+
+  // We have to ensure to stop the test from continuing until the application is
+  // shutting down. The only way to do that is by throwing an exception.
+  throw new errors.ApplicationQuitError();
+}
+
+/**
+ * Stop the application
+ *
+ * @param {boolean} [aResetProfile=false]
+ *        Whether to reset the profile during restart
+ * @param {boolean} [aFlags=undefined]
+ *        Additional flags how to handle the shutdown or restart. The attributes
+ *        eRestarti386 and eRestartx86_64 have not been documented yet.
+ * @see https://developer.mozilla.org/nsIAppStartup#Attributes
+ */
+MozMillController.prototype.stopApplication = function (aResetProfile, aFlags) {
+  var flags = Ci.nsIAppStartup.eAttemptQuit;
+
+  if (aFlags) {
+    flags |= aFlags;
+  }
+
+  broker.sendMessage('shutdown', {'user': false,
+                                  'restart': false,
+                                  'flags': flags,
+                                  'resetProfile': aResetProfile,
+                                  'timeout': 0 });
+
+  // We have to ensure to stop the test from continuing until the application is
+  // shutting down. The only way to do that is by throwing an exception.
+  throw new errors.ApplicationQuitError();
+}
+
+//Browser navigation functions
+MozMillController.prototype.goBack = function () {
+  this.window.content.history.back();
+  broker.pass({'function':'Controller.goBack()'});
+
+  return true;
+}
+
+MozMillController.prototype.goForward = function () {
+  this.window.content.history.forward();
+  broker.pass({'function':'Controller.goForward()'});
+
+  return true;
+}
+
+MozMillController.prototype.refresh = function () {
+  this.window.content.location.reload(true);
+  broker.pass({'function':'Controller.refresh()'});
+
+  return true;
+}
+
+function logDeprecated(funcName, message) {
+  broker.log({'function': funcName + '() - DEPRECATED',
+              'message': funcName + '() is deprecated. ' + message});
+}
+
+function logDeprecatedAssert(funcName) {
+   logDeprecated('controller.' + funcName,
+                 '. Use the generic `assertion` module instead.');
+}
+
+MozMillController.prototype.assertText = function (el, text) {
+  logDeprecatedAssert("assertText");
+
+  var n = el.getNode();
+
+  if (n && n.innerHTML == text) {
+    broker.pass({'function': 'Controller.assertText()'});
+  } else {
+    throw new Error("could not validate element " + el.getInfo() +
+                    " with text "+ text);
+  }
+
+  return true;
+};
+
+/**
+ * Assert that a specified node exists
+ */
+MozMillController.prototype.assertNode = function (el) {
+  logDeprecatedAssert("assertNode");
+
+  //this.window.focus();
+  var element = el.getNode();
+  if (!element) {
+    throw new Error("could not find element " + el.getInfo());
+  }
+
+  broker.pass({'function': 'Controller.assertNode()'});
+  return true;
+};
+
+/**
+ * Assert that a specified node doesn't exist
+ */
+MozMillController.prototype.assertNodeNotExist = function (el) {
+  logDeprecatedAssert("assertNodeNotExist");
+
+  try {
+    var element = el.getNode();
+  } catch (e) {
+    broker.pass({'function': 'Controller.assertNodeNotExist()'});
+  }
+
+  if (element) {
+    throw new Error("Unexpectedly found element " + el.getInfo());
+  } else {
+    broker.pass({'function':'Controller.assertNodeNotExist()'});
+  }
+
+  return true;
+};
+
+/**
+ * Assert that a form element contains the expected value
+ */
+MozMillController.prototype.assertValue = function (el, value) {
+  logDeprecatedAssert("assertValue");
+
+  var n = el.getNode();
+
+  if (n && n.value == value) {
+    broker.pass({'function': 'Controller.assertValue()'});
+  } else {
+    throw new Error("could not validate element " + el.getInfo() +
+                    " with value " + value);
+  }
+
+  return false;
+};
+
+/**
+ * Check if the callback function evaluates to true
+ */
+MozMillController.prototype.assert = function (callback, message, thisObject) {
+  logDeprecatedAssert("assert");
+
+  utils.assert(callback, message, thisObject);
+  broker.pass({'function': ": controller.assert('" + callback + "')"});
+
+  return true;
+}
+
+/**
+ * Assert that a provided value is selected in a select element
+ */
+MozMillController.prototype.assertSelected = function (el, value) {
+  logDeprecatedAssert("assertSelected");
+
+  var n = el.getNode();
+  var validator = value;
+
+  if (n && n.options[n.selectedIndex].value == validator) {
+    broker.pass({'function':'Controller.assertSelected()'});
+  } else {
+    throw new Error("could not assert value for element " + el.getInfo() +
+                    " with value " + value);
+  }
+
+  return true;
+};
+
+/**
+ * Assert that a provided checkbox is checked
+ */
+MozMillController.prototype.assertChecked = function (el) {
+  logDeprecatedAssert("assertChecked");
+
+  var element = el.getNode();
+
+  if (element && element.checked == true) {
+    broker.pass({'function':'Controller.assertChecked()'});
+  } else {
+    throw new Error("assert failed for checked element " + el.getInfo());
+  }
+
+  return true;
+};
+
+/**
+ * Assert that a provided checkbox is not checked
+ */
+MozMillController.prototype.assertNotChecked = function (el) {
+  logDeprecatedAssert("assertNotChecked");
+
+  var element = el.getNode();
+
+  if (!element) {
+    throw new Error("Could not find element" + el.getInfo());
+  }
+
+  if (!element.hasAttribute("checked") || element.checked != true) {
+    broker.pass({'function': 'Controller.assertNotChecked()'});
+  } else {
+    throw new Error("assert failed for not checked element " + el.getInfo());
+  }
+
+  return true;
+};
+
+/**
+ * Assert that an element's javascript property exists or has a particular value
+ *
+ * if val is undefined, will return true if the property exists.
+ * if val is specified, will return true if the property exists and has the correct value
+ */
+MozMillController.prototype.assertJSProperty = function (el, attrib, val) {
+  logDeprecatedAssert("assertJSProperty");
+
+  var element = el.getNode();
+
+  if (!element){
+    throw new Error("could not find element " + el.getInfo());
+  }
+
+  var value = element[attrib];
+  var res = (value !== undefined && (val === undefined ? true :
+                                                         String(value) == String(val)));
+  if (res) {
+    broker.pass({'function':'Controller.assertJSProperty("' + el.getInfo() + '") : ' + val});
+  } else {
+    throw new Error("Controller.assertJSProperty(" + el.getInfo() + ") : " +
+                    (val === undefined ? "property '" + attrib +
+                    "' doesn't exist" : val + " == " + value));
+  }
+
+  return true;
+};
+
+/**
+ * Assert that an element's javascript property doesn't exist or doesn't have a particular value
+ *
+ * if val is undefined, will return true if the property doesn't exist.
+ * if val is specified, will return true if the property doesn't exist or doesn't have the specified value
+ */
+MozMillController.prototype.assertNotJSProperty = function (el, attrib, val) {
+  logDeprecatedAssert("assertNotJSProperty");
+
+  var element = el.getNode();
+
+  if (!element){
+    throw new Error("could not find element " + el.getInfo());
+  }
+
+  var value = element[attrib];
+  var res = (val === undefined ? value === undefined : String(value) != String(val));
+  if (res) {
+    broker.pass({'function':'Controller.assertNotProperty("' + el.getInfo() + '") : ' + val});
+  } else {
+    throw new Error("Controller.assertNotJSProperty(" + el.getInfo() + ") : " +
+                    (val === undefined ? "property '" + attrib +
+                    "' exists" : val + " != " + value));
+  }
+
+  return true;
+};
+
+/**
+ * Assert that an element's dom property exists or has a particular value
+ *
+ * if val is undefined, will return true if the property exists.
+ * if val is specified, will return true if the property exists and has the correct value
+ */
+MozMillController.prototype.assertDOMProperty = function (el, attrib, val) {
+  logDeprecatedAssert("assertDOMProperty");
+
+  var element = el.getNode();
+
+  if (!element){
+    throw new Error("could not find element " + el.getInfo());
+  }
+
+  var value, res = element.hasAttribute(attrib);
+  if (res && val !== undefined) {
+    value = element.getAttribute(attrib);
+    res = (String(value) == String(val));
+  }
+
+  if (res) {
+    broker.pass({'function':'Controller.assertDOMProperty("' + el.getInfo() + '") : ' + val});
+  } else {
+    throw new Error("Controller.assertDOMProperty(" + el.getInfo() + ") : " +
+                    (val === undefined ? "property '" + attrib +
+                    "' doesn't exist" : val + " == " + value));
+  }
+
+  return true;
+};
+
+/**
+ * Assert that an element's dom property doesn't exist or doesn't have a particular value
+ *
+ * if val is undefined, will return true if the property doesn't exist.
+ * if val is specified, will return true if the property doesn't exist or doesn't have the specified value
+ */
+MozMillController.prototype.assertNotDOMProperty = function (el, attrib, val) {
+  logDeprecatedAssert("assertNotDOMProperty");
+
+  var element = el.getNode();
+
+  if (!element) {
+    throw new Error("could not find element " + el.getInfo());
+  }
+
+  var value, res = element.hasAttribute(attrib);
+  if (res && val !== undefined) {
+    value = element.getAttribute(attrib);
+    res = (String(value) == String(val));
+  }
+
+  if (!res) {
+    broker.pass({'function':'Controller.assertNotDOMProperty("' + el.getInfo() + '") : ' + val});
+  } else {
+    throw new Error("Controller.assertNotDOMProperty(" + el.getInfo() + ") : " +
+                    (val == undefined ? "property '" + attrib +
+                    "' exists" : val + " == " + value));
+  }
+
+  return true;
+};
+
+/**
+ * Assert that a specified image has actually loaded. The Safari workaround results
+ * in additional requests for broken images (in Safari only) but works reliably
+ */
+MozMillController.prototype.assertImageLoaded = function (el) {
+  logDeprecatedAssert("assertImageLoaded");
+
+  var img = el.getNode();
+
+  if (!img || img.tagName != 'IMG') {
+    throw new Error('Controller.assertImageLoaded() failed.')
+    return false;
+  }
+
+  var comp = img.complete;
+  var ret = null; // Return value
+
+  // Workaround for Safari -- it only supports the
+  // complete attrib on script-created images
+  if (typeof comp == 'undefined') {
+    test = new Image();
+    // If the original image was successfully loaded,
+    // src for new one should be pulled from cache
+    test.src = img.src;
+    comp = test.complete;
+  }
+
+  // Check the complete attrib. Note the strict
+  // equality check -- we don't want undefined, null, etc.
+  // --------------------------
+  if (comp === false) {
+    // False -- Img failed to load in IE/Safari, or is
+    // still trying to load in FF
+    ret = false;
+  } else if (comp === true && img.naturalWidth == 0) {
+    // True, but image has no size -- image failed to
+    // load in FF
+    ret = false;
+  } else {
+    // Otherwise all we can do is assume everything's
+    // hunky-dory
+   ret = true;
+  }
+
+  if (ret) {
+    broker.pass({'function':'Controller.assertImageLoaded'});
+  } else {
+    throw new Error('Controller.assertImageLoaded() failed.')
+  }
+
+  return true;
+};
+
+/**
+ * Drag one element to the top x,y coords of another specified element
+ */
+MozMillController.prototype.mouseMove = function (doc, start, dest) {
+  // if one of these elements couldn't be looked up
+  if (typeof start != 'object'){
+    throw new Error("received bad coordinates");
+  }
+
+  if (typeof dest != 'object'){
+    throw new Error("received bad coordinates");
+  }
+
+  var triggerMouseEvent = function (element, clientX, clientY) {
+    clientX = clientX ? clientX: 0;
+    clientY = clientY ? clientY: 0;
+
+    // make the mouse understand where it is on the screen
+    var screenX = element.boxObject.screenX ? element.boxObject.screenX : 0;
+    var screenY = element.boxObject.screenY ? element.boxObject.screenY : 0;
+
+    var evt = element.ownerDocument.createEvent('MouseEvents');
+    if (evt.initMouseEvent) {
+      evt.initMouseEvent('mousemove', true, true, element.ownerDocument.defaultView,
+                         1, screenX, screenY, clientX, clientY);
+    } else {
+      evt.initEvent('mousemove', true, true);
+    }
+
+    element.dispatchEvent(evt);
+  };
+
+  // Do the initial move to the drag element position
+  triggerMouseEvent(doc.body, start[0], start[1]);
+  triggerMouseEvent(doc.body, dest[0], dest[1]);
+
+  broker.pass({'function':'Controller.mouseMove()'});
+  return true;
+}
+
+/**
+ * Drag an element to the specified offset on another element, firing mouse and
+ * drag events. Adapted from ChromeUtils.js synthesizeDrop()
+ *
+ * @deprecated Use the MozMillElement object
+ *
+ * @param {MozElement} aSrc
+ *        Source element to be dragged
+ * @param {MozElement} aDest
+ *        Destination element over which the drop occurs
+ * @param {Number} [aOffsetX=element.width/2]
+ *        Relative x offset for dropping on the aDest element
+ * @param {Number} [aOffsetY=element.height/2]
+ *        Relative y offset for dropping on the aDest element
+ * @param {DOMWindow} [aSourceWindow=this.element.ownerDocument.defaultView]
+ *        Custom source Window to be used.
+ * @param {String} [aDropEffect="move"]
+ *        Effect used for the drop event
+ * @param {Object[]} [aDragData]
+ *        An array holding custom drag data to be used during the drag event
+ *        Format: [{ type: "text/plain", "Text to drag"}, ...]
+ *
+ * @returns {String} the captured dropEffect
+ */
+MozMillController.prototype.dragToElement = function (aSrc, aDest, aOffsetX,
+                                                      aOffsetY, aSourceWindow,
+                                                      aDropEffect, aDragData) {
+  logDeprecated("controller.dragToElement", "Use the MozMillElement object.");
+  return aSrc.dragToElement(aDest, aOffsetX, aOffsetY, aSourceWindow, null,
+                            aDropEffect, aDragData);
+};
+
+function Tabs(controller) {
+  this.controller = controller;
+}
+
+Tabs.prototype.getTab = function (index) {
+  return this.controller.browserObject.browsers[index].contentDocument;
+}
+
+Tabs.prototype.__defineGetter__("activeTab", function () {
+  return this.controller.browserObject.selectedBrowser.contentDocument;
+});
+
+Tabs.prototype.selectTab = function (index) {
+  // GO in to tab manager and grab the tab by index and call focus.
+}
+
+Tabs.prototype.findWindow = function (doc) {
+  for (var i = 0; i <= (this.controller.window.frames.length - 1); i++) {
+    if (this.controller.window.frames[i].document == doc) {
+      return this.controller.window.frames[i];
+    }
+  }
+
+  throw new Error("Cannot find window for document. Doc title == " + doc.title);
+}
+
+Tabs.prototype.getTabWindow = function (index) {
+  return this.findWindow(this.getTab(index));
+}
+
+Tabs.prototype.__defineGetter__("activeTabWindow", function () {
+  return this.findWindow(this.activeTab);
+});
+
+Tabs.prototype.__defineGetter__("length", function () {
+  return this.controller.browserObject.browsers.length;
+});
+
+Tabs.prototype.__defineGetter__("activeTabIndex", function () {
+  var browser = this.controller.browserObject;
+
+  switch(this.controller.mozmillModule.Application) {
+    case "MetroFirefox":
+      return browser.tabs.indexOf(browser.selectedTab);
+    case "Firefox":
+    default:
+      return browser.tabContainer.selectedIndex;
+  }
+});
+
+Tabs.prototype.selectTabIndex = function (aIndex) {
+  var browser = this.controller.browserObject;
+
+  switch(this.controller.mozmillModule.Application) {
+    case "MetroFirefox":
+      browser.selectedTab = browser.tabs[aIndex];
+      break;
+    case "Firefox":
+    default:
+      browser.selectTabAtIndex(aIndex);
+  }
+}
+
+function browserAdditions (controller) {
+  controller.tabs = new Tabs(controller);
+
+  controller.waitForPageLoad = function (aDocument, aTimeout, aInterval) {
+    var timeout = aTimeout || 30000;
+    var win = null;
+    var timed_out = false;
+
+    // If a user tries to do waitForPageLoad(2000), this will assign the
+    // interval the first arg which is most likely what they were expecting
+    if (typeof(aDocument) == "number"){
+      timeout = aDocument;
+    }
+
+    // If we have a real document use its default view
+    if (aDocument && (typeof(aDocument) === "object") &&
+        "defaultView" in aDocument)
+      win = aDocument.defaultView;
+
+    // If no document has been specified, fallback to the default view of the
+    // currently selected tab browser
+    win = win || this.browserObject.selectedBrowser.contentWindow;
+
+    // Wait until the content in the tab has been loaded
+    try {
+      this.waitFor(function () {
+        return windows.map.hasPageLoaded(utils.getWindowId(win));
+      }, "Timeout", timeout, aInterval);
+    }
+    catch (ex if ex instanceof errors.TimeoutError) {
+      timed_out = true;
+    }
+    finally {
+      state = 'URI=' + win.document.location.href +
+              ', readyState=' + win.document.readyState;
+      message = "controller.waitForPageLoad(" + state + ")";
+
+      if (timed_out) {
+        throw new errors.AssertionError(message);
+      }
+
+      broker.pass({'function': message});
+    }
+  }
+}
+
+var controllerAdditions = {
+  'navigator:browser'  :browserAdditions
+};
+
+/**
+ *  DEPRECATION WARNING
+ *
+ * The following methods have all been DEPRECATED as of Mozmill 2.0
+ */
+MozMillController.prototype.assertProperty = function (el, attrib, val) {
+  logDeprecatedAssert("assertProperty");
+
+  return this.assertJSProperty(el, attrib, val);
+};
+
+MozMillController.prototype.assertPropertyNotExist = function (el, attrib) {
+  logDeprecatedAssert("assertPropertyNotExist");
+  return this.assertNotJSProperty(el, attrib);
+};
+
+/**
+ *  DEPRECATION WARNING
+ *
+ * The following methods have all been DEPRECATED as of Mozmill 2.0
+ * Use the MozMillElement object instead (https://developer.mozilla.org/en/Mozmill/Mozmill_Element_Object)
+ */
+MozMillController.prototype.select = function (aElement, index, option, value) {
+  logDeprecated("controller.select", "Use the MozMillElement object.");
+
+  return aElement.select(index, option, value);
+};
+
+MozMillController.prototype.keypress = function (aElement, aKey, aModifiers, aExpectedEvent) {
+  logDeprecated("controller.keypress", "Use the MozMillElement object.");
+
+  if (!aElement) {
+    aElement = new mozelement.MozMillElement("Elem", this.window);
+  }
+
+  return aElement.keypress(aKey, aModifiers, aExpectedEvent);
+}
+
+MozMillController.prototype.type = function (aElement, aText, aExpectedEvent) {
+  logDeprecated("controller.type", "Use the MozMillElement object.");
+
+  if (!aElement) {
+    aElement = new mozelement.MozMillElement("Elem", this.window);
+  }
+
+  var that = this;
+  var retval = true;
+  Array.forEach(aText, function (letter) {
+    if (!that.keypress(aElement, letter, {}, aExpectedEvent)) {
+      retval = false; }
+  });
+
+  return retval;
+}
+
+MozMillController.prototype.mouseEvent = function (aElement, aOffsetX, aOffsetY, aEvent, aExpectedEvent) {
+  logDeprecated("controller.mouseEvent", "Use the MozMillElement object.");
+
+  return aElement.mouseEvent(aOffsetX, aOffsetY, aEvent, aExpectedEvent);
+}
+
+MozMillController.prototype.click = function (aElement, left, top, expectedEvent) {
+  logDeprecated("controller.click", "Use the MozMillElement object.");
+
+  return aElement.click(left, top, expectedEvent);
+}
+
+MozMillController.prototype.doubleClick = function (aElement, left, top, expectedEvent) {
+  logDeprecated("controller.doubleClick", "Use the MozMillElement object.");
+
+  return aElement.doubleClick(left, top, expectedEvent);
+}
+
+MozMillController.prototype.mouseDown = function (aElement, button, left, top, expectedEvent) {
+  logDeprecated("controller.mouseDown", "Use the MozMillElement object.");
+
+  return aElement.mouseDown(button, left, top, expectedEvent);
+};
+
+MozMillController.prototype.mouseOut = function (aElement, button, left, top, expectedEvent) {
+  logDeprecated("controller.mouseOut", "Use the MozMillElement object.");
+
+  return aElement.mouseOut(button, left, top, expectedEvent);
+};
+
+MozMillController.prototype.mouseOver = function (aElement, button, left, top, expectedEvent) {
+  logDeprecated("controller.mouseOver", "Use the MozMillElement object.");
+
+  return aElement.mouseOver(button, left, top, expectedEvent);
+};
+
+MozMillController.prototype.mouseUp = function (aElement, button, left, top, expectedEvent) {
+  logDeprecated("controller.mouseUp", "Use the MozMillElement object.");
+
+  return aElement.mouseUp(button, left, top, expectedEvent);
+};
+
+MozMillController.prototype.middleClick = function (aElement, left, top, expectedEvent) {
+  logDeprecated("controller.middleClick", "Use the MozMillElement object.");
+
+  return aElement.middleClick(aElement, left, top, expectedEvent);
+}
+
+MozMillController.prototype.rightClick = function (aElement, left, top, expectedEvent) {
+  logDeprecated("controller.rightClick", "Use the MozMillElement object.");
+
+  return aElement.rightClick(left, top, expectedEvent);
+}
+
+MozMillController.prototype.check = function (aElement, state) {
+  logDeprecated("controller.check", "Use the MozMillElement object.");
+
+  return aElement.check(state);
+}
+
+MozMillController.prototype.radio = function (aElement) {
+  logDeprecated("controller.radio", "Use the MozMillElement object.");
+
+  return aElement.select();
+}
+
+MozMillController.prototype.waitThenClick = function (aElement, timeout, interval) {
+  logDeprecated("controller.waitThenClick", "Use the MozMillElement object.");
+
+  return aElement.waitThenClick(timeout, interval);
+}
+
+MozMillController.prototype.waitForElement = function (aElement, timeout, interval) {
+  logDeprecated("controller.waitForElement", "Use the MozMillElement object.");
+
+  return aElement.waitForElement(timeout, interval);
+}
+
+MozMillController.prototype.waitForElementNotPresent = function (aElement, timeout, interval) {
+  logDeprecated("controller.waitForElementNotPresent", "Use the MozMillElement object.");
+
+  return aElement.waitForElementNotPresent(timeout, interval);
+}
new file mode 100644
--- /dev/null
+++ b/services/sync/tps/extensions/mozmill/resource/driver/elementslib.js
@@ -0,0 +1,537 @@
+/* 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 EXPORTED_SYMBOLS = ["ID", "Link", "XPath", "Selector", "Name", "Anon", "AnonXPath",
+                        "Lookup", "_byID", "_byName", "_byAttrib", "_byAnonAttrib",
+                       ];
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+var utils = {}; Cu.import('resource://mozmill/stdlib/utils.js', utils);
+var strings = {}; Cu.import('resource://mozmill/stdlib/strings.js', strings);
+var arrays = {}; Cu.import('resource://mozmill/stdlib/arrays.js', arrays);
+var json2 = {}; Cu.import('resource://mozmill/stdlib/json2.js', json2);
+var withs = {}; Cu.import('resource://mozmill/stdlib/withs.js', withs);
+var dom = {}; Cu.import('resource://mozmill/stdlib/dom.js', dom);
+var objects = {}; Cu.import('resource://mozmill/stdlib/objects.js', objects);
+
+var countQuotes = function (str) {
+  var count = 0;
+  var i = 0;
+
+  while (i < str.length) {
+    i = str.indexOf('"', i);
+    if (i != -1) {
+      count++;
+      i++;
+    } else {
+      break;
+    }
+  }
+
+  return count;
+};
+
+/**
+ * smartSplit()
+ *
+ * Takes a lookup string as input and returns
+ * a list of each node in the string
+ */
+var smartSplit = function (str) {
+  // Ensure we have an even number of quotes
+  if (countQuotes(str) % 2 != 0) {
+    throw new Error ("Invalid Lookup Expression");
+  }
+
+  /**
+   * This regex matches a single "node" in a lookup string.
+   * In otherwords, it matches the part between the two '/'s
+   *
+   * Regex Explanation:
+   * \/ - start matching at the first forward slash
+   * ([^\/"]*"[^"]*")* - match as many pairs of quotes as possible until we hit a slash (ignore slashes inside quotes)
+   * [^\/]* - match the remainder of text outside of last quote but before next slash
+   */
+  var re = /\/([^\/"]*"[^"]*")*[^\/]*/g
+  var ret = []
+  var match = re.exec(str);
+
+  while (match != null) {
+    ret.push(match[0].replace(/^\//, ""));
+    match = re.exec(str);
+  }
+
+  return ret;
+};
+
+/**
+ * defaultDocuments()
+ *
+ * Returns a list of default documents in which to search for elements
+ * if no document is provided
+ */
+function defaultDocuments() {
+  var win = Services.wm.getMostRecentWindow("navigator:browser");
+
+  return [
+    win.document,
+    utils.getBrowserObject(win).selectedBrowser.contentWindow.document
+  ];
+};
+
+/**
+ * nodeSearch()
+ *
+ * Takes an optional document, callback and locator string
+ * Returns a handle to the located element or null
+ */
+function nodeSearch(doc, func, string) {
+  if (doc != undefined) {
+    var documents = [doc];
+  } else {
+    var documents = defaultDocuments();
+  }
+
+  var e = null;
+  var element = null;
+
+  //inline function to recursively find the element in the DOM, cross frame.
+  var search = function (win, func, string) {
+    if (win == null) {
+      return;
+    }
+
+    //do the lookup in the current window
+    element = func.call(win, string);
+
+    if (!element || (element.length == 0)) {
+      var frames = win.frames;
+      for (var i = 0; i < frames.length; i++) {
+        search(frames[i], func, string);
+      }
+    } else {
+      e = element;
+    }
+  };
+
+  for (var i = 0; i < documents.length; ++i) {
+    var win = documents[i].defaultView;
+    search(win, func, string);
+    if (e) {
+      break;
+    }
+  }
+
+  return e;
+};
+
+/**
+ * Selector()
+ *
+ * Finds an element by selector string
+ */
+function Selector(_document, selector, index) {
+  if (selector == undefined) {
+    throw new Error('Selector constructor did not recieve enough arguments.');
+  }
+
+  this.selector = selector;
+
+  this.getNodeForDocument = function (s) {
+    return this.document.querySelectorAll(s);
+  };
+
+  var nodes = nodeSearch(_document, this.getNodeForDocument, this.selector);
+
+  return nodes ? nodes[index || 0] : null;
+};
+
+/**
+ * ID()
+ *
+ * Finds an element by ID
+ */
+function ID(_document, nodeID) {
+  if (nodeID == undefined) {
+    throw new Error('ID constructor did not recieve enough arguments.');
+  }
+
+  this.getNodeForDocument = function (nodeID) {
+    return this.document.getElementById(nodeID);
+  };
+
+  return nodeSearch(_document, this.getNodeForDocument, nodeID);
+};
+
+/**
+ * Link()
+ *
+ * Finds a link by innerHTML
+ */
+function Link(_document, linkName) {
+  if (linkName == undefined) {
+    throw new Error('Link constructor did not recieve enough arguments.');
+  }
+
+  this.getNodeForDocument = function (linkName) {
+    var getText = function (el) {
+      var text = "";
+
+      if (el.nodeType == 3) { //textNode
+        if (el.data != undefined) {
+          text = el.data;
+        } else {
+          text = el.innerHTML;
+        }
+
+        text = text.replace(/n|r|t/g, " ");
+      }
+      else if (el.nodeType == 1) { //elementNode
+        for (var i = 0; i < el.childNodes.length; i++) {
+          var child = el.childNodes.item(i);
+          text += getText(child);
+        }
+
+        if (el.tagName == "P" || el.tagName == "BR" ||
+            el.tagName == "HR" || el.tagName == "DIV") {
+          text += "\n";
+        }
+      }
+
+      return text;
+    };
+
+    //sometimes the windows won't have this function
+    try {
+      var links = this.document.getElementsByTagName('a');
+    } catch (e) {
+      // ADD LOG LINE mresults.write('Error: '+ e, 'lightred');
+    }
+
+    for (var i = 0; i < links.length; i++) {
+      var el = links[i];
+      //if (getText(el).indexOf(this.linkName) != -1) {
+      if (el.innerHTML.indexOf(linkName) != -1) {
+        return el;
+      }
+    }
+
+    return null;
+  };
+
+  return nodeSearch(_document, this.getNodeForDocument, linkName);
+};
+
+/**
+ * XPath()
+ *
+ * Finds an element by XPath
+ */
+function XPath(_document, expr) {
+  if (expr == undefined) {
+    throw new Error('XPath constructor did not recieve enough arguments.');
+  }
+
+  this.getNodeForDocument = function (s) {
+    var aNode = this.document;
+    var aExpr = s;
+    var xpe = null;
+
+    if (this.document.defaultView == null) {
+      xpe = new getMethodInWindows('XPathEvaluator')();
+    } else {
+      xpe = new this.document.defaultView.XPathEvaluator();
+    }
+
+    var nsResolver = xpe.createNSResolver(aNode.ownerDocument == null ? aNode.documentElement
+                                                                      : aNode.ownerDocument.documentElement);
+    var result = xpe.evaluate(aExpr, aNode, nsResolver, 0, null);
+    var found = [];
+    var res;
+
+    while (res = result.iterateNext()) {
+      found.push(res);
+    }
+
+    return found[0];
+  };
+
+  return nodeSearch(_document, this.getNodeForDocument, expr);
+};
+
+/**
+ * Name()
+ *
+ * Finds an element by Name
+ */
+function Name(_document, nName) {
+  if (nName == undefined) {
+    throw new Error('Name constructor did not recieve enough arguments.');
+  }
+
+  this.getNodeForDocument = function (s) {
+    try{
+      var els = this.document.getElementsByName(s);
+      if (els.length > 0) {
+        return els[0];
+      }
+    } catch (e) {
+    }
+
+    return null;
+  };
+
+  return nodeSearch(_document, this.getNodeForDocument, nName);
+};
+
+
+var _returnResult = function (results) {
+  if (results.length == 0) {
+    return null
+  }
+  else if (results.length == 1) {
+    return results[0];
+  } else {
+    return results;
+  }
+}
+
+var _forChildren = function (element, name, value) {
+  var results = [];
+  var nodes = [e for each (e in element.childNodes) if (e)]
+
+  for (var i in nodes) {
+    var n = nodes[i];
+    if (n[name] == value) {
+      results.push(n);
+    }
+  }
+
+  return results;
+}
+
+var _forAnonChildren = function (_document, element, name, value) {
+  var results = [];
+  var nodes = [e for each (e in _document.getAnoymousNodes(element)) if (e)];
+
+  for (var i in nodes ) {
+    var n = nodes[i];
+    if (n[name] == value) {
+      results.push(n);
+    }
+  }
+
+  return results;
+}
+
+var _byID = function (_document, parent, value) {
+  return _returnResult(_forChildren(parent, 'id', value));
+}
+
+var _byName = function (_document, parent, value) {
+  return _returnResult(_forChildren(parent, 'tagName', value));
+}
+
+var _byAttrib = function (parent, attributes) {
+  var results = [];
+  var nodes = parent.childNodes;
+
+  for (var i in nodes) {
+    var n = nodes[i];
+    requirementPass = 0;
+    requirementLength = 0;
+
+    for (var a in attributes) {
+      requirementLength++;
+      try {
+        if (n.getAttribute(a) == attributes[a]) {
+          requirementPass++;
+        }
+      } catch (e) {
+        // Workaround any bugs in custom attribute crap in XUL elements
+      }
+    }
+
+    if (requirementPass == requirementLength) {
+      results.push(n);
+    }
+  }
+
+  return _returnResult(results)
+}
+
+var _byAnonAttrib = function (_document, parent, attributes) {
+  var results = [];
+
+  if (objects.getLength(attributes) == 1) {
+    for (var i in attributes) {
+      var k = i;
+      var v = attributes[i];
+    }
+
+    var result = _document.getAnonymousElementByAttribute(parent, k, v);
+    if (result) {
+      return result;
+    }
+  }
+
+  var nodes = [n for each (n in _document.getAnonymousNodes(parent)) if (n.getAttribute)];
+
+  function resultsForNodes (nodes) {
+    for (var i in nodes) {
+      var n = nodes[i];
+      requirementPass = 0;
+      requirementLength = 0;
+
+      for (var a in attributes) {
+        requirementLength++;
+        if (n.getAttribute(a) == attributes[a]) {
+          requirementPass++;
+        }
+      }
+
+      if (requirementPass == requirementLength) {
+        results.push(n);
+      }
+    }
+  }
+
+  resultsForNodes(nodes);
+  if (results.length == 0) {
+    resultsForNodes([n for each (n in parent.childNodes) if (n != undefined && n.getAttribute)])
+  }
+
+  return _returnResult(results)
+}
+
+var _byIndex = function (_document, parent, i) {
+  if (parent instanceof Array) {
+    return parent[i];
+  }
+
+  return parent.childNodes[i];
+}
+
+var _anonByName = function (_document, parent, value) {
+  return _returnResult(_forAnonChildren(_document, parent, 'tagName', value));
+}
+
+var _anonByAttrib = function (_document, parent, value) {
+  return _byAnonAttrib(_document, parent, value);
+}
+
+var _anonByIndex = function (_document, parent, i) {
+  return _document.getAnonymousNodes(parent)[i];
+}
+
+/**
+ * Lookup()
+ *
+ * Finds an element by Lookup expression
+ */
+function Lookup(_document, expression) {
+  if (expression == undefined) {
+    throw new Error('Lookup constructor did not recieve enough arguments.');
+  }
+
+  var expSplit = [e for each (e in smartSplit(expression) ) if (e != '')];
+  expSplit.unshift(_document);
+
+  var nCases = {'id':_byID, 'name':_byName, 'attrib':_byAttrib, 'index':_byIndex};
+  var aCases = {'name':_anonByName, 'attrib':_anonByAttrib, 'index':_anonByIndex};
+
+  /**
+   * Reduces the lookup expression
+   * @param {Object} parentNode
+   *        Parent node (previousValue of the formerly executed reduce callback)
+   * @param {String} exp
+   *        Lookup expression for the parents child node
+   *
+   * @returns {Object} Node found by the given expression
+   */
+  var reduceLookup = function (parentNode, exp) {
+    // Abort in case the parent node was not found
+    if (!parentNode) {
+      return false;
+    }
+
+    // Handle case where only index is provided
+    var cases = nCases;
+
+    // Handle ending index before any of the expression gets mangled
+    if (withs.endsWith(exp, ']')) {
+      var expIndex = json2.JSON.parse(strings.vslice(exp, '[', ']'));
+    }
+
+    // Handle anon
+    if (withs.startsWith(exp, 'anon')) {
+      exp = strings.vslice(exp, '(', ')');
+      cases = aCases;
+    }
+
+    if (withs.startsWith(exp, '[')) {
+      try {
+        var obj = json2.JSON.parse(strings.vslice(exp, '[', ']'));
+      } catch (e) {
+        throw new SyntaxError(e + '. String to be parsed was || ' +
+                              strings.vslice(exp, '[', ']') + ' ||');
+      }
+
+      var r = cases['index'](_document, parentNode, obj);
+      if (r == null) {
+        throw new SyntaxError('Expression "' + exp +
+                              '" returned null. Anonymous == ' + (cases == aCases));
+      }
+
+      return r;
+    }
+
+    for (var c in cases) {
+      if (withs.startsWith(exp, c)) {
+        try {
+          var obj = json2.JSON.parse(strings.vslice(exp, '(', ')'))
+        } catch (e) {
+           throw new SyntaxError(e + '. String to be parsed was || ' +
+                                 strings.vslice(exp, '(', ')') + '  ||');
+        }
+        var result = cases[c](_document, parentNode, obj);
+      }
+    }
+
+    if (!result) {
+      if (withs.startsWith(exp, '{')) {
+        try {
+          var obj = json2.JSON.parse(exp);
+        } catch (e) {
+          throw new SyntaxError(e + '. String to be parsed was || ' + exp + ' ||');
+        }
+
+        if (cases == aCases) {
+          var result = _anonByAttrib(_document, parentNode, obj);
+        } else {
+          var result = _byAttrib(parentNode, obj);
+        }
+      }
+    }
+
+    // Final return
+    if (expIndex) {
+      // TODO: Check length and raise error
+      return result[expIndex];
+    } else {
+      // TODO: Check length and raise error
+      return result;
+    }
+
+    // Maybe we should cause an exception here
+    return false;
+  };
+
+  return expSplit.reduce(reduceLookup);
+};
new file mode 100644
--- /dev/null
+++ b/services/sync/tps/extensions/mozmill/resource/driver/mozelement.js
@@ -0,0 +1,1163 @@
+/* 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 EXPORTED_SYMBOLS = ["Elem", "Selector", "ID", "Link", "XPath", "Name", "Lookup",
+                        "MozMillElement", "MozMillCheckBox", "MozMillRadio", "MozMillDropList",
+                        "MozMillTextBox", "subclasses"
+                       ];
+
+const NAMESPACE_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+var EventUtils = {};  Cu.import('resource://mozmill/stdlib/EventUtils.js', EventUtils);
+
+var assertions = {};  Cu.import('resource://mozmill/modules/assertions.js', assertions);
+var broker = {};      Cu.import('resource://mozmill/driver/msgbroker.js', broker);
+var elementslib = {}; Cu.import('resource://mozmill/driver/elementslib.js', elementslib);
+var utils = {};       Cu.import('resource://mozmill/stdlib/utils.js', utils);
+
+var assert = new assertions.Assert();
+
+// A list of all the subclasses available.  Shared modules can push their own subclasses onto this list
+var subclasses = [MozMillCheckBox, MozMillRadio, MozMillDropList, MozMillTextBox];
+
+/**
+ * createInstance()
+ *
+ * Returns an new instance of a MozMillElement
+ * The type of the element is automatically determined
+ */
+function createInstance(locatorType, locator, elem, document) {
+  var args = { "document": document, "element": elem };
+
+  // If we already have an element lets determine the best MozMillElement type
+  if (elem) {
+    for (var i = 0; i < subclasses.length; ++i) {
+      if (subclasses[i].isType(elem)) {
+        return new subclasses[i](locatorType, locator, args);
+      }
+    }
+  }
+
+  // By default we create a base MozMillElement
+  if (MozMillElement.isType(elem)) {
+    return new MozMillElement(locatorType, locator, args);
+  }
+
+  throw new Error("Unsupported element type " + locatorType + ": " + locator);
+}
+
+var Elem = function (node) {
+  return createInstance("Elem", node, node);
+};
+
+var Selector = function (document, selector, index) {
+  return createInstance("Selector", selector, elementslib.Selector(document, selector, index), document);
+};
+
+var ID = function (document, nodeID) {
+  return createInstance("ID", nodeID, elementslib.ID(document, nodeID), document);
+};
+
+var Link = function (document, linkName) {
+  return createInstance("Link", linkName, elementslib.Link(document, linkName), document);
+};
+
+var XPath = function (document, expr) {
+  return createInstance("XPath", expr, elementslib.XPath(document, expr), document);
+};
+
+var Name = function (document, nName) {
+  return createInstance("Name", nName, elementslib.Name(document, nName), document);
+};
+
+var Lookup = function (document, expression) {
+  var elem = createInstance("Lookup", expression, elementslib.Lookup(document, expression), document);
+
+  // Bug 864268 - Expose the expression property to maintain backwards compatibility
+  elem.expression = elem._locator;
+
+  return elem;
+};
+
+/**
+ * MozMillElement
+ * The base class for all mozmill elements
+ */
+function MozMillElement(locatorType, locator, args) {
+  args = args || {};
+  this._locatorType = locatorType;
+  this._locator = locator;
+  this._element = args["element"];
+  this._owner = args["owner"];
+
+  this._document = this._element ? this._element.ownerDocument : args["document"];
+  this._defaultView = this._document ? this._document.defaultView : null;
+
+  // Used to maintain backwards compatibility with controller.js
+  this.isElement = true;
+}
+
+// Static method that returns true if node is of this element type
+MozMillElement.isType = function (node) {
+  return true;
+};
+
+// This getter is the magic behind lazy loading (note distinction between _element and element)
+MozMillElement.prototype.__defineGetter__("element", function () {
+  // If the document is invalid (e.g. reload of the page), invalidate the cached
+  // element and update the document cache
+  if (this._defaultView && this._defaultView.document !== this._document) {
+    this._document = this._defaultView.document;
+    this._element = undefined;
+  }
+
+  if (this._element == undefined) {
+    if (elementslib[this._locatorType]) {
+      this._element = elementslib[this._locatorType](this._document, this._locator);
+    } else if (this._locatorType == "Elem") {
+      this._element = this._locator;
+    } else {
+      throw new Error("Unknown locator type: " + this._locatorType);
+    }
+  }
+
+  return this._element;
+});
+
+/**
+ * Drag an element to the specified offset on another element, firing mouse and
+ * drag events. Adapted from ChromeUtils.js synthesizeDrop()
+ *
+ * By default it will drag the source element over the destination's element
+ * center with a "move" dropEffect.
+ *
+ * @param {MozElement} aElement
+ *        Destination element over which the drop occurs
+ * @param {Number} [aOffsetX=aElement.width/2]
+ *        Relative x offset for dropping on aElement
+ * @param {Number} [aOffsetY=aElement.height/2]
+ *        Relative y offset for dropping on aElement
+ * @param {DOMWindow} [aSourceWindow=this.element.ownerDocument.defaultView]
+ *        Custom source Window to be used.
+ * @param {DOMWindow} [aDestWindow=aElement.getNode().ownerDocument.defaultView]
+ *        Custom destination Window to be used.
+ * @param {String} [aDropEffect="move"]
+ *        Possible values: copy, move, link, none
+ * @param {Object[]} [aDragData]
+ *        An array holding custom drag data to be used during the drag event
+ *        Format: [{ type: "text/plain", "Text to drag"}, ...]
+ *
+ * @returns {String} the captured dropEffect
+ */
+MozMillElement.prototype.dragToElement = function(aElement, aOffsetX, aOffsetY,
+                                                  aSourceWindow, aDestWindow,
+                                                  aDropEffect, aDragData) {
+  if (!this.element) {
+    throw new Error("Could not find element " + this.getInfo());
+  }
+  if (!aElement) {
+    throw new Error("Missing destination element");
+  }
+
+  var srcNode = this.element;
+  var destNode = aElement.getNode();
+  var srcWindow = aSourceWindow ||
+                  (srcNode.ownerDocument ? srcNode.ownerDocument.defaultView
+                                         : srcNode);
+  var destWindow = aDestWindow ||
+                  (destNode.ownerDocument ? destNode.ownerDocument.defaultView
+                                          : destNode);
+
+  var srcRect = srcNode.getBoundingClientRect();
+  var srcCoords = {
+    x: srcRect.width / 2,
+    y: srcRect.height / 2
+  };
+  var destRect = destNode.getBoundingClientRect();
+  var destCoords = {
+    x: (!aOffsetX || isNaN(aOffsetX)) ? (destRect.width / 2) : aOffsetX,
+    y: (!aOffsetY || isNaN(aOffsetY)) ? (destRect.height / 2) : aOffsetY
+  };
+
+  var windowUtils = destWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                              .getInterface(Ci.nsIDOMWindowUtils);
+  var ds = Cc["@mozilla.org/widget/dragservice;1"].getService(Ci.nsIDragService);
+
+  var dataTransfer;
+  var trapDrag = function (event) {
+    srcWindow.removeEventListener("dragstart", trapDrag, true);
+    dataTransfer = event.dataTransfer;
+
+    if (!aDragData) {
+      return;
+    }
+
+    for (var i = 0; i < aDragData.length; i++) {
+      var item = aDragData[i];
+      for (var j = 0; j < item.length; j++) {
+        dataTransfer.mozSetDataAt(item[j].type, item[j].data, i);
+      }
+    }
+
+    dataTransfer.dropEffect = aDropEffect || "move";
+    event.preventDefault();
+    event.stopPropagation();
+  }
+
+  ds.startDragSession();
+
+  try {
+    srcWindow.addEventListener("dragstart", trapDrag, true);
+    EventUtils.synthesizeMouse(srcNode, srcCoords.x, srcCoords.y,
+                               { type: "mousedown" }, srcWindow);
+    EventUtils.synthesizeMouse(destNode, destCoords.x, destCoords.y,
+                               { type: "mousemove" }, destWindow);
+
+    var event = destWindow.document.createEvent("DragEvents");
+    event.initDragEvent("dragenter", true, true, destWindow, 0, 0, 0, 0, 0,
+                        false, false, false, false, 0, null, dataTransfer);
+    event.initDragEvent("dragover", true, true, destWindow, 0, 0, 0, 0, 0,
+                        false, false, false, false, 0, null, dataTransfer);
+    event.initDragEvent("drop", true, true, destWindow, 0, 0, 0, 0, 0,
+                        false, false, false, false, 0, null, dataTransfer);
+    windowUtils.dispatchDOMEventViaPresShell(destNode, event, true);
+
+    EventUtils.synthesizeMouse(destNode, destCoords.x, destCoords.y,
+                               { type: "mouseup" }, destWindow);
+
+    return dataTransfer.dropEffect;
+  } finally {
+    ds.endDragSession(true);
+  }
+
+};
+
+// Returns the actual wrapped DOM node
+MozMillElement.prototype.getNode = function () {
+  return this.element;
+};
+
+MozMillElement.prototype.getInfo = function () {
+  return this._locatorType + ": " + this._locator;
+};
+
+/**
+ * Sometimes an element which once existed will no longer exist in the DOM
+ * This function re-searches for the element
+ */
+MozMillElement.prototype.exists = function () {
+  this._element = undefined;
+  if (this.element) {
+    return true;
+  }
+
+  return false;
+};
+
+/**
+ * Synthesize a keypress event on the given element
+ *
+ * @param {string} aKey
+ *        Key to use for synthesizing the keypress event. It can be a simple
+ *        character like "k" or a string like "VK_ESCAPE" for command keys
+ * @param {object} aModifiers
+ *        Information about the modifier keys to send
+ *        Elements: accelKey   - Hold down the accelerator key (ctrl/meta)
+ *                               [optional - default: false]
+ *                  altKey     - Hold down the alt key
+ *                              [optional - default: false]
+ *                  ctrlKey    - Hold down the ctrl key
+ *                               [optional - default: false]
+ *                  metaKey    - Hold down the meta key (command key on Mac)
+ *                               [optional - default: false]
+ *                  shiftKey   - Hold down the shift key
+ *                               [optional - default: false]
+ * @param {object} aExpectedEvent
+ *        Information about the expected event to occur
+ *        Elements: target     - Element which should receive the event
+ *                               [optional - default: current element]
+ *                  type       - Type of the expected key event
+ */
+MozMillElement.prototype.keypress = function (aKey, aModifiers, aExpectedEvent) {
+  if (!this.element) {
+    throw new Error("Could not find element " + this.getInfo());
+  }
+
+  var win = this.element.ownerDocument ? this.element.ownerDocument.defaultView
+                                       : this.element;
+  this.element.focus();
+
+  if (aExpectedEvent) {
+    if (!aExpectedEvent.type) {
+      throw new Error(arguments.callee.name + ": Expected event type not specified");
+    }
+
+    var target = aExpectedEvent.target ? aExpectedEvent.target.getNode()
+                                       : this.element;
+    EventUtils.synthesizeKeyExpectEvent(aKey, aModifiers || {}, target, aExpectedEvent.type,
+                                        "MozMillElement.keypress()", win);
+  } else {
+    EventUtils.synthesizeKey(aKey, aModifiers || {}, win);
+  }
+
+  broker.pass({'function':'MozMillElement.keypress()'});
+
+  return true;
+};
+
+
+/**
+ * Synthesize a general mouse event on the given element
+ *
+ * @param {number} aOffsetX
+ *        Relative x offset in the elements bounds to click on
+ * @param {number} aOffsetY
+ *        Relative y offset in the elements bounds to click on
+ * @param {object} aEvent
+ *        Information about the event to send
+ *        Elements: accelKey   - Hold down the accelerator key (ctrl/meta)
+ *                               [optional - default: false]
+ *                  altKey     - Hold down the alt key
+ *                               [optional - default: false]
+ *                  button     - Mouse button to use
+ *                               [optional - default: 0]
+ *                  clickCount - Number of counts to click
+ *                               [optional - default: 1]
+ *                  ctrlKey    - Hold down the ctrl key
+ *                               [optional - default: false]
+ *                  metaKey    - Hold down the meta key (command key on Mac)
+ *                               [optional - default: false]
+ *                  shiftKey   - Hold down the shift key
+ *                               [optional - default: false]
+ *                  type       - Type of the mouse event ('click', 'mousedown',
+ *                               'mouseup', 'mouseover', 'mouseout')
+ *                               [optional - default: 'mousedown' + 'mouseup']
+ * @param {object} aExpectedEvent
+ *        Information about the expected event to occur
+ *        Elements: target     - Element which should receive the event
+ *                               [optional - default: current element]
+ *                  type       - Type of the expected mouse event
+ */
+MozMillElement.prototype.mouseEvent = function (aOffsetX, aOffsetY, aEvent, aExpectedEvent) {
+  if (!this.element) {
+    throw new Error(arguments.callee.name + ": could not find element " + this.getInfo());
+  }
+
+  if ("document" in this.element) {
+    throw new Error("A window cannot be a target for mouse events.");
+  }
+
+  var rect = this.element.getBoundingClientRect();
+
+  if (!aOffsetX || isNaN(aOffsetX)) {
+    aOffsetX = rect.width / 2;
+  }
+
+  if (!aOffsetY || isNaN(aOffsetY)) {
+    aOffsetY = rect.height / 2;
+  }
+
+  // Scroll element into view otherwise the click will fail
+  if ("scrollIntoView" in this.element)
+    this.element.scrollIntoView();
+
+  if (aExpectedEvent) {
+    // The expected event type has to be set
+    if (!aExpectedEvent.type) {
+      throw new Error(arguments.callee.name + ": Expected event type not specified");
+    }
+
+    // If no target has been specified use the specified element
+    var target = aExpectedEvent.target ? aExpectedEvent.target.getNode()
+                                       : this.element;
+    if (!target) {
+      throw new Error(arguments.callee.name + ": could not find element " +
+                      aExpectedEvent.target.getInfo());
+    }
+
+    EventUtils.synthesizeMouseExpectEvent(this.element, aOffsetX, aOffsetY, aEvent,
+                                          target, aExpectedEvent.type,
+                                          "MozMillElement.mouseEvent()",
+                                          this.element.ownerDocument.defaultView);
+  } else {
+    EventUtils.synthesizeMouse(this.element, aOffsetX, aOffsetY, aEvent,
+                               this.element.ownerDocument.defaultView);
+  }
+
+  // Bug 555347
+  // We don't know why this sleep is necessary but more investigation is needed
+  // before it can be removed
+  utils.sleep(0);
+
+  return true;
+};
+
+/**
+ * Synthesize a mouse click event on the given element
+ */
+MozMillElement.prototype.click = function (aOffsetX, aOffsetY, aExpectedEvent) {
+  // Handle menu items differently
+  if (this.element && this.element.tagName == "menuitem") {
+    this.element.click();
+  } else {
+    this.mouseEvent(aOffsetX, aOffsetY, {}, aExpectedEvent);
+  }
+
+  broker.pass({'function':'MozMillElement.click()'});
+
+  return true;
+};
+
+/**
+ * Synthesize a double click on the given element
+ */
+MozMillElement.prototype.doubleClick = function (aOffsetX, aOffsetY, aExpectedEvent) {
+  this.mouseEvent(aOffsetX, aOffsetY, {clickCount: 2}, aExpectedEvent);
+
+  broker.pass({'function':'MozMillElement.doubleClick()'});
+
+  return true;
+};
+
+/**
+ * Synthesize a mouse down event on the given element
+ */
+MozMillElement.prototype.mouseDown = function (aButton, aOffsetX, aOffsetY, aExpectedEvent) {
+  this.mouseEvent(aOffsetX, aOffsetY, {button: aButton, type: "mousedown"}, aExpectedEvent);
+
+  broker.pass({'function':'MozMillElement.mouseDown()'});
+
+  return true;
+};
+
+/**
+ * Synthesize a mouse out event on the given element
+ */
+MozMillElement.prototype.mouseOut = function (aButton, aOffsetX, aOffsetY, aExpectedEvent) {
+  this.mouseEvent(aOffsetX, aOffsetY, {button: aButton, type: "mouseout"}, aExpectedEvent);
+
+  broker.pass({'function':'MozMillElement.mouseOut()'});
+
+  return true;
+};
+
+/**
+ * Synthesize a mouse over event on the given element
+ */
+MozMillElement.prototype.mouseOver = function (aButton, aOffsetX, aOffsetY, aExpectedEvent) {
+  this.mouseEvent(aOffsetX, aOffsetY, {button: aButton, type: "mouseover"}, aExpectedEvent);
+
+  broker.pass({'function':'MozMillElement.mouseOver()'});
+
+  return true;
+};
+
+/**
+ * Synthesize a mouse up event on the given element
+ */
+MozMillElement.prototype.mouseUp = function (aButton, aOffsetX, aOffsetY, aExpectedEvent) {
+  this.mouseEvent(aOffsetX, aOffsetY, {button: aButton, type: "mouseup"}, aExpectedEvent);
+
+  broker.pass({'function':'MozMillElement.mouseUp()'});
+
+  return true;
+};
+
+/**
+ * Synthesize a mouse middle click event on the given element
+ */
+MozMillElement.prototype.middleClick = function (aOffsetX, aOffsetY, aExpectedEvent) {
+  this.mouseEvent(aOffsetX, aOffsetY, {button: 1}, aExpectedEvent);
+
+  broker.pass({'function':'MozMillElement.middleClick()'});
+
+  return true;
+};
+
+/**
+ * Synthesize a mouse right click event on the given element
+ */
+MozMillElement.prototype.rightClick = function (aOffsetX, aOffsetY, aExpectedEvent) {
+  this.mouseEvent(aOffsetX, aOffsetY, {type : "contextmenu", button: 2 }, aExpectedEvent);
+
+  broker.pass({'function':'MozMillElement.rightClick()'});
+
+  return true;
+};
+
+/**
+ * Synthesize a general touch event on the given element
+ *
+ * @param {Number} [aOffsetX=aElement.width / 2]
+ *        Relative x offset in the elements bounds to click on
+ * @param {Number} [aOffsetY=aElement.height / 2]
+ *        Relative y offset in the elements bounds to click on
+ * @param {Object} [aEvent]
+ *        Information about the event to send
+ * @param {Boolean} [aEvent.altKey=false]
+ *        A Boolean value indicating whether or not the alt key was down when
+ *        the touch event was fired
+ * @param {Number} [aEvent.angle=0]
+ *        The angle (in degrees) that the ellipse described by rx and
+ *        ry must be rotated, clockwise, to most accurately cover the area
+ *        of contact between the user and the surface.
+ * @param {Touch[]} [aEvent.changedTouches]
+ *        A TouchList of all the Touch objects representing individual points of
+ *        contact whose states changed between the previous touch event and
+ *        this one
+ * @param {Boolean} [aEvent.ctrlKey]
+ *        A Boolean value indicating whether or not the control key was down
+ *        when the touch event was fired
+ * @param {Number} [aEvent.force=1]
+ *        The amount of pressure being applied to the surface by the user, as a
+ *        float between 0.0 (no pressure) and 1.0 (maximum pressure)
+ * @param {Number} [aEvent.id=0]
+ *        A unique identifier for this Touch object. A given touch (say, by a
+ *        finger) will have the same identifier for the duration of its movement
+ *        around the surface. This lets you ensure that you're tracking the same
+ *        touch all the time
+ * @param {Boolean} [aEvent.metaKey]
+ *        A Boolean value indicating whether or not the meta key was down when
+ *        the touch event was fired.
+ * @param {Number} [aEvent.rx=1]
+ *        The X radius of the ellipse that most closely circumscribes the area
+ *        of contact with the screen.
+ * @param {Number} [aEvent.ry=1]
+ *        The Y radius of the ellipse that most closely circumscribes the area
+ *        of contact with the screen.
+ * @param {Boolean} [aEvent.shiftKey]
+ *        A Boolean value indicating whether or not the shift key was down when
+ *        the touch event was fired
+ * @param {Touch[]} [aEvent.targetTouches]
+ *        A TouchList of all the Touch objects that are both currently in
+ *        contact with the touch surface and were also started on the same
+ *        element that is the target of the event
+ * @param {Touch[]} [aEvent.touches]
+ *        A TouchList of all the Touch objects representing all current points
+ *        of contact with the surface, regardless of target or changed status
+ * @param {Number} [aEvent.type=*|touchstart|touchend|touchmove|touchenter|touchleave|touchcancel]
+ *        The type of touch event that occurred
+ * @param {Element} [aEvent.target]
+ *        The target of the touches associated with this event. This target
+ *        corresponds to the target of all the touches in the targetTouches
+ *        attribute, but note that other touches in this event may have a
+ *        different target. To be careful, you should use the target associated
+ *        with individual touches
+ */
+MozMillElement.prototype.touchEvent = function (aOffsetX, aOffsetY, aEvent) {
+  if (!this.element) {
+    throw new Error(arguments.callee.name + ": could not find element " + this.getInfo());
+  }
+
+  if ("document" in this.element) {
+    throw new Error("A window cannot be a target for touch events.");
+  }
+
+  var rect = this.element.getBoundingClientRect();
+
+  if (!aOffsetX || isNaN(aOffsetX)) {
+    aOffsetX = rect.width / 2;
+  }
+
+  if (!aOffsetY || isNaN(aOffsetY)) {
+    aOffsetY = rect.height / 2;
+  }
+
+  // Scroll element into view otherwise the click will fail
+  if ("scrollIntoView" in this.element) {
+    this.element.scrollIntoView();
+  }
+
+  EventUtils.synthesizeTouch(this.element, aOffsetX, aOffsetY, aEvent,
+                             this.element.ownerDocument.defaultView);
+
+  return true;
+};
+
+/**
+ * Synthesize a touch tap event on the given element
+ *
+ * @param {Number} [aOffsetX=aElement.width / 2]
+ *        Left offset in px where the event is triggered
+ * @param {Number} [aOffsetY=aElement.height / 2]
+ *        Top offset in px where the event is triggered
+ * @param {Object} [aExpectedEvent]
+ *        Information about the expected event to occur
+ * @param {MozMillElement} [aExpectedEvent.target=this.element]
+ *        Element which should receive the event
+ * @param {MozMillElement} [aExpectedEvent.type]
+ *        Type of the expected mouse event
+ */
+MozMillElement.prototype.tap = function (aOffsetX, aOffsetY, aExpectedEvent) {
+  this.mouseEvent(aOffsetX, aOffsetY, {
+    clickCount: 1,
+    inputSource: Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH
+  }, aExpectedEvent);
+
+  broker.pass({'function':'MozMillElement.tap()'});
+
+  return true;
+};
+
+/**
+ * Synthesize a double tap on the given element
+ *
+ * @param {Number} [aOffsetX=aElement.width / 2]
+ *        Left offset in px where the event is triggered
+ * @param {Number} [aOffsetY=aElement.height / 2]
+ *        Top offset in px where the event is triggered
+ * @param {Object} [aExpectedEvent]
+ *        Information about the expected event to occur
+ * @param {MozMillElement} [aExpectedEvent.target=this.element]
+ *        Element which should receive the event
+ * @param {MozMillElement} [aExpectedEvent.type]
+ *        Type of the expected mouse event
+ */
+MozMillElement.prototype.doubleTap = function (aOffsetX, aOffsetY, aExpectedEvent) {
+  this.mouseEvent(aOffsetX, aOffsetY, {
+    clickCount: 2,
+    inputSource: Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH
+  }, aExpectedEvent);
+
+  broker.pass({'function':'MozMillElement.doubleTap()'});
+
+  return true;
+};
+
+/**
+ * Synthesize a long press
+ *
+ * @param {Number} aOffsetX
+ *        Left offset in px where the event is triggered
+ * @param {Number} aOffsetY
+ *        Top offset in px where the event is triggered
+ * @param {Number} [aTime=1000]
+ *        Duration of the "press" event in ms
+ */
+MozMillElement.prototype.longPress = function (aOffsetX, aOffsetY, aTime) {
+  var time = aTime || 1000;
+
+  this.touchStart(aOffsetX, aOffsetY);
+  utils.sleep(time);
+  this.touchEnd(aOffsetX, aOffsetY);
+
+  broker.pass({'function':'MozMillElement.longPress()'});
+
+  return true;
+};
+
+/**
+ * Synthesize a touch & drag event on the given element
+ *
+ * @param {Number} aOffsetX1
+ *        Left offset of the start position
+ * @param {Number} aOffsetY1
+ *        Top offset of the start position
+ * @param {Number} aOffsetX2
+ *        Left offset of the end position
+ * @param {Number} aOffsetY2
+ *        Top offset of the end position
+ */
+MozMillElement.prototype.touchDrag = function (aOffsetX1, aOffsetY1, aOffsetX2, aOffsetY2) {
+  this.touchStart(aOffsetX1, aOffsetY1);
+  this.touchMove(aOffsetX2, aOffsetY2);
+  this.touchEnd(aOffsetX2, aOffsetY2);
+
+  broker.pass({'function':'MozMillElement.move()'});
+
+  return true;
+};
+
+/**
+ * Synthesize a press / touchstart event on the given element
+ *
+ * @param {Number} aOffsetX
+ *        Left offset where the event is triggered
+ * @param {Number} aOffsetY
+ *        Top offset where the event is triggered
+ */
+MozMillElement.prototype.touchStart = function (aOffsetX, aOffsetY) {
+  this.touchEvent(aOffsetX, aOffsetY, { type: "touchstart" });
+
+  broker.pass({'function':'MozMillElement.touchStart()'});
+
+  return true;
+};
+
+/**
+ * Synthesize a release / touchend event on the given element
+ *
+ * @param {Number} aOffsetX
+ *        Left offset where the event is triggered
+ * @param {Number} aOffsetY
+ *        Top offset where the event is triggered
+ */
+MozMillElement.prototype.touchEnd = function (aOffsetX, aOffsetY) {
+  this.touchEvent(aOffsetX, aOffsetY, { type: "touchend" });
+
+  broker.pass({'function':'MozMillElement.touchEnd()'});
+
+  return true;
+};
+
+/**
+ * Synthesize a touchMove event on the given element
+ *
+ * @param {Number} aOffsetX
+ *        Left offset where the event is triggered
+ * @param {Number} aOffsetY
+ *        Top offset where the event is triggered
+ */
+MozMillElement.prototype.touchMove = function (aOffsetX, aOffsetY) {
+  this.touchEvent(aOffsetX, aOffsetY, { type: "touchmove" });
+
+  broker.pass({'function':'MozMillElement.touchMove()'});
+
+  return true;
+};
+
+MozMillElement.prototype.waitForElement = function (timeout, interval) {
+  var elem = this;
+
+  assert.waitFor(function () {
+    return elem.exists();
+  }, "Element.waitForElement(): Element '" + this.getInfo() +
+     "' has been found", timeout, interval);
+
+  broker.pass({'function':'MozMillElement.waitForElement()'});
+};
+
+MozMillElement.prototype.waitForElementNotPresent = function (timeout, interval) {
+  var elem = this;
+
+  assert.waitFor(function () {
+    return !elem.exists();
+  }, "Element.waitForElementNotPresent(): Element '" + this.getInfo() +
+     "' has not been found", timeout, interval);
+
+  broker.pass({'function':'MozMillElement.waitForElementNotPresent()'});
+};
+
+MozMillElement.prototype.waitThenClick = function (timeout, interval,
+                                                   aOffsetX, aOffsetY, aExpectedEvent) {
+  this.waitForElement(timeout, interval);
+  this.click(aOffsetX, aOffsetY, aExpectedEvent);
+};
+
+/**
+ * Waits for the element to be available in the DOM, then trigger a tap event
+ *
+ * @param {Number} [aTimeout=5000]
+ *        Time to wait for the element to be available
+ * @param {Number} [aInterval=100]
+ *        Interval to check for availability
+ * @param {Number} [aOffsetX=aElement.width / 2]
+ *        Left offset where the event is triggered
+ * @param {Number} [aOffsetY=aElement.height / 2]
+ *        Top offset where the event is triggered
+ * @param {Object} [aExpectedEvent]
+ *        Information about the expected event to occur
+ * @param {MozMillElement} [aExpectedEvent.target=this.element]
+ *        Element which should receive the event
+ * @param {MozMillElement} [aExpectedEvent.type]
+ *        Type of the expected mouse event
+ */
+MozMillElement.prototype.waitThenTap = function (aTimeout, aInterval,
+                                                 aOffsetX, aOffsetY, aExpectedEvent) {
+  this.waitForElement(aTimeout, aInterval);
+  this.tap(aOffsetX, aOffsetY, aExpectedEvent);
+};
+
+// Dispatches an HTMLEvent
+MozMillElement.prototype.dispatchEvent = function (eventType, canBubble, modifiers) {
+  canBubble = canBubble || true;
+  modifiers = modifiers || { };
+
+  let document = 'ownerDocument' in this.element ? this.element.ownerDocument
+                                                 : this.element.document;
+
+  let evt = document.createEvent('HTMLEvents');
+  evt.shiftKey = modifiers["shift"];
+  evt.metaKey = modifiers["meta"];
+  evt.altKey = modifiers["alt"];
+  evt.ctrlKey = modifiers["ctrl"];
+  evt.initEvent(eventType, canBubble, true);
+
+  this.element.dispatchEvent(evt);
+};
+
+
+/**
+ * MozMillCheckBox, which inherits from MozMillElement
+ */
+function MozMillCheckBox(locatorType, locator, args) {
+  MozMillElement.call(this, locatorType, locator, args);
+}
+
+
+MozMillCheckBox.prototype = Object.create(MozMillElement.prototype, {
+  check : {
+    /**
+     * Enable/Disable a checkbox depending on the target state
+     *
+     * @param {boolean} state State to set
+     * @return {boolean} Success state
+     */
+    value : function MMCB_check(state) {
+      var result = false;
+
+      if (!this.element) {
+        throw new Error("could not find element " + this.getInfo());
+      }
+
+      // If we have a XUL element, unwrap its XPCNativeWrapper
+      if (this.element.namespaceURI == NAMESPACE_XUL) {
+        this.element = utils.unwrapNode(this.element);
+      }
+
+      state = (typeof(state) == "boolean") ? state : false;
+      if (state != this.element.checked) {
+        this.click();
+        var element = this.element;
+
+        assert.waitFor(function () {
+          return element.checked == state;
+        }, "CheckBox.check(): Checkbox " + this.getInfo() + " could not be checked/unchecked", 500);
+
+        result = true;
+      }
+
+      broker.pass({'function':'MozMillCheckBox.check(' + this.getInfo() +
+                   ', state: ' + state + ')'});
+
+      return result;
+    }
+  }
+});
+
+
+/**
+ * Returns true if node is of type MozMillCheckBox
+ *
+ * @static
+ * @param {DOMNode} node Node to check for its type
+ * @return {boolean} True if node is of type checkbox
+ */
+MozMillCheckBox.isType = function MMCB_isType(node) {
+  return ((node.localName.toLowerCase() == "input" && node.getAttribute("type") == "checkbox") ||
+    (node.localName.toLowerCase() == 'toolbarbutton' && node.getAttribute('type') == 'checkbox') ||
+    (node.localName.toLowerCase() == 'checkbox'));
+};
+
+
+/**
+ * MozMillRadio, which inherits from MozMillElement
+ */
+function MozMillRadio(locatorType, locator, args) {
+  MozMillElement.call(this, locatorType, locator, args);
+}
+
+
+MozMillRadio.prototype = Object.create(MozMillElement.prototype, {
+  select : {
+    /**
+     * Select the given radio button
+     *
+     * @param {number} [index=0]
+     *        Specifies which radio button in the group to select (only
+     *        applicable to radiogroup elements)
+     * @return {boolean} Success state
+     */
+    value : function MMR_select(index) {
+      if (!this.element) {
+        throw new Error("could not find element " + this.getInfo());
+      }
+
+      if (this.element.localName.toLowerCase() == "radiogroup") {
+        var element = this.element.getElementsByTagName("radio")[index || 0];
+        new MozMillRadio("Elem", element).click();
+      } else {
+        var element = this.element;
+        this.click();
+      }
+
+      assert.waitFor(function () {
+        // If we have a XUL element, unwrap its XPCNativeWrapper
+        if (element.namespaceURI == NAMESPACE_XUL) {
+          element = utils.unwrapNode(element);
+          return element.selected == true;
+        }
+
+        return element.checked == true;
+      }, "Radio.select(): Radio button " + this.getInfo() + " has been selected", 500);
+
+      broker.pass({'function':'MozMillRadio.select(' + this.getInfo() + ')'});
+
+      return true;
+    }
+  }
+});
+
+
+/**
+ * Returns true if node is of type MozMillRadio
+ *
+ * @static
+ * @param {DOMNode} node Node to check for its type
+ * @return {boolean} True if node is of type radio
+ */
+MozMillRadio.isType = function MMR_isType(node) {
+  return ((node.localName.toLowerCase() == 'input' && node.getAttribute('type') == 'radio') ||
+    (node.localName.toLowerCase() == 'toolbarbutton' && node.getAttribute('type') == 'radio') ||
+    (node.localName.toLowerCase() == 'radio') ||
+    (node.localName.toLowerCase() == 'radiogroup'));
+};
+
+
+/**
+ * MozMillDropList, which inherits from MozMillElement
+ */
+function MozMillDropList(locatorType, locator, args) {
+  MozMillElement.call(this, locatorType, locator, args);
+}
+
+
+MozMillDropList.prototype = Object.create(MozMillElement.prototype, {
+  select : {
+    /**
+     * Select the specified option and trigger the relevant events of the element
+     * @return {boolean}
+     */
+    value : function MMDL_select(index, option, value) {
+      if (!this.element){
+        throw new Error("Could not find element " + this.getInfo());
+      }
+
+      //if we have a select drop down
+      if (this.element.localName.toLowerCase() == "select"){
+        var item = null;
+
+        // The selected item should be set via its index
+        if (index != undefined) {
+          // Resetting a menulist has to be handled separately
+          if (index == -1) {
+            this.dispatchEvent('focus', false);
+            this.element.selectedIndex = index;
+            this.dispatchEvent('change', true);
+
+            broker.pass({'function':'MozMillDropList.select()'});
+
+            return true;
+          } else {
+            item = this.element.options.item(index);
+          }
+        } else {
+          for (var i = 0; i < this.element.options.length; i++) {
+            var entry = this.element.options.item(i);
+            if (option != undefined && entry.innerHTML == option ||
+              value != undefined && entry.value == value) {
+              item = entry;
+              break;
+            }
+          }
+        }
+
+        // Click the item
+        try {
+          // EventUtils.synthesizeMouse doesn't work.
+          this.dispatchEvent('focus', false);
+          item.selected = true;
+          this.dispatchEvent('change', true);
+
+          var self = this;
+          var selected = index || option || value;
+          assert.waitFor(function () {
+            switch (selected) {
+              case index:
+                return selected === self.element.selectedIndex;
+                break;
+              case option:
+                return selected === item.label;
+                break;
+              case value:
+                return selected === item.value;
+                break;
+            }
+          }, "DropList.select(): The correct item has been selected");
+
+          broker.pass({'function':'MozMillDropList.select()'});
+
+          return true;
+        } catch (e) {
+          throw new Error("No item selected for element " + this.getInfo());
+        }
+      }
+      //if we have a xul menupopup select accordingly
+      else if (this.element.namespaceURI.toLowerCase() == NAMESPACE_XUL) {
+        var ownerDoc = this.element.ownerDocument;
+        // Unwrap the XUL element's XPCNativeWrapper
+        this.element = utils.unwrapNode(this.element);
+        // Get the list of menuitems
+        var menuitems = this.element.
+                        getElementsByTagNameNS(NAMESPACE_XUL, "menupopup")[0].
+                        getElementsByTagNameNS(NAMESPACE_XUL, "menuitem");
+
+        var item = null;
+
+        if (index != undefined) {
+          if (index == -1) {
+            this.dispatchEvent('focus', false);
+            this.element.boxObject.QueryInterface(Ci.nsIMenuBoxObject).activeChild = null;
+            this.dispatchEvent('change', true);
+
+            broker.pass({'function':'MozMillDropList.select()'});
+
+            return true;
+          } else {
+            item = menuitems[index];
+          }
+        } else {
+          for (var i = 0; i < menuitems.length; i++) {
+            var entry = menuitems[i];
+            if (option != undefined && entry.label == option ||
+              value != undefined && entry.value == value) {
+              item = entry;
+              break;
+            }
+          }
+        }
+
+        // Click the item
+        try {
+          item.click();
+
+          var self = this;
+          var selected = index || option || value;
+          assert.waitFor(function () {
+            switch (selected) {
+              case index:
+                return selected === self.element.selectedIndex;
+                break;
+              case option:
+                return selected === self.element.label;
+                break;
+              case value:
+                return selected === self.element.value;
+                break;
+            }
+          }, "DropList.select(): The correct item has been selected");
+
+          broker.pass({'function':'MozMillDropList.select()'});
+
+          return true;
+        } catch (e) {
+          throw new Error('No item selected for element ' + this.getInfo());
+        }
+      }
+    }
+  }
+});
+
+
+/**
+ * Returns true if node is of type MozMillDropList
+ *
+ * @static
+ * @param {DOMNode} node Node to check for its type
+ * @return {boolean} True if node is of type dropdown list
+ */
+MozMillDropList.isType = function MMR_isType(node) {
+  return ((node.localName.toLowerCase() == 'toolbarbutton' &&
+    (node.getAttribute('type') == 'menu' || node.getAttribute('type') == 'menu-button')) ||
+    (node.localName.toLowerCase() == 'menu') ||
+    (node.localName.toLowerCase() == 'menulist') ||
+    (node.localName.toLowerCase() == 'select' ));
+};
+
+
+/**
+ * MozMillTextBox, which inherits from MozMillElement
+ */
+function MozMillTextBox(locatorType, locator, args) {
+  MozMillElement.call(this, locatorType, locator, args);
+}
+
+
+MozMillTextBox.prototype = Object.create(MozMillElement.prototype, {
+  sendKeys : {
+    /**
+     * Synthesize keypress events for each character on the given element
+     *
+     * @param {string} aText
+     *        The text to send as single keypress events
+     * @param {object} aModifiers
+     *        Information about the modifier keys to send
+     *        Elements: accelKey   - Hold down the accelerator key (ctrl/meta)
+     *